Compare commits

..

14 Commits

Author SHA1 Message Date
Lakhan Samani
5bf26f7385 fix: setting custom access token script env 2022-02-18 16:45:12 +05:30
Lakhan Samani
1b269dc6db fix: rename session_client -> redis_client 2022-02-18 09:21:02 +05:30
Lakhan Samani
ce9a115a14 Merge pull request #128 from agarwal-nitesh/feat/redis_cluster_client
Add redis cluster client as a session store.
2022-02-18 09:19:24 +05:30
Nitesh Agarwal
f2f4c72aa6 Add redis cluster client as a session store. 2022-02-17 20:49:54 +05:30
Samyak Bhuta
9970eb16c9 Update README
Minor changes.
2022-02-17 15:04:05 +05:30
Lakhan Samani
23e53286bd Merge pull request #124 from anik-ghosh-au7/feat/jwt-types
support for more jwt encryption types added
2022-02-14 18:56:06 +05:30
Anik Ghosh
47acff05e2 support for more jwt encryption types added 2022-02-14 16:00:35 +05:30
Lakhan Samani
5572928619 fix: remove redundunt break statement 2022-02-12 22:55:33 +05:30
Lakhan Samani
85b4cd6339 Add support for maria db 2022-02-12 22:49:53 +05:30
Lakhan Samani
f0d38ab260 Merge pull request #121 from authorizerdev/feat/add-jwt-algos
feat: add jwt algos
2022-02-12 19:37:28 +05:30
Lakhan Samani
1276af43ef Add new line char 2022-02-12 19:36:29 +05:30
Lakhan Samani
66d42fc2bc Add support for public private key from admin apis 2022-02-12 19:34:22 +05:30
Lakhan Samani
1f058f954d Add test for jwt tokens 2022-02-12 19:26:37 +05:30
Lakhan Samani
8259fb515c Add support for more JWT algo methods 2022-02-12 15:54:23 +05:30
28 changed files with 579 additions and 174 deletions

3
.gitignore vendored
View File

@@ -10,4 +10,5 @@ build
data.db data.db
.DS_Store .DS_Store
.env.local .env.local
*.tar.gz *.tar.gz
.vscode/

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

