feat: bootstrap twitter login config

This commit is contained in:
Lakhan Samani 2022-08-13 12:35:00 +05:30
parent b6e8023104
commit 05d276246b
18 changed files with 289 additions and 0 deletions

View File

@ -15,6 +15,7 @@ import {
FaFacebookF, FaFacebookF,
FaLinkedin, FaLinkedin,
FaApple, FaApple,
FaTwitter,
} from 'react-icons/fa'; } from 'react-icons/fa';
import { TextInputType, HiddenInputType } from '../../constants'; import { TextInputType, HiddenInputType } from '../../constants';
@ -264,6 +265,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"
>
<FaTwitter />
</Center>
<Center
w={isNotSmallerScreen ? '70%' : '100%'}
mt={isNotSmallerScreen ? '0' : '3'}
marginRight="1.5%"
>
<InputField
borderRadius={5}
variables={envVariables}
setVariables={setVariables}
inputType={TextInputType.TWITTER_CLIENT_ID}
placeholder="Twitter 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.TWITTER_CLIENT_SECRET}
placeholder="Twitter Client Secret"
/>
</Center>
</Flex>
</Stack> </Stack>
</Box> </Box>
</div> </div>

View File

@ -9,6 +9,7 @@ export const TextInputType = {
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID', FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID', LINKEDIN_CLIENT_ID: 'LINKEDIN_CLIENT_ID',
APPLE_CLIENT_ID: 'APPLE_CLIENT_ID', APPLE_CLIENT_ID: 'APPLE_CLIENT_ID',
TWITTER_CLIENT_ID: 'TWITTER_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',
@ -35,6 +36,7 @@ export const HiddenInputType = {
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET', FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',
LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET', LINKEDIN_CLIENT_SECRET: 'LINKEDIN_CLIENT_SECRET',
APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET', APPLE_CLIENT_SECRET: 'APPLE_CLIENT_SECRET',
TWITTER_CLIENT_SECRET: 'TWITTER_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',
@ -110,6 +112,8 @@ export interface envVarTypes {
LINKEDIN_CLIENT_SECRET: string; LINKEDIN_CLIENT_SECRET: string;
APPLE_CLIENT_ID: string; APPLE_CLIENT_ID: string;
APPLE_CLIENT_SECRET: string; APPLE_CLIENT_SECRET: string;
TWITTER_CLIENT_ID: string;
TWITTER_CLIENT_SECRET: string;
ROLES: [string] | []; ROLES: [string] | [];
DEFAULT_ROLES: [string] | []; DEFAULT_ROLES: [string] | [];
PROTECTED_ROLES: [string] | []; PROTECTED_ROLES: [string] | [];

View File

@ -30,6 +30,8 @@ export const EnvVariablesQuery = `
LINKEDIN_CLIENT_SECRET LINKEDIN_CLIENT_SECRET
APPLE_CLIENT_ID APPLE_CLIENT_ID
APPLE_CLIENT_SECRET APPLE_CLIENT_SECRET
TWITTER_CLIENT_ID
TWITTER_CLIENT_SECRET
DEFAULT_ROLES DEFAULT_ROLES
PROTECTED_ROLES PROTECTED_ROLES
ROLES ROLES

View File

@ -50,6 +50,8 @@ const Environment = () => {
LINKEDIN_CLIENT_SECRET: '', LINKEDIN_CLIENT_SECRET: '',
APPLE_CLIENT_ID: '', APPLE_CLIENT_ID: '',
APPLE_CLIENT_SECRET: '', APPLE_CLIENT_SECRET: '',
TWITTER_CLIENT_ID: '',
TWITTER_CLIENT_SECRET: '',
ROLES: [], ROLES: [],
DEFAULT_ROLES: [], DEFAULT_ROLES: [],
PROTECTED_ROLES: [], PROTECTED_ROLES: [],
@ -92,6 +94,7 @@ const Environment = () => {
FACEBOOK_CLIENT_SECRET: false, FACEBOOK_CLIENT_SECRET: false,
LINKEDIN_CLIENT_SECRET: false, LINKEDIN_CLIENT_SECRET: false,
APPLE_CLIENT_SECRET: false, APPLE_CLIENT_SECRET: false,
TWITTER_CLIENT_SECRET: false,
JWT_SECRET: false, JWT_SECRET: false,
SMTP_PASSWORD: false, SMTP_PASSWORD: false,
ADMIN_SECRET: false, ADMIN_SECRET: false,

View File

@ -15,4 +15,6 @@ const (
AuthRecipeMethodLinkedIn = "linkedin" AuthRecipeMethodLinkedIn = "linkedin"
// AuthRecipeMethodApple is the apple auth method // AuthRecipeMethodApple is the apple auth method
AuthRecipeMethodApple = "apple" AuthRecipeMethodApple = "apple"
// AuthRecipeMethodTwitter is the twitter auth method
AuthRecipeMethodTwitter = "twitter"
) )

View File

@ -85,6 +85,10 @@ const (
EnvKeyAppleClientID = "APPLE_CLIENT_ID" EnvKeyAppleClientID = "APPLE_CLIENT_ID"
// EnvKeyAppleClientSecret key for env variable APPLE_CLIENT_SECRET // EnvKeyAppleClientSecret key for env variable APPLE_CLIENT_SECRET
EnvKeyAppleClientSecret = "APPLE_CLIENT_SECRET" EnvKeyAppleClientSecret = "APPLE_CLIENT_SECRET"
// EnvKeyTwitterClientID key for env variable TWITTER_CLIENT_ID
EnvKeyTwitterClientID = "TWITTER_CLIENT_ID"
// EnvKeyTwitterClientSecret key for env variable TWITTER_CLIENT_SECRET
EnvKeyTwitterClientSecret = "TWITTER_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

16
server/env/env.go vendored
View File

@ -72,6 +72,8 @@ func InitAllEnv() error {
osLinkedInClientSecret := os.Getenv(constants.EnvKeyLinkedInClientSecret) osLinkedInClientSecret := os.Getenv(constants.EnvKeyLinkedInClientSecret)
osAppleClientID := os.Getenv(constants.EnvKeyAppleClientID) osAppleClientID := os.Getenv(constants.EnvKeyAppleClientID)
osAppleClientSecret := os.Getenv(constants.EnvKeyAppleClientSecret) osAppleClientSecret := os.Getenv(constants.EnvKeyAppleClientSecret)
osTwitterClientID := os.Getenv(constants.EnvKeyTwitterClientID)
osTwitterClientSecret := os.Getenv(constants.EnvKeyTwitterClientSecret)
osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL) osResetPasswordURL := os.Getenv(constants.EnvKeyResetPasswordURL)
osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName) osOrganizationName := os.Getenv(constants.EnvKeyOrganizationName)
osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo) osOrganizationLogo := os.Getenv(constants.EnvKeyOrganizationLogo)
@ -380,6 +382,20 @@ func InitAllEnv() error {
envData[constants.EnvKeyAppleClientSecret] = osAppleClientSecret envData[constants.EnvKeyAppleClientSecret] = osAppleClientSecret
} }
if val, ok := envData[constants.EnvKeyTwitterClientID]; !ok || val == "" {
envData[constants.EnvKeyTwitterClientID] = osTwitterClientID
}
if osTwitterClientID != "" && envData[constants.EnvKeyTwitterClientID] != osTwitterClientID {
envData[constants.EnvKeyTwitterClientID] = osTwitterClientID
}
if val, ok := envData[constants.EnvKeyTwitterClientSecret]; !ok || val == "" {
envData[constants.EnvKeyTwitterClientSecret] = osTwitterClientSecret
}
if osTwitterClientSecret != "" && envData[constants.EnvKeyTwitterClientSecret] != osTwitterClientSecret {
envData[constants.EnvKeyTwitterClientSecret] = osTwitterClientSecret
}
if val, ok := envData[constants.EnvKeyResetPasswordURL]; !ok || val == "" { if val, ok := envData[constants.EnvKeyResetPasswordURL]; !ok || val == "" {
envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(osResetPasswordURL, "/") envData[constants.EnvKeyResetPasswordURL] = strings.TrimPrefix(osResetPasswordURL, "/")
} }

View File

@ -119,6 +119,8 @@ type ComplexityRoot struct {
SMTPPort func(childComplexity int) int SMTPPort func(childComplexity int) int
SMTPUsername func(childComplexity int) int SMTPUsername func(childComplexity int) int
SenderEmail func(childComplexity int) int SenderEmail func(childComplexity int) int
TwitterClientID func(childComplexity int) int
TwitterClientSecret func(childComplexity int) int
} }
Error struct { Error struct {
@ -145,6 +147,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
IsTwitterLoginEnabled func(childComplexity int) int
Version func(childComplexity int) int Version func(childComplexity int) int
} }
@ -813,6 +816,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Env.SenderEmail(childComplexity), true return e.complexity.Env.SenderEmail(childComplexity), true
case "Env.TWITTER_CLIENT_ID":
if e.complexity.Env.TwitterClientID == nil {
break
}
return e.complexity.Env.TwitterClientID(childComplexity), true
case "Env.TWITTER_CLIENT_SECRET":
if e.complexity.Env.TwitterClientSecret == nil {
break
}
return e.complexity.Env.TwitterClientSecret(childComplexity), true
case "Error.message": case "Error.message":
if e.complexity.Error.Message == nil { if e.complexity.Error.Message == nil {
break break
@ -932,6 +949,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_twitter_login_enabled":
if e.complexity.Meta.IsTwitterLoginEnabled == nil {
break
}
return e.complexity.Meta.IsTwitterLoginEnabled(childComplexity), true
case "Meta.version": case "Meta.version":
if e.complexity.Meta.Version == nil { if e.complexity.Meta.Version == nil {
break break
@ -1893,6 +1917,7 @@ type Meta {
is_github_login_enabled: Boolean! is_github_login_enabled: Boolean!
is_linkedin_login_enabled: Boolean! is_linkedin_login_enabled: Boolean!
is_apple_login_enabled: Boolean! is_apple_login_enabled: Boolean!
is_twitter_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!
@ -2014,6 +2039,8 @@ type Env {
LINKEDIN_CLIENT_SECRET: String LINKEDIN_CLIENT_SECRET: String
APPLE_CLIENT_ID: String APPLE_CLIENT_ID: String
APPLE_CLIENT_SECRET: String APPLE_CLIENT_SECRET: String
TWITTER_CLIENT_ID: String
TWITTER_CLIENT_SECRET: String
ORGANIZATION_NAME: String ORGANIZATION_NAME: String
ORGANIZATION_LOGO: String ORGANIZATION_LOGO: String
} }
@ -2118,6 +2145,8 @@ input UpdateEnvInput {
LINKEDIN_CLIENT_SECRET: String LINKEDIN_CLIENT_SECRET: String
APPLE_CLIENT_ID: String APPLE_CLIENT_ID: String
APPLE_CLIENT_SECRET: String APPLE_CLIENT_SECRET: String
TWITTER_CLIENT_ID: String
TWITTER_CLIENT_SECRET: String
ORGANIZATION_NAME: String ORGANIZATION_NAME: String
ORGANIZATION_LOGO: String ORGANIZATION_LOGO: String
} }
@ -5054,6 +5083,70 @@ func (ec *executionContext) _Env_APPLE_CLIENT_SECRET(ctx context.Context, field
return ec.marshalOString2ᚖstring(ctx, field.Selections, res) return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
} }
func (ec *executionContext) _Env_TWITTER_CLIENT_ID(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.TwitterClientID, 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_TWITTER_CLIENT_SECRET(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.TwitterClientSecret, 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_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) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -5529,6 +5622,41 @@ func (ec *executionContext) _Meta_is_apple_login_enabled(ctx context.Context, fi
return ec.marshalNBoolean2bool(ctx, field.Selections, res) return ec.marshalNBoolean2bool(ctx, field.Selections, res)
} }
func (ec *executionContext) _Meta_is_twitter_login_enabled(ctx context.Context, field graphql.CollectedField, obj *model.Meta) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "Meta",
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.IsTwitterLoginEnabled, 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) _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) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -11720,6 +11848,22 @@ func (ec *executionContext) unmarshalInputUpdateEnvInput(ctx context.Context, ob
if err != nil { if err != nil {
return it, err return it, err
} }
case "TWITTER_CLIENT_ID":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("TWITTER_CLIENT_ID"))
it.TwitterClientID, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "TWITTER_CLIENT_SECRET":
var err error
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("TWITTER_CLIENT_SECRET"))
it.TwitterClientSecret, err = ec.unmarshalOString2ᚖstring(ctx, v)
if err != nil {
return it, err
}
case "ORGANIZATION_NAME": case "ORGANIZATION_NAME":
var err error var err error
@ -12421,6 +12565,10 @@ func (ec *executionContext) _Env(ctx context.Context, sel ast.SelectionSet, obj
out.Values[i] = ec._Env_APPLE_CLIENT_ID(ctx, field, obj) out.Values[i] = ec._Env_APPLE_CLIENT_ID(ctx, field, obj)
case "APPLE_CLIENT_SECRET": case "APPLE_CLIENT_SECRET":
out.Values[i] = ec._Env_APPLE_CLIENT_SECRET(ctx, field, obj) out.Values[i] = ec._Env_APPLE_CLIENT_SECRET(ctx, field, obj)
case "TWITTER_CLIENT_ID":
out.Values[i] = ec._Env_TWITTER_CLIENT_ID(ctx, field, obj)
case "TWITTER_CLIENT_SECRET":
out.Values[i] = ec._Env_TWITTER_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":
@ -12542,6 +12690,11 @@ func (ec *executionContext) _Meta(ctx context.Context, sel ast.SelectionSet, obj
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
invalids++ invalids++
} }
case "is_twitter_login_enabled":
out.Values[i] = ec._Meta_is_twitter_login_enabled(ctx, field, obj)
if out.Values[i] == graphql.Null {
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 {

View File

@ -106,6 +106,8 @@ type Env struct {
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET"` LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET"`
AppleClientID *string `json:"APPLE_CLIENT_ID"` AppleClientID *string `json:"APPLE_CLIENT_ID"`
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"` AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"`
TwitterClientID *string `json:"TWITTER_CLIENT_ID"`
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET"`
OrganizationName *string `json:"ORGANIZATION_NAME"` OrganizationName *string `json:"ORGANIZATION_NAME"`
OrganizationLogo *string `json:"ORGANIZATION_LOGO"` OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
} }
@ -164,6 +166,7 @@ type Meta struct {
IsGithubLoginEnabled bool `json:"is_github_login_enabled"` IsGithubLoginEnabled bool `json:"is_github_login_enabled"`
IsLinkedinLoginEnabled bool `json:"is_linkedin_login_enabled"` IsLinkedinLoginEnabled bool `json:"is_linkedin_login_enabled"`
IsAppleLoginEnabled bool `json:"is_apple_login_enabled"` IsAppleLoginEnabled bool `json:"is_apple_login_enabled"`
IsTwitterLoginEnabled bool `json:"is_twitter_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"`
@ -297,6 +300,8 @@ type UpdateEnvInput struct {
LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET"` LinkedinClientSecret *string `json:"LINKEDIN_CLIENT_SECRET"`
AppleClientID *string `json:"APPLE_CLIENT_ID"` AppleClientID *string `json:"APPLE_CLIENT_ID"`
AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"` AppleClientSecret *string `json:"APPLE_CLIENT_SECRET"`
TwitterClientID *string `json:"TWITTER_CLIENT_ID"`
TwitterClientSecret *string `json:"TWITTER_CLIENT_SECRET"`
OrganizationName *string `json:"ORGANIZATION_NAME"` OrganizationName *string `json:"ORGANIZATION_NAME"`
OrganizationLogo *string `json:"ORGANIZATION_LOGO"` OrganizationLogo *string `json:"ORGANIZATION_LOGO"`
} }

View File

@ -20,6 +20,7 @@ type Meta {
is_github_login_enabled: Boolean! is_github_login_enabled: Boolean!
is_linkedin_login_enabled: Boolean! is_linkedin_login_enabled: Boolean!
is_apple_login_enabled: Boolean! is_apple_login_enabled: Boolean!
is_twitter_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!
@ -141,6 +142,8 @@ type Env {
LINKEDIN_CLIENT_SECRET: String LINKEDIN_CLIENT_SECRET: String
APPLE_CLIENT_ID: String APPLE_CLIENT_ID: String
APPLE_CLIENT_SECRET: String APPLE_CLIENT_SECRET: String
TWITTER_CLIENT_ID: String
TWITTER_CLIENT_SECRET: String
ORGANIZATION_NAME: String ORGANIZATION_NAME: String
ORGANIZATION_LOGO: String ORGANIZATION_LOGO: String
} }
@ -245,6 +248,8 @@ input UpdateEnvInput {
LINKEDIN_CLIENT_SECRET: String LINKEDIN_CLIENT_SECRET: String
APPLE_CLIENT_ID: String APPLE_CLIENT_ID: String
APPLE_CLIENT_SECRET: String APPLE_CLIENT_SECRET: String
TWITTER_CLIENT_ID: String
TWITTER_CLIENT_SECRET: String
ORGANIZATION_NAME: String ORGANIZATION_NAME: String
ORGANIZATION_LOGO: String ORGANIZATION_LOGO: String
} }

