Add github login

Resolves #18
This commit is contained in:
Lakhan Samani 2021-07-18 04:48:42 +05:30
parent 245a5b5e1b
commit 7b16213e22
5 changed files with 149 additions and 66 deletions

View File

@ -10,27 +10,27 @@ import (
)
var (
ENV = ""
DB_TYPE = ""
DB_URL = ""
SMTP_HOST = ""
SMTP_PORT = ""
SENDER_EMAIL = ""
SENDER_PASSWORD = ""
JWT_TYPE = ""
JWT_SECRET = ""
FRONTEND_URL = ""
SERVER_URL = ""
PORT = "8080"
REDIS_URL = ""
IS_PROD = false
COOKIE_NAME = ""
GOOGLE_CLIENT_ID = ""
GOOGLE_CLIENT_SECRET = ""
GITHUB_CLIENT_ID = ""
GITHUB_CLIENT_SECRET = ""
FACEBOOK_CLIENT_ID = ""
FACEBOOK_CLIENT_SECRET = ""
ENV = ""
DB_TYPE = ""
DB_URL = ""
SMTP_HOST = ""
SMTP_PORT = ""
SENDER_EMAIL = ""
SENDER_PASSWORD = ""
JWT_TYPE = ""
JWT_SECRET = ""
FRONTEND_URL = ""
SERVER_URL = ""
PORT = "8080"
REDIS_URL = ""
IS_PROD = false
COOKIE_NAME = ""
GOOGLE_CLIENT_ID = ""
GOOGLE_CLIENT_SECRET = ""
GITHUB_CLIENT_ID = ""
GITHUB_CLIENT_SECRET = ""
// FACEBOOK_CLIENT_ID = ""
// FACEBOOK_CLIENT_SECRET = ""
)
func init() {
@ -57,8 +57,8 @@ func init() {
GOOGLE_CLIENT_SECRET = os.Getenv("GOOGLE_CLIENT_SECRET")
GITHUB_CLIENT_ID = os.Getenv("GITHUB_CLIENT_ID")
GITHUB_CLIENT_SECRET = os.Getenv("GITHUB_CLIENT_SECRET")
FACEBOOK_CLIENT_ID = os.Getenv("FACEBOOK_CLIENT_ID")
FACEBOOK_CLIENT_SECRET = os.Getenv("FACEBOOK_CLIENT_SECRET")
// FACEBOOK_CLIENT_ID = os.Getenv("FACEBOOK_CLIENT_ID")
// FACEBOOK_CLIENT_SECRET = os.Getenv("FACEBOOK_CLIENT_SECRET")
if ENV == "" {
ENV = "production"

View File

@ -44,43 +44,111 @@ func processGoogleUserInfo(state string, code string, c *gin.Context) error {
json.Unmarshal(body, &userRawData)
existingUser, err := db.Mgr.GetUserByEmail(userRawData["email"])
user := db.User{}
user := db.User{
FirstName: userRawData["given_name"],
LastName: userRawData["family_name"],
Image: userRawData["picture"],
Email: userRawData["email"],
EmailVerifiedAt: time.Now().Unix(),
}
if err != nil {
// user not registered, register user and generate session token
user = db.User{
FirstName: userRawData["given_name"],
LastName: userRawData["family_name"],
Image: userRawData["picture"],
Email: userRawData["email"],
EmailVerifiedAt: time.Now().Unix(),
SignupMethod: enum.Google.String(),
}
user, _ = db.Mgr.SaveUser(user)
user.SignupMethod = enum.Google.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.Google.String()) {
signupMethod += signupMethod + "," + enum.Google.String()
signupMethod = signupMethod + "," + enum.Google.String()
}
user = db.User{
FirstName: userRawData["given_name"],
LastName: userRawData["family_name"],
Image: userRawData["picture"],
Email: userRawData["email"],
EmailVerifiedAt: time.Now().Unix(),
SignupMethod: signupMethod,
Password: existingUser.Password,
}
user, _ = db.Mgr.SaveUser(user)
user.SignupMethod = signupMethod
user.Password = existingUser.Password
}
user, _ = db.Mgr.SaveUser(user)
userIdStr := fmt.Sprintf("%d", 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 processGithubUserInfo(state string, code string, c *gin.Context) error {
sessionState := session.GetToken(state)
if sessionState == "" {
return fmt.Errorf("invalid oauth state")
}
session.DeleteToken(sessionState)
token, err := oauth.OAuthProvider.GithubConfig.Exchange(oauth2.NoContext, code)
if err != nil {
return fmt.Errorf("invalid google exchange code: %s", err.Error())
}
client := http.Client{}
req, err := http.NewRequest("GET", constants.GithubUserInfoURL, nil)
if err != nil {
return fmt.Errorf("error creating github user info request: %s", err.Error())
}
req.Header = http.Header{
"Authorization": []string{fmt.Sprintf("token %s", token.AccessToken)},
}
response, err := client.Do(req)
if err != nil {
return err
}
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return fmt.Errorf("failed to read google response body: %s", err.Error())
}
userRawData := make(map[string]string)
json.Unmarshal(body, &userRawData)
existingUser, err := db.Mgr.GetUserByEmail(userRawData["email"])
name := strings.Split(userRawData["name"], " ")
firstName := ""
lastName := ""
if len(name) >= 1 && strings.TrimSpace(name[0]) != "" {
firstName = name[0]
}
if len(name) > 1 && strings.TrimSpace(name[1]) != "" {
lastName = name[0]
}
user := db.User{
FirstName: firstName,
LastName: lastName,
Image: userRawData["avatar_url"],
Email: userRawData["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)
userIdStr := fmt.Sprintf("%d", user.ID)
refreshToken, _, _ := utils.CreateAuthToken(utils.UserAuthInfo{
ID: userIdStr,
Email: user.Email,
@ -97,13 +165,18 @@ func processGoogleUserInfo(state string, code string, c *gin.Context) error {
func HandleOAuthCallback(provider enum.OAuthProvider) gin.HandlerFunc {
return func(c *gin.Context) {
var err error
if provider == enum.GoogleProvider {
err := processGoogleUserInfo(c.Request.FormValue("state"), c.Request.FormValue("code"), c)
if err != nil {
c.Redirect(http.StatusTemporaryRedirect, constants.FRONTEND_URL+"?error="+err.Error())
}
c.Redirect(http.StatusTemporaryRedirect, constants.FRONTEND_URL)
err = processGoogleUserInfo(c.Request.FormValue("state"), c.Request.FormValue("code"), c)
}
if provider == enum.GithubProvider {
err = processGithubUserInfo(c.Request.FormValue("state"), c.Request.FormValue("code"), c)
}
if err != nil {
c.Redirect(http.StatusTemporaryRedirect, constants.FRONTEND_URL+"?error="+err.Error())
}
c.Redirect(http.StatusTemporaryRedirect, constants.FRONTEND_URL)
}
}

View File

@ -20,5 +20,10 @@ func HandleOAuthLogin(provider enum.OAuthProvider) gin.HandlerFunc {
url := oauth.OAuthProvider.GoogleConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url)
}
if provider == enum.GithubProvider {
session.SetToken(oauthStateString, enum.Github.String())
url := oauth.OAuthProvider.GithubConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url)
}
}
}

View File

@ -3,15 +3,14 @@ package oauth
import (
"github.com/yauthdev/yauth/server/constants"
"golang.org/x/oauth2"
facebookOAuth2 "golang.org/x/oauth2/facebook"
githubOAuth2 "golang.org/x/oauth2/github"
googleOAuth2 "golang.org/x/oauth2/google"
)
type OAuthProviders struct {
GoogleConfig *oauth2.Config
GithubConfig *oauth2.Config
FacebookConfig *oauth2.Config
GoogleConfig *oauth2.Config
GithubConfig *oauth2.Config
// FacebookConfig *oauth2.Config
}
var OAuthProvider OAuthProviders
@ -27,19 +26,19 @@ func init() {
}
}
if constants.GITHUB_CLIENT_ID != "" && constants.GITHUB_CLIENT_SECRET != "" {
OAuthProvider.GoogleConfig = &oauth2.Config{
OAuthProvider.GithubConfig = &oauth2.Config{
ClientID: constants.GITHUB_CLIENT_ID,
ClientSecret: constants.GITHUB_CLIENT_SECRET,
RedirectURL: constants.SERVER_URL + "/callback/github",
Endpoint: githubOAuth2.Endpoint,
}
}
if constants.FACEBOOK_CLIENT_ID != "" && constants.FACEBOOK_CLIENT_SECRET != "" {
OAuthProvider.GoogleConfig = &oauth2.Config{
ClientID: constants.FACEBOOK_CLIENT_ID,
ClientSecret: constants.FACEBOOK_CLIENT_SECRET,
RedirectURL: constants.SERVER_URL + "/callback/facebook/",
Endpoint: facebookOAuth2.Endpoint,
}
}
// if constants.FACEBOOK_CLIENT_ID != "" && constants.FACEBOOK_CLIENT_SECRET != "" {
// OAuthProvider.FacebookConfig = &oauth2.Config{
// ClientID: constants.FACEBOOK_CLIENT_ID,
// ClientSecret: constants.FACEBOOK_CLIENT_SECRET,
// RedirectURL: constants.SERVER_URL + "/callback/facebook/",
// Endpoint: facebookOAuth2.Endpoint,
// }
// }
}

View File

@ -2,6 +2,7 @@ package main
import (
"context"
"log"
"github.com/gin-gonic/gin"
"github.com/yauthdev/yauth/server/enum"
@ -26,5 +27,10 @@ func main() {
r.GET("/login/google", handlers.HandleOAuthLogin(enum.GoogleProvider))
r.GET("/callback/google", handlers.HandleOAuthCallback(enum.GoogleProvider))
}
log.Println(oauth.OAuthProvider.GithubConfig)
if oauth.OAuthProvider.GithubConfig != nil {
r.GET("/login/github", handlers.HandleOAuthLogin(enum.GithubProvider))
r.GET("/callback/github", handlers.HandleOAuthCallback(enum.GithubProvider))
}
r.Run()
}