Merge pull request #121 from authorizerdev/feat/add-jwt-algos

feat: add jwt algos
This commit is contained in:
Lakhan Samani 2022-02-12 19:37:28 +05:30 committed by GitHub
commit f0d38ab260
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 419 additions and 120 deletions

View File

@ -11,3 +11,6 @@ clean:
rm -rf build rm -rf build
test: test:
cd server && go clean --testcache && go test -v ./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

View File

@ -43,6 +43,10 @@ const (
EnvKeyJwtType = "JWT_TYPE" EnvKeyJwtType = "JWT_TYPE"
// EnvKeyJwtSecret key for env variable JWT_SECRET // EnvKeyJwtSecret key for env variable JWT_SECRET
EnvKeyJwtSecret = "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 key for env variable ALLOWED_ORIGINS
EnvKeyAllowedOrigins = "ALLOWED_ORIGINS" EnvKeyAllowedOrigins = "ALLOWED_ORIGINS"
// EnvKeyAppURL key for env variable APP_URL // EnvKeyAppURL key for env variable APP_URL

78
server/env/env.go vendored
View File

@ -19,7 +19,7 @@ func InitEnv() {
envData := envstore.EnvInMemoryStoreObj.GetEnvStoreClone() envData := envstore.EnvInMemoryStoreObj.GetEnvStoreClone()
if envData.StringEnv[constants.EnvKeyEnv] == "" { 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] == "" { if envData.StringEnv[constants.EnvKeyEnv] == "" {
envData.StringEnv[constants.EnvKeyEnv] = "production" envData.StringEnv[constants.EnvKeyEnv] = "production"
} }
@ -50,18 +50,18 @@ func InitEnv() {
} }
if envData.StringEnv[constants.EnvKeyPort] == "" { 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] == "" { if envData.StringEnv[constants.EnvKeyPort] == "" {
envData.StringEnv[constants.EnvKeyPort] = "8080" envData.StringEnv[constants.EnvKeyPort] = "8080"
} }
} }
if envData.StringEnv[constants.EnvKeyAdminSecret] == "" { 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] == "" { 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 != "" { if envstore.ARG_DB_TYPE != nil && *envstore.ARG_DB_TYPE != "" {
envData.StringEnv[constants.EnvKeyDatabaseType] = *envstore.ARG_DB_TYPE envData.StringEnv[constants.EnvKeyDatabaseType] = *envstore.ARG_DB_TYPE
@ -73,7 +73,7 @@ func InitEnv() {
} }
if envData.StringEnv[constants.EnvKeyDatabaseURL] == "" { 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 != "" { if envstore.ARG_DB_URL != nil && *envstore.ARG_DB_URL != "" {
envData.StringEnv[constants.EnvKeyDatabaseURL] = *envstore.ARG_DB_URL envData.StringEnv[constants.EnvKeyDatabaseURL] = *envstore.ARG_DB_URL
@ -85,48 +85,56 @@ func InitEnv() {
} }
if envData.StringEnv[constants.EnvKeyDatabaseName] == "" { 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] == "" { if envData.StringEnv[constants.EnvKeyDatabaseName] == "" {
envData.StringEnv[constants.EnvKeyDatabaseName] = "authorizer" envData.StringEnv[constants.EnvKeyDatabaseName] = "authorizer"
} }
} }
if envData.StringEnv[constants.EnvKeySmtpHost] == "" { 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] == "" { 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] == "" { 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] == "" { 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] == "" { 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] == "" { 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] == "" { if envData.StringEnv[constants.EnvKeyJwtSecret] == "" {
envData.StringEnv[constants.EnvKeyJwtSecret] = uuid.New().String() 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] == "" { 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] == "" { if envData.StringEnv[constants.EnvKeyJwtType] == "" {
envData.StringEnv[constants.EnvKeyJwtType] = "HS256" envData.StringEnv[constants.EnvKeyJwtType] = "HS256"
} }
} }
if envData.StringEnv[constants.EnvKeyJwtRoleClaim] == "" { 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] == "" { if envData.StringEnv[constants.EnvKeyJwtRoleClaim] == "" {
envData.StringEnv[constants.EnvKeyJwtRoleClaim] = "role" envData.StringEnv[constants.EnvKeyJwtRoleClaim] = "role"
@ -134,48 +142,48 @@ func InitEnv() {
} }
if envData.StringEnv[constants.EnvKeyRedisURL] == "" { 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] == "" { 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] == "" { if envData.StringEnv[constants.EnvKeyCookieName] == "" {
envData.StringEnv[constants.EnvKeyCookieName] = "authorizer" envData.StringEnv[constants.EnvKeyCookieName] = "authorizer"
} }
} }
if envData.StringEnv[constants.EnvKeyGoogleClientID] == "" { 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] == "" { 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] == "" { 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] == "" { 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] == "" { 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] == "" { 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] == "" { 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.EnvKeyDisableBasicAuthentication] = os.Getenv(constants.EnvKeyDisableBasicAuthentication) == "true"
envData.BoolEnv[constants.EnvKeyDisableEmailVerification] = os.Getenv("DISABLE_EMAIL_VERIFICATION") == "true" envData.BoolEnv[constants.EnvKeyDisableEmailVerification] = os.Getenv(constants.EnvKeyDisableEmailVerification) == "true"
envData.BoolEnv[constants.EnvKeyDisableMagicLinkLogin] = os.Getenv("DISABLE_MAGIC_LINK_LOGIN") == "true" envData.BoolEnv[constants.EnvKeyDisableMagicLinkLogin] = os.Getenv(constants.EnvKeyDisableMagicLinkLogin) == "true"
envData.BoolEnv[constants.EnvKeyDisableLoginPage] = os.Getenv("DISABLE_LOGIN_PAGE") == "true" envData.BoolEnv[constants.EnvKeyDisableLoginPage] = os.Getenv(constants.EnvKeyDisableLoginPage) == "true"
// no need to add nil check as its already done above // 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] == "" { 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 envData.BoolEnv[constants.EnvKeyDisableMagicLinkLogin] = true
} }
allowedOriginsSplit := strings.Split(os.Getenv("ALLOWED_ORIGINS"), ",") allowedOriginsSplit := strings.Split(os.Getenv(constants.EnvKeyAllowedOrigins), ",")
allowedOrigins := []string{} allowedOrigins := []string{}
hasWildCard := false hasWildCard := false
@ -215,14 +223,14 @@ func InitEnv() {
envData.SliceEnv[constants.EnvKeyAllowedOrigins] = allowedOrigins envData.SliceEnv[constants.EnvKeyAllowedOrigins] = allowedOrigins
rolesEnv := strings.TrimSpace(os.Getenv("ROLES")) rolesEnv := strings.TrimSpace(os.Getenv(constants.EnvKeyRoles))
rolesSplit := strings.Split(rolesEnv, ",") rolesSplit := strings.Split(rolesEnv, ",")
roles := []string{} roles := []string{}
if len(rolesEnv) == 0 { if len(rolesEnv) == 0 {
roles = []string{"user"} roles = []string{"user"}
} }
defaultRolesEnv := strings.TrimSpace(os.Getenv("DEFAULT_ROLES")) defaultRolesEnv := strings.TrimSpace(os.Getenv(constants.EnvKeyDefaultRoles))
defaultRoleSplit := strings.Split(defaultRolesEnv, ",") defaultRoleSplit := strings.Split(defaultRolesEnv, ",")
defaultRoles := []string{} defaultRoles := []string{}
@ -230,7 +238,7 @@ func InitEnv() {
defaultRoles = []string{"user"} defaultRoles = []string{"user"}
} }
protectedRolesEnv := strings.TrimSpace(os.Getenv("PROTECTED_ROLES")) protectedRolesEnv := strings.TrimSpace(os.Getenv(constants.EnvKeyProtectedRoles))
protectedRolesSplit := strings.Split(protectedRolesEnv, ",") protectedRolesSplit := strings.Split(protectedRolesEnv, ",")
protectedRoles := []string{} protectedRoles := []string{}
@ -259,12 +267,12 @@ func InitEnv() {
envData.SliceEnv[constants.EnvKeyDefaultRoles] = defaultRoles envData.SliceEnv[constants.EnvKeyDefaultRoles] = defaultRoles
envData.SliceEnv[constants.EnvKeyProtectedRoles] = protectedRoles envData.SliceEnv[constants.EnvKeyProtectedRoles] = protectedRoles
if os.Getenv("ORGANIZATION_NAME") != "" { if os.Getenv(constants.EnvKeyOrganizationName) != "" {
envData.StringEnv[constants.EnvKeyOrganizationName] = os.Getenv("ORGANIZATION_NAME") envData.StringEnv[constants.EnvKeyOrganizationName] = os.Getenv(constants.EnvKeyOrganizationName)
} }
if os.Getenv("ORGANIZATION_LOGO") != "" { if os.Getenv(constants.EnvKeyOrganizationLogo) != "" {
envData.StringEnv[constants.EnvKeyOrganizationLogo] = os.Getenv("ORGANIZATION_LOGO") envData.StringEnv[constants.EnvKeyOrganizationLogo] = os.Getenv(constants.EnvKeyOrganizationLogo)
} }
envstore.EnvInMemoryStoreObj.UpdateEnvStore(envData) envstore.EnvInMemoryStoreObj.UpdateEnvStore(envData)

View File

@ -70,6 +70,8 @@ type ComplexityRoot struct {
GithubClientSecret func(childComplexity int) int GithubClientSecret func(childComplexity int) int
GoogleClientID func(childComplexity int) int GoogleClientID func(childComplexity int) int
GoogleClientSecret func(childComplexity int) int GoogleClientSecret func(childComplexity int) int
JwtPrivateKey func(childComplexity int) int
JwtPublicKey func(childComplexity int) int
JwtRoleClaim func(childComplexity int) int JwtRoleClaim func(childComplexity int) int
JwtSecret func(childComplexity int) int JwtSecret func(childComplexity int) int
JwtType 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 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": case "Env.JWT_ROLE_CLAIM":
if e.complexity.Env.JwtRoleClaim == nil { if e.complexity.Env.JwtRoleClaim == nil {
break break
@ -1206,6 +1222,8 @@ type Env {
SENDER_EMAIL: String SENDER_EMAIL: String
JWT_TYPE: String JWT_TYPE: String
JWT_SECRET: String JWT_SECRET: String
JWT_PRIVATE_KEY: String
JWT_PUBLIC_KEY: String
ALLOWED_ORIGINS: [String!] ALLOWED_ORIGINS: [String!]
APP_URL: String APP_URL: String
REDIS_URL: String REDIS_URL: String
@ -1240,6 +1258,8 @@ input UpdateEnvInput {
SENDER_EMAIL: String SENDER_EMAIL: String
JWT_TYPE: String JWT_TYPE: String
JWT_SECRET: String JWT_SECRET: String
JWT_PRIVATE_KEY: String
JWT_PUBLIC_KEY: String
ALLOWED_ORIGINS: [String!] ALLOWED_ORIGINS: [String!]
APP_URL: String APP_URL: String
REDIS_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) 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) { func (ec *executionContext) _Env_ALLOWED_ORIGINS(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -7044,6 +7128,22 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
if err != nil { if err != nil {
return it, err 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": case "ALLOWED_ORIGINS":
var err error 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) out.Values[i] = ec._Env_JWT_TYPE(ctx, field, obj)
case "JWT_SECRET": case "JWT_SECRET":
out.Values[i] = ec._Env_JWT_SECRET(ctx, field, obj) 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": case "ALLOWED_ORIGINS":
out.Values[i] = ec._Env_ALLOWED_ORIGINS(ctx, field, obj) out.Values[i] = ec._Env_ALLOWED_ORIGINS(ctx, field, obj)
case "APP_URL": case "APP_URL":

View File

@ -34,6 +34,8 @@ type Env struct {
SenderEmail *string `json:"SENDER_EMAIL"` SenderEmail *string `json:"SENDER_EMAIL"`
JwtType *string `json:"JWT_TYPE"` JwtType *string `json:"JWT_TYPE"`
JwtSecret *string `json:"JWT_SECRET"` JwtSecret *string `json:"JWT_SECRET"`
JwtPrivateKey *string `json:"JWT_PRIVATE_KEY"`
JwtPublicKey *string `json:"JWT_PUBLIC_KEY"`
AllowedOrigins []string `json:"ALLOWED_ORIGINS"` AllowedOrigins []string `json:"ALLOWED_ORIGINS"`
AppURL *string `json:"APP_URL"` AppURL *string `json:"APP_URL"`
RedisURL *string `json:"REDIS_URL"` RedisURL *string `json:"REDIS_URL"`
@ -153,6 +155,8 @@ type UpdateEnvInput struct {
SenderEmail *string `json:"SENDER_EMAIL"` SenderEmail *string `json:"SENDER_EMAIL"`
JwtType *string `json:"JWT_TYPE"` JwtType *string `json:"JWT_TYPE"`
JwtSecret *string `json:"JWT_SECRET"` JwtSecret *string `json:"JWT_SECRET"`
JwtPrivateKey *string `json:"JWT_PRIVATE_KEY"`
JwtPublicKey *string `json:"JWT_PUBLIC_KEY"`
AllowedOrigins []string `json:"ALLOWED_ORIGINS"` AllowedOrigins []string `json:"ALLOWED_ORIGINS"`
AppURL *string `json:"APP_URL"` AppURL *string `json:"APP_URL"`
RedisURL *string `json:"REDIS_URL"` RedisURL *string `json:"REDIS_URL"`

View File

@ -97,6 +97,8 @@ type Env {
SENDER_EMAIL: String SENDER_EMAIL: String
JWT_TYPE: String JWT_TYPE: String
JWT_SECRET: String JWT_SECRET: String
JWT_PRIVATE_KEY: String
JWT_PUBLIC_KEY: String
ALLOWED_ORIGINS: [String!] ALLOWED_ORIGINS: [String!]
APP_URL: String APP_URL: String
REDIS_URL: String REDIS_URL: String
@ -131,6 +133,8 @@ input UpdateEnvInput {
SENDER_EMAIL: String SENDER_EMAIL: String
JWT_TYPE: String JWT_TYPE: String
JWT_SECRET: String JWT_SECRET: String
JWT_PRIVATE_KEY: String
JWT_PUBLIC_KEY: String
ALLOWED_ORIGINS: [String!] ALLOWED_ORIGINS: [String!]
APP_URL: String APP_URL: String
REDIS_URL: String REDIS_URL: String

View File

@ -33,13 +33,13 @@ func VerifyEmailHandler() gin.HandlerFunc {
} }
// verify if token exists in db // verify if token exists in db
claim, err := token.VerifyVerificationToken(tokenInQuery) claim, err := token.ParseJWTToken(tokenInQuery)
if err != nil { if err != nil {
c.JSON(400, errorRes) c.JSON(400, errorRes)
return return
} }
user, err := db.Provider.GetUserByEmail(claim.Email) user, err := db.Provider.GetUserByEmail(claim["email"].(string))
if err != nil { if err != nil {
c.JSON(400, gin.H{ c.JSON(400, gin.H{
"message": err.Error(), "message": err.Error(),
@ -68,6 +68,6 @@ func VerifyEmailHandler() gin.HandlerFunc {
cookie.SetCookie(c, authToken.AccessToken.Token, authToken.RefreshToken.Token, authToken.FingerPrintHash) cookie.SetCookie(c, authToken.AccessToken.Token, authToken.RefreshToken.Token, authToken.FingerPrintHash)
utils.SaveSessionInDB(user.ID, c) utils.SaveSessionInDB(user.ID, c)
c.Redirect(http.StatusTemporaryRedirect, claim.RedirectURL) c.Redirect(http.StatusTemporaryRedirect, claim["redirect_url"].(string))
} }
} }

View File

@ -40,6 +40,8 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
jwtType := store.StringEnv[constants.EnvKeyJwtType] jwtType := store.StringEnv[constants.EnvKeyJwtType]
jwtSecret := store.StringEnv[constants.EnvKeyJwtSecret] jwtSecret := store.StringEnv[constants.EnvKeyJwtSecret]
jwtRoleClaim := store.StringEnv[constants.EnvKeyJwtRoleClaim] jwtRoleClaim := store.StringEnv[constants.EnvKeyJwtRoleClaim]
jwtPublicKey := store.StringEnv[constants.EnvKeyJwtPublicKey]
jwtPrivateKey := store.StringEnv[constants.EnvKeyJwtPrivateKey]
allowedOrigins := store.SliceEnv[constants.EnvKeyAllowedOrigins] allowedOrigins := store.SliceEnv[constants.EnvKeyAllowedOrigins]
appURL := store.StringEnv[constants.EnvKeyAppURL] appURL := store.StringEnv[constants.EnvKeyAppURL]
redisURL := store.StringEnv[constants.EnvKeyRedisURL] redisURL := store.StringEnv[constants.EnvKeyRedisURL]
@ -74,6 +76,8 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
SenderEmail: &senderEmail, SenderEmail: &senderEmail,
JwtType: &jwtType, JwtType: &jwtType,
JwtSecret: &jwtSecret, JwtSecret: &jwtSecret,
JwtPrivateKey: &jwtPrivateKey,
JwtPublicKey: &jwtPublicKey,
JwtRoleClaim: &jwtRoleClaim, JwtRoleClaim: &jwtRoleClaim,
AllowedOrigins: allowedOrigins, AllowedOrigins: allowedOrigins,
AppURL: &appURL, AppURL: &appURL,

View File

@ -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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -38,7 +38,7 @@ func LogoutResolver(ctx context.Context) (*model.Response, error) {
fingerPrint := string(decryptedFingerPrint) fingerPrint := string(decryptedFingerPrint)
// verify refresh token and fingerprint // verify refresh token and fingerprint
claims, err := token.VerifyJWTToken(refreshToken) claims, err := token.ParseJWTToken(refreshToken)
if err != nil { if err != nil {
return res, err return res, err
} }

View File

@ -31,12 +31,12 @@ func ResetPasswordResolver(ctx context.Context, params model.ResetPasswordInput)
} }
// verify if token exists in db // verify if token exists in db
claim, err := token.VerifyVerificationToken(params.Token) claim, err := token.ParseJWTToken(params.Token)
if err != nil { if err != nil {
return res, fmt.Errorf(`invalid token`) return res, fmt.Errorf(`invalid token`)
} }
user, err := db.Provider.GetUserByEmail(claim.Email) user, err := db.Provider.GetUserByEmail(claim["email"].(string))
if err != nil { if err != nil {
return res, err return res, err
} }

View File

@ -41,7 +41,7 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
fingerPrint := string(decryptedFingerPrint) fingerPrint := string(decryptedFingerPrint)
// verify refresh token and fingerprint // verify refresh token and fingerprint
claims, err := token.VerifyJWTToken(refreshToken) claims, err := token.ParseJWTToken(refreshToken)
if err != nil { if err != nil {
return res, err return res, err
} }

View File

@ -28,12 +28,12 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
} }
// verify if token exists in db // verify if token exists in db
claim, err := token.VerifyVerificationToken(params.Token) claim, err := token.ParseJWTToken(params.Token)
if err != nil { if err != nil {
return res, fmt.Errorf(`invalid token`) return res, fmt.Errorf(`invalid token`)
} }
user, err := db.Provider.GetUserByEmail(claim.Email) user, err := db.Provider.GetUserByEmail(claim["email"].(string))
if err != nil { if err != nil {
return res, err return res, err
} }

143
server/test/jwt_test.go Normal file
View File

@ -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)
}

View File

@ -62,7 +62,6 @@ func CreateAuthToken(user models.User, roles []string) (*Token, error) {
// CreateRefreshToken util to create JWT token // CreateRefreshToken util to create JWT token
func CreateRefreshToken(user models.User, roles []string) (string, int64, error) { func CreateRefreshToken(user models.User, roles []string) (string, int64, error) {
t := jwt.New(jwt.GetSigningMethod(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType)))
// expires in 1 year // expires in 1 year
expiryBound := time.Hour * 8760 expiryBound := time.Hour * 8760
expiresAt := time.Now().Add(expiryBound).Unix() expiresAt := time.Now().Add(expiryBound).Unix()
@ -75,8 +74,7 @@ func CreateRefreshToken(user models.User, roles []string) (string, int64, error)
"id": user.ID, "id": user.ID,
} }
t.Claims = customClaims token, err := SignJWTToken(customClaims)
token, err := t.SignedString([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret)))
if err != nil { if err != nil {
return "", 0, err 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 // CreateAccessToken util to create JWT token, based on
// user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT // user information, roles config and CUSTOM_ACCESS_TOKEN_SCRIPT
func CreateAccessToken(user models.User, roles []string) (string, int64, error) { func CreateAccessToken(user models.User, roles []string) (string, int64, error) {
t := jwt.New(jwt.GetSigningMethod(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType)))
expiryBound := time.Minute * 30 expiryBound := time.Minute * 30
expiresAt := time.Now().Add(expiryBound).Unix() expiresAt := time.Now().Add(expiryBound).Unix()
resUser := user.AsAPIUser() resUser := user.AsAPIUser()
@ -141,9 +137,7 @@ func CreateAccessToken(user models.User, roles []string) (string, int64, error)
} }
} }
t.Claims = customClaims token, err := SignJWTToken(customClaims)
token, err := t.SignedString([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret)))
if err != nil { if err != nil {
return "", 0, err return "", 0, err
} }
@ -187,43 +181,13 @@ func GetFingerPrint(gc *gin.Context) (string, error) {
return fingerPrint, nil 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) { func ValidateAccessToken(gc *gin.Context) (map[string]interface{}, error) {
token, err := GetAccessToken(gc) token, err := GetAccessToken(gc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
claims, err := VerifyJWTToken(token) claims, err := ParseJWTToken(token)
if err != nil { if err != nil {
return nil, err return nil, err
} }

89
server/token/jwt.go Normal file
View File

@ -0,0 +1,89 @@
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)
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 {
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
}

View File

@ -8,44 +8,16 @@ import (
"github.com/golang-jwt/jwt" "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 // CreateVerificationToken creates a verification JWT token
func CreateVerificationToken(email, tokenType, hostname string) (string, error) { func CreateVerificationToken(email, tokenType, hostname string) (string, error) {
t := jwt.New(jwt.GetSigningMethod(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtType))) claims := jwt.MapClaims{
"exp": time.Now().Add(time.Minute * 30).Unix(),
t.Claims = &CustomClaim{ "iat": time.Now().Unix(),
&jwt.StandardClaims{ "token_type": tokenType,
ExpiresAt: time.Now().Add(time.Minute * 30).Unix(), "email": email,
}, "host": hostname,
tokenType, "redirect_url": envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAppURL),
VerificationRequestToken{Email: email, Host: hostname, RedirectURL: envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAppURL)},
} }
return t.SignedString([]byte(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyJwtSecret))) return SignJWTToken(claims)
}
// 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
} }