Compare commits

...

8 Commits

Author SHA1 Message Date
Lakhan Samani
d5f1c5a5eb Resolves #156 2022-04-02 17:34:50 +05:30
Lakhan Samani
39947f1753 Merge pull request #155 from authorizerdev/fix/gateway-based-setup
fix: setting the cookie for proxy setup
2022-03-30 11:51:20 +05:30
Lakhan Samani
4fa9f79c3f fix: setting the cookie for proxy setup 2022-03-30 11:50:22 +05:30
Lakhan Samani
fe73c2f6f8 Update README.md 2022-03-26 07:00:01 +05:30
Lakhan Samani
4a3e3633ea fix: default access token expiry time 2022-03-25 20:29:00 +05:30
Lakhan Samani
dbbe36f6b5 Merge pull request #154 from MedvedewEM/enhancement/access_token_expiry_time
enhancement: add access_token_expiry_time env variable
2022-03-25 18:57:53 +05:30
egor.medvedev
819dd57377 Merge branch 'authorizerdev/authorizer:main' into main 2022-03-25 16:13:46 +03:00
egor.medvedev
044b025ba2 enhancement: add access_token_expiry_time env variable 2022-03-25 15:21:20 +03:00
26 changed files with 212 additions and 39 deletions

View File

@@ -26,18 +26,16 @@
- ✅ Sign-in / Sign-up with email ID and password - ✅ Sign-in / Sign-up with email ID and password
- ✅ Secure session management - ✅ Secure session management
- ✅ Email verification - ✅ Email verification
- ✅ OAuth2 and OpenID compatible APIs
- ✅ APIs to update profile securely - ✅ APIs to update profile securely
- ✅ Forgot password flow using email - ✅ Forgot password flow using email
- ✅ Social logins (Google, Github, Facebook, more coming soon) - ✅ Social logins (Google, Github, Facebook, more coming soon)
- ✅ Role-based access management - ✅ Role-based access management
- ✅ Password-less login with email and magic link - ✅ Password-less login with magic link login
## Roadmap ## Roadmap
- Support more JWT encryption algorithms (Currently supporting HS256)
- 2 Factor authentication - 2 Factor authentication
- Back office (Admin dashboard to manage user)
- Support more database
- VueJS SDK - VueJS SDK
- Svelte SDK - Svelte SDK
- React Native SDK - React Native SDK

30
app/package-lock.json generated
View File

