From 8259fb515cb5959aa8dbe48976584b5dcf80df0e Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sat, 12 Feb 2022 15:54:23 +0530 Subject: [PATCH 1/4] Add support for more JWT algo methods --- server/constants/env.go | 4 ++ server/env/env.go | 78 +++++++++++++++------------- server/handlers/verify_email.go | 6 +-- server/resolvers/is_valid_jwt.go | 2 +- server/resolvers/logout.go | 2 +- server/resolvers/reset_password.go | 4 +- server/resolvers/session.go | 2 +- server/resolvers/verify_email.go | 4 +- server/token/auth_token.go | 42 ++------------- server/token/jwt.go | 83 ++++++++++++++++++++++++++++++ server/token/verification_token.go | 44 +++------------- 11 files changed, 151 insertions(+), 120 deletions(-) create mode 100644 server/token/jwt.go diff --git a/server/constants/env.go b/server/constants/env.go index f36f278..e36c5e3 100644 --- a/server/constants/env.go +++ b/server/constants/env.go @@ -43,6 +43,10 @@ const ( EnvKeyJwtType = "JWT_TYPE" // EnvKeyJwtSecret key for env variable JWT_SECRET EnvKeyJwtSecret = "JWT_SECRET" + // EnvKeyJwtPrivateKey key for env variable JWT_PRIVATE_KEY + EnvKeyJwtPrivateKey = "JWT_PRIVATE_KEY" + // EnvKeyJwtPublicKey key for env variable JWT_PUBLIC_KEY + EnvKeyJwtPublicKey = "JWT_PUBLIC_KEY" // EnvKeyAllowedOrigins key for env variable ALLOWED_ORIGINS EnvKeyAllowedOrigins = "ALLOWED_ORIGINS" // EnvKeyAppURL key for env variable APP_URL diff --git a/server/env/env.go b/server/env/env.go index 7e65e9f..9658e8b 100644 --- a/server/env/env.go +++ b/server/env/env.go @@ -19,7 +19,7 @@ func InitEnv() { envData := envstore.EnvInMemoryStoreObj.GetEnvStoreClone() if envData.StringEnv[constants.EnvKeyEnv] == "" { - envData.StringEnv[constants.EnvKeyEnv] = os.Getenv("ENV") + envData.StringEnv[constants.EnvKeyEnv] = os.Getenv(constants.EnvKeyEnv) if envData.StringEnv[constants.EnvKeyEnv] == "" { envData.StringEnv[constants.EnvKeyEnv] = "production" } @@ -50,18 +50,18 @@ func InitEnv() { } if envData.StringEnv[constants.EnvKeyPort] == "" { - envData.StringEnv[constants.EnvKeyPort] = os.Getenv("PORT") + envData.StringEnv[constants.EnvKeyPort] = os.Getenv(constants.EnvKeyPort) if envData.StringEnv[constants.EnvKeyPort] == "" { envData.StringEnv[constants.EnvKeyPort] = "8080" } } if envData.StringEnv[constants.EnvKeyAdminSecret] == "" { - envData.StringEnv[constants.EnvKeyAdminSecret] = os.Getenv("ADMIN_SECRET") + envData.StringEnv[constants.EnvKeyAdminSecret] = os.Getenv(constants.EnvKeyAdminSecret) } if envData.StringEnv[constants.EnvKeyDatabaseType] == "" { - envData.StringEnv[constants.EnvKeyDatabaseType] = os.Getenv("DATABASE_TYPE") + envData.StringEnv[constants.EnvKeyDatabaseType] = os.Getenv(constants.EnvKeyDatabaseType) if envstore.ARG_DB_TYPE != nil && *envstore.ARG_DB_TYPE != "" { envData.StringEnv[constants.EnvKeyDatabaseType] = *envstore.ARG_DB_TYPE @@ -73,7 +73,7 @@ func InitEnv() { } if envData.StringEnv[constants.EnvKeyDatabaseURL] == "" { - envData.StringEnv[constants.EnvKeyDatabaseURL] = os.Getenv("DATABASE_URL") + envData.StringEnv[constants.EnvKeyDatabaseURL] = os.Getenv(constants.EnvKeyDatabaseURL) if envstore.ARG_DB_URL != nil && *envstore.ARG_DB_URL != "" { envData.StringEnv[constants.EnvKeyDatabaseURL] = *envstore.ARG_DB_URL @@ -85,48 +85,56 @@ func InitEnv() { } if envData.StringEnv[constants.EnvKeyDatabaseName] == "" { - envData.StringEnv[constants.EnvKeyDatabaseName] = os.Getenv("DATABASE_NAME") + envData.StringEnv[constants.EnvKeyDatabaseName] = os.Getenv(constants.EnvKeyDatabaseName) if envData.StringEnv[constants.EnvKeyDatabaseName] == "" { envData.StringEnv[constants.EnvKeyDatabaseName] = "authorizer" } } if envData.StringEnv[constants.EnvKeySmtpHost] == "" { - envData.StringEnv[constants.EnvKeySmtpHost] = os.Getenv("SMTP_HOST") + envData.StringEnv[constants.EnvKeySmtpHost] = os.Getenv(constants.EnvKeySmtpHost) } if envData.StringEnv[constants.EnvKeySmtpPort] == "" { - envData.StringEnv[constants.EnvKeySmtpPort] = os.Getenv("SMTP_PORT") + envData.StringEnv[constants.EnvKeySmtpPort] = os.Getenv(constants.EnvKeySmtpPort) } if envData.StringEnv[constants.EnvKeySmtpUsername] == "" { - envData.StringEnv[constants.EnvKeySmtpUsername] = os.Getenv("SMTP_USERNAME") + envData.StringEnv[constants.EnvKeySmtpUsername] = os.Getenv(constants.EnvKeySmtpUsername) } if envData.StringEnv[constants.EnvKeySmtpPassword] == "" { - envData.StringEnv[constants.EnvKeySmtpPassword] = os.Getenv("SMTP_PASSWORD") + envData.StringEnv[constants.EnvKeySmtpPassword] = os.Getenv(constants.EnvKeySmtpPassword) } if envData.StringEnv[constants.EnvKeySenderEmail] == "" { - envData.StringEnv[constants.EnvKeySenderEmail] = os.Getenv("SENDER_EMAIL") + envData.StringEnv[constants.EnvKeySenderEmail] = os.Getenv(constants.EnvKeySenderEmail) } if envData.StringEnv[constants.EnvKeyJwtSecret] == "" { - envData.StringEnv[constants.EnvKeyJwtSecret] = os.Getenv("JWT_SECRET") + envData.StringEnv[constants.EnvKeyJwtSecret] = os.Getenv(constants.EnvKeyJwtSecret) if envData.StringEnv[constants.EnvKeyJwtSecret] == "" { envData.StringEnv[constants.EnvKeyJwtSecret] = uuid.New().String() } } + if envData.StringEnv[constants.EnvKeyJwtPrivateKey] == "" { + envData.StringEnv[constants.EnvKeyJwtPrivateKey] = os.Getenv(constants.EnvKeyJwtPrivateKey) + } + + if envData.StringEnv[constants.EnvKeyJwtPublicKey] == "" { + envData.StringEnv[constants.EnvKeyJwtPublicKey] = os.Getenv(constants.EnvKeyJwtPublicKey) + } + if envData.StringEnv[constants.EnvKeyJwtType] == "" { - envData.StringEnv[constants.EnvKeyJwtType] = os.Getenv("JWT_TYPE") + envData.StringEnv[constants.EnvKeyJwtType] = os.Getenv(constants.EnvKeyJwtType) if envData.StringEnv[constants.EnvKeyJwtType] == "" { envData.StringEnv[constants.EnvKeyJwtType] = "HS256" } } if envData.StringEnv[constants.EnvKeyJwtRoleClaim] == "" { - envData.StringEnv[constants.EnvKeyJwtRoleClaim] = os.Getenv("JWT_ROLE_CLAIM") + envData.StringEnv[constants.EnvKeyJwtRoleClaim] = os.Getenv(constants.EnvKeyJwtRoleClaim) if envData.StringEnv[constants.EnvKeyJwtRoleClaim] == "" { envData.StringEnv[constants.EnvKeyJwtRoleClaim] = "role" @@ -134,48 +142,48 @@ func InitEnv() { } if envData.StringEnv[constants.EnvKeyRedisURL] == "" { - envData.StringEnv[constants.EnvKeyRedisURL] = os.Getenv("REDIS_URL") + envData.StringEnv[constants.EnvKeyRedisURL] = os.Getenv(constants.EnvKeyRedisURL) } if envData.StringEnv[constants.EnvKeyCookieName] == "" { - envData.StringEnv[constants.EnvKeyCookieName] = os.Getenv("COOKIE_NAME") + envData.StringEnv[constants.EnvKeyCookieName] = os.Getenv(constants.EnvKeyCookieName) if envData.StringEnv[constants.EnvKeyCookieName] == "" { envData.StringEnv[constants.EnvKeyCookieName] = "authorizer" } } if envData.StringEnv[constants.EnvKeyGoogleClientID] == "" { - envData.StringEnv[constants.EnvKeyGoogleClientID] = os.Getenv("GOOGLE_CLIENT_ID") + envData.StringEnv[constants.EnvKeyGoogleClientID] = os.Getenv(constants.EnvKeyGoogleClientID) } if envData.StringEnv[constants.EnvKeyGoogleClientSecret] == "" { - envData.StringEnv[constants.EnvKeyGoogleClientSecret] = os.Getenv("GOOGLE_CLIENT_SECRET") + envData.StringEnv[constants.EnvKeyGoogleClientSecret] = os.Getenv(constants.EnvKeyGoogleClientSecret) } if envData.StringEnv[constants.EnvKeyGithubClientID] == "" { - envData.StringEnv[constants.EnvKeyGithubClientID] = os.Getenv("GITHUB_CLIENT_ID") + envData.StringEnv[constants.EnvKeyGithubClientID] = os.Getenv(constants.EnvKeyGithubClientID) } if envData.StringEnv[constants.EnvKeyGithubClientSecret] == "" { - envData.StringEnv[constants.EnvKeyGithubClientSecret] = os.Getenv("GITHUB_CLIENT_SECRET") + envData.StringEnv[constants.EnvKeyGithubClientSecret] = os.Getenv(constants.EnvKeyGithubClientSecret) } if envData.StringEnv[constants.EnvKeyFacebookClientID] == "" { - envData.StringEnv[constants.EnvKeyFacebookClientID] = os.Getenv("FACEBOOK_CLIENT_ID") + envData.StringEnv[constants.EnvKeyFacebookClientID] = os.Getenv(constants.EnvKeyFacebookClientID) } if envData.StringEnv[constants.EnvKeyFacebookClientSecret] == "" { - envData.StringEnv[constants.EnvKeyFacebookClientSecret] = os.Getenv("FACEBOOK_CLIENT_SECRET") + envData.StringEnv[constants.EnvKeyFacebookClientSecret] = os.Getenv(constants.EnvKeyFacebookClientSecret) } if envData.StringEnv[constants.EnvKeyResetPasswordURL] == "" { - envData.StringEnv[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(os.Getenv("RESET_PASSWORD_URL"), "/") + envData.StringEnv[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(os.Getenv(constants.EnvKeyResetPasswordURL), "/") } - envData.BoolEnv[constants.EnvKeyDisableBasicAuthentication] = os.Getenv("DISABLE_BASIC_AUTHENTICATION") == "true" - envData.BoolEnv[constants.EnvKeyDisableEmailVerification] = os.Getenv("DISABLE_EMAIL_VERIFICATION") == "true" - envData.BoolEnv[constants.EnvKeyDisableMagicLinkLogin] = os.Getenv("DISABLE_MAGIC_LINK_LOGIN") == "true" - envData.BoolEnv[constants.EnvKeyDisableLoginPage] = os.Getenv("DISABLE_LOGIN_PAGE") == "true" + envData.BoolEnv[constants.EnvKeyDisableBasicAuthentication] = os.Getenv(constants.EnvKeyDisableBasicAuthentication) == "true" + envData.BoolEnv[constants.EnvKeyDisableEmailVerification] = os.Getenv(constants.EnvKeyDisableEmailVerification) == "true" + envData.BoolEnv[constants.EnvKeyDisableMagicLinkLogin] = os.Getenv(constants.EnvKeyDisableMagicLinkLogin) == "true" + envData.BoolEnv[constants.EnvKeyDisableLoginPage] = os.Getenv(constants.EnvKeyDisableLoginPage) == "true" // no need to add nil check as its already done above if envData.StringEnv[constants.EnvKeySmtpHost] == "" || envData.StringEnv[constants.EnvKeySmtpUsername] == "" || envData.StringEnv[constants.EnvKeySmtpPassword] == "" || envData.StringEnv[constants.EnvKeySenderEmail] == "" && envData.StringEnv[constants.EnvKeySmtpPort] == "" { @@ -187,7 +195,7 @@ func InitEnv() { envData.BoolEnv[constants.EnvKeyDisableMagicLinkLogin] = true } - allowedOriginsSplit := strings.Split(os.Getenv("ALLOWED_ORIGINS"), ",") + allowedOriginsSplit := strings.Split(os.Getenv(constants.EnvKeyAllowedOrigins), ",") allowedOrigins := []string{} hasWildCard := false @@ -215,14 +223,14 @@ func InitEnv() { envData.SliceEnv[constants.EnvKeyAllowedOrigins] = allowedOrigins - rolesEnv := strings.TrimSpace(os.Getenv("ROLES")) + rolesEnv := strings.TrimSpace(os.Getenv(constants.EnvKeyRoles)) rolesSplit := strings.Split(rolesEnv, ",") roles := []string{} if len(rolesEnv) == 0 { roles = []string{"user"} } - defaultRolesEnv := strings.TrimSpace(os.Getenv("DEFAULT_ROLES")) + defaultRolesEnv := strings.TrimSpace(os.Getenv(constants.EnvKeyDefaultRoles)) defaultRoleSplit := strings.Split(defaultRolesEnv, ",") defaultRoles := []string{} @@ -230,7 +238,7 @@ func InitEnv() { defaultRoles = []string{"user"} } - protectedRolesEnv := strings.TrimSpace(os.Getenv("PROTECTED_ROLES")) + protectedRolesEnv := strings.TrimSpace(os.Getenv(constants.EnvKeyProtectedRoles)) protectedRolesSplit := strings.Split(protectedRolesEnv, ",") protectedRoles := []string{} @@ -259,12 +267,12 @@ func InitEnv() { envData.SliceEnv[constants.EnvKeyDefaultRoles] = defaultRoles envData.SliceEnv[constants.EnvKeyProtectedRoles] = protectedRoles - if os.Getenv("ORGANIZATION_NAME") != "" { - envData.StringEnv[constants.EnvKeyOrganizationName] = os.Getenv("ORGANIZATION_NAME") + if os.Getenv(constants.EnvKeyOrganizationName) != "" { + envData.StringEnv[constants.EnvKeyOrganizationName] = os.Getenv(constants.EnvKeyOrganizationName) } - if os.Getenv("ORGANIZATION_LOGO") != "" { - envData.StringEnv[constants.EnvKeyOrganizationLogo] = os.Getenv("ORGANIZATION_LOGO") + if os.Getenv(constants.EnvKeyOrganizationLogo) != "" { + envData.StringEnv[constants.EnvKeyOrganizationLogo] = os.Getenv(constants.EnvKeyOrganizationLogo) } envstore.EnvInMemoryStoreObj.UpdateEnvStore(envData) diff --git a/server/handlers/verify_email.go b/server/handlers/verify_email.go index a2d7644..9aecff4 100644 --- a/server/handlers/verify_email.go +++ b/server/handlers/verify_email.go @@ -33,13 +33,13 @@ func VerifyEmailHandler() gin.HandlerFunc { } // verify if token exists in db - claim, err := token.VerifyVerificationToken(tokenInQuery) + claim, err := token.ParseJWTToken(tokenInQuery) if err != nil { c.JSON(400, errorRes) return } - user, err := db.Provider.GetUserByEmail(claim.Email) + user, err := db.Provider.GetUserByEmail(claim["email"].(string)) if err != nil { c.JSON(400, gin.H{ "message": err.Error(), @@ -68,6 +68,6 @@ func VerifyEmailHandler() gin.HandlerFunc { cookie.SetCookie(c, authToken.AccessToken.Token, authToken.RefreshToken.Token, authToken.FingerPrintHash) utils.SaveSessionInDB(user.ID, c) - c.Redirect(http.StatusTemporaryRedirect, claim.RedirectURL) + c.Redirect(http.StatusTemporaryRedirect, claim["redirect_url"].(string)) } } diff --git a/server/resolvers/is_valid_jwt.go b/server/resolvers/is_valid_jwt.go index 7061dcf..f9e33e3 100644 --- a/server/resolvers/is_valid_jwt.go +++ b/server/resolvers/is_valid_jwt.go @@ -26,7 +26,7 @@ func IsValidJwtResolver(ctx context.Context, params *model.IsValidJWTQueryInput) } } - claims, err := tokenHelper.VerifyJWTToken(token) + claims, err := tokenHelper.ParseJWTToken(token) if err != nil { return nil, err } diff --git a/server/resolvers/logout.go b/server/resolvers/logout.go index 0926e70..4653896 100644 --- a/server/resolvers/logout.go +++ b/server/resolvers/logout.go @@ -38,7 +38,7 @@ func LogoutResolver(ctx context.Context) (*model.Response, error) { fingerPrint := string(decryptedFingerPrint) // verify refresh token and fingerprint - claims, err := token.VerifyJWTToken(refreshToken) + claims, err := token.ParseJWTToken(refreshToken) if err != nil { return res, err } diff --git a/server/resolvers/reset_password.go b/server/resolvers/reset_password.go index cc482b8..d48ae4b 100644 --- a/server/resolvers/reset_password.go +++ b/server/resolvers/reset_password.go @@ -31,12 +31,12 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput) } // verify if token exists in db - claim, err := token.VerifyVerificationToken(params.Token) + claim, err := token.ParseJWTToken(params.Token) if err != nil { return res, fmt.Errorf(`invalid token`) } - user, err := db.Provider.GetUserByEmail(claim.Email) + user, err := db.Provider.GetUserByEmail(claim["email"].(string)) if err != nil { return res, err } diff --git a/server/resolvers/session.go b/server/resolvers/session.go index 175fcf9..e390b5a 100644 --- a/server/resolvers/session.go +++ b/server/resolvers/session.go @@ -41,7 +41,7 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod fingerPrint := string(decryptedFingerPrint) // verify refresh token and fingerprint - claims, err := token.VerifyJWTToken(refreshToken) + claims, err := token.ParseJWTToken(refreshToken) if err != nil { return res, err } diff --git a/server/resolvers/verify_email.go b/server/resolvers/verify_email.go index 7b57950..883ba08 100644 --- a/server/resolvers/verify_email.go +++ b/server/resolvers/verify_email.go @@ -28,12 +28,12 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m } // verify if token exists in db - claim, err := token.VerifyVerificationToken(params.Token) + claim, err := token.ParseJWTToken(params.Token) if err != nil { return res, fmt.Errorf(`invalid token`) } - user, err := db.Provider.GetUserByEmail(claim.Email) + user, err := db.Provider.GetUserByEmail(claim["email"].(string)) if err != nil { return res, err } diff --git a/server/token/auth_token.go b/server/token/auth_token.go index 0eb4542..1d8c988 100644 --- a/server/token/auth_token.go +++ b/server/token/auth_token.go @@ -62,7 +62,6 @@ func CreateAuthToken(user models.User, roles []string) (*Token, error) { // CreateRefreshToken util to create JWT token func CreateRefreshToken(user models.User, roles []string) (string, int64, error) { - t := jwt.New(jwt.GetSigningMethod(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType))) // expires in 1 year expiryBound := time.Hour * 8760 expiresAt := time.Now().Add(expiryBound).Unix() @@ -75,8 +74,7 @@ func CreateRefreshToken(user models.User, roles []string) (string, int64, error) "id": user.ID, } - t.Claims = customClaims - token, err := t.SignedString([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret))) + token, err := SignJWTToken(customClaims) if err != nil { return "", 0, err } @@ -86,9 +84,7 @@ func CreateRefreshToken(user models.User, roles []string) (string, int64, error) // CreateAccessToken util to create JWT token, based on // user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT func CreateAccessToken(user models.User, roles []string) (string, int64, error) { - t := jwt.New(jwt.GetSigningMethod(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType))) expiryBound := time.Minute * 30 - expiresAt := time.Now().Add(expiryBound).Unix() resUser := user.AsAPIUser() @@ -141,9 +137,7 @@ func CreateAccessToken(user models.User, roles []string) (string, int64, error) } } - t.Claims = customClaims - - token, err := t.SignedString([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret))) + token, err := SignJWTToken(customClaims) if err != nil { return "", 0, err } @@ -187,43 +181,13 @@ func GetFingerPrint(gc *gin.Context) (string, error) { return fingerPrint, nil } -// VerifyJWTToken helps in verifying the JWT token -func VerifyJWTToken(token string) (map[string]interface{}, error) { - var res map[string]interface{} - claims := jwt.MapClaims{} - - t, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) { - return []byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret)), nil - }) - if err != nil { - return res, err - } - - if !t.Valid { - return res, fmt.Errorf(`invalid token`) - } - - // claim parses exp & iat into float 64 with e^10, - // but we expect it to be int64 - // hence we need to assert interface and convert to int64 - intExp := int64(claims["exp"].(float64)) - intIat := int64(claims["iat"].(float64)) - - data, _ := json.Marshal(claims) - json.Unmarshal(data, &res) - res["exp"] = intExp - res["iat"] = intIat - - return res, nil -} - func ValidateAccessToken(gc *gin.Context) (map[string]interface{}, error) { token, err := GetAccessToken(gc) if err != nil { return nil, err } - claims, err := VerifyJWTToken(token) + claims, err := ParseJWTToken(token) if err != nil { return nil, err } diff --git a/server/token/jwt.go b/server/token/jwt.go new file mode 100644 index 0000000..6c517b1 --- /dev/null +++ b/server/token/jwt.go @@ -0,0 +1,83 @@ +package token + +import ( + "errors" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/envstore" + "github.com/golang-jwt/jwt" +) + +// SignJWTToken common util to sing jwt token +func SignJWTToken(claims jwt.MapClaims) (string, error) { + jwtType := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType) + signingMethod := jwt.GetSigningMethod(jwtType) + t := jwt.New(signingMethod) + t.Claims = claims + + switch signingMethod { + case jwt.SigningMethodHS256, jwt.SigningMethodHS384, jwt.SigningMethodHS512: + return t.SignedString([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret))) + case jwt.SigningMethodRS256, jwt.SigningMethodRS384, jwt.SigningMethodRS512: + key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtPrivateKey))) + if err != nil { + return "", err + } + return t.SignedString(key) + case jwt.SigningMethodES256, jwt.SigningMethodES384, jwt.SigningMethodES512: + key, err := jwt.ParseECPrivateKeyFromPEM([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtPrivateKey))) + if err != nil { + return "", err + } + return t.SignedString(key) + default: + return "", errors.New("unsupported signing method") + } +} + +// ParseJWTToken common util to parse jwt token +func ParseJWTToken(token string) (jwt.MapClaims, error) { + jwtType := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType) + signingMethod := jwt.GetSigningMethod(jwtType) + + var err error + var claims jwt.MapClaims + + switch signingMethod { + case jwt.SigningMethodHS256, jwt.SigningMethodHS384, jwt.SigningMethodHS512: + _, err = jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) { + return []byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret)), nil + }) + case jwt.SigningMethodRS256, jwt.SigningMethodRS384, jwt.SigningMethodRS512: + _, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) { + key, err := jwt.ParseRSAPublicKeyFromPEM([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey))) + if err != nil { + return nil, err + } + return key, nil + }) + case jwt.SigningMethodES256, jwt.SigningMethodES384, jwt.SigningMethodES512: + _, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) { + key, err := jwt.ParseECPublicKeyFromPEM([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtPublicKey))) + if err != nil { + return nil, err + } + return key, nil + }) + default: + err = errors.New("unsupported signing method") + } + if err != nil { + return claims, err + } + + // claim parses exp & iat into float 64 with e^10, + // but we expect it to be int64 + // hence we need to assert interface and convert to int64 + intExp := int64(claims["exp"].(float64)) + intIat := int64(claims["iat"].(float64)) + claims["exp"] = intExp + claims["iat"] = intIat + + return claims, nil +} diff --git a/server/token/verification_token.go b/server/token/verification_token.go index 5e70bfb..8b0bdcc 100644 --- a/server/token/verification_token.go +++ b/server/token/verification_token.go @@ -8,44 +8,16 @@ import ( "github.com/golang-jwt/jwt" ) -// VerificationRequestToken is the user info that is stored in the JWT of verification request -type VerificationRequestToken struct { - Email string `json:"email"` - Host string `json:"host"` - RedirectURL string `json:"redirect_url"` -} - -// CustomClaim is the custom claim that is stored in the JWT of verification request -type CustomClaim struct { - *jwt.StandardClaims - TokenType string `json:"token_type"` - VerificationRequestToken -} - // CreateVerificationToken creates a verification JWT token func CreateVerificationToken(email, tokenType, hostname string) (string, error) { - t := jwt.New(jwt.GetSigningMethod(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType))) - - t.Claims = &CustomClaim{ - &jwt.StandardClaims{ - ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), - }, - tokenType, - VerificationRequestToken{Email: email, Host: hostname, RedirectURL: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAppURL)}, + claims := jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 30).Unix(), + "iat": time.Now().Unix(), + "token_type": tokenType, + "email": email, + "host": hostname, + "redirect_url": envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAppURL), } - return t.SignedString([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret))) -} - -// VerifyVerificationToken verifies the verification JWT token -func VerifyVerificationToken(token string) (*CustomClaim, error) { - claims := &CustomClaim{} - _, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) { - return []byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret)), nil - }) - if err != nil { - return claims, err - } - - return claims, nil + return SignJWTToken(claims) } From 1f058f954daf8319c18700eab189ef86933c262c Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sat, 12 Feb 2022 19:26:37 +0530 Subject: [PATCH 2/4] Add test for jwt tokens --- server/test/jwt_test.go | 143 ++++++++++++++++++++++++++++++++++++++++ server/token/jwt.go | 8 ++- 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 server/test/jwt_test.go diff --git a/server/test/jwt_test.go b/server/test/jwt_test.go new file mode 100644 index 0000000..185e028 --- /dev/null +++ b/server/test/jwt_test.go @@ -0,0 +1,143 @@ +package test + +import ( + "testing" + "time" + + "github.com/authorizerdev/authorizer/server/constants" + "github.com/authorizerdev/authorizer/server/envstore" + "github.com/authorizerdev/authorizer/server/token" + "github.com/golang-jwt/jwt" + "github.com/stretchr/testify/assert" +) + +func TestJwt(t *testing.T) { + claims := jwt.MapClaims{ + "exp": time.Now().Add(time.Minute * 30).Unix(), + "iat": time.Now().Unix(), + "email": "test@yopmail.com", + } + + // persist older data till test is done and then reset it + jwtType := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType) + jwtSecret := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret) + + t.Run("invalid jwt type", func(t *testing.T) { + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtType, "invalid") + token, err := token.SignJWTToken(claims) + assert.Error(t, err, "unsupported signing method") + assert.Empty(t, token) + }) + t.Run("expired jwt token", func(t *testing.T) { + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtType, "HS256") + expiredClaims := jwt.MapClaims{ + "exp": time.Now().Add(-time.Minute * 30).Unix(), + "iat": time.Now().Unix(), + "email": "test@yopmail.com", + } + jwtToken, err := token.SignJWTToken(expiredClaims) + assert.NoError(t, err) + _, err = token.ParseJWTToken(jwtToken) + assert.Error(t, err, err.Error(), "Token is expired") + }) + t.Run("HMAC algorithms", func(t *testing.T) { + t.Run("HS256", func(t *testing.T) { + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtType, "HS256") + jwtToken, err := token.SignJWTToken(claims) + assert.NoError(t, err) + assert.NotEmpty(t, jwtToken) + c, err := token.ParseJWTToken(jwtToken) + assert.NoError(t, err) + assert.Equal(t, c["email"].(string), claims["email"]) + }) + t.Run("HS384", func(t *testing.T) { + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtType, "HS384") + jwtToken, err := token.SignJWTToken(claims) + assert.NoError(t, err) + assert.NotEmpty(t, jwtToken) + c, err := token.ParseJWTToken(jwtToken) + assert.NoError(t, err) + assert.Equal(t, c["email"].(string), claims["email"]) + }) + t.Run("HS512", func(t *testing.T) { + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtType, "HS512") + jwtToken, err := token.SignJWTToken(claims) + assert.NoError(t, err) + assert.NotEmpty(t, jwtToken) + c, err := token.ParseJWTToken(jwtToken) + assert.NoError(t, err) + assert.Equal(t, c["email"].(string), claims["email"]) + }) + }) + + t.Run("RSA algorithms", func(t *testing.T) { + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtPrivateKey, "-----BEGIN RSA PRIVATE KEY-----\nMIICWgIBAAKBgHUQac/v0f3c8m4L9BMWfxBiEzkdV5CoaqfxhO5IwAX/1cs0WceN\njM7g/qzC7YmEOSiYqupiRtsyn6riz0xT/VUg4uv1uZ/muC6EVfOjR5Ack3Brquql\nD+oMxN4CeA0Wzp2dEV4N3Gv7wWHdhg9ZSc4g6+ZUdlkhIPfeO9RNK9pPAgMBAAEC\ngYBqLrIbp0dNQn0vbm48ZhppDNys4L2NfAYKQZs23Aw5JN6Si/CnffBrsk+u+ryl\nEKcb+KaHJQ9qQdfsFAC+FizhMQy0Dq9yw6shnqHX+paB6E6z2/vX8ToPzJRwxBY3\nyuaetCEpSXR7pQEd5YWDTUH7qYnb9FObD+umhVvmlsTHCQJBALagPmexu0DvMXKZ\nWdplik6eXg9lptiuj5MYqitEUyzU9E9HNeHKlZM7szGeWG3jNduoKcyo4M0Flvt9\ncP+soVUCQQCkGOQ5Y3/GoZmclKWMVwqGdmL6wEjhNfg4PRfgUalHBif9Q1KnM8FP\nAvIqIH8bttRfyT185WmaM2gml0ApwF0TAkBVil9QoK4t7xvBKtUsd809n+481gc9\njR4Q70edtoYjBKhejeNOHF7NNPRtNFcFOZybg3v4sc2CGrEqoQoRp+F1AkBeLmMe\nhPrbF/jAI5h4WaSS0/OvExlBGOaj8Hx5pKTRPLlK5I7VpCC4pmoyv3/0ehSd/TQr\nMMhRVlvaeki7Lcq9AkBravJUadVCAIsB6oh03mo8gUFFFqXDyEl6BiJYqrjCQ5wd\nAQYJGbqQvgjPxN9+PTPldDNi6KVXntSg5gF/dA+Z\n-----END RSA PRIVATE KEY-----") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtPublicKey, "-----BEGIN PUBLIC KEY-----\nMIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHUQac/v0f3c8m4L9BMWfxBiEzkd\nV5CoaqfxhO5IwAX/1cs0WceNjM7g/qzC7YmEOSiYqupiRtsyn6riz0xT/VUg4uv1\nuZ/muC6EVfOjR5Ack3BrquqlD+oMxN4CeA0Wzp2dEV4N3Gv7wWHdhg9ZSc4g6+ZU\ndlkhIPfeO9RNK9pPAgMBAAE=\n-----END PUBLIC KEY-----") + t.Run("RS256", func(t *testing.T) { + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtType, "RS256") + jwtToken, err := token.SignJWTToken(claims) + assert.NoError(t, err) + assert.NotEmpty(t, jwtToken) + c, err := token.ParseJWTToken(jwtToken) + assert.NoError(t, err) + assert.Equal(t, c["email"].(string), claims["email"]) + }) + t.Run("RS384", func(t *testing.T) { + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtType, "RS384") + jwtToken, err := token.SignJWTToken(claims) + assert.NoError(t, err) + assert.NotEmpty(t, jwtToken) + c, err := token.ParseJWTToken(jwtToken) + assert.NoError(t, err) + assert.Equal(t, c["email"].(string), claims["email"]) + }) + t.Run("RS512", func(t *testing.T) { + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtType, "RS512") + jwtToken, err := token.SignJWTToken(claims) + assert.NoError(t, err) + assert.NotEmpty(t, jwtToken) + c, err := token.ParseJWTToken(jwtToken) + assert.NoError(t, err) + assert.Equal(t, c["email"].(string), claims["email"]) + }) + }) + + t.Run("ECDSA algorithms", func(t *testing.T) { + t.Run("ES256", func(t *testing.T) { + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtPrivateKey, "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2\nOF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r\n1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G\n-----END PRIVATE KEY-----") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtPublicKey, "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9\nq9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg==\n-----END PUBLIC KEY-----") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtType, "ES256") + jwtToken, err := token.SignJWTToken(claims) + assert.NoError(t, err) + assert.NotEmpty(t, jwtToken) + c, err := token.ParseJWTToken(jwtToken) + assert.NoError(t, err) + assert.Equal(t, c["email"].(string), claims["email"]) + }) + t.Run("ES384", func(t *testing.T) { + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtPrivateKey, "-----BEGIN PRIVATE KEY-----\nMIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCAHpFQ62QnGCEvYh/p\nE9QmR1C9aLcDItRbslbmhen/h1tt8AyMhskeenT+rAyyPhGhZANiAAQLW5ZJePZz\nMIPAxMtZXkEWbDF0zo9f2n4+T1h/2sh/fviblc/VTyrv10GEtIi5qiOy85Pf1RRw\n8lE5IPUWpgu553SteKigiKLUPeNpbqmYZUkWGh3MLfVzLmx85ii2vMU=\n-----END PRIVATE KEY-----") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtPublicKey, "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEC1uWSXj2czCDwMTLWV5BFmwxdM6PX9p+\nPk9Yf9rIf374m5XP1U8q79dBhLSIuaojsvOT39UUcPJROSD1FqYLued0rXiooIii\n1D3jaW6pmGVJFhodzC31cy5sfOYotrzF\n-----END PUBLIC KEY-----") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtType, "ES384") + jwtToken, err := token.SignJWTToken(claims) + assert.NoError(t, err) + assert.NotEmpty(t, jwtToken) + c, err := token.ParseJWTToken(jwtToken) + assert.NoError(t, err) + assert.Equal(t, c["email"].(string), claims["email"]) + }) + t.Run("ES512", func(t *testing.T) { + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtPrivateKey, "-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBiyAa7aRHFDCh2qga\n9sTUGINE5jHAFnmM8xWeT/uni5I4tNqhV5Xx0pDrmCV9mbroFtfEa0XVfKuMAxxf\nZ6LM/yKhgYkDgYYABAGBzgdnP798FsLuWYTDDQA7c0r3BVk8NnRUSexpQUsRilPN\nv3SchO0lRw9Ru86x1khnVDx+duq4BiDFcvlSAcyjLACJvjvoyTLJiA+TQFdmrear\njMiZNE25pT2yWP1NUndJxPcvVtfBW48kPOmvkY4WlqP5bAwCXwbsKrCgk6xbsp12\new==\n-----END PRIVATE KEY-----") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtPublicKey, "-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBgc4HZz+/fBbC7lmEww0AO3NK9wVZ\nPDZ0VEnsaUFLEYpTzb90nITtJUcPUbvOsdZIZ1Q8fnbquAYgxXL5UgHMoywAib47\n6MkyyYgPk0BXZq3mq4zImTRNuaU9slj9TVJ3ScT3L1bXwVuPJDzpr5GOFpaj+WwM\nAl8G7CqwoJOsW7Kddns=\n-----END PUBLIC KEY-----") + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtType, "ES512") + jwtToken, err := token.SignJWTToken(claims) + assert.NoError(t, err) + assert.NotEmpty(t, jwtToken) + c, err := token.ParseJWTToken(jwtToken) + assert.NoError(t, err) + assert.Equal(t, c["email"].(string), claims["email"]) + }) + }) + + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtType, jwtType) + envstore.EnvInMemoryStoreObj.UpdateEnvVariable(constants.StringStoreIdentifier, constants.EnvKeyJwtSecret, jwtSecret) +} diff --git a/server/token/jwt.go b/server/token/jwt.go index 6c517b1..ee64695 100644 --- a/server/token/jwt.go +++ b/server/token/jwt.go @@ -12,7 +12,13 @@ import ( func SignJWTToken(claims jwt.MapClaims) (string, error) { jwtType := envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType) signingMethod := jwt.GetSigningMethod(jwtType) + if signingMethod == nil { + return "", errors.New("unsupported signing method") + } t := jwt.New(signingMethod) + if t == nil { + return "", errors.New("unsupported signing method") + } t.Claims = claims switch signingMethod { @@ -45,7 +51,7 @@ func ParseJWTToken(token string) (jwt.MapClaims, error) { switch signingMethod { case jwt.SigningMethodHS256, jwt.SigningMethodHS384, jwt.SigningMethodHS512: - _, err = jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) { + _, err = jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) { return []byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret)), nil }) case jwt.SigningMethodRS256, jwt.SigningMethodRS384, jwt.SigningMethodRS512: From 66d42fc2bcd05af20918e4c06e5133d32249ca0b Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sat, 12 Feb 2022 19:34:22 +0530 Subject: [PATCH 3/4] Add support for public private key from admin apis --- Makefile | 2 + server/graph/generated/generated.go | 104 ++++++++++++++++++++++++++++ server/graph/model/models_gen.go | 4 ++ server/graph/schema.graphqls | 4 ++ server/resolvers/env.go | 4 ++ 5 files changed, 118 insertions(+) diff --git a/Makefile b/Makefile index 1fca360..021f761 100644 --- a/Makefile +++ b/Makefile @@ -11,3 +11,5 @@ clean: rm -rf build test: cd server && go clean --testcache && go test -v ./test +generate: + cd server && go get github.com/99designs/gqlgen/cmd@v0.14.0 && go run github.com/99designs/gqlgen generate \ No newline at end of file diff --git a/server/graph/generated/generated.go b/server/graph/generated/generated.go index f5979c4..a93dbe4 100644 --- a/server/graph/generated/generated.go +++ b/server/graph/generated/generated.go @@ -70,6 +70,8 @@ type ComplexityRoot struct { GithubClientSecret func(childComplexity int) int GoogleClientID func(childComplexity int) int GoogleClientSecret func(childComplexity int) int + JwtPrivateKey func(childComplexity int) int + JwtPublicKey func(childComplexity int) int JwtRoleClaim func(childComplexity int) int JwtSecret func(childComplexity int) int JwtType func(childComplexity int) int @@ -391,6 +393,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Env.GoogleClientSecret(childComplexity), true + case "Env.JWT_PRIVATE_KEY": + if e.complexity.Env.JwtPrivateKey == nil { + break + } + + return e.complexity.Env.JwtPrivateKey(childComplexity), true + + case "Env.JWT_PUBLIC_KEY": + if e.complexity.Env.JwtPublicKey == nil { + break + } + + return e.complexity.Env.JwtPublicKey(childComplexity), true + case "Env.JWT_ROLE_CLAIM": if e.complexity.Env.JwtRoleClaim == nil { break @@ -1206,6 +1222,8 @@ type Env { SENDER_EMAIL: String JWT_TYPE: String JWT_SECRET: String + JWT_PRIVATE_KEY: String + JWT_PUBLIC_KEY: String ALLOWED_ORIGINS: [String!] APP_URL: String REDIS_URL: String @@ -1240,6 +1258,8 @@ input UpdateEnvInput { SENDER_EMAIL: String JWT_TYPE: String JWT_SECRET: String + JWT_PRIVATE_KEY: String + JWT_PUBLIC_KEY: String ALLOWED_ORIGINS: [String!] APP_URL: String REDIS_URL: String @@ -2229,6 +2249,70 @@ func (ec *executionContext) _Env_JWT_SECRET(ctx context.Context, field graphql.C return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } +func (ec *executionContext) _Env_JWT_PRIVATE_KEY(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Env", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.JwtPrivateKey, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Env_JWT_PUBLIC_KEY(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Env", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.JwtPublicKey, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + func (ec *executionContext) _Env_ALLOWED_ORIGINS(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -7044,6 +7128,22 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob if err != nil { return it, err } + case "JWT_PRIVATE_KEY": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("JWT_PRIVATE_KEY")) + it.JwtPrivateKey, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + case "JWT_PUBLIC_KEY": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("JWT_PUBLIC_KEY")) + it.JwtPublicKey, err = ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } case "ALLOWED_ORIGINS": var err error @@ -7539,6 +7639,10 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj out.Values[i] = ec._Env_JWT_TYPE(ctx, field, obj) case "JWT_SECRET": out.Values[i] = ec._Env_JWT_SECRET(ctx, field, obj) + case "JWT_PRIVATE_KEY": + out.Values[i] = ec._Env_JWT_PRIVATE_KEY(ctx, field, obj) + case "JWT_PUBLIC_KEY": + out.Values[i] = ec._Env_JWT_PUBLIC_KEY(ctx, field, obj) case "ALLOWED_ORIGINS": out.Values[i] = ec._Env_ALLOWED_ORIGINS(ctx, field, obj) case "APP_URL": diff --git a/server/graph/model/models_gen.go b/server/graph/model/models_gen.go index 5533a70..0d5a4cc 100644 --- a/server/graph/model/models_gen.go +++ b/server/graph/model/models_gen.go @@ -34,6 +34,8 @@ type Env struct { SenderEmail *string `json:"SENDER_EMAIL"` JwtType *string `json:"JWT_TYPE"` JwtSecret *string `json:"JWT_SECRET"` + JwtPrivateKey *string `json:"JWT_PRIVATE_KEY"` + JwtPublicKey *string `json:"JWT_PUBLIC_KEY"` AllowedOrigins []string `json:"ALLOWED_ORIGINS"` AppURL *string `json:"APP_URL"` RedisURL *string `json:"REDIS_URL"` @@ -153,6 +155,8 @@ type UpdateEnvInput struct { SenderEmail *string `json:"SENDER_EMAIL"` JwtType *string `json:"JWT_TYPE"` JwtSecret *string `json:"JWT_SECRET"` + JwtPrivateKey *string `json:"JWT_PRIVATE_KEY"` + JwtPublicKey *string `json:"JWT_PUBLIC_KEY"` AllowedOrigins []string `json:"ALLOWED_ORIGINS"` AppURL *string `json:"APP_URL"` RedisURL *string `json:"REDIS_URL"` diff --git a/server/graph/schema.graphqls b/server/graph/schema.graphqls index 1bbd2f8..0b88775 100644 --- a/server/graph/schema.graphqls +++ b/server/graph/schema.graphqls @@ -97,6 +97,8 @@ type Env { SENDER_EMAIL: String JWT_TYPE: String JWT_SECRET: String + JWT_PRIVATE_KEY: String + JWT_PUBLIC_KEY: String ALLOWED_ORIGINS: [String!] APP_URL: String REDIS_URL: String @@ -131,6 +133,8 @@ input UpdateEnvInput { SENDER_EMAIL: String JWT_TYPE: String JWT_SECRET: String + JWT_PRIVATE_KEY: String + JWT_PUBLIC_KEY: String ALLOWED_ORIGINS: [String!] APP_URL: String REDIS_URL: String diff --git a/server/resolvers/env.go b/server/resolvers/env.go index d514ef3..ab4769f 100644 --- a/server/resolvers/env.go +++ b/server/resolvers/env.go @@ -40,6 +40,8 @@ func EnvResolver(ctx context.Context) (*model.Env, error) { jwtType := store.StringEnv[constants.EnvKeyJwtType] jwtSecret := store.StringEnv[constants.EnvKeyJwtSecret] jwtRoleClaim := store.StringEnv[constants.EnvKeyJwtRoleClaim] + jwtPublicKey := store.StringEnv[constants.EnvKeyJwtPublicKey] + jwtPrivateKey := store.StringEnv[constants.EnvKeyJwtPrivateKey] allowedOrigins := store.SliceEnv[constants.EnvKeyAllowedOrigins] appURL := store.StringEnv[constants.EnvKeyAppURL] redisURL := store.StringEnv[constants.EnvKeyRedisURL] @@ -74,6 +76,8 @@ func EnvResolver(ctx context.Context) (*model.Env, error) { SenderEmail: &senderEmail, JwtType: &jwtType, JwtSecret: &jwtSecret, + JwtPrivateKey: &jwtPrivateKey, + JwtPublicKey: &jwtPublicKey, JwtRoleClaim: &jwtRoleClaim, AllowedOrigins: allowedOrigins, AppURL: &appURL, From 1276af43efbbf312c5d23405bd2136effa2d5ecd Mon Sep 17 00:00:00 2001 From: Lakhan Samani Date: Sat, 12 Feb 2022 19:36:29 +0530 Subject: [PATCH 4/4] Add new line char --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 021f761..635edec 100644 --- a/Makefile +++ b/Makefile @@ -12,4 +12,5 @@ clean: test: cd server && go clean --testcache && go test -v ./test generate: - cd server && go get github.com/99designs/gqlgen/cmd@v0.14.0 && go run github.com/99designs/gqlgen generate \ No newline at end of file + cd server && go get github.com/99designs/gqlgen/cmd@v0.14.0 && go run github.com/99designs/gqlgen generate + \ No newline at end of file