Merge branch 'main' of https://github.com/authorizerdev/authorizer
All checks were successful
deploy / deploy (push) Successful in 1m38s
All checks were successful
deploy / deploy (push) Successful in 1m38s
This commit is contained in:
commit
6930797181
22
app/package-lock.json
generated
22
app/package-lock.json
generated
|
@ -9,7 +9,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^1.1.13",
|
"@authorizerdev/authorizer-react": "^1.1.15",
|
||||||
"@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",
|
||||||
|
@ -27,9 +27,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@authorizerdev/authorizer-js": {
|
"node_modules/@authorizerdev/authorizer-js": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.17",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.17.tgz",
|
||||||
"integrity": "sha512-9+9phHUMF+AeDM0y+XQvIRDoerOXnQ1vfTfYN6KxWN1apdrkAd9nzS1zUsA2uJSnX3fFZOErn83GjbYYCYF1BA==",
|
"integrity": "sha512-aF/lu9wZR7TBRaRMAes/hy1q8cZzz5Zo60QLU9Iu09sqnhliHJCp5wSkjsVH+V4ER9i7bmJ2HNABTmOdluxj3A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-fetch": "^3.1.5"
|
"cross-fetch": "^3.1.5"
|
||||||
},
|
},
|
||||||
|
@ -41,11 +41,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@authorizerdev/authorizer-react": {
|
"node_modules/@authorizerdev/authorizer-react": {
|
||||||
"version": "1.1.13",
|
"version": "1.1.15",
|
||||||
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.15.tgz",
|
||||||
"integrity": "sha512-LmpzyfR0+nEn+bjUrb/QU9b3kiVoYzMBIvcQ1nV4TNvrvVSqbLPKk+GmoIPkiBEtfy/QSM6XFLkiGNGD9BRP+g==",
|
"integrity": "sha512-Y71qC4GUAHL0QCNj5mVv0Jwv1cIg4Y0yXRiOeYV21C1NMleyLRXgw4qzJ/Vk8rmXsxqSHmr8SGrwOLcSKA2oMA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-js": "^1.2.6"
|
"@authorizerdev/authorizer-js": "^1.2.17"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
|
@ -607,9 +607,9 @@
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
},
|
},
|
||||||
"node_modules/node-fetch": {
|
"node_modules/node-fetch": {
|
||||||
"version": "2.6.12",
|
"version": "2.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||||
"integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==",
|
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"whatwg-url": "^5.0.0"
|
"whatwg-url": "^5.0.0"
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"author": "Lakhan Samani",
|
"author": "Lakhan Samani",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@authorizerdev/authorizer-react": "^1.1.13",
|
"@authorizerdev/authorizer-react": "^1.1.15",
|
||||||
"@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",
|
||||||
|
|
|
@ -37,8 +37,8 @@ export default function Login({ urlProps }: { urlProps: Record<string, any> }) {
|
||||||
{view === VIEW_TYPES.LOGIN && (
|
{view === VIEW_TYPES.LOGIN && (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<h1 style={{ textAlign: 'center' }}>Login</h1>
|
<h1 style={{ textAlign: 'center' }}>Login</h1>
|
||||||
<br />
|
|
||||||
<AuthorizerSocialLogin urlProps={urlProps} />
|
<AuthorizerSocialLogin urlProps={urlProps} />
|
||||||
|
<br />
|
||||||
{config.is_basic_authentication_enabled &&
|
{config.is_basic_authentication_enabled &&
|
||||||
!config.is_magic_link_login_enabled && (
|
!config.is_magic_link_login_enabled && (
|
||||||
<AuthorizerBasicAuthLogin urlProps={urlProps} />
|
<AuthorizerBasicAuthLogin urlProps={urlProps} />
|
||||||
|
|
|
@ -2,19 +2,19 @@
|
||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"@authorizerdev/authorizer-js@^1.2.6":
|
"@authorizerdev/authorizer-js@^1.2.17":
|
||||||
version "1.2.6"
|
version "1.2.17"
|
||||||
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.6.tgz"
|
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-js/-/authorizer-js-1.2.17.tgz"
|
||||||
integrity sha512-9+9phHUMF+AeDM0y+XQvIRDoerOXnQ1vfTfYN6KxWN1apdrkAd9nzS1zUsA2uJSnX3fFZOErn83GjbYYCYF1BA==
|
integrity sha512-aF/lu9wZR7TBRaRMAes/hy1q8cZzz5Zo60QLU9Iu09sqnhliHJCp5wSkjsVH+V4ER9i7bmJ2HNABTmOdluxj3A==
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-fetch "^3.1.5"
|
cross-fetch "^3.1.5"
|
||||||
|
|
||||||
"@authorizerdev/authorizer-react@^1.1.13":
|
"@authorizerdev/authorizer-react@^1.1.15":
|
||||||
version "1.1.13"
|
version "1.1.15"
|
||||||
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.13.tgz"
|
resolved "https://registry.npmjs.org/@authorizerdev/authorizer-react/-/authorizer-react-1.1.15.tgz"
|
||||||
integrity sha512-LmpzyfR0+nEn+bjUrb/QU9b3kiVoYzMBIvcQ1nV4TNvrvVSqbLPKk+GmoIPkiBEtfy/QSM6XFLkiGNGD9BRP+g==
|
integrity sha512-Y71qC4GUAHL0QCNj5mVv0Jwv1cIg4Y0yXRiOeYV21C1NMleyLRXgw4qzJ/Vk8rmXsxqSHmr8SGrwOLcSKA2oMA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@authorizerdev/authorizer-js" "^1.2.6"
|
"@authorizerdev/authorizer-js" "^1.2.17"
|
||||||
|
|
||||||
"@babel/code-frame@^7.22.13":
|
"@babel/code-frame@^7.22.13":
|
||||||
version "7.22.13"
|
version "7.22.13"
|
||||||
|
@ -420,9 +420,9 @@ ms@2.1.2:
|
||||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||||
|
|
||||||
node-fetch@^2.6.12:
|
node-fetch@^2.6.12:
|
||||||
version "2.6.12"
|
version "2.7.0"
|
||||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz"
|
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz"
|
||||||
integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==
|
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-url "^5.0.0"
|
whatwg-url "^5.0.0"
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import {
|
||||||
FaApple,
|
FaApple,
|
||||||
FaTwitter,
|
FaTwitter,
|
||||||
FaMicrosoft,
|
FaMicrosoft,
|
||||||
|
FaTwitch,
|
||||||
} from 'react-icons/fa';
|
} from 'react-icons/fa';
|
||||||
import {
|
import {
|
||||||
TextInputType,
|
TextInputType,
|
||||||
|
@ -397,6 +398,44 @@ const OAuthConfig = ({
|
||||||
/>
|
/>
|
||||||
</Center>
|
</Center>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex direction={isNotSmallerScreen ? 'row' : 'column'}>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '55px' : '35px'}
|
||||||
|
h="35px"
|
||||||
|
marginRight="1.5%"
|
||||||
|
border="1px solid #3b5998"
|
||||||
|
borderRadius="5px"
|
||||||
|
>
|
||||||
|
<FaTwitch />
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
marginRight="1.5%"
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
inputType={TextInputType.TWITCH_CLIENT_ID}
|
||||||
|
placeholder="Twitch Client ID"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
<Center
|
||||||
|
w={isNotSmallerScreen ? '70%' : '100%'}
|
||||||
|
mt={isNotSmallerScreen ? '0' : '3'}
|
||||||
|
>
|
||||||
|
<InputField
|
||||||
|
borderRadius={5}
|
||||||
|
variables={envVariables}
|
||||||
|
setVariables={setVariables}
|
||||||
|
fieldVisibility={fieldVisibility}
|
||||||
|
setFieldVisibility={setFieldVisibility}
|
||||||
|
inputType={HiddenInputType.TWITCH_CLIENT_SECRET}
|
||||||
|
placeholder="Twitch Client Secret"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Flex>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,6 +12,7 @@ export const TextInputType = {
|
||||||
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
|
TWITTER_CLIENT_ID: 'TWITTER_CLIENT_ID',
|
||||||
MICROSOFT_CLIENT_ID: 'MICROSOFT_CLIENT_ID',
|
MICROSOFT_CLIENT_ID: 'MICROSOFT_CLIENT_ID',
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: 'MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID',
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: 'MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID',
|
||||||
|
TWITCH_CLIENT_ID: 'TWITCH_CLIENT_ID',
|
||||||
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
|
JWT_ROLE_CLAIM: 'JWT_ROLE_CLAIM',
|
||||||
REDIS_URL: 'REDIS_URL',
|
REDIS_URL: 'REDIS_URL',
|
||||||
SMTP_HOST: 'SMTP_HOST',
|
SMTP_HOST: 'SMTP_HOST',
|
||||||
|
@ -42,6 +43,7 @@ export const HiddenInputType = {
|
||||||
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
|
||||||
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
TWITTER_CLIENT_SECRET: 'TWITTER_CLIENT_SECRET',
|
||||||
MICROSOFT_CLIENT_SECRET: 'MICROSOFT_CLIENT_SECRET',
|
MICROSOFT_CLIENT_SECRET: 'MICROSOFT_CLIENT_SECRET',
|
||||||
|
TWITCH_CLIENT_SECRET: 'TWITCH_CLIENT_SECRET',
|
||||||
JWT_SECRET: 'JWT_SECRET',
|
JWT_SECRET: 'JWT_SECRET',
|
||||||
SMTP_PASSWORD: 'SMTP_PASSWORD',
|
SMTP_PASSWORD: 'SMTP_PASSWORD',
|
||||||
ADMIN_SECRET: 'ADMIN_SECRET',
|
ADMIN_SECRET: 'ADMIN_SECRET',
|
||||||
|
@ -132,6 +134,8 @@ export interface envVarTypes {
|
||||||
MICROSOFT_CLIENT_ID: string;
|
MICROSOFT_CLIENT_ID: string;
|
||||||
MICROSOFT_CLIENT_SECRET: string;
|
MICROSOFT_CLIENT_SECRET: string;
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: string;
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: string;
|
||||||
|
TWITCH_CLIENT_ID: string;
|
||||||
|
TWITCH_CLIENT_SECRET: string;
|
||||||
ROLES: [string] | [];
|
ROLES: [string] | [];
|
||||||
DEFAULT_ROLES: [string] | [];
|
DEFAULT_ROLES: [string] | [];
|
||||||
PROTECTED_ROLES: [string] | [];
|
PROTECTED_ROLES: [string] | [];
|
||||||
|
|
|
@ -35,6 +35,8 @@ export const EnvVariablesQuery = `
|
||||||
MICROSOFT_CLIENT_ID
|
MICROSOFT_CLIENT_ID
|
||||||
MICROSOFT_CLIENT_SECRET
|
MICROSOFT_CLIENT_SECRET
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID
|
||||||
|
TWITCH_CLIENT_ID
|
||||||
|
TWITCH_CLIENT_SECRET
|
||||||
DEFAULT_ROLES
|
DEFAULT_ROLES
|
||||||
PROTECTED_ROLES
|
PROTECTED_ROLES
|
||||||
ROLES
|
ROLES
|
||||||
|
|
|
@ -55,6 +55,8 @@ const Environment = () => {
|
||||||
MICROSOFT_CLIENT_ID: '',
|
MICROSOFT_CLIENT_ID: '',
|
||||||
MICROSOFT_CLIENT_SECRET: '',
|
MICROSOFT_CLIENT_SECRET: '',
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: '',
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: '',
|
||||||
|
TWITCH_CLIENT_ID: '',
|
||||||
|
TWITCH_CLIENT_SECRET: '',
|
||||||
ROLES: [],
|
ROLES: [],
|
||||||
DEFAULT_ROLES: [],
|
DEFAULT_ROLES: [],
|
||||||
PROTECTED_ROLES: [],
|
PROTECTED_ROLES: [],
|
||||||
|
@ -107,6 +109,7 @@ const Environment = () => {
|
||||||
LINKEDIN_CLIENT_SECRET: false,
|
LINKEDIN_CLIENT_SECRET: false,
|
||||||
APPLE_CLIENT_SECRET: false,
|
APPLE_CLIENT_SECRET: false,
|
||||||
TWITTER_CLIENT_SECRET: false,
|
TWITTER_CLIENT_SECRET: false,
|
||||||
|
TWITCH_CLIENT_SECRET: false,
|
||||||
JWT_SECRET: false,
|
JWT_SECRET: false,
|
||||||
SMTP_PASSWORD: false,
|
SMTP_PASSWORD: false,
|
||||||
ADMIN_SECRET: false,
|
ADMIN_SECRET: false,
|
||||||
|
|
|
@ -19,7 +19,7 @@ type Provider interface {
|
||||||
// Generate totp: to generate totp, store secret into db and returns base64 of QR code image
|
// Generate totp: to generate totp, store secret into db and returns base64 of QR code image
|
||||||
Generate(ctx context.Context, id string) (*AuthenticatorConfig, error)
|
Generate(ctx context.Context, id string) (*AuthenticatorConfig, error)
|
||||||
// Validate totp: user passcode with secret stored in our db
|
// Validate totp: user passcode with secret stored in our db
|
||||||
Validate(ctx context.Context, passcode string, id string) (bool, error)
|
Validate(ctx context.Context, passcode string, userID string) (bool, error)
|
||||||
// RecoveryCode totp: gives a recovery code for first time user
|
// ValidateRecoveryCode totp: allows user to validate using recovery code incase if they lost their device
|
||||||
RecoveryCode(ctx context.Context, id string) (*string, error)
|
ValidateRecoveryCode(ctx context.Context, recoveryCode, userID string) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"image/png"
|
"image/png"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -113,24 +114,38 @@ func (p *provider) Validate(ctx context.Context, passcode string, userID string)
|
||||||
return status, nil
|
return status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecoveryCode generates a recovery code for a user's TOTP authentication, if not already verified.
|
// ValidateRecoveryCode validates a Time-Based One-Time Password (TOTP) recovery code against the stored TOTP recovery code for a user.
|
||||||
func (p *provider) RecoveryCode(ctx context.Context, id string) (*string, error) {
|
func (p *provider) ValidateRecoveryCode(ctx context.Context, recoveryCode, userID string) (bool, error) {
|
||||||
// get totp details
|
// get totp details
|
||||||
// totpModel, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, id, constants.EnvKeyTOTPAuthenticator)
|
totpModel, err := db.Provider.GetAuthenticatorDetailsByUserId(ctx, userID, constants.EnvKeyTOTPAuthenticator)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return nil, fmt.Errorf("error while getting totp details from authenticators")
|
return false, err
|
||||||
// }
|
}
|
||||||
// //TODO *totpModel.RecoveryCode == "null" used to just verify couchbase recoveryCode value to be nil
|
// convert recoveryCodes to map
|
||||||
// // have to find another way round
|
recoveryCodesMap := map[string]bool{}
|
||||||
// if totpModel.RecoveryCode == nil || *totpModel.RecoveryCode == "null" {
|
err = json.Unmarshal([]byte(refs.StringValue(totpModel.RecoveryCodes)), &recoveryCodesMap)
|
||||||
// recoveryCode := utils.GenerateTOTPRecoveryCode()
|
if err != nil {
|
||||||
// totpModel.RecoveryCode = &recoveryCode
|
return false, err
|
||||||
|
}
|
||||||
// _, err = db.Provider.UpdateAuthenticator(ctx, totpModel)
|
// check if recovery code is valid
|
||||||
// if err != nil {
|
if val, ok := recoveryCodesMap[recoveryCode]; !ok {
|
||||||
// return nil, fmt.Errorf("error while updaing authenticator table for totp")
|
return false, fmt.Errorf("invalid recovery code")
|
||||||
// }
|
} else if val {
|
||||||
// return &recoveryCode, nil
|
return false, fmt.Errorf("recovery code already used")
|
||||||
// }
|
}
|
||||||
return nil, nil
|
// update recovery code map
|
||||||
|
recoveryCodesMap[recoveryCode] = true
|
||||||
|
// convert recoveryCodesMap to string
|
||||||
|
jsonData, err := json.Marshal(recoveryCodesMap)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
recoveryCodesString := string(jsonData)
|
||||||
|
totpModel.RecoveryCodes = refs.NewStringRef(recoveryCodesString)
|
||||||
|
// update recovery code map in db
|
||||||
|
_, err = db.Provider.UpdateAuthenticator(ctx, totpModel)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,4 +23,6 @@ const (
|
||||||
AuthRecipeMethodTwitter = "twitter"
|
AuthRecipeMethodTwitter = "twitter"
|
||||||
// AuthRecipeMethodMicrosoft is the microsoft auth method
|
// AuthRecipeMethodMicrosoft is the microsoft auth method
|
||||||
AuthRecipeMethodMicrosoft = "microsoft"
|
AuthRecipeMethodMicrosoft = "microsoft"
|
||||||
|
// AuthRecipeMethodTwitch is the twitch auth method
|
||||||
|
AuthRecipeMethodTwitch = "twitch"
|
||||||
)
|
)
|
||||||
|
|
|
@ -118,6 +118,10 @@ const (
|
||||||
EnvKeyMicrosoftActiveDirectoryTenantID = "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID"
|
EnvKeyMicrosoftActiveDirectoryTenantID = "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID"
|
||||||
// EnvKeyMicrosoftClientSecret key for env variable MICROSOFT_CLIENT_SECRET
|
// EnvKeyMicrosoftClientSecret key for env variable MICROSOFT_CLIENT_SECRET
|
||||||
EnvKeyMicrosoftClientSecret = "MICROSOFT_CLIENT_SECRET"
|
EnvKeyMicrosoftClientSecret = "MICROSOFT_CLIENT_SECRET"
|
||||||
|
// EnvKeyTwitchClientID key for env variable TWITCH_CLIENT_ID
|
||||||
|
EnvKeyTwitchClientID = "TWITCH_CLIENT_ID"
|
||||||
|
// EnvKeyTwitchClientSecret key for env variable TWITCH_CLIENT_SECRET
|
||||||
|
EnvKeyTwitchClientSecret = "TWITCH_CLIENT_SECRET"
|
||||||
// EnvKeyOrganizationName key for env variable ORGANIZATION_NAME
|
// EnvKeyOrganizationName key for env variable ORGANIZATION_NAME
|
||||||
EnvKeyOrganizationName = "ORGANIZATION_NAME"
|
EnvKeyOrganizationName = "ORGANIZATION_NAME"
|
||||||
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
|
// EnvKeyOrganizationLogo key for env variable ORGANIZATION_LOGO
|
||||||
|
|
|
@ -139,6 +139,8 @@ type ComplexityRoot struct {
|
||||||
SMTPUsername func(childComplexity int) int
|
SMTPUsername func(childComplexity int) int
|
||||||
SenderEmail func(childComplexity int) int
|
SenderEmail func(childComplexity int) int
|
||||||
SenderName func(childComplexity int) int
|
SenderName func(childComplexity int) int
|
||||||
|
TwitchClientID func(childComplexity int) int
|
||||||
|
TwitchClientSecret func(childComplexity int) int
|
||||||
TwitterClientID func(childComplexity int) int
|
TwitterClientID func(childComplexity int) int
|
||||||
TwitterClientSecret func(childComplexity int) int
|
TwitterClientSecret func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
@ -173,6 +175,7 @@ type ComplexityRoot struct {
|
||||||
IsMultiFactorAuthEnabled func(childComplexity int) int
|
IsMultiFactorAuthEnabled func(childComplexity int) int
|
||||||
IsSignUpEnabled func(childComplexity int) int
|
IsSignUpEnabled func(childComplexity int) int
|
||||||
IsStrongPasswordEnabled func(childComplexity int) int
|
IsStrongPasswordEnabled func(childComplexity int) int
|
||||||
|
IsTwitchLoginEnabled func(childComplexity int) int
|
||||||
IsTwitterLoginEnabled func(childComplexity int) int
|
IsTwitterLoginEnabled func(childComplexity int) int
|
||||||
Version func(childComplexity int) int
|
Version func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
@ -992,6 +995,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Env.SenderName(childComplexity), true
|
return e.complexity.Env.SenderName(childComplexity), true
|
||||||
|
|
||||||
|
case "Env.TWITCH_CLIENT_ID":
|
||||||
|
if e.complexity.Env.TwitchClientID == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Env.TwitchClientID(childComplexity), true
|
||||||
|
|
||||||
|
case "Env.TWITCH_CLIENT_SECRET":
|
||||||
|
if e.complexity.Env.TwitchClientSecret == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Env.TwitchClientSecret(childComplexity), true
|
||||||
|
|
||||||
case "Env.TWITTER_CLIENT_ID":
|
case "Env.TWITTER_CLIENT_ID":
|
||||||
if e.complexity.Env.TwitterClientID == nil {
|
if e.complexity.Env.TwitterClientID == nil {
|
||||||
break
|
break
|
||||||
|
@ -1146,6 +1163,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
||||||
|
|
||||||
return e.complexity.Meta.IsStrongPasswordEnabled(childComplexity), true
|
return e.complexity.Meta.IsStrongPasswordEnabled(childComplexity), true
|
||||||
|
|
||||||
|
case "Meta.is_twitch_login_enabled":
|
||||||
|
if e.complexity.Meta.IsTwitchLoginEnabled == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.complexity.Meta.IsTwitchLoginEnabled(childComplexity), true
|
||||||
|
|
||||||
case "Meta.is_twitter_login_enabled":
|
case "Meta.is_twitter_login_enabled":
|
||||||
if e.complexity.Meta.IsTwitterLoginEnabled == nil {
|
if e.complexity.Meta.IsTwitterLoginEnabled == nil {
|
||||||
break
|
break
|
||||||
|
@ -2324,6 +2348,7 @@ type Meta {
|
||||||
is_apple_login_enabled: Boolean!
|
is_apple_login_enabled: Boolean!
|
||||||
is_twitter_login_enabled: Boolean!
|
is_twitter_login_enabled: Boolean!
|
||||||
is_microsoft_login_enabled: Boolean!
|
is_microsoft_login_enabled: Boolean!
|
||||||
|
is_twitch_login_enabled: Boolean!
|
||||||
is_email_verification_enabled: Boolean!
|
is_email_verification_enabled: Boolean!
|
||||||
is_basic_authentication_enabled: Boolean!
|
is_basic_authentication_enabled: Boolean!
|
||||||
is_magic_link_login_enabled: Boolean!
|
is_magic_link_login_enabled: Boolean!
|
||||||
|
@ -2477,6 +2502,8 @@ type Env {
|
||||||
MICROSOFT_CLIENT_ID: String
|
MICROSOFT_CLIENT_ID: String
|
||||||
MICROSOFT_CLIENT_SECRET: String
|
MICROSOFT_CLIENT_SECRET: String
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
||||||
|
TWITCH_CLIENT_ID: String
|
||||||
|
TWITCH_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
ORGANIZATION_NAME: String
|
||||||
ORGANIZATION_LOGO: String
|
ORGANIZATION_LOGO: String
|
||||||
APP_COOKIE_SECURE: Boolean!
|
APP_COOKIE_SECURE: Boolean!
|
||||||
|
@ -2604,6 +2631,8 @@ input UpdateEnvInput {
|
||||||
MICROSOFT_CLIENT_ID: String
|
MICROSOFT_CLIENT_ID: String
|
||||||
MICROSOFT_CLIENT_SECRET: String
|
MICROSOFT_CLIENT_SECRET: String
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
||||||
|
TWITCH_CLIENT_ID: String
|
||||||
|
TWITCH_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
ORGANIZATION_NAME: String
|
||||||
ORGANIZATION_LOGO: String
|
ORGANIZATION_LOGO: String
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
||||||
|
@ -2870,7 +2899,7 @@ input VerifyOTPRequest {
|
||||||
email: String
|
email: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
otp: String!
|
otp: String!
|
||||||
totp: Boolean
|
is_totp: Boolean
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
# it is used to get code for an on-going auth process during login
|
# it is used to get code for an on-going auth process during login
|
||||||
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
|
# and use that code for setting ` + "`" + `c_hash` + "`" + ` in id_token
|
||||||
|
@ -6833,6 +6862,88 @@ func (ec *executionContext) fieldContext_Env_MICROSOFT_ACTIVE_DIRECTORY_TENANT_I
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Env_TWITCH_CLIENT_ID(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Env_TWITCH_CLIENT_ID(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.TwitchClientID, 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) fieldContext_Env_TWITCH_CLIENT_ID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Env",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Env_TWITCH_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Env_TWITCH_CLIENT_SECRET(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.TwitchClientSecret, 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) fieldContext_Env_TWITCH_CLIENT_SECRET(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Env",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Env_ORGANIZATION_NAME(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Env_ORGANIZATION_NAME(ctx context.Context, field graphql.CollectedField, obj *model.Env) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_Env_ORGANIZATION_NAME(ctx, field)
|
fc, err := ec.fieldContext_Env_ORGANIZATION_NAME(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7954,6 +8065,50 @@ func (ec *executionContext) fieldContext_Meta_is_microsoft_login_enabled(ctx con
|
||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) _Meta_is_twitch_login_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
|
||||||
|
fc, err := ec.fieldContext_Meta_is_twitch_login_enabled(ctx, field)
|
||||||
|
if err != nil {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = graphql.Null
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
return obj.IsTwitchLoginEnabled, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if resTmp == nil {
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
res := resTmp.(bool)
|
||||||
|
fc.Result = res
|
||||||
|
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ec *executionContext) fieldContext_Meta_is_twitch_login_enabled(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
|
fc = &graphql.FieldContext{
|
||||||
|
Object: "Meta",
|
||||||
|
Field: field,
|
||||||
|
IsMethod: false,
|
||||||
|
IsResolver: false,
|
||||||
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
|
return nil, errors.New("field of type Boolean does not have child fields")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return fc, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Meta_is_email_verification_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Meta_is_email_verification_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_Meta_is_email_verification_enabled(ctx, field)
|
fc, err := ec.fieldContext_Meta_is_email_verification_enabled(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -10484,6 +10639,8 @@ func (ec *executionContext) fieldContext_Query_meta(ctx context.Context, field g
|
||||||
return ec.fieldContext_Meta_is_twitter_login_enabled(ctx, field)
|
return ec.fieldContext_Meta_is_twitter_login_enabled(ctx, field)
|
||||||
case "is_microsoft_login_enabled":
|
case "is_microsoft_login_enabled":
|
||||||
return ec.fieldContext_Meta_is_microsoft_login_enabled(ctx, field)
|
return ec.fieldContext_Meta_is_microsoft_login_enabled(ctx, field)
|
||||||
|
case "is_twitch_login_enabled":
|
||||||
|
return ec.fieldContext_Meta_is_twitch_login_enabled(ctx, field)
|
||||||
case "is_email_verification_enabled":
|
case "is_email_verification_enabled":
|
||||||
return ec.fieldContext_Meta_is_email_verification_enabled(ctx, field)
|
return ec.fieldContext_Meta_is_email_verification_enabled(ctx, field)
|
||||||
case "is_basic_authentication_enabled":
|
case "is_basic_authentication_enabled":
|
||||||
|
@ -11208,6 +11365,10 @@ func (ec *executionContext) fieldContext_Query__env(ctx context.Context, field g
|
||||||
return ec.fieldContext_Env_MICROSOFT_CLIENT_SECRET(ctx, field)
|
return ec.fieldContext_Env_MICROSOFT_CLIENT_SECRET(ctx, field)
|
||||||
case "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID":
|
case "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID":
|
||||||
return ec.fieldContext_Env_MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID(ctx, field)
|
return ec.fieldContext_Env_MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID(ctx, field)
|
||||||
|
case "TWITCH_CLIENT_ID":
|
||||||
|
return ec.fieldContext_Env_TWITCH_CLIENT_ID(ctx, field)
|
||||||
|
case "TWITCH_CLIENT_SECRET":
|
||||||
|
return ec.fieldContext_Env_TWITCH_CLIENT_SECRET(ctx, field)
|
||||||
case "ORGANIZATION_NAME":
|
case "ORGANIZATION_NAME":
|
||||||
return ec.fieldContext_Env_ORGANIZATION_NAME(ctx, field)
|
return ec.fieldContext_Env_ORGANIZATION_NAME(ctx, field)
|
||||||
case "ORGANIZATION_LOGO":
|
case "ORGANIZATION_LOGO":
|
||||||
|
@ -17715,7 +17876,7 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_LOCAL_NAME", "SENDER_EMAIL", "SENDER_NAME", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "MICROSOFT_CLIENT_ID", "MICROSOFT_CLIENT_SECRET", "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID", "ORGANIZATION_NAME", "ORGANIZATION_LOGO", "DEFAULT_AUTHORIZE_RESPONSE_TYPE", "DEFAULT_AUTHORIZE_RESPONSE_MODE", "DISABLE_PLAYGROUND", "DISABLE_MAIL_OTP_LOGIN", "DISABLE_TOTP_LOGIN"}
|
fieldsInOrder := [...]string{"ACCESS_TOKEN_EXPIRY_TIME", "ADMIN_SECRET", "CUSTOM_ACCESS_TOKEN_SCRIPT", "OLD_ADMIN_SECRET", "SMTP_HOST", "SMTP_PORT", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_LOCAL_NAME", "SENDER_EMAIL", "SENDER_NAME", "JWT_TYPE", "JWT_SECRET", "JWT_PRIVATE_KEY", "JWT_PUBLIC_KEY", "ALLOWED_ORIGINS", "APP_URL", "RESET_PASSWORD_URL", "APP_COOKIE_SECURE", "ADMIN_COOKIE_SECURE", "DISABLE_EMAIL_VERIFICATION", "DISABLE_BASIC_AUTHENTICATION", "DISABLE_MAGIC_LINK_LOGIN", "DISABLE_LOGIN_PAGE", "DISABLE_SIGN_UP", "DISABLE_REDIS_FOR_ENV", "DISABLE_STRONG_PASSWORD", "DISABLE_MULTI_FACTOR_AUTHENTICATION", "ENFORCE_MULTI_FACTOR_AUTHENTICATION", "ROLES", "PROTECTED_ROLES", "DEFAULT_ROLES", "JWT_ROLE_CLAIM", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "FACEBOOK_CLIENT_ID", "FACEBOOK_CLIENT_SECRET", "LINKEDIN_CLIENT_ID", "LINKEDIN_CLIENT_SECRET", "APPLE_CLIENT_ID", "APPLE_CLIENT_SECRET", "TWITTER_CLIENT_ID", "TWITTER_CLIENT_SECRET", "MICROSOFT_CLIENT_ID", "MICROSOFT_CLIENT_SECRET", "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID", "TWITCH_CLIENT_ID", "TWITCH_CLIENT_SECRET", "ORGANIZATION_NAME", "ORGANIZATION_LOGO", "DEFAULT_AUTHORIZE_RESPONSE_TYPE", "DEFAULT_AUTHORIZE_RESPONSE_MODE", "DISABLE_PLAYGROUND", "DISABLE_MAIL_OTP_LOGIN", "DISABLE_TOTP_LOGIN"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -18154,6 +18315,24 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.MicrosoftActiveDirectoryTenantID = data
|
it.MicrosoftActiveDirectoryTenantID = data
|
||||||
|
case "TWITCH_CLIENT_ID":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("TWITCH_CLIENT_ID"))
|
||||||
|
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.TwitchClientID = data
|
||||||
|
case "TWITCH_CLIENT_SECRET":
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("TWITCH_CLIENT_SECRET"))
|
||||||
|
data, err := ec.unmarshalOString2ᚖstring(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return it, err
|
||||||
|
}
|
||||||
|
it.TwitchClientSecret = data
|
||||||
case "ORGANIZATION_NAME":
|
case "ORGANIZATION_NAME":
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -18719,7 +18898,7 @@ func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context,
|
||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"email", "phone_number", "otp", "totp", "state"}
|
fieldsInOrder := [...]string{"email", "phone_number", "otp", "is_totp", "state"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -18753,15 +18932,15 @@ func (ec *executionContext) unmarshalInputVerifyOTPRequest(ctx context.Context,
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.Otp = data
|
it.Otp = data
|
||||||
case "totp":
|
case "is_totp":
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("totp"))
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("is_totp"))
|
||||||
data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
data, err := ec.unmarshalOBoolean2ᚖbool(ctx, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.Totp = data
|
it.IsTotp = data
|
||||||
case "state":
|
case "state":
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -19136,6 +19315,10 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
|
||||||
out.Values[i] = ec._Env_MICROSOFT_CLIENT_SECRET(ctx, field, obj)
|
out.Values[i] = ec._Env_MICROSOFT_CLIENT_SECRET(ctx, field, obj)
|
||||||
case "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID":
|
case "MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID":
|
||||||
out.Values[i] = ec._Env_MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID(ctx, field, obj)
|
out.Values[i] = ec._Env_MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID(ctx, field, obj)
|
||||||
|
case "TWITCH_CLIENT_ID":
|
||||||
|
out.Values[i] = ec._Env_TWITCH_CLIENT_ID(ctx, field, obj)
|
||||||
|
case "TWITCH_CLIENT_SECRET":
|
||||||
|
out.Values[i] = ec._Env_TWITCH_CLIENT_SECRET(ctx, field, obj)
|
||||||
case "ORGANIZATION_NAME":
|
case "ORGANIZATION_NAME":
|
||||||
out.Values[i] = ec._Env_ORGANIZATION_NAME(ctx, field, obj)
|
out.Values[i] = ec._Env_ORGANIZATION_NAME(ctx, field, obj)
|
||||||
case "ORGANIZATION_LOGO":
|
case "ORGANIZATION_LOGO":
|
||||||
|
@ -19376,6 +19559,11 @@ func (ec *executionContext) _Meta(ctx context.Context, sel ast.SelectionSet, obj
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
out.Invalids++
|
out.Invalids++
|
||||||
}
|
}
|
||||||
|
case "is_twitch_login_enabled":
|
||||||
|
out.Values[i] = ec._Meta_is_twitch_login_enabled(ctx, field, obj)
|
||||||
|
if out.Values[i] == graphql.Null {
|
||||||
|
out.Invalids++
|
||||||
|
}
|
||||||
case "is_email_verification_enabled":
|
case "is_email_verification_enabled":
|
||||||
out.Values[i] = ec._Meta_is_email_verification_enabled(ctx, field, obj)
|
out.Values[i] = ec._Meta_is_email_verification_enabled(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
|
|
|
@ -119,6 +119,8 @@ type Env struct {
|
||||||
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID,omitempty"`
|
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID,omitempty"`
|
||||||
MicrosoftClientSecret *string `json:"MICROSOFT_CLIENT_SECRET,omitempty"`
|
MicrosoftClientSecret *string `json:"MICROSOFT_CLIENT_SECRET,omitempty"`
|
||||||
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID,omitempty"`
|
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID,omitempty"`
|
||||||
|
TwitchClientID *string `json:"TWITCH_CLIENT_ID,omitempty"`
|
||||||
|
TwitchClientSecret *string `json:"TWITCH_CLIENT_SECRET,omitempty"`
|
||||||
OrganizationName *string `json:"ORGANIZATION_NAME,omitempty"`
|
OrganizationName *string `json:"ORGANIZATION_NAME,omitempty"`
|
||||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO,omitempty"`
|
OrganizationLogo *string `json:"ORGANIZATION_LOGO,omitempty"`
|
||||||
AppCookieSecure bool `json:"APP_COOKIE_SECURE"`
|
AppCookieSecure bool `json:"APP_COOKIE_SECURE"`
|
||||||
|
@ -198,6 +200,7 @@ type Meta struct {
|
||||||
IsAppleLoginEnabled bool `json:"is_apple_login_enabled"`
|
IsAppleLoginEnabled bool `json:"is_apple_login_enabled"`
|
||||||
IsTwitterLoginEnabled bool `json:"is_twitter_login_enabled"`
|
IsTwitterLoginEnabled bool `json:"is_twitter_login_enabled"`
|
||||||
IsMicrosoftLoginEnabled bool `json:"is_microsoft_login_enabled"`
|
IsMicrosoftLoginEnabled bool `json:"is_microsoft_login_enabled"`
|
||||||
|
IsTwitchLoginEnabled bool `json:"is_twitch_login_enabled"`
|
||||||
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
|
IsEmailVerificationEnabled bool `json:"is_email_verification_enabled"`
|
||||||
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
|
IsBasicAuthenticationEnabled bool `json:"is_basic_authentication_enabled"`
|
||||||
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
|
IsMagicLinkLoginEnabled bool `json:"is_magic_link_login_enabled"`
|
||||||
|
@ -383,6 +386,8 @@ type UpdateEnvInput struct {
|
||||||
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID,omitempty"`
|
MicrosoftClientID *string `json:"MICROSOFT_CLIENT_ID,omitempty"`
|
||||||
MicrosoftClientSecret *string `json:"MICROSOFT_CLIENT_SECRET,omitempty"`
|
MicrosoftClientSecret *string `json:"MICROSOFT_CLIENT_SECRET,omitempty"`
|
||||||
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID,omitempty"`
|
MicrosoftActiveDirectoryTenantID *string `json:"MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID,omitempty"`
|
||||||
|
TwitchClientID *string `json:"TWITCH_CLIENT_ID,omitempty"`
|
||||||
|
TwitchClientSecret *string `json:"TWITCH_CLIENT_SECRET,omitempty"`
|
||||||
OrganizationName *string `json:"ORGANIZATION_NAME,omitempty"`
|
OrganizationName *string `json:"ORGANIZATION_NAME,omitempty"`
|
||||||
OrganizationLogo *string `json:"ORGANIZATION_LOGO,omitempty"`
|
OrganizationLogo *string `json:"ORGANIZATION_LOGO,omitempty"`
|
||||||
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE,omitempty"`
|
DefaultAuthorizeResponseType *string `json:"DEFAULT_AUTHORIZE_RESPONSE_TYPE,omitempty"`
|
||||||
|
@ -510,7 +515,7 @@ type VerifyOTPRequest struct {
|
||||||
Email *string `json:"email,omitempty"`
|
Email *string `json:"email,omitempty"`
|
||||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||||
Otp string `json:"otp"`
|
Otp string `json:"otp"`
|
||||||
Totp *bool `json:"totp,omitempty"`
|
IsTotp *bool `json:"is_totp,omitempty"`
|
||||||
State *string `json:"state,omitempty"`
|
State *string `json:"state,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ type Meta {
|
||||||
is_apple_login_enabled: Boolean!
|
is_apple_login_enabled: Boolean!
|
||||||
is_twitter_login_enabled: Boolean!
|
is_twitter_login_enabled: Boolean!
|
||||||
is_microsoft_login_enabled: Boolean!
|
is_microsoft_login_enabled: Boolean!
|
||||||
|
is_twitch_login_enabled: Boolean!
|
||||||
is_email_verification_enabled: Boolean!
|
is_email_verification_enabled: Boolean!
|
||||||
is_basic_authentication_enabled: Boolean!
|
is_basic_authentication_enabled: Boolean!
|
||||||
is_magic_link_login_enabled: Boolean!
|
is_magic_link_login_enabled: Boolean!
|
||||||
|
@ -175,6 +176,8 @@ type Env {
|
||||||
MICROSOFT_CLIENT_ID: String
|
MICROSOFT_CLIENT_ID: String
|
||||||
MICROSOFT_CLIENT_SECRET: String
|
MICROSOFT_CLIENT_SECRET: String
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
||||||
|
TWITCH_CLIENT_ID: String
|
||||||
|
TWITCH_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
ORGANIZATION_NAME: String
|
||||||
ORGANIZATION_LOGO: String
|
ORGANIZATION_LOGO: String
|
||||||
APP_COOKIE_SECURE: Boolean!
|
APP_COOKIE_SECURE: Boolean!
|
||||||
|
@ -302,6 +305,8 @@ input UpdateEnvInput {
|
||||||
MICROSOFT_CLIENT_ID: String
|
MICROSOFT_CLIENT_ID: String
|
||||||
MICROSOFT_CLIENT_SECRET: String
|
MICROSOFT_CLIENT_SECRET: String
|
||||||
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
MICROSOFT_ACTIVE_DIRECTORY_TENANT_ID: String
|
||||||
|
TWITCH_CLIENT_ID: String
|
||||||
|
TWITCH_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
ORGANIZATION_NAME: String
|
||||||
ORGANIZATION_LOGO: String
|
ORGANIZATION_LOGO: String
|
||||||
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
DEFAULT_AUTHORIZE_RESPONSE_TYPE: String
|
||||||
|
@ -568,7 +573,7 @@ input VerifyOTPRequest {
|
||||||
email: String
|
email: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
otp: String!
|
otp: String!
|
||||||
totp: Boolean
|
is_totp: Boolean
|
||||||
# state is used for authorization code grant flow
|
# state is used for authorization code grant flow
|
||||||
# it is used to get code for an on-going auth process during login
|
# it is used to get code for an on-going auth process during login
|
||||||
# and use that code for setting `c_hash` in id_token
|
# and use that code for setting `c_hash` in id_token
|
||||||
|
|
|
@ -11,11 +11,13 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
"github.com/coreos/go-oidc/v3/oidc"
|
"github.com/coreos/go-oidc/v3/oidc"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/oauth2"
|
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/cookie"
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
|
@ -75,6 +77,8 @@ func OAuthCallbackHandler() gin.HandlerFunc {
|
||||||
user, err = processTwitterUserInfo(ctx, oauthCode, sessionState)
|
user, err = processTwitterUserInfo(ctx, oauthCode, sessionState)
|
||||||
case constants.AuthRecipeMethodMicrosoft:
|
case constants.AuthRecipeMethodMicrosoft:
|
||||||
user, err = processMicrosoftUserInfo(ctx, oauthCode)
|
user, err = processMicrosoftUserInfo(ctx, oauthCode)
|
||||||
|
case constants.AuthRecipeMethodTwitch:
|
||||||
|
user, err = processTwitchUserInfo(ctx, oauthCode)
|
||||||
default:
|
default:
|
||||||
log.Info("Invalid oauth provider")
|
log.Info("Invalid oauth provider")
|
||||||
err = fmt.Errorf(`invalid oauth provider`)
|
err = fmt.Errorf(`invalid oauth provider`)
|
||||||
|
@ -703,3 +707,38 @@ func processMicrosoftUserInfo(ctx context.Context, code string) (*models.User, e
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process twitch user information
|
||||||
|
func processTwitchUserInfo(ctx context.Context, code string) (*models.User, error) {
|
||||||
|
oauth2Token, err := oauth.OAuthProviders.TwitchConfig.Exchange(ctx, code)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to exchange code for token: ", err)
|
||||||
|
return nil, fmt.Errorf("invalid twitch exchange code: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the ID Token from OAuth2 token.
|
||||||
|
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
||||||
|
if !ok {
|
||||||
|
log.Debug("Failed to extract ID Token from OAuth2 token")
|
||||||
|
return nil, fmt.Errorf("unable to extract id_token")
|
||||||
|
}
|
||||||
|
verifier := oauth.OIDCProviders.TwitchOIDC.Verifier(&oidc.Config{
|
||||||
|
ClientID: oauth.OAuthProviders.TwitchConfig.ClientID,
|
||||||
|
SkipIssuerCheck: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Parse and verify ID Token payload.
|
||||||
|
idToken, err := verifier.Verify(ctx, rawIDToken)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to verify ID Token: ", err)
|
||||||
|
return nil, fmt.Errorf("unable to verify id_token: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
user := &models.User{}
|
||||||
|
if err := idToken.Claims(&user); err != nil {
|
||||||
|
log.Debug("Failed to parse ID Token claims: ", err)
|
||||||
|
return nil, fmt.Errorf("unable to extract claims")
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
|
@ -4,10 +4,12 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
"github.com/authorizerdev/authorizer/server/oauth"
|
"github.com/authorizerdev/authorizer/server/oauth"
|
||||||
|
@ -227,6 +229,24 @@ func OAuthLoginHandler() gin.HandlerFunc {
|
||||||
oauth.OAuthProviders.MicrosoftConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodMicrosoft
|
oauth.OAuthProviders.MicrosoftConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodMicrosoft
|
||||||
url := oauth.OAuthProviders.MicrosoftConfig.AuthCodeURL(oauthStateString)
|
url := oauth.OAuthProviders.MicrosoftConfig.AuthCodeURL(oauthStateString)
|
||||||
c.Redirect(http.StatusTemporaryRedirect, url)
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
|
case constants.AuthRecipeMethodTwitch:
|
||||||
|
if oauth.OAuthProviders.TwitchConfig == nil {
|
||||||
|
log.Debug("Twitch OAuth provider is not configured")
|
||||||
|
isProviderConfigured = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodTwitch)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error setting state: ", err)
|
||||||
|
c.JSON(500, gin.H{
|
||||||
|
"error": "internal server error",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// during the init of OAuthProvider authorizer url might be empty
|
||||||
|
oauth.OAuthProviders.TwitchConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodTwitch
|
||||||
|
url := oauth.OAuthProviders.TwitchConfig.AuthCodeURL(oauthStateString)
|
||||||
|
c.Redirect(http.StatusTemporaryRedirect, url)
|
||||||
default:
|
default:
|
||||||
log.Debug("Invalid oauth provider: ", provider)
|
log.Debug("Invalid oauth provider: ", provider)
|
||||||
c.JSON(422, gin.H{
|
c.JSON(422, gin.H{
|
||||||
|
|
|
@ -4,13 +4,16 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/coreos/go-oidc/v3/oidc"
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
"google.golang.org/appengine/log"
|
||||||
|
|
||||||
facebookOAuth2 "golang.org/x/oauth2/facebook"
|
facebookOAuth2 "golang.org/x/oauth2/facebook"
|
||||||
githubOAuth2 "golang.org/x/oauth2/github"
|
githubOAuth2 "golang.org/x/oauth2/github"
|
||||||
linkedInOAuth2 "golang.org/x/oauth2/linkedin"
|
linkedInOAuth2 "golang.org/x/oauth2/linkedin"
|
||||||
microsoftOAuth2 "golang.org/x/oauth2/microsoft"
|
microsoftOAuth2 "golang.org/x/oauth2/microsoft"
|
||||||
"google.golang.org/appengine/log"
|
twitchOAuth2 "golang.org/x/oauth2/twitch"
|
||||||
|
|
||||||
|
"github.com/coreos/go-oidc/v3/oidc"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
@ -29,12 +32,14 @@ type OAuthProvider struct {
|
||||||
AppleConfig *oauth2.Config
|
AppleConfig *oauth2.Config
|
||||||
TwitterConfig *oauth2.Config
|
TwitterConfig *oauth2.Config
|
||||||
MicrosoftConfig *oauth2.Config
|
MicrosoftConfig *oauth2.Config
|
||||||
|
TwitchConfig *oauth2.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// OIDCProviders is a struct that contains reference all the OpenID providers
|
// OIDCProviders is a struct that contains reference all the OpenID providers
|
||||||
type OIDCProvider struct {
|
type OIDCProvider struct {
|
||||||
GoogleOIDC *oidc.Provider
|
GoogleOIDC *oidc.Provider
|
||||||
MicrosoftOIDC *oidc.Provider
|
MicrosoftOIDC *oidc.Provider
|
||||||
|
TwitchOIDC *oidc.Provider
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -198,5 +203,31 @@ func InitOAuth() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
twitchClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitchClientID)
|
||||||
|
if err != nil {
|
||||||
|
twitchClientID = ""
|
||||||
|
}
|
||||||
|
twitchClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitchClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
twitchClientSecret = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if twitchClientID != "" && twitchClientSecret != "" {
|
||||||
|
p, err := oidc.NewProvider(ctx, "https://id.twitch.tv/oauth2")
|
||||||
|
if err != nil {
|
||||||
|
log.Debugf(ctx, "Error while creating OIDC provider for Twitch: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
OIDCProviders.TwitchOIDC = p
|
||||||
|
OAuthProviders.TwitchConfig = &oauth2.Config{
|
||||||
|
ClientID: twitchClientID,
|
||||||
|
ClientSecret: twitchClientSecret,
|
||||||
|
RedirectURL: "/oauth_callback/twitch",
|
||||||
|
Endpoint: twitchOAuth2.Endpoint,
|
||||||
|
Scopes: []string{oidc.ScopeOpenID},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,7 +164,12 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
|
||||||
if val, ok := store[constants.EnvKeyMicrosoftActiveDirectoryTenantID]; ok {
|
if val, ok := store[constants.EnvKeyMicrosoftActiveDirectoryTenantID]; ok {
|
||||||
res.MicrosoftActiveDirectoryTenantID = refs.NewStringRef(val.(string))
|
res.MicrosoftActiveDirectoryTenantID = refs.NewStringRef(val.(string))
|
||||||
}
|
}
|
||||||
|
if val, ok := store[constants.EnvKeyTwitchClientID]; ok {
|
||||||
|
res.TwitchClientID = refs.NewStringRef(val.(string))
|
||||||
|
}
|
||||||
|
if val, ok := store[constants.EnvKeyTwitchClientSecret]; ok {
|
||||||
|
res.TwitchClientSecret = refs.NewStringRef(val.(string))
|
||||||
|
}
|
||||||
if val, ok := store[constants.EnvKeyOrganizationName]; ok {
|
if val, ok := store[constants.EnvKeyOrganizationName]; ok {
|
||||||
res.OrganizationName = refs.NewStringRef(val.(string))
|
res.OrganizationName = refs.NewStringRef(val.(string))
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
|
||||||
isCurrentLinkedInLoginEnabled := currentData[constants.EnvKeyLinkedInClientID] != nil && currentData[constants.EnvKeyLinkedInClientSecret] != nil && currentData[constants.EnvKeyLinkedInClientID].(string) != "" && currentData[constants.EnvKeyLinkedInClientSecret].(string) != ""
|
isCurrentLinkedInLoginEnabled := currentData[constants.EnvKeyLinkedInClientID] != nil && currentData[constants.EnvKeyLinkedInClientSecret] != nil && currentData[constants.EnvKeyLinkedInClientID].(string) != "" && currentData[constants.EnvKeyLinkedInClientSecret].(string) != ""
|
||||||
isCurrentTwitterLoginEnabled := currentData[constants.EnvKeyTwitterClientID] != nil && currentData[constants.EnvKeyTwitterClientSecret] != nil && currentData[constants.EnvKeyTwitterClientID].(string) != "" && currentData[constants.EnvKeyTwitterClientSecret].(string) != ""
|
isCurrentTwitterLoginEnabled := currentData[constants.EnvKeyTwitterClientID] != nil && currentData[constants.EnvKeyTwitterClientSecret] != nil && currentData[constants.EnvKeyTwitterClientID].(string) != "" && currentData[constants.EnvKeyTwitterClientSecret].(string) != ""
|
||||||
isCurrentMicrosoftLoginEnabled := currentData[constants.EnvKeyMicrosoftClientID] != nil && currentData[constants.EnvKeyMicrosoftClientSecret] != nil && currentData[constants.EnvKeyMicrosoftClientID].(string) != "" && currentData[constants.EnvKeyMicrosoftClientSecret].(string) != ""
|
isCurrentMicrosoftLoginEnabled := currentData[constants.EnvKeyMicrosoftClientID] != nil && currentData[constants.EnvKeyMicrosoftClientSecret] != nil && currentData[constants.EnvKeyMicrosoftClientID].(string) != "" && currentData[constants.EnvKeyMicrosoftClientSecret].(string) != ""
|
||||||
|
isCurrentTwitchLoginEnabled := currentData[constants.EnvKeyTwitchClientID] != nil && currentData[constants.EnvKeyTwitchClientSecret] != nil && currentData[constants.EnvKeyTwitchClientID].(string) != "" && currentData[constants.EnvKeyTwitchClientSecret].(string) != ""
|
||||||
|
|
||||||
isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool)
|
isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool)
|
||||||
isUpdatedMobileBasicAuthEnabled := !updatedData[constants.EnvKeyDisableMobileBasicAuthentication].(bool)
|
isUpdatedMobileBasicAuthEnabled := !updatedData[constants.EnvKeyDisableMobileBasicAuthentication].(bool)
|
||||||
|
@ -45,6 +46,7 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
|
||||||
isUpdatedLinkedInLoginEnabled := updatedData[constants.EnvKeyLinkedInClientID] != nil && updatedData[constants.EnvKeyLinkedInClientSecret] != nil && updatedData[constants.EnvKeyLinkedInClientID].(string) != "" && updatedData[constants.EnvKeyLinkedInClientSecret].(string) != ""
|
isUpdatedLinkedInLoginEnabled := updatedData[constants.EnvKeyLinkedInClientID] != nil && updatedData[constants.EnvKeyLinkedInClientSecret] != nil && updatedData[constants.EnvKeyLinkedInClientID].(string) != "" && updatedData[constants.EnvKeyLinkedInClientSecret].(string) != ""
|
||||||
isUpdatedTwitterLoginEnabled := updatedData[constants.EnvKeyTwitterClientID] != nil && updatedData[constants.EnvKeyTwitterClientSecret] != nil && updatedData[constants.EnvKeyTwitterClientID].(string) != "" && updatedData[constants.EnvKeyTwitterClientSecret].(string) != ""
|
isUpdatedTwitterLoginEnabled := updatedData[constants.EnvKeyTwitterClientID] != nil && updatedData[constants.EnvKeyTwitterClientSecret] != nil && updatedData[constants.EnvKeyTwitterClientID].(string) != "" && updatedData[constants.EnvKeyTwitterClientSecret].(string) != ""
|
||||||
isUpdatedMicrosoftLoginEnabled := updatedData[constants.EnvKeyMicrosoftClientID] != nil && updatedData[constants.EnvKeyMicrosoftClientSecret] != nil && updatedData[constants.EnvKeyMicrosoftClientID].(string) != "" && updatedData[constants.EnvKeyMicrosoftClientSecret].(string) != ""
|
isUpdatedMicrosoftLoginEnabled := updatedData[constants.EnvKeyMicrosoftClientID] != nil && updatedData[constants.EnvKeyMicrosoftClientSecret] != nil && updatedData[constants.EnvKeyMicrosoftClientID].(string) != "" && updatedData[constants.EnvKeyMicrosoftClientSecret].(string) != ""
|
||||||
|
isUpdatedTwitchLoginEnabled := updatedData[constants.EnvKeyTwitchClientID] != nil && updatedData[constants.EnvKeyTwitchClientSecret] != nil && updatedData[constants.EnvKeyTwitchClientID].(string) != "" && updatedData[constants.EnvKeyTwitchClientSecret].(string) != ""
|
||||||
|
|
||||||
if isCurrentBasicAuthEnabled && !isUpdatedBasicAuthEnabled {
|
if isCurrentBasicAuthEnabled && !isUpdatedBasicAuthEnabled {
|
||||||
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth)
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth)
|
||||||
|
@ -85,6 +87,10 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
|
||||||
if isCurrentMicrosoftLoginEnabled && !isUpdatedMicrosoftLoginEnabled {
|
if isCurrentMicrosoftLoginEnabled && !isUpdatedMicrosoftLoginEnabled {
|
||||||
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMicrosoft)
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMicrosoft)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isCurrentTwitchLoginEnabled && !isUpdatedTwitchLoginEnabled {
|
||||||
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodTwitch)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateEnvResolver is a resolver for update config mutation
|
// UpdateEnvResolver is a resolver for update config mutation
|
||||||
|
|
|
@ -56,16 +56,26 @@ func VerifyOtpResolver(ctx context.Context, params model.VerifyOTPRequest) (*mod
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
// Verify OTP based on TOPT or OTP
|
// Verify OTP based on TOPT or OTP
|
||||||
if refs.BoolValue(params.Totp) {
|
if refs.BoolValue(params.IsTotp) {
|
||||||
status, err := authenticators.Provider.Validate(ctx, params.Otp, user.ID)
|
status, err := authenticators.Provider.Validate(ctx, params.Otp, user.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to validate totp: ", err)
|
log.Debug("Failed to validate totp: ", err)
|
||||||
return nil, fmt.Errorf("error while validating passcode")
|
return nil, fmt.Errorf("error while validating passcode")
|
||||||
}
|
}
|
||||||
if !status {
|
if !status {
|
||||||
|
log.Debug("Failed to verify otp request: Incorrect value")
|
||||||
|
log.Info("Checking if otp is recovery code")
|
||||||
|
// Check if otp is recovery code
|
||||||
|
isValidRecoveryCode, err := authenticators.Provider.ValidateRecoveryCode(ctx, params.Otp, user.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to validate recovery code: ", err)
|
||||||
|
return nil, fmt.Errorf("error while validating recovery code")
|
||||||
|
}
|
||||||
|
if !isValidRecoveryCode {
|
||||||
log.Debug("Failed to verify otp request: Incorrect value")
|
log.Debug("Failed to verify otp request: Incorrect value")
|
||||||
return res, fmt.Errorf(`invalid otp`)
|
return res, fmt.Errorf(`invalid otp`)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var otp *models.OTP
|
var otp *models.OTP
|
||||||
if currentField == models.FieldNameEmail {
|
if currentField == models.FieldNameEmail {
|
||||||
|
|
|
@ -100,7 +100,7 @@ func totpLoginTest(t *testing.T, s TestSetup) {
|
||||||
req.Header.Set("Cookie", cookie)
|
req.Header.Set("Cookie", cookie)
|
||||||
valid, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
valid, err := resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
||||||
Email: &email,
|
Email: &email,
|
||||||
Totp: refs.NewBoolRef(true),
|
IsTotp: refs.NewBoolRef(true),
|
||||||
Otp: code,
|
Otp: code,
|
||||||
})
|
})
|
||||||
accessToken := valid.AccessToken
|
accessToken := valid.AccessToken
|
||||||
|
@ -149,7 +149,7 @@ func totpLoginTest(t *testing.T, s TestSetup) {
|
||||||
valid, err = resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
valid, err = resolvers.VerifyOtpResolver(ctx, model.VerifyOTPRequest{
|
||||||
Otp: code,
|
Otp: code,
|
||||||
Email: &email,
|
Email: &email,
|
||||||
Totp: refs.NewBoolRef(true),
|
IsTotp: refs.NewBoolRef(true),
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, *valid.AccessToken)
|
assert.NotNil(t, *valid.AccessToken)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user