feat: add facebook login

Resolves #36
This commit is contained in:
Lakhan Samani 2021-09-05 03:57:29 +05:30
parent af3222b5e0
commit 88d2195c0a
7 changed files with 132 additions and 67 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,21 +3,11 @@ import { useAuthorizer } from '@authorizerdev/authorizer-react';
export default function Dashboard() { export default function Dashboard() {
const [loading, setLoading] = React.useState(false); const [loading, setLoading] = React.useState(false);
const { user, setToken, graphQlRef } = useAuthorizer(); const { user, setToken, authorizerRef } = useAuthorizer();
const onLogout = async () => { const onLogout = async () => {
setLoading(true); setLoading(true);
await graphQlRef await authorizerRef.logout();
.mutation(
`
mutation {
logout {
message
}
}
`
)
.toPromise();
setToken(null); setToken(null);
setLoading(false); setLoading(false);
}; };

View File

@ -4,7 +4,7 @@ var (
// Ref: https://github.com/qor/auth/blob/master/providers/google/google.go // Ref: https://github.com/qor/auth/blob/master/providers/google/google.go
GoogleUserInfoURL = "https://www.googleapis.com/oauth2/v3/userinfo" GoogleUserInfoURL = "https://www.googleapis.com/oauth2/v3/userinfo"
// Ref: https://github.com/qor/auth/blob/master/providers/facebook/facebook.go#L18 // Ref: https://github.com/qor/auth/blob/master/providers/facebook/facebook.go#L18
FacebookUserInfoURL = "https://graph.facebook.com/me?access_token=" FacebookUserInfoURL = "https://graph.facebook.com/me?fields=id,first_name,last_name,name,email,picture&access_token="
// Ref: https://docs.github.com/en/developers/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#3-your-github-app-accesses-the-api-with-the-users-access-token // Ref: https://docs.github.com/en/developers/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#3-your-github-app-accesses-the-api-with-the-users-access-token
GithubUserInfoURL = "https://api.github.com/user" GithubUserInfoURL = "https://api.github.com/user"
) )

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -82,7 +83,7 @@ func processGoogleUserInfo(code string, c *gin.Context) error {
func processGithubUserInfo(code string, c *gin.Context) error { func processGithubUserInfo(code string, c *gin.Context) error {
token, err := oauth.OAuthProvider.GithubConfig.Exchange(oauth2.NoContext, code) token, err := oauth.OAuthProvider.GithubConfig.Exchange(oauth2.NoContext, code)
if err != nil { if err != nil {
return fmt.Errorf("invalid google exchange code: %s", err.Error()) return fmt.Errorf("invalid github exchange code: %s", err.Error())
} }
client := http.Client{} client := http.Client{}
req, err := http.NewRequest("GET", constants.GithubUserInfoURL, nil) req, err := http.NewRequest("GET", constants.GithubUserInfoURL, nil)
@ -101,7 +102,7 @@ func processGithubUserInfo(code string, c *gin.Context) error {
defer response.Body.Close() defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body) body, err := ioutil.ReadAll(response.Body)
if err != nil { if err != nil {
return fmt.Errorf("failed to read google response body: %s", err.Error()) return fmt.Errorf("failed to read github response body: %s", err.Error())
} }
userRawData := make(map[string]string) userRawData := make(map[string]string)
@ -156,6 +157,77 @@ func processGithubUserInfo(code string, c *gin.Context) error {
return nil return nil
} }
func processFacebookUserInfo(code string, c *gin.Context) error {
token, err := oauth.OAuthProvider.FacebookConfig.Exchange(oauth2.NoContext, code)
if err != nil {
return fmt.Errorf("invalid facebook exchange code: %s", err.Error())
}
client := http.Client{}
req, err := http.NewRequest("GET", constants.FacebookUserInfoURL+token.AccessToken, nil)
if err != nil {
return fmt.Errorf("error creating facebook user info request: %s", err.Error())
}
response, err := client.Do(req)
if err != nil {
log.Println("err:", err)
return err
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return fmt.Errorf("failed to read facebook response body: %s", err.Error())
}
userRawData := make(map[string]interface{})
json.Unmarshal(body, &userRawData)
email := fmt.Sprintf("%v", userRawData["email"])
existingUser, err := db.Mgr.GetUserByEmail(email)
picObject := userRawData["picture"].(map[string]interface{})["data"]
picDataObject := picObject.(map[string]interface{})
user := db.User{
FirstName: fmt.Sprintf("%v", userRawData["first_name"]),
LastName: fmt.Sprintf("%v", userRawData["last_name"]),
Image: fmt.Sprintf("%v", picDataObject["url"]),
Email: email,
EmailVerifiedAt: time.Now().Unix(),
}
if err != nil {
// user not registered, register user and generate session token
user.SignupMethod = enum.Github.String()
} else {
// user exists in db, check if method was google
// if not append google to existing signup method and save it
signupMethod := existingUser.SignupMethod
if !strings.Contains(signupMethod, enum.Github.String()) {
signupMethod = signupMethod + "," + enum.Github.String()
}
user.SignupMethod = signupMethod
user.Password = existingUser.Password
}
user, _ = db.Mgr.SaveUser(user)
user, _ = db.Mgr.GetUserByEmail(user.Email)
userIdStr := fmt.Sprintf("%v", user.ID)
refreshToken, _, _ := utils.CreateAuthToken(utils.UserAuthInfo{
ID: userIdStr,
Email: user.Email,
}, enum.RefreshToken)
accessToken, _, _ := utils.CreateAuthToken(utils.UserAuthInfo{
ID: userIdStr,
Email: user.Email,
}, enum.AccessToken)
utils.SetCookie(c, accessToken)
session.SetToken(userIdStr, refreshToken)
return nil
}
func OAuthCallbackHandler() gin.HandlerFunc { func OAuthCallbackHandler() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
provider := c.Param("oauth_provider") provider := c.Param("oauth_provider")
@ -181,6 +253,8 @@ func OAuthCallbackHandler() gin.HandlerFunc {
err = processGoogleUserInfo(code, c) err = processGoogleUserInfo(code, c)
case enum.Github.String(): case enum.Github.String():
err = processGithubUserInfo(code, c) err = processGithubUserInfo(code, c)
case enum.Facebook.String():
err = processFacebookUserInfo(code, c)
default: default:
err = fmt.Errorf(`invalid oauth provider`) err = fmt.Errorf(`invalid oauth provider`)
} }

View File

@ -41,6 +41,11 @@ func OAuthLoginHandler() gin.HandlerFunc {
oauth.OAuthProvider.GithubConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/github" oauth.OAuthProvider.GithubConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/github"
url := oauth.OAuthProvider.GithubConfig.AuthCodeURL(oauthStateString) url := oauth.OAuthProvider.GithubConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url) c.Redirect(http.StatusTemporaryRedirect, url)
case enum.Facebook.String():
session.SetToken(oauthStateString, enum.Github.String())
oauth.OAuthProvider.FacebookConfig.RedirectURL = constants.AUTHORIZER_URL + "/oauth_callback/facebook"
url := oauth.OAuthProvider.FacebookConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url)
default: default:
c.JSON(422, gin.H{ c.JSON(422, gin.H{
"message": "Invalid oauth provider", "message": "Invalid oauth provider",

View File

@ -3,6 +3,7 @@ package oauth
import ( import (
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"golang.org/x/oauth2" "golang.org/x/oauth2"
facebookOAuth2 "golang.org/x/oauth2/facebook"
githubOAuth2 "golang.org/x/oauth2/github" githubOAuth2 "golang.org/x/oauth2/github"
googleOAuth2 "golang.org/x/oauth2/google" googleOAuth2 "golang.org/x/oauth2/google"
) )
@ -10,7 +11,7 @@ import (
type OAuthProviders struct { type OAuthProviders struct {
GoogleConfig *oauth2.Config GoogleConfig *oauth2.Config
GithubConfig *oauth2.Config GithubConfig *oauth2.Config
// FacebookConfig *oauth2.Config FacebookConfig *oauth2.Config
} }
var OAuthProvider OAuthProviders var OAuthProvider OAuthProviders
@ -33,12 +34,13 @@ func InitOAuth() {
Endpoint: githubOAuth2.Endpoint, Endpoint: githubOAuth2.Endpoint,
} }
} }
// if constants.FACEBOOK_CLIENT_ID != "" && constants.FACEBOOK_CLIENT_SECRET != "" { if constants.FACEBOOK_CLIENT_ID != "" && constants.FACEBOOK_CLIENT_SECRET != "" {
// OAuthProvider.FacebookConfig = &oauth2.Config{ OAuthProvider.FacebookConfig = &oauth2.Config{
// ClientID: constants.FACEBOOK_CLIENT_ID, ClientID: constants.FACEBOOK_CLIENT_ID,
// ClientSecret: constants.FACEBOOK_CLIENT_SECRET, ClientSecret: constants.FACEBOOK_CLIENT_SECRET,
// RedirectURL: "/oauth_callback/facebook/", RedirectURL: constants.AUTHORIZER_URL + "/oauth_callback/facebook",
// Endpoint: facebookOAuth2.Endpoint, Endpoint: facebookOAuth2.Endpoint,
// } Scopes: []string{"public_profile", "email"},
// } }
}
} }