From 5646e7a0e791cdd143682eb026f57a8de7a82363 Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sun, 12 Jun 2022 18:30:33 +0530 Subject: [PATCH] feat: add test code to process apple user --- server/constants/signup_methods.go | 2 ++ server/handlers/oauth_callback.go | 56 ++++++++++++++++++++++++------ server/handlers/oauth_login.go | 25 ++++++++++--- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/server/constants/signup_methods.go b/server/constants/signup_methods.go index 7db56b7..279ccae 100644 --- a/server/constants/signup_methods.go +++ b/server/constants/signup_methods.go @@ -13,4 +13,6 @@ const ( SignupMethodFacebook = "facebook" // SignupMethodLinkedin is the linkedin signup method SignupMethodLinkedIn = "linkedin" + // SignupMethodApple is the apple signup method + SignupMethodApple = "apple" ) diff --git a/server/handlers/oauth_callback.go b/server/handlers/oauth_callback.go index 0ccc113..9201692 100644 --- a/server/handlers/oauth_callback.go +++ b/server/handlers/oauth_callback.go @@ -64,6 +64,8 @@ func OAuthCallbackHandler() gin.HandlerFunc { user, err = processFacebookUserInfo(code) case constants.SignupMethodLinkedIn: user, err = processLinkedInUserInfo(code) + case constants.SignupMethodApple: + user, err = processAppleUserInfo(code) default: log.Info("Invalid oauth provider") err = fmt.Errorf(`invalid oauth provider`) @@ -261,7 +263,7 @@ func processGoogleUserInfo(code string) (models.User, error) { func processGithubUserInfo(code string) (models.User, error) { user := models.User{} - token, err := oauth.OAuthProviders.GithubConfig.Exchange(oauth2.NoContext, code) + oauth2Token, err := oauth.OAuthProviders.GithubConfig.Exchange(oauth2.NoContext, code) if err != nil { log.Debug("Failed to exchange code for token: ", err) return user, fmt.Errorf("invalid github exchange code: %s", err.Error()) @@ -273,7 +275,7 @@ func processGithubUserInfo(code string) (models.User, error) { return user, fmt.Errorf("error creating github user info request: %s", err.Error()) } req.Header = http.Header{ - "Authorization": []string{fmt.Sprintf("token %s", token.AccessToken)}, + "Authorization": []string{fmt.Sprintf("token %s", oauth2Token.AccessToken)}, } response, err := client.Do(req) @@ -289,8 +291,8 @@ func processGithubUserInfo(code string) (models.User, error) { return user, fmt.Errorf("failed to read github response body: %s", err.Error()) } if response.StatusCode >= 400 { - log.Debug("Failed to request linkedin user info: ", string(body)) - return user, fmt.Errorf("failed to request linkedin user info: %s", string(body)) + log.Debug("Failed to request github user info: ", string(body)) + return user, fmt.Errorf("failed to request github user info: %s", string(body)) } userRawData := make(map[string]string) @@ -320,13 +322,13 @@ func processGithubUserInfo(code string) (models.User, error) { func processFacebookUserInfo(code string) (models.User, error) { user := models.User{} - token, err := oauth.OAuthProviders.FacebookConfig.Exchange(oauth2.NoContext, code) + oauth2Token, err := oauth.OAuthProviders.FacebookConfig.Exchange(oauth2.NoContext, code) if err != nil { log.Debug("Invalid facebook exchange code: ", err) return user, fmt.Errorf("invalid facebook exchange code: %s", err.Error()) } client := http.Client{} - req, err := http.NewRequest("GET", constants.FacebookUserInfoURL+token.AccessToken, nil) + req, err := http.NewRequest("GET", constants.FacebookUserInfoURL+oauth2Token.AccessToken, nil) if err != nil { log.Debug("Error creating facebook user info request: ", err) return user, fmt.Errorf("error creating facebook user info request: %s", err.Error()) @@ -345,8 +347,8 @@ func processFacebookUserInfo(code string) (models.User, error) { return user, fmt.Errorf("failed to read facebook response body: %s", err.Error()) } if response.StatusCode >= 400 { - log.Debug("Failed to request linkedin user info: ", string(body)) - return user, fmt.Errorf("failed to request linkedin user info: %s", string(body)) + log.Debug("Failed to request facebook user info: ", string(body)) + return user, fmt.Errorf("failed to request facebook user info: %s", string(body)) } userRawData := make(map[string]interface{}) json.Unmarshal(body, &userRawData) @@ -371,7 +373,7 @@ func processFacebookUserInfo(code string) (models.User, error) { func processLinkedInUserInfo(code string) (models.User, error) { user := models.User{} - token, err := oauth.OAuthProviders.LinkedInConfig.Exchange(oauth2.NoContext, code) + oauth2Token, err := oauth.OAuthProviders.LinkedInConfig.Exchange(oauth2.NoContext, code) if err != nil { log.Debug("Failed to exchange code for token: ", err) return user, fmt.Errorf("invalid linkedin exchange code: %s", err.Error()) @@ -384,7 +386,7 @@ func processLinkedInUserInfo(code string) (models.User, error) { return user, fmt.Errorf("error creating linkedin user info request: %s", err.Error()) } req.Header = http.Header{ - "Authorization": []string{fmt.Sprintf("Bearer %s", token.AccessToken)}, + "Authorization": []string{fmt.Sprintf("Bearer %s", oauth2Token.AccessToken)}, } response, err := client.Do(req) @@ -414,7 +416,7 @@ func processLinkedInUserInfo(code string) (models.User, error) { return user, fmt.Errorf("error creating linkedin user info request: %s", err.Error()) } req.Header = http.Header{ - "Authorization": []string{fmt.Sprintf("Bearer %s", token.AccessToken)}, + "Authorization": []string{fmt.Sprintf("Bearer %s", oauth2Token.AccessToken)}, } response, err = client.Do(req) @@ -450,3 +452,35 @@ func processLinkedInUserInfo(code string) (models.User, error) { return user, nil } + +func processAppleUserInfo(code string) (models.User, error) { + user := models.User{} + oauth2Token, err := oauth.OAuthProviders.AppleConfig.Exchange(oauth2.NoContext, code) + if err != nil { + log.Debug("Failed to exchange code for token: ", err) + return user, fmt.Errorf("invalid apple exchange code: %s", err.Error()) + } + + fmt.Println("=> token", oauth2Token.AccessToken) + + // Extract the ID Token from OAuth2 token. + rawIDToken, ok := oauth2Token.Extra("id_token").(string) + if !ok { + log.Debug("Failed to extract ID Token from OAuth2 token") + return user, fmt.Errorf("unable to extract id_token") + } + + fmt.Println("=> rawIDToken", rawIDToken) + + // Parse and verify ID Token payload. + claims, err := token.ParseJWTToken(rawIDToken) + if err != nil { + log.Debug("Failed to parse apple id token: ", err) + return user, err + } + fmt.Println("claims:", claims) + email := claims["email"].(string) + user.Email = email + + return user, err +} diff --git a/server/handlers/oauth_login.go b/server/handlers/oauth_login.go index f326928..614157b 100644 --- a/server/handlers/oauth_login.go +++ b/server/handlers/oauth_login.go @@ -114,7 +114,7 @@ func OAuthLoginHandler() gin.HandlerFunc { return } // during the init of OAuthProvider authorizer url might be empty - oauth.OAuthProviders.GoogleConfig.RedirectURL = hostname + "/oauth_callback/google" + oauth.OAuthProviders.GoogleConfig.RedirectURL = hostname + "/oauth_callback/" + constants.SignupMethodGoogle url := oauth.OAuthProviders.GoogleConfig.AuthCodeURL(oauthStateString) c.Redirect(http.StatusTemporaryRedirect, url) case constants.SignupMethodGithub: @@ -131,7 +131,7 @@ func OAuthLoginHandler() gin.HandlerFunc { }) return } - oauth.OAuthProviders.GithubConfig.RedirectURL = hostname + "/oauth_callback/github" + oauth.OAuthProviders.GithubConfig.RedirectURL = hostname + "/oauth_callback/" + constants.SignupMethodGithub url := oauth.OAuthProviders.GithubConfig.AuthCodeURL(oauthStateString) c.Redirect(http.StatusTemporaryRedirect, url) case constants.SignupMethodFacebook: @@ -148,7 +148,7 @@ func OAuthLoginHandler() gin.HandlerFunc { }) return } - oauth.OAuthProviders.FacebookConfig.RedirectURL = hostname + "/oauth_callback/facebook" + oauth.OAuthProviders.FacebookConfig.RedirectURL = hostname + "/oauth_callback/" + constants.SignupMethodFacebook url := oauth.OAuthProviders.FacebookConfig.AuthCodeURL(oauthStateString) c.Redirect(http.StatusTemporaryRedirect, url) case constants.SignupMethodLinkedIn: @@ -165,9 +165,26 @@ func OAuthLoginHandler() gin.HandlerFunc { }) return } - oauth.OAuthProviders.LinkedInConfig.RedirectURL = hostname + "/oauth_callback/linkedin" + oauth.OAuthProviders.LinkedInConfig.RedirectURL = hostname + "/oauth_callback/" + constants.SignupMethodLinkedIn url := oauth.OAuthProviders.LinkedInConfig.AuthCodeURL(oauthStateString) c.Redirect(http.StatusTemporaryRedirect, url) + case constants.SignupMethodApple: + if oauth.OAuthProviders.AppleConfig == nil { + log.Debug("Linkedin OAuth provider is not configured") + isProviderConfigured = false + break + } + err := memorystore.Provider.SetState(oauthStateString, constants.SignupMethodApple) + if err != nil { + log.Debug("Error setting state: ", err) + c.JSON(500, gin.H{ + "error": "internal server error", + }) + return + } + oauth.OAuthProviders.AppleConfig.RedirectURL = hostname + "/oauth_callback/" + constants.SignupMethodApple + url := oauth.OAuthProviders.AppleConfig.AuthCodeURL(oauthStateString) + c.Redirect(http.StatusTemporaryRedirect, url) default: log.Debug("Invalid oauth provider: ", provider) c.JSON(422, gin.H{