@@ -9,7 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@authorizerdev/authorizer-react": "latest", "@authorizerdev/authorizer-react": "^0.17.0",
"@types/react": "^17.0.15", "@types/react": "^17.0.15",
"@types/react-dom": "^17.0.9", "@types/react-dom": "^17.0.9",
"esbuild": "^0.12.17", "esbuild": "^0.12.17",
@@ -24,9 +24,9 @@
} }
}, },
"node_modules/@authorizerdev/authorizer-js": { "node_modules/@authorizerdev/authorizer-js": {
"version": "0.6.0", "version": "0.10.0",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.6.0.tgz", "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.10.0.tgz",
"integrity": "sha512-WbqeUmhQwLNlvk4ZYTptlbAIINh7aZPyTCVA/B0FE3EoPtx1tNOtkPtJOycrn0H0HyueeXQnBSCDxkvPAP65Bw==", "integrity": "sha512-REM8FLD/Ej9gzA2zDGDAke6QFss33ubePlTDmLDmIYUuQmpHFlO5mCCS6nVsKkN7F/Bcwkmp+eUNQjkdGCaKLg==",
"dependencies": { "dependencies": {
"node-fetch": "^2.6.1" "node-fetch": "^2.6.1"
}, },
@@ -35,11 +35,11 @@
} }
}, },
"node_modules/@authorizerdev/authorizer-react": { "node_modules/@authorizerdev/authorizer-react": {
"version": "0.11.0", "version": "0.17.0",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.11.0.tgz", "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.17.0.tgz",
"integrity": "sha512-VzSZvEB/t6N2ESn4O8c/+2hPUO7L4Iux8IBzXKrobKkoqRyb+u5TPZn0UWCOaoxIdiiZY+1Yq2A/H6q9LAqLGw==", "integrity": "sha512-7WcNCU7hDFkVfFb8LcJXFwWiLYd8aY78z1AbNPxCa2Cw5G85PaRkzjKybP6h01ITVOHO6M03lLwPj8p6Sr6fEg==",
"dependencies": { "dependencies": {
"@authorizerdev/authorizer-js": "^0.6.0", "@authorizerdev/authorizer-js": "^0.10.0",
"final-form": "^4.20.2", "final-form": "^4.20.2",
"react-final-form": "^6.5.3", "react-final-form": "^6.5.3",
"styled-components": "^5.3.0" "styled-components": "^5.3.0"
@@ -829,19 +829,19 @@
}, },
"dependencies": { "dependencies": {
"@authorizerdev/authorizer-js": { "@authorizerdev/authorizer-js": {
"version": "0.6.0", "version": "0.10.0",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.6.0.tgz", "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-0.10.0.tgz",
"integrity": "sha512-WbqeUmhQwLNlvk4ZYTptlbAIINh7aZPyTCVA/B0FE3EoPtx1tNOtkPtJOycrn0H0HyueeXQnBSCDxkvPAP65Bw==", "integrity": "sha512-REM8FLD/Ej9gzA2zDGDAke6QFss33ubePlTDmLDmIYUuQmpHFlO5mCCS6nVsKkN7F/Bcwkmp+eUNQjkdGCaKLg==",
"requires": { "requires": {
"node-fetch": "^2.6.1" "node-fetch": "^2.6.1"
} }
}, },
"@authorizerdev/authorizer-react": { "@authorizerdev/authorizer-react": {
"version": "0.11.0", "version": "0.17.0",
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.11.0.tgz", "resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-0.17.0.tgz",
"integrity": "sha512-VzSZvEB/t6N2ESn4O8c/+2hPUO7L4Iux8IBzXKrobKkoqRyb+u5TPZn0UWCOaoxIdiiZY+1Yq2A/H6q9LAqLGw==", "integrity": "sha512-7WcNCU7hDFkVfFb8LcJXFwWiLYd8aY78z1AbNPxCa2Cw5G85PaRkzjKybP6h01ITVOHO6M03lLwPj8p6Sr6fEg==",
"requires": { "requires": {
"@authorizerdev/authorizer-js": "^0.6.0", "@authorizerdev/authorizer-js": "^0.10.0",
"final-form": "^4.20.2", "final-form": "^4.20.2",
"react-final-form": "^6.5.3", "react-final-form": "^6.5.3",
"styled-components": "^5.3.0" "styled-components": "^5.3.0"

View File

@@ -11,7 +11,7 @@
"author": "Lakhan Samani", "author": "Lakhan Samani",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@authorizerdev/authorizer-react": "latest", "@authorizerdev/authorizer-react": "^0.17.0",
"@types/react": "^17.0.15", "@types/react": "^17.0.15",
"@types/react-dom": "^17.0.9", "@types/react-dom": "^17.0.9",
"esbuild": "^0.12.17", "esbuild": "^0.12.17",

View File

@@ -10,6 +10,9 @@ const queryClient = createClient({
fetchOptions: () => { fetchOptions: () => {
return { return {
credentials: 'include', credentials: 'include',
headers: {
'x-authorizer-url': window.location.origin,
},
}; };
}, },
requestPolicy: 'network-only', requestPolicy: 'network-only',

View File

@@ -2,6 +2,7 @@ export const LOGO_URL =
'https://user-images.githubusercontent.com/6964334/147834043-fc384cab-e7ca-40f8-9663-38fc25fd5f3a.png'; 'https://user-images.githubusercontent.com/6964334/147834043-fc384cab-e7ca-40f8-9663-38fc25fd5f3a.png';
export const TextInputType = { export const TextInputType = {
ACCESS_TOKEN_EXPIRY_TIME: 'ACCESS_TOKEN_EXPIRY_TIME',
CLIENT_ID: 'CLIENT_ID', CLIENT_ID: 'CLIENT_ID',
GOOGLE_CLIENT_ID: 'GOOGLE_CLIENT_ID', GOOGLE_CLIENT_ID: 'GOOGLE_CLIENT_ID',
GITHUB_CLIENT_ID: 'GITHUB_CLIENT_ID', GITHUB_CLIENT_ID: 'GITHUB_CLIENT_ID',
@@ -125,4 +126,5 @@ export interface envVarTypes {
DATABASE_NAME: string; DATABASE_NAME: string;
DATABASE_TYPE: string; DATABASE_TYPE: string;
DATABASE_URL: string; DATABASE_URL: string;
ACCESS_TOKEN_EXPIRY_TIME: string;
} }

View File

@@ -53,6 +53,7 @@ export const EnvVariablesQuery = `
DATABASE_NAME, DATABASE_NAME,
DATABASE_TYPE, DATABASE_TYPE,
DATABASE_URL, DATABASE_URL,
ACCESS_TOKEN_EXPIRY_TIME,
} }
} }
`; `;

View File

@@ -85,6 +85,7 @@ export default function Environment() {
DATABASE_NAME: '', DATABASE_NAME: '',
DATABASE_TYPE: '', DATABASE_TYPE: '',
DATABASE_URL: '', DATABASE_URL: '',
ACCESS_TOKEN_EXPIRY_TIME: '',
}); });
const [fieldVisibility, setFieldVisibility] = React.useState< const [fieldVisibility, setFieldVisibility] = React.useState<
@@ -600,11 +601,28 @@ export default function Environment() {
</Stack> </Stack>
<Divider marginTop="2%" marginBottom="2%" /> <Divider marginTop="2%" marginBottom="2%" />
<Text fontSize="md" paddingTop="2%" fontWeight="bold"> <Text fontSize="md" paddingTop="2%" fontWeight="bold">
Custom Access Token Scripts Access Token
</Text> </Text>
<Stack spacing={6} padding="2% 0%"> <Stack spacing={6} padding="2% 0%">
<Flex> <Flex>
<Center w="100%"> <Flex w="30%" justifyContent="start" alignItems="center">
<Text fontSize="sm">Access Token Expiry Time:</Text>
</Flex>
<Flex w="70%">
<InputField
variables={envVariables}
setVariables={setEnvVariables}
inputType={TextInputType.ACCESS_TOKEN_EXPIRY_TIME}
placeholder="0h15m0s"
/>
</Flex>
</Flex>
<Flex>
<Flex w="30%" justifyContent="start" direction="column">
<Text fontSize="sm">Custom Scripts:</Text>
<Text fontSize="sm">Used to add custom fields in ID token</Text>
</Flex>
<Flex w="70%">
<InputField <InputField
variables={envVariables} variables={envVariables}
setVariables={setEnvVariables} setVariables={setEnvVariables}
@@ -612,7 +630,7 @@ export default function Environment() {
placeholder="Add script here" placeholder="Add script here"
minH="25vh" minH="25vh"
/> />
</Center> </Flex>
</Flex> </Flex>
</Stack> </Stack>
<Divider marginTop="2%" marginBottom="2%" /> <Divider marginTop="2%" marginBottom="2%" />

View File

@@ -16,11 +16,12 @@ const (
// EnvKeyEnvPath key for cli arg variable ENV_PATH // EnvKeyEnvPath key for cli arg variable ENV_PATH
EnvKeyEnvPath = "ENV_PATH" EnvKeyEnvPath = "ENV_PATH"
// EnvKeyAuthorizerURL key for env variable AUTHORIZER_URL // EnvKeyAuthorizerURL key for env variable AUTHORIZER_URL
// TODO: remove support AUTHORIZER_URL env
EnvKeyAuthorizerURL = "AUTHORIZER_URL" EnvKeyAuthorizerURL = "AUTHORIZER_URL"
// EnvKeyPort key for env variable PORT // EnvKeyPort key for env variable PORT
EnvKeyPort = "PORT" EnvKeyPort = "PORT"
// EnvKeyAccessTokenExpiryTime key for env variable ACCESS_TOKEN_EXPIRY_TIME
EnvKeyAccessTokenExpiryTime = "ACCESS_TOKEN_EXPIRY_TIME"
// EnvKeyAdminSecret key for env variable ADMIN_SECRET // EnvKeyAdminSecret key for env variable ADMIN_SECRET
EnvKeyAdminSecret = "ADMIN_SECRET" EnvKeyAdminSecret = "ADMIN_SECRET"
// EnvKeyDatabaseType key for env variable DATABASE_TYPE // EnvKeyDatabaseType key for env variable DATABASE_TYPE

View File

@@ -7,11 +7,11 @@ type VerificationRequest struct {
Key string `json:"_key,omitempty" bson:"_key"` // for arangodb Key string `json:"_key,omitempty" bson:"_key"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"` ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id"`
Token string `gorm:"type:text" json:"token" bson:"token"` Token string `gorm:"type:text" json:"token" bson:"token"`
Identifier string `gorm:"uniqueIndex:idx_email_identifier" json:"identifier" bson:"identifier"` Identifier string `gorm:"uniqueIndex:idx_email_identifier;type:varchar(64)" json:"identifier" bson:"identifier"`
ExpiresAt int64 `json:"expires_at" bson:"expires_at"` ExpiresAt int64 `json:"expires_at" bson:"expires_at"`
CreatedAt int64 `json:"created_at" bson:"created_at"` CreatedAt int64 `json:"created_at" bson:"created_at"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at"` UpdatedAt int64 `json:"updated_at" bson:"updated_at"`
Email string `gorm:"uniqueIndex:idx_email_identifier" json:"email" bson:"email"` Email string `gorm:"uniqueIndex:idx_email_identifier;type:varchar(256)" json:"email" bson:"email"`
Nonce string `gorm:"type:text" json:"nonce" bson:"nonce"` Nonce string `gorm:"type:text" json:"nonce" bson:"nonce"`
RedirectURI string `gorm:"type:text" json:"redirect_uri" bson:"redirect_uri"` RedirectURI string `gorm:"type:text" json:"redirect_uri" bson:"redirect_uri"`
} }

11
server/env/env.go vendored
View File

@@ -113,6 +113,10 @@ func InitAllEnv() error {
envData.StringEnv[constants.EnvKeyAppURL] = os.Getenv(constants.EnvKeyAppURL) envData.StringEnv[constants.EnvKeyAppURL] = os.Getenv(constants.EnvKeyAppURL)
} }
if envData.StringEnv[constants.EnvKeyAuthorizerURL] == "" {
envData.StringEnv[constants.EnvKeyAuthorizerURL] = os.Getenv(constants.EnvKeyAuthorizerURL)
}
if envData.StringEnv[constants.EnvKeyPort] == "" { if envData.StringEnv[constants.EnvKeyPort] == "" {
envData.StringEnv[constants.EnvKeyPort] = os.Getenv(constants.EnvKeyPort) envData.StringEnv[constants.EnvKeyPort] = os.Getenv(constants.EnvKeyPort)
if envData.StringEnv[constants.EnvKeyPort] == "" { if envData.StringEnv[constants.EnvKeyPort] == "" {
@@ -120,6 +124,13 @@ func InitAllEnv() error {
} }
} }
if envData.StringEnv[constants.EnvKeyAccessTokenExpiryTime] == "" {
envData.StringEnv[constants.EnvKeyAccessTokenExpiryTime] = os.Getenv(constants.EnvKeyAccessTokenExpiryTime)
if envData.StringEnv[constants.EnvKeyAccessTokenExpiryTime] == "" {
envData.StringEnv[constants.EnvKeyAccessTokenExpiryTime] = "30m"
}
}
if envData.StringEnv[constants.EnvKeyAdminSecret] == "" { if envData.StringEnv[constants.EnvKeyAdminSecret] == "" {
envData.StringEnv[constants.EnvKeyAdminSecret] = os.Getenv(constants.EnvKeyAdminSecret) envData.StringEnv[constants.EnvKeyAdminSecret] = os.Getenv(constants.EnvKeyAdminSecret)
} }

View File

@@ -165,6 +165,7 @@ func PersistEnv() error {
hasChanged = true hasChanged = true
} }
} }
envstore.EnvStoreObj.UpdateEnvStore(storeData) envstore.EnvStoreObj.UpdateEnvStore(storeData)
jwk, err := crypto.GenerateJWKBasedOnEnv() jwk, err := crypto.GenerateJWKBasedOnEnv()
if err != nil { if err != nil {

View File

@@ -53,6 +53,7 @@ type ComplexityRoot struct {
} }
Env struct { Env struct {
AccessTokenExpiryTime func(childComplexity int) int
AdminSecret func(childComplexity int) int AdminSecret func(childComplexity int) int
AllowedOrigins func(childComplexity int) int AllowedOrigins func(childComplexity int) int
AppURL func(childComplexity int) int AppURL func(childComplexity int) int
@@ -299,6 +300,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.AuthResponse.User(childComplexity), true return e.complexity.AuthResponse.User(childComplexity), true
case "Env.ACCESS_TOKEN_EXPIRY_TIME":
if e.complexity.Env.AccessTokenExpiryTime == nil {
break
}
return e.complexity.Env.AccessTokenExpiryTime(childComplexity), true
case "Env.ADMIN_SECRET": case "Env.ADMIN_SECRET":
if e.complexity.Env.AdminSecret == nil { if e.complexity.Env.AdminSecret == nil {
break break
@@ -1381,6 +1389,7 @@ type Response {
} }
type Env { type Env {
ACCESS_TOKEN_EXPIRY_TIME: String
ADMIN_SECRET: String ADMIN_SECRET: String
DATABASE_NAME: String! DATABASE_NAME: String!
DATABASE_URL: String! DATABASE_URL: String!
@@ -1432,6 +1441,7 @@ type GenerateJWTKeysResponse {
} }
input UpdateEnvInput { input UpdateEnvInput {
ACCESS_TOKEN_EXPIRY_TIME: String
ADMIN_SECRET: String ADMIN_SECRET: String
CUSTOM_ACCESS_TOKEN_SCRIPT: String CUSTOM_ACCESS_TOKEN_SCRIPT: String
OLD_ADMIN_SECRET: String OLD_ADMIN_SECRET: String
@@ -2221,6 +2231,38 @@ func (ec *executionContext) _AuthResponse_user(ctx context.Context, field graphq
return ec.marshalOUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) return ec.marshalOUser2ᚖgithubᚗcomᚋauthorizerdevᚋauthorizerᚋserverᚋgraphᚋmodelᚐUser(ctx, field.Selections, res)
} }
func (ec *executionContext) _Env_ACCESS_TOKEN_EXPIRY_TIME(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.AccessTokenExpiryTime, 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_ADMIN_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) { func (ec *executionContext) _Env_ADMIN_SECRET(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 {
@@ -8093,6 +8135,14 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
for k, v := range asMap { for k, v := range asMap {
switch k { switch k {
case "ACCESS_TOKEN_EXPIRY_TIME":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("ACCESS_TOKEN_EXPIRY_TIME"))
it.AccessTokenExpiryTime, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "ADMIN_SECRET": case "ADMIN_SECRET":
var err error var err error
@@ -8711,6 +8761,8 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
switch field.Name { switch field.Name {
case "__typename": case "__typename":
out.Values[i] = graphql.MarshalString("Env") out.Values[i] = graphql.MarshalString("Env")
case "ACCESS_TOKEN_EXPIRY_TIME":
out.Values[i] = ec._Env_ACCESS_TOKEN_EXPIRY_TIME(ctx, field, obj)
case "ADMIN_SECRET": case "ADMIN_SECRET":
out.Values[i] = ec._Env_ADMIN_SECRET(ctx, field, obj) out.Values[i] = ec._Env_ADMIN_SECRET(ctx, field, obj)
case "DATABASE_NAME": case "DATABASE_NAME":

View File

@@ -24,6 +24,7 @@ type DeleteUserInput struct {
} }
type Env struct { type Env struct {
AccessTokenExpiryTime *string `json:"ACCESS_TOKEN_EXPIRY_TIME"`
AdminSecret *string `json:"ADMIN_SECRET"` AdminSecret *string `json:"ADMIN_SECRET"`
DatabaseName string `json:"DATABASE_NAME"` DatabaseName string `json:"DATABASE_NAME"`
DatabaseURL string `json:"DATABASE_URL"` DatabaseURL string `json:"DATABASE_URL"`
@@ -179,6 +180,7 @@ type UpdateAccessInput struct {
} }
type UpdateEnvInput struct { type UpdateEnvInput struct {
AccessTokenExpiryTime *string `json:"ACCESS_TOKEN_EXPIRY_TIME"`
AdminSecret *string `json:"ADMIN_SECRET"` AdminSecret *string `json:"ADMIN_SECRET"`
CustomAccessTokenScript *string `json:"CUSTOM_ACCESS_TOKEN_SCRIPT"` CustomAccessTokenScript *string `json:"CUSTOM_ACCESS_TOKEN_SCRIPT"`
OldAdminSecret *string `json:"OLD_ADMIN_SECRET"` OldAdminSecret *string `json:"OLD_ADMIN_SECRET"`

View File

@@ -87,6 +87,7 @@ type Response {
} }
type Env { type Env {
ACCESS_TOKEN_EXPIRY_TIME: String
ADMIN_SECRET: String ADMIN_SECRET: String
DATABASE_NAME: String! DATABASE_NAME: String!
DATABASE_URL: String! DATABASE_URL: String!
@@ -138,6 +139,7 @@ type GenerateJWTKeysResponse {
} }
input UpdateEnvInput { input UpdateEnvInput {
ACCESS_TOKEN_EXPIRY_TIME: String
ADMIN_SECRET: String ADMIN_SECRET: String
CUSTOM_ACCESS_TOKEN_SCRIPT: String CUSTOM_ACCESS_TOKEN_SCRIPT: String
OLD_ADMIN_SECRET: String OLD_ADMIN_SECRET: String

View File

@@ -1,10 +1,10 @@
package handlers package handlers
import ( import (
"fmt"
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/cookie"
@@ -51,8 +51,6 @@ func AuthorizeHandler() gin.HandlerFunc {
gc.JSON(400, gin.H{"error": "invalid response mode"}) gc.JSON(400, gin.H{"error": "invalid response mode"})
} }
fmt.Println("=> redirect URI:", redirectURI)
fmt.Println("=> state:", state)
if redirectURI == "" { if redirectURI == "" {
redirectURI = "/app" redirectURI = "/app"
} }
@@ -279,7 +277,11 @@ func AuthorizeHandler() gin.HandlerFunc {
sessionstore.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID) sessionstore.SetState(authToken.FingerPrintHash, authToken.FingerPrint+"@"+user.ID)
sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID) sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
cookie.SetSession(gc, authToken.FingerPrintHash) cookie.SetSession(gc, authToken.FingerPrintHash)
expiresIn := int64(1800)
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {
expiresIn = 1
}
// used of query mode // used of query mode
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token

View File

@@ -157,7 +157,12 @@ func OAuthCallbackHandler() gin.HandlerFunc {
if err != nil { if err != nil {
c.JSON(500, gin.H{"error": err.Error()}) c.JSON(500, gin.H{"error": err.Error()})
} }
expiresIn := int64(1800)
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {
expiresIn = 1
}
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + stateValue + "&id_token=" + authToken.IDToken.Token
cookie.SetSession(c, authToken.FingerPrintHash) cookie.SetSession(c, authToken.FingerPrintHash)

View File

@@ -5,6 +5,7 @@ import (
"encoding/base64" "encoding/base64"
"net/http" "net/http"
"strings" "strings"
"time"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/cookie"
@@ -174,7 +175,11 @@ func TokenHandler() gin.HandlerFunc {
sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID) sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
cookie.SetSession(gc, authToken.FingerPrintHash) cookie.SetSession(gc, authToken.FingerPrintHash)
expiresIn := int64(1800) expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {
expiresIn = 1
}
res := map[string]interface{}{ res := map[string]interface{}{
"access_token": authToken.AccessToken.Token, "access_token": authToken.AccessToken.Token,
"id_token": authToken.IDToken.Token, "id_token": authToken.IDToken.Token,

View File

@@ -82,7 +82,12 @@ func VerifyEmailHandler() gin.HandlerFunc {
c.JSON(500, errorRes) c.JSON(500, errorRes)
return return
} }
expiresIn := int64(1800)
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {
expiresIn = 1
}
params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token params := "access_token=" + authToken.AccessToken.Token + "&token_type=bearer&expires_in=" + strconv.FormatInt(expiresIn, 10) + "&state=" + state + "&id_token=" + authToken.IDToken.Token
cookie.SetSession(c, authToken.FingerPrintHash) cookie.SetSession(c, authToken.FingerPrintHash)

View File

@@ -27,6 +27,7 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
// get clone of store // get clone of store
store := envstore.EnvStoreObj.GetEnvStoreClone() store := envstore.EnvStoreObj.GetEnvStoreClone()
accessTokenExpiryTime := store.StringEnv[constants.EnvKeyAccessTokenExpiryTime]
adminSecret := store.StringEnv[constants.EnvKeyAdminSecret] adminSecret := store.StringEnv[constants.EnvKeyAdminSecret]
clientID := store.StringEnv[constants.EnvKeyClientID] clientID := store.StringEnv[constants.EnvKeyClientID]
clientSecret := store.StringEnv[constants.EnvKeyClientSecret] clientSecret := store.StringEnv[constants.EnvKeyClientSecret]
@@ -66,7 +67,12 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
organizationName := store.StringEnv[constants.EnvKeyOrganizationName] organizationName := store.StringEnv[constants.EnvKeyOrganizationName]
organizationLogo := store.StringEnv[constants.EnvKeyOrganizationLogo] organizationLogo := store.StringEnv[constants.EnvKeyOrganizationLogo]
if accessTokenExpiryTime == "" {
accessTokenExpiryTime = "30m"
}
res = &model.Env{ res = &model.Env{
AccessTokenExpiryTime: &accessTokenExpiryTime,
AdminSecret: &adminSecret, AdminSecret: &adminSecret,
DatabaseName: databaseName, DatabaseName: databaseName,
DatabaseURL: databaseURL, DatabaseURL: databaseURL,

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"log" "log"
"strings" "strings"
"time"
"github.com/authorizerdev/authorizer/server/constants" "github.com/authorizerdev/authorizer/server/constants"
"github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/cookie"
@@ -73,7 +74,11 @@ func LoginResolver(ctx context.Context, params model.LoginInput) (*model.AuthRes
return res, err return res, err
} }
expiresIn := int64(1800) expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {
expiresIn = 1
}
res = &model.AuthResponse{ res = &model.AuthResponse{
Message: `Logged in successfully`, Message: `Logged in successfully`,
AccessToken: &authToken.AccessToken.Token, AccessToken: &authToken.AccessToken.Token,

View File

@@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"log" "log"
"time"
"github.com/authorizerdev/authorizer/server/cookie" "github.com/authorizerdev/authorizer/server/cookie"
"github.com/authorizerdev/authorizer/server/db" "github.com/authorizerdev/authorizer/server/db"
@@ -73,7 +74,11 @@ func SessionResolver(ctx context.Context, params *model.SessionQueryInput) (*mod
sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID) sessionstore.SetState(authToken.AccessToken.Token, authToken.FingerPrint+"@"+user.ID)
cookie.SetSession(gc, authToken.FingerPrintHash) cookie.SetSession(gc, authToken.FingerPrintHash)
expiresIn := int64(1800) expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {
expiresIn = 1
}
res = &model.AuthResponse{ res = &model.AuthResponse{
Message: `Session token refreshed`, Message: `Session token refreshed`,
AccessToken: &authToken.AccessToken.Token, AccessToken: &authToken.AccessToken.Token,

View File

@@ -176,7 +176,10 @@ func SignupResolver(ctx context.Context, params model.SignUpInput) (*model.AuthR
cookie.SetSession(gc, authToken.FingerPrintHash) cookie.SetSession(gc, authToken.FingerPrintHash)
go utils.SaveSessionInDB(gc, user.ID) go utils.SaveSessionInDB(gc, user.ID)
expiresIn := int64(1800) expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {
expiresIn = 1
}
res = &model.AuthResponse{ res = &model.AuthResponse{
Message: `Signed up successfully.`, Message: `Signed up successfully.`,

View File

@@ -64,7 +64,11 @@ func VerifyEmailResolver(ctx context.Context, params model.VerifyEmailInput) (*m
cookie.SetSession(gc, authToken.FingerPrintHash) cookie.SetSession(gc, authToken.FingerPrintHash)
go utils.SaveSessionInDB(gc, user.ID) go utils.SaveSessionInDB(gc, user.ID)
expiresIn := int64(1800) expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
if expiresIn <= 0 {
expiresIn = 1
}
res = &model.AuthResponse{ res = &model.AuthResponse{
Message: `Email verified successfully.`, Message: `Email verified successfully.`,
AccessToken: &authToken.AccessToken.Token, AccessToken: &authToken.AccessToken.Token,

View File

@@ -130,7 +130,11 @@ func CreateRefreshToken(user models.User, roles, scopes []string, hostname, nonc
// 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, scopes []string, hostName, nonce string) (string, int64, error) { func CreateAccessToken(user models.User, roles, scopes []string, hostName, nonce string) (string, int64, error) {
expiryBound := time.Minute * 30 expiryBound, err := utils.ParseDurationInSeconds(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAccessTokenExpiryTime))
if err != nil {
expiryBound = time.Minute * 30
}
expiresAt := time.Now().Add(expiryBound).Unix() expiresAt := time.Now().Add(expiryBound).Unix()
customClaims := jwt.MapClaims{ customClaims := jwt.MapClaims{
@@ -282,7 +286,11 @@ func ValidateBrowserSession(gc *gin.Context, encryptedSession string) (*SessionD
// CreateIDToken util to create JWT token, based on // CreateIDToken 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 CreateIDToken(user models.User, roles []string, hostname, nonce string) (string, int64, error) { func CreateIDToken(user models.User, roles []string, hostname, nonce string) (string, int64, error) {
expiryBound := time.Minute * 30 expiryBound, err := utils.ParseDurationInSeconds(envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAccessTokenExpiryTime))
if err != nil {
expiryBound = time.Minute * 30
}
expiresAt := time.Now().Add(expiryBound).Unix() expiresAt := time.Now().Add(expiryBound).Unix()
resUser := user.AsAPIUser() resUser := user.AsAPIUser()

21
server/utils/parser.go Normal file
View File

@@ -0,0 +1,21 @@
package utils
import (
"errors"
"time"
)
// ParseDurationInSeconds parses input s, removes ms/us/ns and returns result duration
func ParseDurationInSeconds(s string) (time.Duration, error) {
d, err := time.ParseDuration(s)
if err != nil {
return 0, err
}
d = d.Truncate(time.Second)
if d <= 0 {
return 0, errors.New(`duration must be greater than 0s`)
}
return d, nil
}

View File

@@ -10,7 +10,20 @@ import (
) )
// GetHost returns hostname from request context // GetHost returns hostname from request context
// if X-Authorizer-URL header is set it is given highest priority
// if EnvKeyAuthorizerURL is set it is given second highest priority.
// if above 2 are not set the requesting host name is used
func GetHost(c *gin.Context) string { func GetHost(c *gin.Context) string {
authorizerURL := c.Request.Header.Get("X-Authorizer-URL")
if authorizerURL != "" {
return authorizerURL
}
authorizerURL = envstore.EnvStoreObj.GetStringStoreEnvVariable(constants.EnvKeyAuthorizerURL)
if authorizerURL != "" {
return authorizerURL
}
scheme := c.Request.Header.Get("X-Forwarded-Proto") scheme := c.Request.Header.Get("X-Forwarded-Proto")
if scheme != "https" { if scheme != "https" {
scheme = "http" scheme = "http"