View File

@ -67,6 +67,8 @@ func OAuthCallbackHandler() gin.HandlerFunc {
user, err = processLinkedInUserInfo(code) user, err = processLinkedInUserInfo(code)
case constants.AuthRecipeMethodApple: case constants.AuthRecipeMethodApple:
user, err = processAppleUserInfo(code) user, err = processAppleUserInfo(code)
case constants.AuthRecipeMethodTwitter:
user, err = processTwitterUserInfo(code)
default: default:
log.Info("Invalid oauth provider") log.Info("Invalid oauth provider")
err = fmt.Errorf(`invalid oauth provider`) err = fmt.Errorf(`invalid oauth provider`)
@ -564,3 +566,9 @@ func processAppleUserInfo(code string) (models.User, error) {
return user, err return user, err
} }
func processTwitterUserInfo(code string) (models.User, error) {
user := models.User{}
// TODO exchange code and get user information
return user, nil
}

View File

@ -169,6 +169,23 @@ func OAuthLoginHandler() gin.HandlerFunc {
oauth.OAuthProviders.LinkedInConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodLinkedIn oauth.OAuthProviders.LinkedInConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodLinkedIn
url := oauth.OAuthProviders.LinkedInConfig.AuthCodeURL(oauthStateString) url := oauth.OAuthProviders.LinkedInConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url) c.Redirect(http.StatusTemporaryRedirect, url)
case constants.AuthRecipeMethodTwitter:
if oauth.OAuthProviders.TwitterConfig == nil {
log.Debug("Twitter OAuth provider is not configured")
isProviderConfigured = false
break
}
err := memorystore.Provider.SetState(oauthStateString, constants.AuthRecipeMethodTwitter)
if err != nil {
log.Debug("Error setting state: ", err)
c.JSON(500, gin.H{
"error": "internal server error",
})
return
}
oauth.OAuthProviders.TwitterConfig.RedirectURL = hostname + "/oauth_callback/" + constants.AuthRecipeMethodTwitter
url := oauth.OAuthProviders.TwitterConfig.AuthCodeURL(oauthStateString)
c.Redirect(http.StatusTemporaryRedirect, url)
case constants.AuthRecipeMethodApple: case constants.AuthRecipeMethodApple:
if oauth.OAuthProviders.AppleConfig == nil { if oauth.OAuthProviders.AppleConfig == nil {
log.Debug("Apple OAuth provider is not configured") log.Debug("Apple OAuth provider is not configured")

View File

@ -34,6 +34,7 @@ func (c *provider) DeleteAllUserSessions(userId string) error {
constants.AuthRecipeMethodGithub, constants.AuthRecipeMethodGithub,
constants.AuthRecipeMethodGoogle, constants.AuthRecipeMethodGoogle,
constants.AuthRecipeMethodLinkedIn, constants.AuthRecipeMethodLinkedIn,
constants.AuthRecipeMethodTwitter,
} }
for _, namespace := range namespaces { for _, namespace := range namespaces {

View File

@ -71,6 +71,7 @@ func (c *provider) DeleteAllUserSessions(userID string) error {
constants.AuthRecipeMethodGithub, constants.AuthRecipeMethodGithub,
constants.AuthRecipeMethodGoogle, constants.AuthRecipeMethodGoogle,
constants.AuthRecipeMethodLinkedIn, constants.AuthRecipeMethodLinkedIn,
constants.AuthRecipeMethodTwitter,
} }
for _, namespace := range namespaces { for _, namespace := range namespaces {
err := c.store.Del(c.ctx, namespace+":"+userID).Err() err := c.store.Del(c.ctx, namespace+":"+userID).Err()

View File

@ -20,6 +20,7 @@ type OAuthProvider struct {
FacebookConfig *oauth2.Config FacebookConfig *oauth2.Config
LinkedInConfig *oauth2.Config LinkedInConfig *oauth2.Config
AppleConfig *oauth2.Config AppleConfig *oauth2.Config
TwitterConfig *oauth2.Config
} }
// OIDCProviders is a struct that contains reference all the OpenID providers // OIDCProviders is a struct that contains reference all the OpenID providers
@ -133,5 +134,7 @@ func InitOAuth() error {
} }
} }
// TODO add support for twitter provider and update OAuthProviders.TwitterConfig
return nil return nil
} }