@@ -7,7 +7,7 @@
Authorizer Authorizer
</h1> </h1>
**Authorizer** is an open-source authentication and authorization solution for your applications. Bring your database and have complete control over the user information. You can self-host authorizer instances and connect to any database (Currently supports [Postgres](https://www.postgresql.org/), [MySQL](https://www.mysql.com/), [SQLite](https://www.sqlite.org/index.html), [SQLServer](https://www.microsoft.com/en-us/sql-server/), [MongoDB](https://mongodb.com/),[ArangoDB](https://www.arangodb.com/)). **Authorizer** is an open-source authentication and authorization solution for your applications. Bring your database and have complete control over the user information. You can self-host authorizer instances and connect to any database (Currently supports [Postgres](https://www.postgresql.org/), [MySQL](https://www.mysql.com/), [SQLite](https://www.sqlite.org/index.html), [SQLServer](https://www.microsoft.com/en-us/sql-server/), [MongoDB](https://mongodb.com/), [ArangoDB](https://www.arangodb.com/)).
## Table of contents ## Table of contents

View File

@@ -259,17 +259,6 @@ const InputField = ({
); );
} }
if (Object.values(SelectInputType).includes(inputType)) { if (Object.values(SelectInputType).includes(inputType)) {
if (inputType === SelectInputType.JWT_TYPE) {
return (
<Select size="sm" {...props}>
{[variables[inputType]].map((value: string) => (
<option value="value" key={value}>
{value}
</option>
))}
</Select>
);
}
const { options, ...rest } = props; const { options, ...rest } = props;
return ( return (
<Select <Select
@@ -293,10 +282,18 @@ const InputField = ({
<Textarea <Textarea
{...props} {...props}
size="lg" size="lg"
value={inputData[inputType]} fontSize={14}
onChange={(e: any) => { value={variables[inputType] ? variables[inputType] : ''}
setInputData({ ...inputData, [inputType]: e.target.value }); onChange={(
}} event: Event & {
target: HTMLInputElement;
}
) =>
setVariables({
...variables,
[inputType]: event.target.value,
})
}
/> />
); );
} }

View File

@@ -49,6 +49,8 @@ export const SelectInputType = {
export const TextAreaInputType = { export const TextAreaInputType = {
CUSTOM_ACCESS_TOKEN_SCRIPT: 'CUSTOM_ACCESS_TOKEN_SCRIPT', CUSTOM_ACCESS_TOKEN_SCRIPT: 'CUSTOM_ACCESS_TOKEN_SCRIPT',
JWT_PRIVATE_KEY: 'JWT_PRIVATE_KEY',
JWT_PUBLIC_KEY: 'JWT_PUBLIC_KEY',
}; };
export const SwitchInputType = { export const SwitchInputType = {
@@ -66,3 +68,21 @@ export const ArrayInputOperations = {
APPEND: 'APPEND', APPEND: 'APPEND',
REMOVE: 'REMOVE', REMOVE: 'REMOVE',
}; };
export const HMACEncryptionType = {
HS256: 'HS256',
HS384: 'HS384',
HS512: 'HS512',
};
export const RSAEncryptionType = {
RS256: 'RS256',
RS384: 'RS384',
RS512: 'RS512',
};
export const ECDSAEncryptionType = {
ES256: 'ES256',
ES384: 'ES384',
ES512: 'ES512',
};

View File

@@ -21,6 +21,8 @@ export const EnvVariablesQuery = `
JWT_TYPE, JWT_TYPE,
JWT_SECRET, JWT_SECRET,
JWT_ROLE_CLAIM, JWT_ROLE_CLAIM,
JWT_PRIVATE_KEY,
JWT_PUBLIC_KEY,
REDIS_URL, REDIS_URL,
SMTP_HOST, SMTP_HOST,
SMTP_PORT, SMTP_PORT,

View File

@@ -31,6 +31,9 @@ import {
TextInputType, TextInputType,
TextAreaInputType, TextAreaInputType,
SwitchInputType, SwitchInputType,
HMACEncryptionType,
RSAEncryptionType,
ECDSAEncryptionType,
} from '../constants'; } from '../constants';
import { UpdateEnvVariables } from '../graphql/mutation'; import { UpdateEnvVariables } from '../graphql/mutation';
import { getObjectDiff, capitalizeFirstLetter } from '../utils'; import { getObjectDiff, capitalizeFirstLetter } from '../utils';
@@ -48,6 +51,8 @@ interface envVarTypes {
JWT_TYPE: string; JWT_TYPE: string;
JWT_SECRET: string; JWT_SECRET: string;
JWT_ROLE_CLAIM: string; JWT_ROLE_CLAIM: string;
JWT_PRIVATE_KEY: string;
JWT_PUBLIC_KEY: string;
REDIS_URL: string; REDIS_URL: string;
SMTP_HOST: string; SMTP_HOST: string;
SMTP_PORT: string; SMTP_PORT: string;
@@ -92,6 +97,8 @@ export default function Environment() {
JWT_TYPE: '', JWT_TYPE: '',
JWT_SECRET: '', JWT_SECRET: '',
JWT_ROLE_CLAIM: '', JWT_ROLE_CLAIM: '',
JWT_PRIVATE_KEY: '',
JWT_PUBLIC_KEY: '',
REDIS_URL: '', REDIS_URL: '',
SMTP_HOST: '', SMTP_HOST: '',
SMTP_PORT: '', SMTP_PORT: '',
@@ -177,7 +184,6 @@ export default function Environment() {
const { const {
data: { _env: envData }, data: { _env: envData },
} = await client.query(EnvVariablesQuery).toPromise(); } = await client.query(EnvVariablesQuery).toPromise();
const diff = getObjectDiff(envVariables, envData); const diff = getObjectDiff(envVariables, envData);
const updatedEnvVariables = diff.reduce( const updatedEnvVariables = diff.reduce(
(acc: any, property: string) => ({ (acc: any, property: string) => ({
@@ -374,39 +380,67 @@ export default function Environment() {
<Flex w="30%" justifyContent="start" alignItems="center"> <Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">JWT Type:</Text> <Text fontSize="sm">JWT Type:</Text>
</Flex> </Flex>
<Center w="70%"> <Flex w="70%">
<Flex w="100%" justifyContent="space-between">
<Flex flex="2">
<InputField
variables={envVariables}
setVariables={setEnvVariables}
inputType={SelectInputType.JWT_TYPE}
isDisabled={true}
defaultValue={SelectInputType.JWT_TYPE}
/>
</Flex>
<Flex flex="3" justifyContent="center" alignItems="center">
<Text fontSize="sm">
More JWT types will be enabled in upcoming releases.
</Text>
</Flex>
</Flex>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">JWT Secret</Text>
</Flex>
<Center w="70%">
<InputField <InputField
variables={envVariables} variables={envVariables}
setVariables={setEnvVariables} setVariables={setEnvVariables}
fieldVisibility={fieldVisibility} inputType={SelectInputType.JWT_TYPE}
setFieldVisibility={setFieldVisibility} value={SelectInputType.JWT_TYPE}
inputType={HiddenInputType.JWT_SECRET} options={{
...HMACEncryptionType,
...RSAEncryptionType,
...ECDSAEncryptionType,
}}
/> />
</Center> </Flex>
</Flex> </Flex>
{Object.values(HMACEncryptionType).includes(envVariables.JWT_TYPE) ? (
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">JWT Secret</Text>
</Flex>
<Center w="70%">
<InputField
variables={envVariables}
setVariables={setEnvVariables}
fieldVisibility={fieldVisibility}
setFieldVisibility={setFieldVisibility}
inputType={HiddenInputType.JWT_SECRET}
/>
</Center>
</Flex>
) : (
<>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Public Key</Text>
</Flex>
<Center w="70%">
<InputField
variables={envVariables}
setVariables={setEnvVariables}
inputType={TextAreaInputType.JWT_PUBLIC_KEY}
placeholder="Add public key here"
minH="25vh"
/>
</Center>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Private Key</Text>
</Flex>
<Center w="70%">
<InputField
variables={envVariables}
setVariables={setEnvVariables}
inputType={TextAreaInputType.JWT_PRIVATE_KEY}
placeholder="Add private key here"
minH="25vh"
/>
</Center>
</Flex>
</>
)}
<Flex> <Flex>
<Flex w="30%" justifyContent="start" alignItems="center"> <Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">JWT Role Claim:</Text> <Text fontSize="sm">JWT Role Claim:</Text>

View File

@@ -15,4 +15,6 @@ const (
DbTypeMongodb = "mongodb" DbTypeMongodb = "mongodb"
// DbTypeYugabyte is the yugabyte database type // DbTypeYugabyte is the yugabyte database type
DbTypeYugabyte = "yugabyte" DbTypeYugabyte = "yugabyte"
// DbTypeMariaDB is the mariadb database type
DbTypeMariaDB = "mariadb"
) )

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

View File

@@ -44,16 +44,12 @@ func NewProvider() (*provider, error) {
switch envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) { switch envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseType) {
case constants.DbTypePostgres, constants.DbTypeYugabyte: case constants.DbTypePostgres, constants.DbTypeYugabyte:
sqlDB, err = gorm.Open(postgres.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig) sqlDB, err = gorm.Open(postgres.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
break
case constants.DbTypeSqlite: case constants.DbTypeSqlite:
sqlDB, err = gorm.Open(sqlite.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig) sqlDB, err = gorm.Open(sqlite.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
break case constants.DbTypeMysql, constants.DbTypeMariaDB:
case constants.DbTypeMysql:
sqlDB, err = gorm.Open(mysql.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig) sqlDB, err = gorm.Open(mysql.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
break
case constants.DbTypeSqlserver: case constants.DbTypeSqlserver:
sqlDB, err = gorm.Open(sqlserver.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig) sqlDB, err = gorm.Open(sqlserver.Open(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyDatabaseURL)), ormConfig)
break
} }
if err != nil { if err != nil {

82
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,60 @@ 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.EnvKeyCustomAccessTokenScript] == "" {
envData.StringEnv[constants.EnvKeyCustomAccessTokenScript] = os.Getenv(constants.EnvKeyCustomAccessTokenScript)
}
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 +146,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 +199,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 +227,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 +242,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 +271,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
} }

View File

@@ -0,0 +1,18 @@
package sessionstore
import (
"context"
"time"
"github.com/go-redis/redis/v8"
)
type RedisSessionClient interface {
HMSet(ctx context.Context, key string, values ...interface{}) *redis.BoolCmd
Del(ctx context.Context, keys ...string) *redis.IntCmd
HDel(ctx context.Context, key string, fields ...string) *redis.IntCmd
HMGet(ctx context.Context, key string, fields ...string) *redis.SliceCmd
HGetAll(ctx context.Context, key string) *redis.StringStringMapCmd
Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *redis.StatusCmd
Get(ctx context.Context, key string) *redis.StringCmd
}

View File

@@ -4,13 +4,11 @@ import (
"context" "context"
"fmt" "fmt"
"log" "log"
"github.com/go-redis/redis/v8"
) )
type RedisStore struct { type RedisStore struct {
ctx context.Context ctx context.Context
store *redis.Client store RedisSessionClient
} }
// AddUserSession adds the user session to redis // AddUserSession adds the user session to redis

View File

@@ -3,6 +3,7 @@ package sessionstore
import ( import (
"context" "context"
"log" "log"
"strings"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/envstore" "github.com/authorizerdev/authorizer/server/envstore"
@@ -121,6 +122,23 @@ func RemoveSocialLoginState(key string) {
func InitSession() { func InitSession() {
if envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL) != "" { if envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL) != "" {
log.Println("using redis store to save sessions") log.Println("using redis store to save sessions")
if isCluster(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL)) {
clusterOpt, err := getClusterOptions(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL))
if err != nil {
log.Fatalln("Error parsing redis url:", err)
}
rdb := redis.NewClusterClient(clusterOpt)
ctx := context.Background()
_, err = rdb.Ping(ctx).Result()
if err != nil {
log.Fatalln("Error connecting to redis cluster server", err)
}
SessionStoreObj.RedisMemoryStoreObj = &RedisStore{
ctx: ctx,
store: rdb,
}
return
}
opt, err := redis.ParseURL(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL)) opt, err := redis.ParseURL(envstore.EnvInMemoryStoreObj.GetStringStoreEnvVariable(constants.EnvKeyRedisURL))
if err != nil { if err != nil {
log.Fatalln("Error parsing redis url:", err) log.Fatalln("Error parsing redis url:", err)
@@ -144,3 +162,19 @@ func InitSession() {
} }
} }
} }
func isCluster(url string) bool {
return len(strings.Split(url, ",")) > 1
}
func getClusterOptions(url string) (*redis.ClusterOptions, error) {
hostPortsList := strings.Split(url, ",")
opt, err := redis.ParseURL(hostPortsList[0])
if err != nil {
return nil, err
}
urls := []string{opt.Addr}
urlList := hostPortsList[1:]
urls = append(urls, urlList...)
return &redis.ClusterOptions{Addrs: urls}, nil
}

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