fix: auth flow
This commit is contained in:
@@ -29,7 +29,7 @@ func DeleteUserResolver(ctx context.Context, params model.DeleteUserInput) (*mod
|
||||
return res, err
|
||||
}
|
||||
|
||||
sessionstore.DeleteAllUserSession(fmt.Sprintf("%x", user.ID))
|
||||
go sessionstore.DeleteAllUserSession(fmt.Sprintf("%x", user.ID))
|
||||
|
||||
err = db.Provider.DeleteUser(user)
|
||||
if err != nil {
|
||||
|
@@ -39,7 +39,11 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
}
|
||||
|
||||
hostname := utils.GetHost(gc)
|
||||
verificationToken, err := token.CreateVerificationToken(params.Email, constants.VerificationTypeForgotPassword, hostname)
|
||||
nonce, nonceHash, err := utils.GenerateNonce()
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
verificationToken, err := token.CreateVerificationToken(params.Email, constants.VerificationTypeForgotPassword, hostname, nonceHash)
|
||||
if err != nil {
|
||||
log.Println(`error generating token`, err)
|
||||
}
|
||||
@@ -48,12 +52,11 @@ func ForgotPasswordResolver(ctx context.Context, params model.ForgotPasswordInpu
|
||||
Identifier: constants.VerificationTypeForgotPassword,
|
||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||
Email: params.Email,
|
||||
Nonce: nonce,
|
||||
})
|
||||
|
||||
// exec it as go routin so that we can reduce the api latency
|
||||
go func() {
|
||||
email.SendForgotPasswordMail(params.Email, verificationToken, hostname)
|
||||
}()
|
||||
go email.SendForgotPasswordMail(params.Email, verificationToken, hostname)
|
||||
|
||||
res = &model.Response{
|
||||
Message: `Please check your inbox! We have sent a password reset link.`,
|
||||
|
@@ -1,52 +0,0 @@
|
||||
package resolvers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/token"
|
||||
tokenHelper "github.com/authorizerdev/authorizer/server/token"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
)
|
||||
|
||||
// IsValidJwtResolver resolver to return if given jwt is valid
|
||||
func IsValidJwtResolver(ctx context.Context, params *model.IsValidJWTQueryInput) (*model.ValidJWTResponse, error) {
|
||||
gc, err := utils.GinContextFromContext(ctx)
|
||||
token, err := token.GetAccessToken(gc)
|
||||
|
||||
if token == "" || err != nil {
|
||||
if params != nil && *params.Jwt != "" {
|
||||
token = *params.Jwt
|
||||
} else {
|
||||
return nil, errors.New("no jwt provided via cookie / header / params")
|
||||
}
|
||||
}
|
||||
|
||||
claims, err := tokenHelper.ParseJWTToken(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
claimRoleInterface := claims[envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtRoleClaim)].([]interface{})
|
||||
claimRoles := []string{}
|
||||
for _, v := range claimRoleInterface {
|
||||
claimRoles = append(claimRoles, v.(string))
|
||||
}
|
||||
|
||||
if params != nil && params.Roles != nil && len(params.Roles) > 0 {
|
||||
for _, v := range params.Roles {
|
||||
if !utils.StringSliceContains(claimRoles, v) {
|
||||
return nil, fmt.Errorf(`unauthorized`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &model.ValidJWTResponse{
|
||||
Valid: true,
|
||||
Message: "Valid JWT",
|
||||
}, nil
|
||||
}
|
@@ -59,20 +59,36 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
|
||||
roles = params.Roles
|
||||
}
|
||||
|
||||
authToken, err := token.CreateAuthToken(user, roles)
|
||||
scope := []string{"openid", "email", "profile"}
|
||||
if params.Scope != nil && len(scope) > 0 {
|
||||
scope = params.Scope
|
||||
}
|
||||
|
||||
authToken, err := token.CreateAuthToken(gc, user, roles, scope)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
sessionstore.SetUserSession(user.ID, authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||
cookie.SetCookie(gc, authToken.AccessToken.Token, authToken.RefreshToken.Token, authToken.FingerPrintHash)
|
||||
utils.SaveSessionInDB(user.ID, gc)
|
||||
|
||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||
|
||||
expiresIn := int64(1800)
|
||||
res = &model.AuthResponse{
|
||||
Message: `Logged in successfully`,
|
||||
AccessToken: &authToken.AccessToken.Token,
|
||||
ExpiresAt: &authToken.AccessToken.ExpiresAt,
|
||||
IDToken: &authToken.IDToken.Token,
|
||||
ExpiresIn: &expiresIn,
|
||||
User: user.AsAPIUser(),
|
||||
}
|
||||
|
||||
sessionstore.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
||||
sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
||||
|
||||
if authToken.RefreshToken != nil {
|
||||
res.RefreshToken = &authToken.RefreshToken.Token
|
||||
sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
||||
}
|
||||
|
||||
go utils.SaveSessionInDB(gc, user.ID)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/authorizerdev/authorizer/server/crypto"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/sessionstore"
|
||||
"github.com/authorizerdev/authorizer/server/token"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
)
|
||||
|
||||
@@ -19,34 +18,21 @@ func LogoutResolver(ctx context.Context) (*model.Response, error) {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// get refresh token
|
||||
refreshToken, err := token.GetRefreshToken(gc)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// get fingerprint hash
|
||||
fingerprintHash, err := token.GetFingerPrint(gc)
|
||||
fingerprintHash, err := cookie.GetSession(gc)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
decryptedFingerPrint, err := crypto.DecryptAES([]byte(fingerprintHash))
|
||||
decryptedFingerPrint, err := crypto.DecryptAES(fingerprintHash)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
fingerPrint := string(decryptedFingerPrint)
|
||||
|
||||
// verify refresh token and fingerprint
|
||||
claims, err := token.ParseJWTToken(refreshToken)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
userID := claims["id"].(string)
|
||||
sessionstore.DeleteUserSession(userID, fingerPrint)
|
||||
cookie.DeleteCookie(gc)
|
||||
sessionstore.RemoveState(fingerPrint)
|
||||
cookie.DeleteSession(gc)
|
||||
|
||||
res = &model.Response{
|
||||
Message: "Logged out successfully",
|
||||
|
@@ -109,8 +109,12 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu
|
||||
hostname := utils.GetHost(gc)
|
||||
if !envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) {
|
||||
// insert verification request
|
||||
nonce, nonceHash, err := utils.GenerateNonce()
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
verificationType := constants.VerificationTypeMagicLinkLogin
|
||||
verificationToken, err := token.CreateVerificationToken(params.Email, verificationType, hostname)
|
||||
verificationToken, err := token.CreateVerificationToken(params.Email, verificationType, hostname, nonceHash)
|
||||
if err != nil {
|
||||
log.Println(`error generating token`, err)
|
||||
}
|
||||
@@ -119,12 +123,11 @@ func MagicLinkLoginResolver(ctx context.Context, params model.MagicLinkLoginInpu
|
||||
Identifier: verificationType,
|
||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||
Email: params.Email,
|
||||
Nonce: nonce,
|
||||
})
|
||||
|
||||
// exec it as go routin so that we can reduce the api latency
|
||||
go func() {
|
||||
email.SendVerificationMail(params.Email, verificationToken, hostname)
|
||||
}()
|
||||
go email.SendVerificationMail(params.Email, verificationToken, hostname)
|
||||
}
|
||||
|
||||
res = &model.Response{
|
||||
|
@@ -2,7 +2,6 @@ package resolvers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
@@ -18,13 +17,17 @@ func ProfileResolver(ctx context.Context) (*model.User, error) {
|
||||
return res, err
|
||||
}
|
||||
|
||||
claims, err := token.ValidateAccessToken(gc)
|
||||
accessToken, err := token.GetAccessToken(gc)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
userID := fmt.Sprintf("%v", claims["id"])
|
||||
claims, err := token.ValidateAccessToken(gc, accessToken)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
userID := claims["sub"].(string)
|
||||
user, err := db.Provider.GetUserByID(userID)
|
||||
if err != nil {
|
||||
return res, err
|
||||
|
@@ -44,7 +44,11 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma
|
||||
}
|
||||
|
||||
hostname := utils.GetHost(gc)
|
||||
verificationToken, err := token.CreateVerificationToken(params.Email, params.Identifier, hostname)
|
||||
nonce, nonceHash, err := utils.GenerateNonce()
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
verificationToken, err := token.CreateVerificationToken(params.Email, params.Identifier, hostname, nonceHash)
|
||||
if err != nil {
|
||||
log.Println(`error generating token`, err)
|
||||
}
|
||||
@@ -53,12 +57,11 @@ func ResendVerifyEmailResolver(ctx context.Context, params model.ResendVerifyEma
|
||||
Identifier: params.Identifier,
|
||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||
Email: params.Email,
|
||||
Nonce: nonce,
|
||||
})
|
||||
|
||||
// exec it as go routin so that we can reduce the api latency
|
||||
go func() {
|
||||
email.SendVerificationMail(params.Email, verificationToken, hostname)
|
||||
}()
|
||||
go email.SendVerificationMail(params.Email, verificationToken, hostname)
|
||||
|
||||
res = &model.Response{
|
||||
Message: `Verification email has been sent. Please check your inbox`,
|
||||
|
@@ -12,11 +12,16 @@ import (
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/token"
|
||||
"github.com/authorizerdev/authorizer/server/utils"
|
||||
)
|
||||
|
||||
// ResetPasswordResolver is a resolver for reset password mutation
|
||||
func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput) (*model.Response, error) {
|
||||
var res *model.Response
|
||||
gc, err := utils.GinContextFromContext(ctx)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
if envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) {
|
||||
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
|
||||
}
|
||||
@@ -31,12 +36,17 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput)
|
||||
}
|
||||
|
||||
// verify if token exists in db
|
||||
claim, err := token.ParseJWTToken(params.Token)
|
||||
hostname := utils.GetHost(gc)
|
||||
encryptedNonce, err := utils.EncryptNonce(verificationRequest.Nonce)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
claim, err := token.ParseJWTToken(params.Token, hostname, encryptedNonce, verificationRequest.Email)
|
||||
if err != nil {
|
||||
return res, fmt.Errorf(`invalid token`)
|
||||
}
|
||||
|
||||
user, err := db.Provider.GetUserByEmail(claim["email"].(string))
|
||||
user, err := db.Provider.GetUserByEmail(claim["sub"].(string))
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/cookie"
|
||||
"github.com/authorizerdev/authorizer/server/crypto"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/sessionstore"
|
||||
@@ -14,6 +13,7 @@ import (
|
||||
)
|
||||
|
||||
// SessionResolver is a resolver for session query
|
||||
// TODO allow validating with code and code verifier instead of cookie (PKCE flow)
|
||||
func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*model.AuthResponse, error) {
|
||||
var res *model.AuthResponse
|
||||
|
||||
@@ -22,48 +22,27 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
|
||||
return res, err
|
||||
}
|
||||
|
||||
// get refresh token
|
||||
refreshToken, err := token.GetRefreshToken(gc)
|
||||
sessionToken, err := cookie.GetSession(gc)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// get fingerprint hash
|
||||
fingerprintHash, err := token.GetFingerPrint(gc)
|
||||
// get session from cookie
|
||||
claims, err := token.ValidateBrowserSession(gc, sessionToken)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
decryptedFingerPrint, err := crypto.DecryptAES([]byte(fingerprintHash))
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
fingerPrint := string(decryptedFingerPrint)
|
||||
|
||||
// verify refresh token and fingerprint
|
||||
claims, err := token.ParseJWTToken(refreshToken)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
userID := claims["id"].(string)
|
||||
|
||||
persistedRefresh := sessionstore.GetUserSession(userID, fingerPrint)
|
||||
if refreshToken != persistedRefresh {
|
||||
return res, fmt.Errorf(`unauthorized`)
|
||||
}
|
||||
|
||||
userID := claims.Subject
|
||||
user, err := db.Provider.GetUserByID(userID)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// refresh token has "roles" as claim
|
||||
claimRoleInterface := claims["roles"].([]interface{})
|
||||
claimRoleInterface := claims.Roles
|
||||
claimRoles := []string{}
|
||||
for _, v := range claimRoleInterface {
|
||||
claimRoles = append(claimRoles, v.(string))
|
||||
claimRoles = append(claimRoles, v)
|
||||
}
|
||||
|
||||
if params != nil && params.Roles != nil && len(params.Roles) > 0 {
|
||||
@@ -74,22 +53,35 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
|
||||
}
|
||||
}
|
||||
|
||||
// delete older session
|
||||
sessionstore.DeleteUserSession(userID, fingerPrint)
|
||||
scope := []string{"openid", "email", "profile"}
|
||||
if params != nil && params.Scope != nil && len(scope) > 0 {
|
||||
scope = params.Scope
|
||||
}
|
||||
|
||||
authToken, err := token.CreateAuthToken(user, claimRoles)
|
||||
authToken, err := token.CreateAuthToken(gc, user, claimRoles, scope)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
sessionstore.SetUserSession(user.ID, authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||
cookie.SetCookie(gc, authToken.AccessToken.Token, authToken.RefreshToken.Token, authToken.FingerPrintHash)
|
||||
|
||||
// rollover the session for security
|
||||
sessionstore.RemoveState(sessionToken)
|
||||
sessionstore.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
||||
sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||
|
||||
expiresIn := int64(1800)
|
||||
res = &model.AuthResponse{
|
||||
Message: `Session token refreshed`,
|
||||
AccessToken: &authToken.AccessToken.Token,
|
||||
ExpiresAt: &authToken.AccessToken.ExpiresAt,
|
||||
ExpiresIn: &expiresIn,
|
||||
IDToken: &authToken.IDToken.Token,
|
||||
User: user.AsAPIUser(),
|
||||
}
|
||||
|
||||
if authToken.RefreshToken != nil {
|
||||
res.RefreshToken = &authToken.RefreshToken.Token
|
||||
sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
@@ -123,41 +123,48 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
|
||||
hostname := utils.GetHost(gc)
|
||||
if !envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) {
|
||||
// insert verification request
|
||||
verificationType := constants.VerificationTypeBasicAuthSignup
|
||||
verificationToken, err := token.CreateVerificationToken(params.Email, verificationType, hostname)
|
||||
nonce, nonceHash, err := utils.GenerateNonce()
|
||||
if err != nil {
|
||||
log.Println(`error generating token`, err)
|
||||
return res, err
|
||||
}
|
||||
verificationType := constants.VerificationTypeBasicAuthSignup
|
||||
verificationToken, err := token.CreateVerificationToken(params.Email, verificationType, hostname, nonceHash)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
db.Provider.AddVerificationRequest(models.VerificationRequest{
|
||||
Token: verificationToken,
|
||||
Identifier: verificationType,
|
||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||
Email: params.Email,
|
||||
Nonce: nonce,
|
||||
})
|
||||
|
||||
// exec it as go routin so that we can reduce the api latency
|
||||
go func() {
|
||||
email.SendVerificationMail(params.Email, verificationToken, hostname)
|
||||
}()
|
||||
go email.SendVerificationMail(params.Email, verificationToken, hostname)
|
||||
|
||||
res = &model.AuthResponse{
|
||||
Message: `Verification email has been sent. Please check your inbox`,
|
||||
User: userToReturn,
|
||||
}
|
||||
} else {
|
||||
scope := []string{"openid", "email", "profile"}
|
||||
|
||||
authToken, err := token.CreateAuthToken(user, roles)
|
||||
authToken, err := token.CreateAuthToken(gc, user, roles, scope)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
sessionstore.SetUserSession(user.ID, authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||
cookie.SetCookie(gc, authToken.AccessToken.Token, authToken.RefreshToken.Token, authToken.FingerPrintHash)
|
||||
utils.SaveSessionInDB(user.ID, gc)
|
||||
|
||||
sessionstore.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||
go utils.SaveSessionInDB(gc, user.ID)
|
||||
|
||||
expiresIn := int64(1800)
|
||||
|
||||
res = &model.AuthResponse{
|
||||
Message: `Signed up successfully.`,
|
||||
AccessToken: &authToken.AccessToken.Token,
|
||||
ExpiresAt: &authToken.AccessToken.ExpiresAt,
|
||||
ExpiresIn: &expiresIn,
|
||||
User: userToReturn,
|
||||
}
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/email"
|
||||
"github.com/authorizerdev/authorizer/server/envstore"
|
||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||
"github.com/authorizerdev/authorizer/server/sessionstore"
|
||||
"github.com/authorizerdev/authorizer/server/token"
|
||||
@@ -28,7 +29,11 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
||||
return res, err
|
||||
}
|
||||
|
||||
claims, err := token.ValidateAccessToken(gc)
|
||||
accessToken, err := token.GetAccessToken(gc)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
claims, err := token.ValidateAccessToken(gc, accessToken)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
@@ -38,8 +43,8 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
||||
return res, fmt.Errorf("please enter at least one param to update")
|
||||
}
|
||||
|
||||
userEmail := fmt.Sprintf("%v", claims["email"])
|
||||
user, err := db.Provider.GetUserByEmail(userEmail)
|
||||
userID := claims["sub"].(string)
|
||||
user, err := db.Provider.GetUserByID(userID)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
@@ -108,38 +113,44 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
||||
newEmail := strings.ToLower(*params.Email)
|
||||
// check if user with new email exists
|
||||
_, err := db.Provider.GetUserByEmail(newEmail)
|
||||
|
||||
// err = nil means user exists
|
||||
if err == nil {
|
||||
return res, fmt.Errorf("user with this email address already exists")
|
||||
}
|
||||
|
||||
sessionstore.DeleteAllUserSession(fmt.Sprintf("%v", user.ID))
|
||||
cookie.DeleteCookie(gc)
|
||||
// TODO figure out how to delete all user sessions
|
||||
go sessionstore.DeleteAllUserSession(user.ID)
|
||||
|
||||
hostname := utils.GetHost(gc)
|
||||
cookie.DeleteSession(gc)
|
||||
user.Email = newEmail
|
||||
user.EmailVerifiedAt = nil
|
||||
hasEmailChanged = true
|
||||
// insert verification request
|
||||
verificationType := constants.VerificationTypeUpdateEmail
|
||||
verificationToken, err := token.CreateVerificationToken(newEmail, verificationType, hostname)
|
||||
if err != nil {
|
||||
log.Println(`error generating token`, err)
|
||||
|
||||
if !envstore.EnvStoreObj.GetBoolStoreEnvVariable(constants.EnvKeyDisableEmailVerification) {
|
||||
hostname := utils.GetHost(gc)
|
||||
user.EmailVerifiedAt = nil
|
||||
hasEmailChanged = true
|
||||
// insert verification request
|
||||
nonce, nonceHash, err := utils.GenerateNonce()
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
verificationType := constants.VerificationTypeUpdateEmail
|
||||
verificationToken, err := token.CreateVerificationToken(newEmail, verificationType, hostname, nonceHash)
|
||||
if err != nil {
|
||||
log.Println(`error generating token`, err)
|
||||
}
|
||||
db.Provider.AddVerificationRequest(models.VerificationRequest{
|
||||
Token: verificationToken,
|
||||
Identifier: verificationType,
|
||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||
Email: newEmail,
|
||||
Nonce: nonce,
|
||||
})
|
||||
|
||||
// exec it as go routin so that we can reduce the api latency
|
||||
go email.SendVerificationMail(newEmail, verificationToken, hostname)
|
||||
|
||||
}
|
||||
db.Provider.AddVerificationRequest(models.VerificationRequest{
|
||||
Token: verificationToken,
|
||||
Identifier: verificationType,
|
||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||
Email: newEmail,
|
||||
})
|
||||
|
||||
// exec it as go routin so that we can reduce the api latency
|
||||
go func() {
|
||||
email.SendVerificationMail(newEmail, verificationToken, hostname)
|
||||
}()
|
||||
}
|
||||
|
||||
_, err = db.Provider.UpdateUser(user)
|
||||
if err != nil {
|
||||
log.Println("error updating user:", err)
|
||||
|
@@ -8,7 +8,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/authorizerdev/authorizer/server/constants"
|
||||
"github.com/authorizerdev/authorizer/server/cookie"
|
||||
"github.com/authorizerdev/authorizer/server/db"
|
||||
"github.com/authorizerdev/authorizer/server/db/models"
|
||||
"github.com/authorizerdev/authorizer/server/email"
|
||||
@@ -95,15 +94,19 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
||||
return res, fmt.Errorf("user with this email address already exists")
|
||||
}
|
||||
|
||||
sessionstore.DeleteAllUserSession(fmt.Sprintf("%v", user.ID))
|
||||
cookie.DeleteCookie(gc)
|
||||
// TODO figure out how to do this
|
||||
go sessionstore.DeleteAllUserSession(user.ID)
|
||||
|
||||
hostname := utils.GetHost(gc)
|
||||
user.Email = newEmail
|
||||
user.EmailVerifiedAt = nil
|
||||
// insert verification request
|
||||
nonce, nonceHash, err := utils.GenerateNonce()
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
verificationType := constants.VerificationTypeUpdateEmail
|
||||
verificationToken, err := token.CreateVerificationToken(newEmail, verificationType, hostname)
|
||||
verificationToken, err := token.CreateVerificationToken(newEmail, verificationType, hostname, nonceHash)
|
||||
if err != nil {
|
||||
log.Println(`error generating token`, err)
|
||||
}
|
||||
@@ -112,12 +115,12 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
||||
Identifier: verificationType,
|
||||
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(),
|
||||
Email: newEmail,
|
||||
Nonce: nonce,
|
||||
})
|
||||
|
||||
// exec it as go routin so that we can reduce the api latency
|
||||
go func() {
|
||||
email.SendVerificationMail(newEmail, verificationToken, hostname)
|
||||
}()
|
||||
go email.SendVerificationMail(newEmail, verificationToken, hostname)
|
||||
|
||||
}
|
||||
|
||||
rolesToSave := ""
|
||||
@@ -136,8 +139,7 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
||||
rolesToSave = strings.Join(inputRoles, ",")
|
||||
}
|
||||
|
||||
sessionstore.DeleteAllUserSession(fmt.Sprintf("%v", user.ID))
|
||||
cookie.DeleteCookie(gc)
|
||||
go sessionstore.DeleteAllUserSession(user.ID)
|
||||
}
|
||||
|
||||
if rolesToSave != "" {
|
||||
|
@@ -28,12 +28,17 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
|
||||
}
|
||||
|
||||
// verify if token exists in db
|
||||
claim, err := token.ParseJWTToken(params.Token)
|
||||
hostname := utils.GetHost(gc)
|
||||
encryptedNonce, err := utils.EncryptNonce(verificationRequest.Nonce)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
claim, err := token.ParseJWTToken(params.Token, hostname, encryptedNonce, verificationRequest.Email)
|
||||
if err != nil {
|
||||
return res, fmt.Errorf(`invalid token: %s`, err.Error())
|
||||
}
|
||||
|
||||
user, err := db.Provider.GetUserByEmail(claim["email"].(string))
|
||||
user, err := db.Provider.GetUserByEmail(claim["sub"].(string))
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
@@ -41,25 +46,35 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
|
||||
// update email_verified_at in users table
|
||||
now := time.Now().Unix()
|
||||
user.EmailVerifiedAt = &now
|
||||
db.Provider.UpdateUser(user)
|
||||
// delete from verification table
|
||||
db.Provider.DeleteVerificationRequest(verificationRequest)
|
||||
|
||||
roles := strings.Split(user.Roles, ",")
|
||||
authToken, err := token.CreateAuthToken(user, roles)
|
||||
user, err = db.Provider.UpdateUser(user)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
// delete from verification table
|
||||
err = db.Provider.DeleteVerificationRequest(verificationRequest)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
sessionstore.SetUserSession(user.ID, authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||
cookie.SetCookie(gc, authToken.AccessToken.Token, authToken.RefreshToken.Token, authToken.FingerPrintHash)
|
||||
utils.SaveSessionInDB(user.ID, gc)
|
||||
|
||||
roles := strings.Split(user.Roles, ",")
|
||||
scope := []string{"openid", "email", "profile"}
|
||||
authToken, err := token.CreateAuthToken(gc, user, roles, scope)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
sessionstore.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
|
||||
sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
|
||||
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||
go utils.SaveSessionInDB(gc, user.ID)
|
||||
|
||||
expiresIn := int64(1800)
|
||||
res = &model.AuthResponse{
|
||||
Message: `Email verified successfully.`,
|
||||
AccessToken: &authToken.AccessToken.Token,
|
||||
ExpiresAt: &authToken.AccessToken.ExpiresAt,
|
||||
IDToken: &authToken.IDToken.Token,
|
||||
ExpiresIn: &expiresIn,
|
||||
User: user.AsAPIUser(),
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user