View File

@ -143,6 +143,13 @@ func EnvResolver(ctx context.Context) (*model.Env, error) {
if val, ok := store[constants.EnvKeyAppleClientSecret]; ok { if val, ok := store[constants.EnvKeyAppleClientSecret]; ok {
res.AppleClientSecret = refs.NewStringRef(val.(string)) res.AppleClientSecret = refs.NewStringRef(val.(string))
} }
if val, ok := store[constants.EnvKeyTwitterClientID]; ok {
res.TwitterClientID = refs.NewStringRef(val.(string))
}
if val, ok := store[constants.EnvKeyTwitterClientSecret]; ok {
res.TwitterClientSecret = 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))
} }

View File

@ -77,6 +77,18 @@ func MetaResolver(ctx context.Context) (*model.Meta, error) {
githubClientSecret = "" githubClientSecret = ""
} }
twitterClientID, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitterClientID)
if err != nil {
log.Debug("Failed to get Twitter Client ID from environment variable", err)
twitterClientID = ""
}
twitterClientSecret, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyTwitterClientSecret)
if err != nil {
log.Debug("Failed to get Twitter Client Secret from environment variable", err)
twitterClientSecret = ""
}
isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication) isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableBasicAuthentication)
if err != nil { if err != nil {
log.Debug("Failed to get Disable Basic Authentication from environment variable", err) log.Debug("Failed to get Disable Basic Authentication from environment variable", err)
@ -121,6 +133,7 @@ func MetaResolver(ctx context.Context) (*model.Meta, error) {
IsFacebookLoginEnabled: facebookClientID != "" && facebookClientSecret != "", IsFacebookLoginEnabled: facebookClientID != "" && facebookClientSecret != "",
IsLinkedinLoginEnabled: linkedClientID != "" && linkedInClientSecret != "", IsLinkedinLoginEnabled: linkedClientID != "" && linkedInClientSecret != "",
IsAppleLoginEnabled: appleClientID != "" && appleClientSecret != "", IsAppleLoginEnabled: appleClientID != "" && appleClientSecret != "",
IsTwitterLoginEnabled: twitterClientID != "" && twitterClientSecret != "",
IsBasicAuthenticationEnabled: !isBasicAuthDisabled, IsBasicAuthenticationEnabled: !isBasicAuthDisabled,
IsEmailVerificationEnabled: !isEmailVerificationDisabled, IsEmailVerificationEnabled: !isEmailVerificationDisabled,
IsMagicLinkLoginEnabled: !isMagicLinkLoginDisabled, IsMagicLinkLoginEnabled: !isMagicLinkLoginDisabled,

View File

@ -31,6 +31,7 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
isCurrentGoogleLoginEnabled := currentData[constants.EnvKeyGoogleClientID] != nil && currentData[constants.EnvKeyGoogleClientSecret] != nil && currentData[constants.EnvKeyGoogleClientID].(string) != "" && currentData[constants.EnvKeyGoogleClientSecret].(string) != "" isCurrentGoogleLoginEnabled := currentData[constants.EnvKeyGoogleClientID] != nil && currentData[constants.EnvKeyGoogleClientSecret] != nil && currentData[constants.EnvKeyGoogleClientID].(string) != "" && currentData[constants.EnvKeyGoogleClientSecret].(string) != ""
isCurrentGithubLoginEnabled := currentData[constants.EnvKeyGithubClientID] != nil && currentData[constants.EnvKeyGithubClientSecret] != nil && currentData[constants.EnvKeyGithubClientID].(string) != "" && currentData[constants.EnvKeyGithubClientSecret].(string) != "" isCurrentGithubLoginEnabled := currentData[constants.EnvKeyGithubClientID] != nil && currentData[constants.EnvKeyGithubClientSecret] != nil && currentData[constants.EnvKeyGithubClientID].(string) != "" && currentData[constants.EnvKeyGithubClientSecret].(string) != ""
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) != ""
isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool) isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool)
isUpdatedMagicLinkLoginEnabled := !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool) isUpdatedMagicLinkLoginEnabled := !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool)
@ -39,6 +40,7 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
isUpdatedGoogleLoginEnabled := updatedData[constants.EnvKeyGoogleClientID] != nil && updatedData[constants.EnvKeyGoogleClientSecret] != nil && updatedData[constants.EnvKeyGoogleClientID].(string) != "" && updatedData[constants.EnvKeyGoogleClientSecret].(string) != "" isUpdatedGoogleLoginEnabled := updatedData[constants.EnvKeyGoogleClientID] != nil && updatedData[constants.EnvKeyGoogleClientSecret] != nil && updatedData[constants.EnvKeyGoogleClientID].(string) != "" && updatedData[constants.EnvKeyGoogleClientSecret].(string) != ""
isUpdatedGithubLoginEnabled := updatedData[constants.EnvKeyGithubClientID] != nil && updatedData[constants.EnvKeyGithubClientSecret] != nil && updatedData[constants.EnvKeyGithubClientID].(string) != "" && updatedData[constants.EnvKeyGithubClientSecret].(string) != "" isUpdatedGithubLoginEnabled := updatedData[constants.EnvKeyGithubClientID] != nil && updatedData[constants.EnvKeyGithubClientSecret] != nil && updatedData[constants.EnvKeyGithubClientID].(string) != "" && updatedData[constants.EnvKeyGithubClientSecret].(string) != ""
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) != ""
if isCurrentBasicAuthEnabled && !isUpdatedBasicAuthEnabled { if isCurrentBasicAuthEnabled && !isUpdatedBasicAuthEnabled {
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth) memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth)
@ -67,6 +69,10 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
if isCurrentLinkedInLoginEnabled && !isUpdatedLinkedInLoginEnabled { if isCurrentLinkedInLoginEnabled && !isUpdatedLinkedInLoginEnabled {
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodLinkedIn) memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodLinkedIn)
} }
if isCurrentTwitterLoginEnabled && !isUpdatedTwitterLoginEnabled {
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodTwitter)
}
} }
// UpdateEnvResolver is a resolver for update config mutation // UpdateEnvResolver is a resolver for update config mutation