Merge pull request #307 from authorizerdev/feat/mobile-basic-auth
feat: add mobile based basic auth
This commit is contained in:
commit
4f810d2f8b
|
@ -3,6 +3,8 @@ package constants
|
||||||
const (
|
const (
|
||||||
// AuthRecipeMethodBasicAuth is the basic_auth auth method
|
// AuthRecipeMethodBasicAuth is the basic_auth auth method
|
||||||
AuthRecipeMethodBasicAuth = "basic_auth"
|
AuthRecipeMethodBasicAuth = "basic_auth"
|
||||||
|
// AuthRecipeMethodMobileBasicAuth is the mobile basic_auth method, where user can signup using mobile number and password
|
||||||
|
AuthRecipeMethodMobileBasicAuth = "mobile_basic_auth"
|
||||||
// AuthRecipeMethodMagicLinkLogin is the magic_link_login auth method
|
// AuthRecipeMethodMagicLinkLogin is the magic_link_login auth method
|
||||||
AuthRecipeMethodMagicLinkLogin = "magic_link_login"
|
AuthRecipeMethodMagicLinkLogin = "magic_link_login"
|
||||||
// AuthRecipeMethodGoogle is the google auth method
|
// AuthRecipeMethodGoogle is the google auth method
|
||||||
|
|
|
@ -125,6 +125,8 @@ const (
|
||||||
EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION"
|
EnvKeyDisableEmailVerification = "DISABLE_EMAIL_VERIFICATION"
|
||||||
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH
|
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_BASIC_AUTH
|
||||||
EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION"
|
EnvKeyDisableBasicAuthentication = "DISABLE_BASIC_AUTHENTICATION"
|
||||||
|
// EnvKeyDisableBasicAuthentication key for env variable DISABLE_MOBILE_BASIC_AUTH
|
||||||
|
EnvKeyDisableMobileBasicAuthentication = "DISABLE_MOBILE_BASIC_AUTHENTICATION"
|
||||||
// EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN
|
// EnvKeyDisableMagicLinkLogin key for env variable DISABLE_MAGIC_LINK_LOGIN
|
||||||
EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN"
|
EnvKeyDisableMagicLinkLogin = "DISABLE_MAGIC_LINK_LOGIN"
|
||||||
// EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE
|
// EnvKeyDisableLoginPage key for env variable DISABLE_LOGIN_PAGE
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddUser to save user information in database
|
// AddUser to save user information in database
|
||||||
|
@ -32,6 +33,12 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||||
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
userCollection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||||
|
@ -48,6 +55,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
// UpdateUser to update user information in database
|
// UpdateUser to update user information in database
|
||||||
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
collection, _ := p.db.Collection(ctx, models.Collections.User)
|
||||||
meta, err := collection.UpdateDocument(ctx, user.Key, user)
|
meta, err := collection.UpdateDocument(ctx, user.Key, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -211,3 +219,34 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
query := fmt.Sprintf("FOR d in %s FILTER d.phone_number == @phone_number RETURN d", models.Collections.User)
|
||||||
|
bindVars := map[string]interface{}{
|
||||||
|
"phone_number": phoneNumber,
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor, err := p.db.Query(ctx, query, bindVars)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cursor.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if !cursor.HasMore() {
|
||||||
|
if user.Key == "" {
|
||||||
|
return nil, fmt.Errorf("user not found")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
_, err := cursor.ReadDocument(ctx, &user)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
|
|
@ -161,6 +161,12 @@ func NewProvider() (*provider, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userPhoneNumberIndexQuery := fmt.Sprintf("CREATE INDEX IF NOT EXISTS authorizer_user_phone_number ON %s.%s (phone_number)", KeySpace, models.Collections.User)
|
||||||
|
err = session.Query(userPhoneNumberIndexQuery).Exec()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
// add is_multi_factor_auth_enabled on users table
|
// add is_multi_factor_auth_enabled on users table
|
||||||
userTableAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD is_multi_factor_auth_enabled boolean`, KeySpace, models.Collections.User)
|
userTableAlterQuery := fmt.Sprintf(`ALTER TABLE %s.%s ADD is_multi_factor_auth_enabled boolean`, KeySpace, models.Collections.User)
|
||||||
err = session.Query(userTableAlterQuery).Exec()
|
err = session.Query(userTableAlterQuery).Exec()
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
"github.com/gocql/gocql"
|
"github.com/gocql/gocql"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
@ -30,6 +31,12 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
||||||
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
@ -299,3 +306,14 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user models.User
|
||||||
|
query := fmt.Sprintf("SELECT id, email, email_verified_at, password, signup_methods, given_name, family_name, middle_name, nickname, birthdate, phone_number, phone_number_verified_at, picture, roles, revoked_timestamp, is_multi_factor_auth_enabled, created_at, updated_at FROM %s WHERE phone_number = '%s' LIMIT 1 ALLOW FILTERING", KeySpace+"."+models.Collections.User, phoneNumber)
|
||||||
|
err := p.db.Query(query).Consistency(gocql.One).Scan(&user.ID, &user.Email, &user.EmailVerifiedAt, &user.Password, &user.SignupMethods, &user.GivenName, &user.FamilyName, &user.MiddleName, &user.Nickname, &user.Birthdate, &user.PhoneNumber, &user.PhoneNumberVerifiedAt, &user.Picture, &user.Roles, &user.RevokedTimestamp, &user.IsMultiFactorAuthEnabled, &user.CreatedAt, &user.UpdatedAt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ func (p *provider) AddEnv(ctx context.Context, env models.Env) (models.Env, erro
|
||||||
|
|
||||||
// UpdateEnv to update environment information in database
|
// UpdateEnv to update environment information in database
|
||||||
func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
func (p *provider) UpdateEnv(ctx context.Context, env models.Env) (models.Env, error) {
|
||||||
|
|
||||||
collection := p.db.Table(models.Collections.Env)
|
collection := p.db.Table(models.Collections.Env)
|
||||||
env.UpdatedAt = time.Now().Unix()
|
env.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,15 @@ package dynamodb
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/authorizerdev/authorizer/server/constants"
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
"github.com/authorizerdev/authorizer/server/db/models"
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
"github.com/authorizerdev/authorizer/server/graph/model"
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
"github.com/authorizerdev/authorizer/server/memorystore"
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/guregu/dynamo"
|
"github.com/guregu/dynamo"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
@ -30,6 +33,12 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
user.Roles = defaultRoles
|
user.Roles = defaultRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
||||||
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
user.CreatedAt = time.Now().Unix()
|
user.CreatedAt = time.Now().Unix()
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
|
@ -193,3 +202,23 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var users []models.User
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
collection := p.db.Table(models.Collections.User)
|
||||||
|
err := collection.Scan().Filter("'phone_number' = ?", phoneNumber).AllWithContext(ctx, &users)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(users) > 0 {
|
||||||
|
user = users[0]
|
||||||
|
return &user, nil
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("no record found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -155,3 +155,16 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user models.User
|
||||||
|
|
||||||
|
userCollection := p.db.Collection(models.Collections.User, options.Collection())
|
||||||
|
err := userCollection.FindOne(ctx, bson.M{"phone_number": phoneNumber}).Decode(&user)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &user, nil
|
||||||
|
}
|
||||||
|
|
|
@ -69,3 +69,10 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
|
var user *models.User
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ type Provider interface {
|
||||||
ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error)
|
ListUsers(ctx context.Context, pagination model.Pagination) (*model.Users, error)
|
||||||
// GetUserByEmail to get user information from database using email address
|
// GetUserByEmail to get user information from database using email address
|
||||||
GetUserByEmail(ctx context.Context, email string) (models.User, error)
|
GetUserByEmail(ctx context.Context, email string) (models.User, error)
|
||||||
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error)
|
||||||
// GetUserByID to get user information from database using user ID
|
// GetUserByID to get user information from database using user ID
|
||||||
GetUserByID(ctx context.Context, id string) (models.User, error)
|
GetUserByID(ctx context.Context, id string) (models.User, error)
|
||||||
// UpdateUsers to update multiple users, with parameters of user IDs slice
|
// UpdateUsers to update multiple users, with parameters of user IDs slice
|
||||||
|
|
|
@ -31,7 +31,7 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
||||||
if u, _ := p.GetUserByPhone(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
if u, _ := p.GetUserByPhoneNumber(ctx, refs.StringValue(user.PhoneNumber)); u != nil {
|
||||||
return user, fmt.Errorf("user with given phone number already exists")
|
return user, fmt.Errorf("user with given phone number already exists")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,6 @@ func (p *provider) AddUser(ctx context.Context, user models.User) (models.User,
|
||||||
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
func (p *provider) UpdateUser(ctx context.Context, user models.User) (models.User, error) {
|
||||||
user.UpdatedAt = time.Now().Unix()
|
user.UpdatedAt = time.Now().Unix()
|
||||||
|
|
||||||
if user.PhoneNumber != nil && strings.TrimSpace(refs.StringValue(user.PhoneNumber)) != "" {
|
|
||||||
if u, _ := p.GetUserByPhone(ctx, refs.StringValue(user.PhoneNumber)); u != nil && u.ID != user.ID {
|
|
||||||
return user, fmt.Errorf("user with given phone number already exists")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result := p.db.Save(&user)
|
result := p.db.Save(&user)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
|
@ -156,12 +150,13 @@ func (p *provider) UpdateUsers(ctx context.Context, data map[string]interface{},
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *provider) GetUserByPhone(ctx context.Context, phoneNumber string) (*models.User, error) {
|
// GetUserByPhoneNumber to get user information from database using phone number
|
||||||
|
func (p *provider) GetUserByPhoneNumber(ctx context.Context, phoneNumber string) (*models.User, error) {
|
||||||
var user *models.User
|
var user *models.User
|
||||||
result := p.db.Where("phone_number = ?", phoneNumber).First(&user)
|
result := p.db.Where("phone_number = ?", phoneNumber).First(&user)
|
||||||
|
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
return user, result.Error
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
|
|
14
server/env/env.go
vendored
14
server/env/env.go
vendored
|
@ -86,6 +86,7 @@ func InitAllEnv() error {
|
||||||
osAppCookieSecure := os.Getenv(constants.EnvKeyAppCookieSecure)
|
osAppCookieSecure := os.Getenv(constants.EnvKeyAppCookieSecure)
|
||||||
osAdminCookieSecure := os.Getenv(constants.EnvKeyAdminCookieSecure)
|
osAdminCookieSecure := os.Getenv(constants.EnvKeyAdminCookieSecure)
|
||||||
osDisableBasicAuthentication := os.Getenv(constants.EnvKeyDisableBasicAuthentication)
|
osDisableBasicAuthentication := os.Getenv(constants.EnvKeyDisableBasicAuthentication)
|
||||||
|
osDisableMobileBasicAuthentication := os.Getenv(constants.AuthRecipeMethodMobileBasicAuth)
|
||||||
osDisableEmailVerification := os.Getenv(constants.EnvKeyDisableEmailVerification)
|
osDisableEmailVerification := os.Getenv(constants.EnvKeyDisableEmailVerification)
|
||||||
osDisableMagicLinkLogin := os.Getenv(constants.EnvKeyDisableMagicLinkLogin)
|
osDisableMagicLinkLogin := os.Getenv(constants.EnvKeyDisableMagicLinkLogin)
|
||||||
osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage)
|
osDisableLoginPage := os.Getenv(constants.EnvKeyDisableLoginPage)
|
||||||
|
@ -498,6 +499,19 @@ func InitAllEnv() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, ok := envData[constants.EnvKeyDisableMobileBasicAuthentication]; !ok {
|
||||||
|
envData[constants.EnvKeyDisableMobileBasicAuthentication] = osDisableBasicAuthentication == "true"
|
||||||
|
}
|
||||||
|
if osDisableMobileBasicAuthentication != "" {
|
||||||
|
boolValue, err := strconv.ParseBool(osDisableMobileBasicAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if boolValue != envData[constants.EnvKeyDisableMobileBasicAuthentication].(bool) {
|
||||||
|
envData[constants.EnvKeyDisableMobileBasicAuthentication] = boolValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if _, ok := envData[constants.EnvKeyDisableEmailVerification]; !ok {
|
if _, ok := envData[constants.EnvKeyDisableEmailVerification]; !ok {
|
||||||
envData[constants.EnvKeyDisableEmailVerification] = osDisableEmailVerification == "true"
|
envData[constants.EnvKeyDisableEmailVerification] = osDisableEmailVerification == "true"
|
||||||
}
|
}
|
||||||
|
|
3
server/env/persist_env.go
vendored
3
server/env/persist_env.go
vendored
|
@ -75,7 +75,6 @@ func GetEnvData() (map[string]interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyEncryptionKey, decryptedEncryptionKey)
|
||||||
|
|
||||||
b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData)
|
b64DecryptedConfig, err := crypto.DecryptB64(env.EnvData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Error while decrypting env data from B64: ", err)
|
log.Debug("Error while decrypting env data from B64: ", err)
|
||||||
|
@ -201,7 +200,7 @@ func PersistEnv() error {
|
||||||
envValue := strings.TrimSpace(os.Getenv(key))
|
envValue := strings.TrimSpace(os.Getenv(key))
|
||||||
if envValue != "" {
|
if envValue != "" {
|
||||||
switch key {
|
switch key {
|
||||||
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure:
|
case constants.EnvKeyIsProd, constants.EnvKeyDisableBasicAuthentication, constants.EnvKeyDisableMobileBasicAuthentication, constants.EnvKeyDisableEmailVerification, constants.EnvKeyDisableLoginPage, constants.EnvKeyDisableMagicLinkLogin, constants.EnvKeyDisableSignUp, constants.EnvKeyDisableRedisForEnv, constants.EnvKeyDisableStrongPassword, constants.EnvKeyIsEmailServiceEnabled, constants.EnvKeyEnforceMultiFactorAuthentication, constants.EnvKeyDisableMultiFactorAuthentication, constants.EnvKeyAdminCookieSecure, constants.EnvKeyAppCookieSecure:
|
||||||
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
|
if envValueBool, err := strconv.ParseBool(envValue); err == nil {
|
||||||
if value.(bool) != envValueBool {
|
if value.(bool) != envValueBool {
|
||||||
storeData[key] = envValueBool
|
storeData[key] = envValueBool
|
||||||
|
|
|
@ -447,7 +447,6 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b h1:huxqepDufQpLLIRXiVkTvnxrzJlpwmIWAObmcCcUFr0=
|
|
||||||
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
||||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||||
|
@ -524,8 +523,6 @@ golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b h1:uKO3Js8lXGjpjdc4J3rqs0/Ex5yDKUGfk43tTYWVLas=
|
|
||||||
golang.org/x/net v0.0.0-20220930213112-107f3e3c3b0b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
|
||||||
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
||||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
@ -598,16 +595,12 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
|
||||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
@ -617,7 +610,6 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -179,6 +179,33 @@ type Meta struct {
|
||||||
IsMultiFactorAuthEnabled bool `json:"is_multi_factor_auth_enabled"`
|
IsMultiFactorAuthEnabled bool `json:"is_multi_factor_auth_enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MobileLoginInput struct {
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Roles []string `json:"roles"`
|
||||||
|
Scope []string `json:"scope"`
|
||||||
|
State *string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MobileSignUpInput struct {
|
||||||
|
Email *string `json:"email"`
|
||||||
|
GivenName *string `json:"given_name"`
|
||||||
|
FamilyName *string `json:"family_name"`
|
||||||
|
MiddleName *string `json:"middle_name"`
|
||||||
|
Nickname *string `json:"nickname"`
|
||||||
|
Gender *string `json:"gender"`
|
||||||
|
Birthdate *string `json:"birthdate"`
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
Picture *string `json:"picture"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
ConfirmPassword string `json:"confirm_password"`
|
||||||
|
Roles []string `json:"roles"`
|
||||||
|
Scope []string `json:"scope"`
|
||||||
|
RedirectURI *string `json:"redirect_uri"`
|
||||||
|
IsMultiFactorAuthEnabled *bool `json:"is_multi_factor_auth_enabled"`
|
||||||
|
State *string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
type OAuthRevokeInput struct {
|
type OAuthRevokeInput struct {
|
||||||
RefreshToken string `json:"refresh_token"`
|
RefreshToken string `json:"refresh_token"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,527 +6,562 @@ scalar Map
|
||||||
scalar Any
|
scalar Any
|
||||||
|
|
||||||
type Pagination {
|
type Pagination {
|
||||||
limit: Int64!
|
limit: Int64!
|
||||||
page: Int64!
|
page: Int64!
|
||||||
offset: Int64!
|
offset: Int64!
|
||||||
total: Int64!
|
total: Int64!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Meta {
|
type Meta {
|
||||||
version: String!
|
version: String!
|
||||||
client_id: String!
|
client_id: String!
|
||||||
is_google_login_enabled: Boolean!
|
is_google_login_enabled: Boolean!
|
||||||
is_facebook_login_enabled: Boolean!
|
is_facebook_login_enabled: Boolean!
|
||||||
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_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!
|
||||||
is_sign_up_enabled: Boolean!
|
is_sign_up_enabled: Boolean!
|
||||||
is_strong_password_enabled: Boolean!
|
is_strong_password_enabled: Boolean!
|
||||||
is_multi_factor_auth_enabled: Boolean!
|
is_multi_factor_auth_enabled: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
type User {
|
type User {
|
||||||
id: ID!
|
id: ID!
|
||||||
email: String!
|
email: String!
|
||||||
email_verified: Boolean!
|
email_verified: Boolean!
|
||||||
signup_methods: String!
|
signup_methods: String!
|
||||||
given_name: String
|
given_name: String
|
||||||
family_name: String
|
family_name: String
|
||||||
middle_name: String
|
middle_name: String
|
||||||
nickname: String
|
nickname: String
|
||||||
# defaults to email
|
# defaults to email
|
||||||
preferred_username: String
|
preferred_username: String
|
||||||
gender: String
|
gender: String
|
||||||
birthdate: String
|
birthdate: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
phone_number_verified: Boolean
|
phone_number_verified: Boolean
|
||||||
picture: String
|
picture: String
|
||||||
roles: [String!]!
|
roles: [String!]!
|
||||||
created_at: Int64
|
created_at: Int64
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
revoked_timestamp: Int64
|
revoked_timestamp: Int64
|
||||||
is_multi_factor_auth_enabled: Boolean
|
is_multi_factor_auth_enabled: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type Users {
|
type Users {
|
||||||
pagination: Pagination!
|
pagination: Pagination!
|
||||||
users: [User!]!
|
users: [User!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type VerificationRequest {
|
type VerificationRequest {
|
||||||
id: ID!
|
id: ID!
|
||||||
identifier: String
|
identifier: String
|
||||||
token: String
|
token: String
|
||||||
email: String
|
email: String
|
||||||
expires: Int64
|
expires: Int64
|
||||||
created_at: Int64
|
created_at: Int64
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
nonce: String
|
nonce: String
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type VerificationRequests {
|
type VerificationRequests {
|
||||||
pagination: Pagination!
|
pagination: Pagination!
|
||||||
verification_requests: [VerificationRequest!]!
|
verification_requests: [VerificationRequest!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Error {
|
type Error {
|
||||||
message: String!
|
message: String!
|
||||||
reason: String!
|
reason: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthResponse {
|
type AuthResponse {
|
||||||
message: String!
|
message: String!
|
||||||
should_show_otp_screen: Boolean
|
should_show_otp_screen: Boolean
|
||||||
access_token: String
|
access_token: String
|
||||||
id_token: String
|
id_token: String
|
||||||
refresh_token: String
|
refresh_token: String
|
||||||
expires_in: Int64
|
expires_in: Int64
|
||||||
user: User
|
user: User
|
||||||
}
|
}
|
||||||
|
|
||||||
type Response {
|
type Response {
|
||||||
message: String!
|
message: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Env {
|
type Env {
|
||||||
ACCESS_TOKEN_EXPIRY_TIME: String
|
ACCESS_TOKEN_EXPIRY_TIME: String
|
||||||
ADMIN_SECRET: String
|
ADMIN_SECRET: String
|
||||||
DATABASE_NAME: String
|
DATABASE_NAME: String
|
||||||
DATABASE_URL: String
|
DATABASE_URL: String
|
||||||
DATABASE_TYPE: String
|
DATABASE_TYPE: String
|
||||||
DATABASE_USERNAME: String
|
DATABASE_USERNAME: String
|
||||||
DATABASE_PASSWORD: String
|
DATABASE_PASSWORD: String
|
||||||
DATABASE_HOST: String
|
DATABASE_HOST: String
|
||||||
DATABASE_PORT: String
|
DATABASE_PORT: String
|
||||||
CLIENT_ID: String!
|
CLIENT_ID: String!
|
||||||
CLIENT_SECRET: String!
|
CLIENT_SECRET: String!
|
||||||
CUSTOM_ACCESS_TOKEN_SCRIPT: String
|
CUSTOM_ACCESS_TOKEN_SCRIPT: String
|
||||||
SMTP_HOST: String
|
SMTP_HOST: String
|
||||||
SMTP_PORT: String
|
SMTP_PORT: String
|
||||||
SMTP_USERNAME: String
|
SMTP_USERNAME: String
|
||||||
SMTP_PASSWORD: String
|
SMTP_PASSWORD: String
|
||||||
SMTP_LOCAL_NAME: String
|
SMTP_LOCAL_NAME: String
|
||||||
SENDER_EMAIL: String
|
SENDER_EMAIL: String
|
||||||
JWT_TYPE: String
|
JWT_TYPE: String
|
||||||
JWT_SECRET: String
|
JWT_SECRET: String
|
||||||
JWT_PRIVATE_KEY: String
|
JWT_PRIVATE_KEY: String
|
||||||
JWT_PUBLIC_KEY: String
|
JWT_PUBLIC_KEY: String
|
||||||
ALLOWED_ORIGINS: [String!]
|
ALLOWED_ORIGINS: [String!]
|
||||||
APP_URL: String
|
APP_URL: String
|
||||||
REDIS_URL: String
|
REDIS_URL: String
|
||||||
RESET_PASSWORD_URL: String
|
RESET_PASSWORD_URL: String
|
||||||
DISABLE_EMAIL_VERIFICATION: Boolean!
|
DISABLE_EMAIL_VERIFICATION: Boolean!
|
||||||
DISABLE_BASIC_AUTHENTICATION: Boolean!
|
DISABLE_BASIC_AUTHENTICATION: Boolean!
|
||||||
DISABLE_MAGIC_LINK_LOGIN: Boolean!
|
DISABLE_MAGIC_LINK_LOGIN: Boolean!
|
||||||
DISABLE_LOGIN_PAGE: Boolean!
|
DISABLE_LOGIN_PAGE: Boolean!
|
||||||
DISABLE_SIGN_UP: Boolean!
|
DISABLE_SIGN_UP: Boolean!
|
||||||
DISABLE_REDIS_FOR_ENV: Boolean!
|
DISABLE_REDIS_FOR_ENV: Boolean!
|
||||||
DISABLE_STRONG_PASSWORD: Boolean!
|
DISABLE_STRONG_PASSWORD: Boolean!
|
||||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: Boolean!
|
DISABLE_MULTI_FACTOR_AUTHENTICATION: Boolean!
|
||||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: Boolean!
|
ENFORCE_MULTI_FACTOR_AUTHENTICATION: Boolean!
|
||||||
ROLES: [String!]
|
ROLES: [String!]
|
||||||
PROTECTED_ROLES: [String!]
|
PROTECTED_ROLES: [String!]
|
||||||
DEFAULT_ROLES: [String!]
|
DEFAULT_ROLES: [String!]
|
||||||
JWT_ROLE_CLAIM: String
|
JWT_ROLE_CLAIM: String
|
||||||
GOOGLE_CLIENT_ID: String
|
GOOGLE_CLIENT_ID: String
|
||||||
GOOGLE_CLIENT_SECRET: String
|
GOOGLE_CLIENT_SECRET: String
|
||||||
GITHUB_CLIENT_ID: String
|
GITHUB_CLIENT_ID: String
|
||||||
GITHUB_CLIENT_SECRET: String
|
GITHUB_CLIENT_SECRET: String
|
||||||
FACEBOOK_CLIENT_ID: String
|
FACEBOOK_CLIENT_ID: String
|
||||||
FACEBOOK_CLIENT_SECRET: String
|
FACEBOOK_CLIENT_SECRET: String
|
||||||
LINKEDIN_CLIENT_ID: String
|
LINKEDIN_CLIENT_ID: String
|
||||||
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_ID: String
|
||||||
TWITTER_CLIENT_SECRET: String
|
TWITTER_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
ORGANIZATION_NAME: String
|
||||||
ORGANIZATION_LOGO: String
|
ORGANIZATION_LOGO: String
|
||||||
APP_COOKIE_SECURE: Boolean!
|
APP_COOKIE_SECURE: Boolean!
|
||||||
ADMIN_COOKIE_SECURE: Boolean!
|
ADMIN_COOKIE_SECURE: Boolean!
|
||||||
}
|
}
|
||||||
|
|
||||||
type ValidateJWTTokenResponse {
|
type ValidateJWTTokenResponse {
|
||||||
is_valid: Boolean!
|
is_valid: Boolean!
|
||||||
claims: Map
|
claims: Map
|
||||||
}
|
}
|
||||||
|
|
||||||
type GenerateJWTKeysResponse {
|
type GenerateJWTKeysResponse {
|
||||||
secret: String
|
secret: String
|
||||||
public_key: String
|
public_key: String
|
||||||
private_key: String
|
private_key: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type Webhook {
|
type Webhook {
|
||||||
id: ID!
|
id: ID!
|
||||||
event_name: String
|
event_name: String
|
||||||
endpoint: String
|
endpoint: String
|
||||||
enabled: Boolean
|
enabled: Boolean
|
||||||
headers: Map
|
headers: Map
|
||||||
created_at: Int64
|
created_at: Int64
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Webhooks {
|
type Webhooks {
|
||||||
pagination: Pagination!
|
pagination: Pagination!
|
||||||
webhooks: [Webhook!]!
|
webhooks: [Webhook!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebhookLog {
|
type WebhookLog {
|
||||||
id: ID!
|
id: ID!
|
||||||
http_status: Int64
|
http_status: Int64
|
||||||
response: String
|
response: String
|
||||||
request: String
|
request: String
|
||||||
webhook_id: ID
|
webhook_id: ID
|
||||||
created_at: Int64
|
created_at: Int64
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestEndpointResponse {
|
type TestEndpointResponse {
|
||||||
http_status: Int64
|
http_status: Int64
|
||||||
response: String
|
response: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebhookLogs {
|
type WebhookLogs {
|
||||||
pagination: Pagination!
|
pagination: Pagination!
|
||||||
webhook_logs: [WebhookLog!]!
|
webhook_logs: [WebhookLog!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmailTemplate {
|
type EmailTemplate {
|
||||||
id: ID!
|
id: ID!
|
||||||
event_name: String!
|
event_name: String!
|
||||||
template: String!
|
template: String!
|
||||||
design: String!
|
design: String!
|
||||||
subject: String!
|
subject: String!
|
||||||
created_at: Int64
|
created_at: Int64
|
||||||
updated_at: Int64
|
updated_at: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmailTemplates {
|
type EmailTemplates {
|
||||||
pagination: Pagination!
|
pagination: Pagination!
|
||||||
email_templates: [EmailTemplate!]!
|
email_templates: [EmailTemplate!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateEnvInput {
|
input UpdateEnvInput {
|
||||||
ACCESS_TOKEN_EXPIRY_TIME: String
|
ACCESS_TOKEN_EXPIRY_TIME: String
|
||||||
ADMIN_SECRET: String
|
ADMIN_SECRET: String
|
||||||
CUSTOM_ACCESS_TOKEN_SCRIPT: String
|
CUSTOM_ACCESS_TOKEN_SCRIPT: String
|
||||||
OLD_ADMIN_SECRET: String
|
OLD_ADMIN_SECRET: String
|
||||||
SMTP_HOST: String
|
SMTP_HOST: String
|
||||||
SMTP_PORT: String
|
SMTP_PORT: String
|
||||||
SMTP_USERNAME: String
|
SMTP_USERNAME: String
|
||||||
SMTP_PASSWORD: String
|
SMTP_PASSWORD: String
|
||||||
SMTP_LOCAL_NAME: String
|
SMTP_LOCAL_NAME: String
|
||||||
SENDER_EMAIL: String
|
SENDER_EMAIL: String
|
||||||
JWT_TYPE: String
|
JWT_TYPE: String
|
||||||
JWT_SECRET: String
|
JWT_SECRET: String
|
||||||
JWT_PRIVATE_KEY: String
|
JWT_PRIVATE_KEY: String
|
||||||
JWT_PUBLIC_KEY: String
|
JWT_PUBLIC_KEY: String
|
||||||
ALLOWED_ORIGINS: [String!]
|
ALLOWED_ORIGINS: [String!]
|
||||||
APP_URL: String
|
APP_URL: String
|
||||||
RESET_PASSWORD_URL: String
|
RESET_PASSWORD_URL: String
|
||||||
APP_COOKIE_SECURE: Boolean
|
APP_COOKIE_SECURE: Boolean
|
||||||
ADMIN_COOKIE_SECURE: Boolean
|
ADMIN_COOKIE_SECURE: Boolean
|
||||||
DISABLE_EMAIL_VERIFICATION: Boolean
|
DISABLE_EMAIL_VERIFICATION: Boolean
|
||||||
DISABLE_BASIC_AUTHENTICATION: Boolean
|
DISABLE_BASIC_AUTHENTICATION: Boolean
|
||||||
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
DISABLE_MAGIC_LINK_LOGIN: Boolean
|
||||||
DISABLE_LOGIN_PAGE: Boolean
|
DISABLE_LOGIN_PAGE: Boolean
|
||||||
DISABLE_SIGN_UP: Boolean
|
DISABLE_SIGN_UP: Boolean
|
||||||
DISABLE_REDIS_FOR_ENV: Boolean
|
DISABLE_REDIS_FOR_ENV: Boolean
|
||||||
DISABLE_STRONG_PASSWORD: Boolean
|
DISABLE_STRONG_PASSWORD: Boolean
|
||||||
DISABLE_MULTI_FACTOR_AUTHENTICATION: Boolean
|
DISABLE_MULTI_FACTOR_AUTHENTICATION: Boolean
|
||||||
ENFORCE_MULTI_FACTOR_AUTHENTICATION: Boolean
|
ENFORCE_MULTI_FACTOR_AUTHENTICATION: Boolean
|
||||||
ROLES: [String!]
|
ROLES: [String!]
|
||||||
PROTECTED_ROLES: [String!]
|
PROTECTED_ROLES: [String!]
|
||||||
DEFAULT_ROLES: [String!]
|
DEFAULT_ROLES: [String!]
|
||||||
JWT_ROLE_CLAIM: String
|
JWT_ROLE_CLAIM: String
|
||||||
GOOGLE_CLIENT_ID: String
|
GOOGLE_CLIENT_ID: String
|
||||||
GOOGLE_CLIENT_SECRET: String
|
GOOGLE_CLIENT_SECRET: String
|
||||||
GITHUB_CLIENT_ID: String
|
GITHUB_CLIENT_ID: String
|
||||||
GITHUB_CLIENT_SECRET: String
|
GITHUB_CLIENT_SECRET: String
|
||||||
FACEBOOK_CLIENT_ID: String
|
FACEBOOK_CLIENT_ID: String
|
||||||
FACEBOOK_CLIENT_SECRET: String
|
FACEBOOK_CLIENT_SECRET: String
|
||||||
LINKEDIN_CLIENT_ID: String
|
LINKEDIN_CLIENT_ID: String
|
||||||
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_ID: String
|
||||||
TWITTER_CLIENT_SECRET: String
|
TWITTER_CLIENT_SECRET: String
|
||||||
ORGANIZATION_NAME: String
|
ORGANIZATION_NAME: String
|
||||||
ORGANIZATION_LOGO: String
|
ORGANIZATION_LOGO: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input AdminLoginInput {
|
input AdminLoginInput {
|
||||||
admin_secret: String!
|
admin_secret: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input AdminSignupInput {
|
input AdminSignupInput {
|
||||||
admin_secret: String!
|
admin_secret: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
input MobileSignUpInput {
|
||||||
|
email: String
|
||||||
|
given_name: String
|
||||||
|
family_name: String
|
||||||
|
middle_name: String
|
||||||
|
nickname: String
|
||||||
|
gender: String
|
||||||
|
birthdate: String
|
||||||
|
phone_number: String!
|
||||||
|
picture: String
|
||||||
|
password: String!
|
||||||
|
confirm_password: String!
|
||||||
|
roles: [String!]
|
||||||
|
scope: [String!]
|
||||||
|
redirect_uri: String
|
||||||
|
is_multi_factor_auth_enabled: Boolean
|
||||||
|
# state is used for authorization code grant flow
|
||||||
|
# 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
|
||||||
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input SignUpInput {
|
input SignUpInput {
|
||||||
email: String!
|
email: String!
|
||||||
given_name: String
|
given_name: String
|
||||||
family_name: String
|
family_name: String
|
||||||
middle_name: String
|
middle_name: String
|
||||||
nickname: String
|
nickname: String
|
||||||
gender: String
|
gender: String
|
||||||
birthdate: String
|
birthdate: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
picture: String
|
picture: String
|
||||||
password: String!
|
password: String!
|
||||||
confirm_password: String!
|
confirm_password: String!
|
||||||
roles: [String!]
|
roles: [String!]
|
||||||
scope: [String!]
|
scope: [String!]
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
is_multi_factor_auth_enabled: Boolean
|
is_multi_factor_auth_enabled: 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
|
||||||
state: String
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input LoginInput {
|
input LoginInput {
|
||||||
email: String!
|
email: String!
|
||||||
password: String!
|
password: String!
|
||||||
roles: [String!]
|
roles: [String!]
|
||||||
scope: [String!]
|
scope: [String!]
|
||||||
# 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
|
||||||
state: String
|
state: String
|
||||||
|
}
|
||||||
|
|
||||||
|
input MobileLoginInput {
|
||||||
|
phone_number: String!
|
||||||
|
password: String!
|
||||||
|
roles: [String!]
|
||||||
|
scope: [String!]
|
||||||
|
# state is used for authorization code grant flow
|
||||||
|
# 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
|
||||||
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input VerifyEmailInput {
|
input VerifyEmailInput {
|
||||||
token: String!
|
token: String!
|
||||||
# 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
|
||||||
state: String
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ResendVerifyEmailInput {
|
input ResendVerifyEmailInput {
|
||||||
email: String!
|
email: String!
|
||||||
identifier: String!
|
identifier: String!
|
||||||
# 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
|
||||||
state: String
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateProfileInput {
|
input UpdateProfileInput {
|
||||||
old_password: String
|
old_password: String
|
||||||
new_password: String
|
new_password: String
|
||||||
confirm_new_password: String
|
confirm_new_password: String
|
||||||
email: String
|
email: String
|
||||||
given_name: String
|
given_name: String
|
||||||
family_name: String
|
family_name: String
|
||||||
middle_name: String
|
middle_name: String
|
||||||
nickname: String
|
nickname: String
|
||||||
gender: String
|
gender: String
|
||||||
birthdate: String
|
birthdate: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
picture: String
|
picture: String
|
||||||
is_multi_factor_auth_enabled: Boolean
|
is_multi_factor_auth_enabled: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateUserInput {
|
input UpdateUserInput {
|
||||||
id: ID!
|
id: ID!
|
||||||
email: String
|
email: String
|
||||||
email_verified: Boolean
|
email_verified: Boolean
|
||||||
given_name: String
|
given_name: String
|
||||||
family_name: String
|
family_name: String
|
||||||
middle_name: String
|
middle_name: String
|
||||||
nickname: String
|
nickname: String
|
||||||
gender: String
|
gender: String
|
||||||
birthdate: String
|
birthdate: String
|
||||||
phone_number: String
|
phone_number: String
|
||||||
picture: String
|
picture: String
|
||||||
roles: [String]
|
roles: [String]
|
||||||
is_multi_factor_auth_enabled: Boolean
|
is_multi_factor_auth_enabled: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
input ForgotPasswordInput {
|
input ForgotPasswordInput {
|
||||||
email: String!
|
email: String!
|
||||||
state: String
|
state: String
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ResetPasswordInput {
|
input ResetPasswordInput {
|
||||||
token: String!
|
token: String!
|
||||||
password: String!
|
password: String!
|
||||||
confirm_password: String!
|
confirm_password: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input DeleteUserInput {
|
input DeleteUserInput {
|
||||||
email: String!
|
email: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input MagicLinkLoginInput {
|
input MagicLinkLoginInput {
|
||||||
email: String!
|
email: String!
|
||||||
roles: [String!]
|
roles: [String!]
|
||||||
scope: [String!]
|
scope: [String!]
|
||||||
state: String
|
state: String
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input SessionQueryInput {
|
input SessionQueryInput {
|
||||||
roles: [String!]
|
roles: [String!]
|
||||||
scope: [String!]
|
scope: [String!]
|
||||||
}
|
}
|
||||||
|
|
||||||
input PaginationInput {
|
input PaginationInput {
|
||||||
limit: Int64
|
limit: Int64
|
||||||
page: Int64
|
page: Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
input PaginatedInput {
|
input PaginatedInput {
|
||||||
pagination: PaginationInput
|
pagination: PaginationInput
|
||||||
}
|
}
|
||||||
|
|
||||||
input OAuthRevokeInput {
|
input OAuthRevokeInput {
|
||||||
refresh_token: String!
|
refresh_token: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input InviteMemberInput {
|
input InviteMemberInput {
|
||||||
emails: [String!]!
|
emails: [String!]!
|
||||||
redirect_uri: String
|
redirect_uri: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateAccessInput {
|
input UpdateAccessInput {
|
||||||
user_id: String!
|
user_id: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input ValidateJWTTokenInput {
|
input ValidateJWTTokenInput {
|
||||||
token_type: String!
|
token_type: String!
|
||||||
token: String!
|
token: String!
|
||||||
roles: [String!]
|
roles: [String!]
|
||||||
}
|
}
|
||||||
|
|
||||||
input GenerateJWTKeysInput {
|
input GenerateJWTKeysInput {
|
||||||
type: String!
|
type: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
input ListWebhookLogRequest {
|
input ListWebhookLogRequest {
|
||||||
pagination: PaginationInput
|
pagination: PaginationInput
|
||||||
webhook_id: String
|
webhook_id: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input AddWebhookRequest {
|
input AddWebhookRequest {
|
||||||
event_name: String!
|
event_name: String!
|
||||||
endpoint: String!
|
endpoint: String!
|
||||||
enabled: Boolean!
|
enabled: Boolean!
|
||||||
headers: Map
|
headers: Map
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateWebhookRequest {
|
input UpdateWebhookRequest {
|
||||||
id: ID!
|
id: ID!
|
||||||
event_name: String
|
event_name: String
|
||||||
endpoint: String
|
endpoint: String
|
||||||
enabled: Boolean
|
enabled: Boolean
|
||||||
headers: Map
|
headers: Map
|
||||||
}
|
}
|
||||||
|
|
||||||
input WebhookRequest {
|
input WebhookRequest {
|
||||||
id: ID!
|
id: ID!
|
||||||
}
|
}
|
||||||
|
|
||||||
input TestEndpointRequest {
|
input TestEndpointRequest {
|
||||||
endpoint: String!
|
endpoint: String!
|
||||||
event_name: String!
|
event_name: String!
|
||||||
headers: Map
|
headers: Map
|
||||||
}
|
}
|
||||||
|
|
||||||
input AddEmailTemplateRequest {
|
input AddEmailTemplateRequest {
|
||||||
event_name: String!
|
event_name: String!
|
||||||
subject: String!
|
subject: String!
|
||||||
template: String!
|
template: String!
|
||||||
# Design value is set when editor is used
|
# Design value is set when editor is used
|
||||||
# If raw HTML is used design value is set to null
|
# If raw HTML is used design value is set to null
|
||||||
design: String
|
design: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input UpdateEmailTemplateRequest {
|
input UpdateEmailTemplateRequest {
|
||||||
id: ID!
|
id: ID!
|
||||||
event_name: String
|
event_name: String
|
||||||
template: String
|
template: String
|
||||||
subject: String
|
subject: String
|
||||||
# Design value is set when editor is used
|
# Design value is set when editor is used
|
||||||
# If raw HTML is used design value is set to null
|
# If raw HTML is used design value is set to null
|
||||||
design: String
|
design: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input DeleteEmailTemplateRequest {
|
input DeleteEmailTemplateRequest {
|
||||||
id: ID!
|
id: ID!
|
||||||
}
|
}
|
||||||
|
|
||||||
input VerifyOTPRequest {
|
input VerifyOTPRequest {
|
||||||
email: String!
|
email: String!
|
||||||
otp: String!
|
otp: String!
|
||||||
# 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
|
||||||
state: String
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
input ResendOTPRequest {
|
input ResendOTPRequest {
|
||||||
email: String!
|
email: String!
|
||||||
# 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
|
||||||
state: String
|
state: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type Mutation {
|
type Mutation {
|
||||||
signup(params: SignUpInput!): AuthResponse!
|
signup(params: SignUpInput!): AuthResponse!
|
||||||
login(params: LoginInput!): AuthResponse!
|
mobile_signup(params: MobileSignUpInput): AuthResponse!
|
||||||
magic_link_login(params: MagicLinkLoginInput!): Response!
|
login(params: LoginInput!): AuthResponse!
|
||||||
logout: Response!
|
mobile_login(params: MobileLoginInput!): AuthResponse!
|
||||||
update_profile(params: UpdateProfileInput!): Response!
|
magic_link_login(params: MagicLinkLoginInput!): Response!
|
||||||
verify_email(params: VerifyEmailInput!): AuthResponse!
|
logout: Response!
|
||||||
resend_verify_email(params: ResendVerifyEmailInput!): Response!
|
update_profile(params: UpdateProfileInput!): Response!
|
||||||
forgot_password(params: ForgotPasswordInput!): Response!
|
verify_email(params: VerifyEmailInput!): AuthResponse!
|
||||||
reset_password(params: ResetPasswordInput!): Response!
|
resend_verify_email(params: ResendVerifyEmailInput!): Response!
|
||||||
revoke(params: OAuthRevokeInput!): Response!
|
forgot_password(params: ForgotPasswordInput!): Response!
|
||||||
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
reset_password(params: ResetPasswordInput!): Response!
|
||||||
resend_otp(params: ResendOTPRequest!): Response!
|
revoke(params: OAuthRevokeInput!): Response!
|
||||||
# admin only apis
|
verify_otp(params: VerifyOTPRequest!): AuthResponse!
|
||||||
_delete_user(params: DeleteUserInput!): Response!
|
resend_otp(params: ResendOTPRequest!): Response!
|
||||||
_update_user(params: UpdateUserInput!): User!
|
# admin only apis
|
||||||
_admin_signup(params: AdminSignupInput!): Response!
|
_delete_user(params: DeleteUserInput!): Response!
|
||||||
_admin_login(params: AdminLoginInput!): Response!
|
_update_user(params: UpdateUserInput!): User!
|
||||||
_admin_logout: Response!
|
_admin_signup(params: AdminSignupInput!): Response!
|
||||||
_update_env(params: UpdateEnvInput!): Response!
|
_admin_login(params: AdminLoginInput!): Response!
|
||||||
_invite_members(params: InviteMemberInput!): Response!
|
_admin_logout: Response!
|
||||||
_revoke_access(param: UpdateAccessInput!): Response!
|
_update_env(params: UpdateEnvInput!): Response!
|
||||||
_enable_access(param: UpdateAccessInput!): Response!
|
_invite_members(params: InviteMemberInput!): Response!
|
||||||
_generate_jwt_keys(params: GenerateJWTKeysInput!): GenerateJWTKeysResponse!
|
_revoke_access(param: UpdateAccessInput!): Response!
|
||||||
_add_webhook(params: AddWebhookRequest!): Response!
|
_enable_access(param: UpdateAccessInput!): Response!
|
||||||
_update_webhook(params: UpdateWebhookRequest!): Response!
|
_generate_jwt_keys(params: GenerateJWTKeysInput!): GenerateJWTKeysResponse!
|
||||||
_delete_webhook(params: WebhookRequest!): Response!
|
_add_webhook(params: AddWebhookRequest!): Response!
|
||||||
_test_endpoint(params: TestEndpointRequest!): TestEndpointResponse!
|
_update_webhook(params: UpdateWebhookRequest!): Response!
|
||||||
_add_email_template(params: AddEmailTemplateRequest!): Response!
|
_delete_webhook(params: WebhookRequest!): Response!
|
||||||
_update_email_template(params: UpdateEmailTemplateRequest!): Response!
|
_test_endpoint(params: TestEndpointRequest!): TestEndpointResponse!
|
||||||
_delete_email_template(params: DeleteEmailTemplateRequest!): Response!
|
_add_email_template(params: AddEmailTemplateRequest!): Response!
|
||||||
|
_update_email_template(params: UpdateEmailTemplateRequest!): Response!
|
||||||
|
_delete_email_template(params: DeleteEmailTemplateRequest!): Response!
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
meta: Meta!
|
meta: Meta!
|
||||||
session(params: SessionQueryInput): AuthResponse!
|
session(params: SessionQueryInput): AuthResponse!
|
||||||
profile: User!
|
profile: User!
|
||||||
validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse!
|
validate_jwt_token(params: ValidateJWTTokenInput!): ValidateJWTTokenResponse!
|
||||||
# admin only apis
|
# admin only apis
|
||||||
_users(params: PaginatedInput): Users!
|
_users(params: PaginatedInput): Users!
|
||||||
_verification_requests(params: PaginatedInput): VerificationRequests!
|
_verification_requests(params: PaginatedInput): VerificationRequests!
|
||||||
_admin_session: Response!
|
_admin_session: Response!
|
||||||
_env: Env!
|
_env: Env!
|
||||||
_webhook(params: WebhookRequest!): Webhook!
|
_webhook(params: WebhookRequest!): Webhook!
|
||||||
_webhooks(params: PaginatedInput): Webhooks!
|
_webhooks(params: PaginatedInput): Webhooks!
|
||||||
_webhook_logs(params: ListWebhookLogRequest): WebhookLogs!
|
_webhook_logs(params: ListWebhookLogRequest): WebhookLogs!
|
||||||
_email_templates(params: PaginatedInput): EmailTemplates!
|
_email_templates(params: PaginatedInput): EmailTemplates!
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,21 @@ func (r *mutationResolver) Signup(ctx context.Context, params model.SignUpInput)
|
||||||
return resolvers.SignupResolver(ctx, params)
|
return resolvers.SignupResolver(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MobileSignup is the resolver for the mobile_signup field.
|
||||||
|
func (r *mutationResolver) MobileSignup(ctx context.Context, params *model.MobileSignUpInput) (*model.AuthResponse, error) {
|
||||||
|
return resolvers.MobileSignupResolver(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
// Login is the resolver for the login field.
|
// Login is the resolver for the login field.
|
||||||
func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) {
|
func (r *mutationResolver) Login(ctx context.Context, params model.LoginInput) (*model.AuthResponse, error) {
|
||||||
return resolvers.LoginResolver(ctx, params)
|
return resolvers.LoginResolver(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MobileLogin is the resolver for the mobile_login field.
|
||||||
|
func (r *mutationResolver) MobileLogin(ctx context.Context, params model.MobileLoginInput) (*model.AuthResponse, error) {
|
||||||
|
return resolvers.MobileLoginResolver(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
// MagicLinkLogin is the resolver for the magic_link_login field.
|
// MagicLinkLogin is the resolver for the magic_link_login field.
|
||||||
func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
|
func (r *mutationResolver) MagicLinkLogin(ctx context.Context, params model.MagicLinkLoginInput) (*model.Response, error) {
|
||||||
return resolvers.MagicLinkLoginResolver(ctx, params)
|
return resolvers.MagicLinkLoginResolver(ctx, params)
|
||||||
|
|
|
@ -26,6 +26,7 @@ func InitMemStore() error {
|
||||||
|
|
||||||
// boolean envs
|
// boolean envs
|
||||||
constants.EnvKeyDisableBasicAuthentication: false,
|
constants.EnvKeyDisableBasicAuthentication: false,
|
||||||
|
constants.EnvKeyDisableMobileBasicAuthentication: false,
|
||||||
constants.EnvKeyDisableMagicLinkLogin: false,
|
constants.EnvKeyDisableMagicLinkLogin: false,
|
||||||
constants.EnvKeyDisableEmailVerification: false,
|
constants.EnvKeyDisableEmailVerification: false,
|
||||||
constants.EnvKeyDisableLoginPage: false,
|
constants.EnvKeyDisableLoginPage: false,
|
||||||
|
|
|
@ -161,7 +161,7 @@ func (c *provider) GetEnvStore() (map[string]interface{}, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for key, value := range data {
|
for key, value := range data {
|
||||||
if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword || key == constants.EnvKeyIsEmailServiceEnabled || key == constants.EnvKeyEnforceMultiFactorAuthentication || key == constants.EnvKeyDisableMultiFactorAuthentication || key == constants.EnvKeyAppCookieSecure || key == constants.EnvKeyAdminCookieSecure {
|
if key == constants.EnvKeyDisableBasicAuthentication || key == constants.EnvKeyDisableMobileBasicAuthentication || key == constants.EnvKeyDisableEmailVerification || key == constants.EnvKeyDisableLoginPage || key == constants.EnvKeyDisableMagicLinkLogin || key == constants.EnvKeyDisableRedisForEnv || key == constants.EnvKeyDisableSignUp || key == constants.EnvKeyDisableStrongPassword || key == constants.EnvKeyIsEmailServiceEnabled || key == constants.EnvKeyEnforceMultiFactorAuthentication || key == constants.EnvKeyDisableMultiFactorAuthentication || key == constants.EnvKeyAppCookieSecure || key == constants.EnvKeyAdminCookieSecure {
|
||||||
boolValue, err := strconv.ParseBool(value)
|
boolValue, err := strconv.ParseBool(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
|
|
216
server/resolvers/mobile_login.go
Normal file
216
server/resolvers/mobile_login.go
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
package resolvers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
|
"github.com/authorizerdev/authorizer/server/validators"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MobileLoginResolver is a resolver for mobile login mutation
|
||||||
|
func MobileLoginResolver(ctx context.Context, params model.MobileLoginInput) (*model.AuthResponse, error) {
|
||||||
|
var res *model.AuthResponse
|
||||||
|
|
||||||
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get GinContext: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
isBasiAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting mobile basic auth disabled: ", err)
|
||||||
|
isBasiAuthDisabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if isBasiAuthDisabled {
|
||||||
|
log.Debug("Basic authentication is disabled.")
|
||||||
|
return res, fmt.Errorf(`phone number based basic authentication is disabled for this instance`)
|
||||||
|
}
|
||||||
|
|
||||||
|
log := log.WithFields(log.Fields{
|
||||||
|
"phone_number": params.PhoneNumber,
|
||||||
|
})
|
||||||
|
|
||||||
|
user, err := db.Provider.GetUserByPhoneNumber(ctx, params.PhoneNumber)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get user by phone number: ", err)
|
||||||
|
return res, fmt.Errorf(`bad user credentials`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.RevokedTimestamp != nil {
|
||||||
|
log.Debug("User access is revoked")
|
||||||
|
return res, fmt.Errorf(`user access has been revoked`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(user.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth) {
|
||||||
|
log.Debug("User signup method is not mobile basic auth")
|
||||||
|
return res, fmt.Errorf(`user has not signed up with phone number & password`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.PhoneNumberVerifiedAt == nil {
|
||||||
|
log.Debug("User phone number is not verified")
|
||||||
|
return res, fmt.Errorf(`phone number is not verified`)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(params.Password))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to compare password: ", err)
|
||||||
|
return res, fmt.Errorf(`bad user credentials`)
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
|
roles := []string{}
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting default roles: ", err)
|
||||||
|
defaultRolesString = ""
|
||||||
|
} else {
|
||||||
|
roles = strings.Split(defaultRolesString, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRoles := strings.Split(user.Roles, ",")
|
||||||
|
if len(params.Roles) > 0 {
|
||||||
|
if !validators.IsValidRoles(params.Roles, currentRoles) {
|
||||||
|
log.Debug("Invalid roles: ", params.Roles)
|
||||||
|
return res, fmt.Errorf(`invalid roles`)
|
||||||
|
}
|
||||||
|
|
||||||
|
roles = params.Roles
|
||||||
|
}
|
||||||
|
|
||||||
|
scope := []string{"openid", "email", "profile"}
|
||||||
|
if params.Scope != nil && len(scope) > 0 {
|
||||||
|
scope = params.Scope
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TODO use sms authentication for MFA
|
||||||
|
isEmailServiceEnabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyIsEmailServiceEnabled)
|
||||||
|
if err != nil || !isEmailServiceEnabled {
|
||||||
|
log.Debug("Email service not enabled: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
isMFADisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMultiFactorAuthentication)
|
||||||
|
if err != nil || !isEmailServiceEnabled {
|
||||||
|
log.Debug("MFA service not enabled: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If email service is not enabled continue the process in any way
|
||||||
|
if refs.BoolValue(user.IsMultiFactorAuthEnabled) && isEmailServiceEnabled && !isMFADisabled {
|
||||||
|
otp := utils.GenerateOTP()
|
||||||
|
otpData, err := db.Provider.UpsertOTP(ctx, &models.OTP{
|
||||||
|
Email: user.Email,
|
||||||
|
Otp: otp,
|
||||||
|
ExpiresAt: time.Now().Add(1 * time.Minute).Unix(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add otp: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// exec it as go routine so that we can reduce the api latency
|
||||||
|
go email.SendEmail([]string{params.PhoneNumber}, constants.VerificationTypeOTP, map[string]interface{}{
|
||||||
|
"user": user.ToMap(),
|
||||||
|
"organization": utils.GetOrganization(),
|
||||||
|
"otp": otpData.Otp,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to send otp email: ", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return &model.AuthResponse{
|
||||||
|
Message: "Please check the OTP in your inbox",
|
||||||
|
ShouldShowOtpScreen: refs.NewBoolRef(true),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
code := ""
|
||||||
|
codeChallenge := ""
|
||||||
|
nonce := ""
|
||||||
|
if params.State != nil {
|
||||||
|
// Get state from store
|
||||||
|
authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State))
|
||||||
|
if authorizeState != "" {
|
||||||
|
authorizeStateSplit := strings.Split(authorizeState, "@@")
|
||||||
|
if len(authorizeStateSplit) > 1 {
|
||||||
|
code = authorizeStateSplit[0]
|
||||||
|
codeChallenge = authorizeStateSplit[1]
|
||||||
|
} else {
|
||||||
|
nonce = authorizeState
|
||||||
|
}
|
||||||
|
go memorystore.Provider.RemoveState(refs.StringValue(params.State))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nonce == "" {
|
||||||
|
nonce = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
authToken, err := token.CreateAuthToken(gc, *user, roles, scope, constants.AuthRecipeMethodMobileBasicAuth, nonce, code)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to create auth token", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO add to other login options as well
|
||||||
|
// Code challenge could be optional if PKCE flow is not used
|
||||||
|
if code != "" {
|
||||||
|
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
|
||||||
|
log.Debug("SetState failed: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||||
|
if expiresIn <= 0 {
|
||||||
|
expiresIn = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
res = &model.AuthResponse{
|
||||||
|
Message: `Logged in successfully`,
|
||||||
|
AccessToken: &authToken.AccessToken.Token,
|
||||||
|
IDToken: &authToken.IDToken.Token,
|
||||||
|
ExpiresIn: &expiresIn,
|
||||||
|
User: user.AsAPIUser(),
|
||||||
|
}
|
||||||
|
|
||||||
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
sessionStoreKey := constants.AuthRecipeMethodMobileBasicAuth + ":" + user.ID
|
||||||
|
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
|
if authToken.RefreshToken != nil {
|
||||||
|
res.RefreshToken = &authToken.RefreshToken.Token
|
||||||
|
memorystore.Provider.SetUserSession(sessionStoreKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
utils.RegisterEvent(ctx, constants.UserLoginWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, *user)
|
||||||
|
db.Provider.AddSession(ctx, models.Session{
|
||||||
|
UserID: user.ID,
|
||||||
|
UserAgent: utils.GetUserAgent(gc.Request),
|
||||||
|
IP: utils.GetIP(gc.Request),
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
270
server/resolvers/mobile_signup.go
Normal file
270
server/resolvers/mobile_signup.go
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
package resolvers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/cookie"
|
||||||
|
"github.com/authorizerdev/authorizer/server/crypto"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db"
|
||||||
|
"github.com/authorizerdev/authorizer/server/db/models"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
"github.com/authorizerdev/authorizer/server/token"
|
||||||
|
"github.com/authorizerdev/authorizer/server/utils"
|
||||||
|
"github.com/authorizerdev/authorizer/server/validators"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MobileSignupResolver is a resolver for mobile_basic_auth_signup mutation
|
||||||
|
func MobileSignupResolver(ctx context.Context, params *model.MobileSignUpInput) (*model.AuthResponse, error) {
|
||||||
|
var res *model.AuthResponse
|
||||||
|
|
||||||
|
gc, err := utils.GinContextFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get GinContext: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
isSignupDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableSignUp)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting signup disabled: ", err)
|
||||||
|
isSignupDisabled = true
|
||||||
|
}
|
||||||
|
if isSignupDisabled {
|
||||||
|
log.Debug("Signup is disabled")
|
||||||
|
return res, fmt.Errorf(`signup is disabled for this instance`)
|
||||||
|
}
|
||||||
|
|
||||||
|
isBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting basic auth disabled: ", err)
|
||||||
|
isBasicAuthDisabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if isBasicAuthDisabled {
|
||||||
|
log.Debug("Mobile based Basic authentication is disabled")
|
||||||
|
return res, fmt.Errorf(`phone number based basic authentication is disabled for this instance`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.ConfirmPassword != params.Password {
|
||||||
|
log.Debug("Passwords do not match")
|
||||||
|
return res, fmt.Errorf(`password and confirm password does not match`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validators.IsValidPassword(params.Password); err != nil {
|
||||||
|
log.Debug("Invalid password")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mobile := strings.TrimSpace(params.PhoneNumber)
|
||||||
|
if mobile == "" || len(mobile) < 10 {
|
||||||
|
log.Debug("Invalid phone number")
|
||||||
|
return res, fmt.Errorf("invalid phone number")
|
||||||
|
}
|
||||||
|
|
||||||
|
emailInput := strings.ToLower(strings.TrimSpace(refs.StringValue(params.Email)))
|
||||||
|
|
||||||
|
// if email is null set random dummy email for db constraint
|
||||||
|
|
||||||
|
if emailInput != "" && !validators.IsValidEmail(emailInput) {
|
||||||
|
log.Debug("Invalid email: ", emailInput)
|
||||||
|
return res, fmt.Errorf(`invalid email address`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if emailInput == "" {
|
||||||
|
emailInput = mobile + "@authorizer.dev"
|
||||||
|
}
|
||||||
|
|
||||||
|
log := log.WithFields(log.Fields{
|
||||||
|
"email": emailInput,
|
||||||
|
"phone_number": mobile,
|
||||||
|
})
|
||||||
|
// find user with email
|
||||||
|
existingUser, err := db.Provider.GetUserByPhoneNumber(ctx, mobile)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to get user by email: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if existingUser != nil {
|
||||||
|
if existingUser.PhoneNumberVerifiedAt != nil {
|
||||||
|
// email is verified
|
||||||
|
log.Debug("Phone number is already verified and signed up.")
|
||||||
|
return res, fmt.Errorf(`%s has already signed up`, mobile)
|
||||||
|
} else if existingUser.ID != "" && existingUser.PhoneNumberVerifiedAt == nil {
|
||||||
|
log.Debug("Phone number is already signed up. Verification pending...")
|
||||||
|
return res, fmt.Errorf("%s has already signed up. please complete the phone number verification process or reset the password", mobile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inputRoles := []string{}
|
||||||
|
|
||||||
|
if len(params.Roles) > 0 {
|
||||||
|
// check if roles exists
|
||||||
|
rolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyRoles)
|
||||||
|
roles := []string{}
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting roles: ", err)
|
||||||
|
return res, err
|
||||||
|
} else {
|
||||||
|
roles = strings.Split(rolesString, ",")
|
||||||
|
}
|
||||||
|
if !validators.IsValidRoles(params.Roles, roles) {
|
||||||
|
log.Debug("Invalid roles: ", params.Roles)
|
||||||
|
return res, fmt.Errorf(`invalid roles`)
|
||||||
|
} else {
|
||||||
|
inputRoles = params.Roles
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputRolesString, err := memorystore.Provider.GetStringStoreEnvVariable(constants.EnvKeyDefaultRoles)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting default roles: ", err)
|
||||||
|
return res, err
|
||||||
|
} else {
|
||||||
|
inputRoles = strings.Split(inputRolesString, ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now().Unix()
|
||||||
|
user := models.User{
|
||||||
|
Email: emailInput,
|
||||||
|
PhoneNumber: &mobile,
|
||||||
|
PhoneNumberVerifiedAt: &now,
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Roles = strings.Join(inputRoles, ",")
|
||||||
|
|
||||||
|
password, _ := crypto.EncryptPassword(params.Password)
|
||||||
|
user.Password = &password
|
||||||
|
|
||||||
|
if params.GivenName != nil {
|
||||||
|
user.GivenName = params.GivenName
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.FamilyName != nil {
|
||||||
|
user.FamilyName = params.FamilyName
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.MiddleName != nil {
|
||||||
|
user.MiddleName = params.MiddleName
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Nickname != nil {
|
||||||
|
user.Nickname = params.Nickname
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Gender != nil {
|
||||||
|
user.Gender = params.Gender
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Birthdate != nil {
|
||||||
|
user.Birthdate = params.Birthdate
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Picture != nil {
|
||||||
|
user.Picture = params.Picture
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.IsMultiFactorAuthEnabled != nil {
|
||||||
|
user.IsMultiFactorAuthEnabled = params.IsMultiFactorAuthEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
isMFAEnforced, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyEnforceMultiFactorAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("MFA service not enabled: ", err)
|
||||||
|
isMFAEnforced = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if isMFAEnforced {
|
||||||
|
user.IsMultiFactorAuthEnabled = refs.NewBoolRef(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
user.SignupMethods = constants.AuthRecipeMethodMobileBasicAuth
|
||||||
|
user, err = db.Provider.AddUser(ctx, user)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to add user: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
roles := strings.Split(user.Roles, ",")
|
||||||
|
userToReturn := user.AsAPIUser()
|
||||||
|
|
||||||
|
scope := []string{"openid", "email", "profile"}
|
||||||
|
if params.Scope != nil && len(scope) > 0 {
|
||||||
|
scope = params.Scope
|
||||||
|
}
|
||||||
|
|
||||||
|
code := ""
|
||||||
|
codeChallenge := ""
|
||||||
|
nonce := ""
|
||||||
|
if params.State != nil {
|
||||||
|
// Get state from store
|
||||||
|
authorizeState, _ := memorystore.Provider.GetState(refs.StringValue(params.State))
|
||||||
|
if authorizeState != "" {
|
||||||
|
authorizeStateSplit := strings.Split(authorizeState, "@@")
|
||||||
|
if len(authorizeStateSplit) > 1 {
|
||||||
|
code = authorizeStateSplit[0]
|
||||||
|
codeChallenge = authorizeStateSplit[1]
|
||||||
|
} else {
|
||||||
|
nonce = authorizeState
|
||||||
|
}
|
||||||
|
go memorystore.Provider.RemoveState(refs.StringValue(params.State))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if nonce == "" {
|
||||||
|
nonce = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
authToken, err := token.CreateAuthToken(gc, user, roles, scope, constants.AuthRecipeMethodMobileBasicAuth, nonce, code)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Failed to create auth token: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code challenge could be optional if PKCE flow is not used
|
||||||
|
if code != "" {
|
||||||
|
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+authToken.FingerPrintHash); err != nil {
|
||||||
|
log.Debug("SetState failed: ", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expiresIn := authToken.AccessToken.ExpiresAt - time.Now().Unix()
|
||||||
|
if expiresIn <= 0 {
|
||||||
|
expiresIn = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
res = &model.AuthResponse{
|
||||||
|
Message: `Signed up successfully.`,
|
||||||
|
AccessToken: &authToken.AccessToken.Token,
|
||||||
|
ExpiresIn: &expiresIn,
|
||||||
|
User: userToReturn,
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionKey := constants.AuthRecipeMethodMobileBasicAuth + ":" + user.ID
|
||||||
|
cookie.SetSession(gc, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+authToken.FingerPrint, authToken.FingerPrintHash)
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+authToken.FingerPrint, authToken.AccessToken.Token)
|
||||||
|
|
||||||
|
if authToken.RefreshToken != nil {
|
||||||
|
res.RefreshToken = &authToken.RefreshToken.Token
|
||||||
|
memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeRefreshToken+"_"+authToken.FingerPrint, authToken.RefreshToken.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
utils.RegisterEvent(ctx, constants.UserSignUpWebhookEvent, constants.AuthRecipeMethodMobileBasicAuth, user)
|
||||||
|
db.Provider.AddSession(ctx, models.Session{
|
||||||
|
UserID: user.ID,
|
||||||
|
UserAgent: utils.GetUserAgent(gc.Request),
|
||||||
|
IP: utils.GetIP(gc.Request),
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
|
@ -25,6 +25,7 @@ import (
|
||||||
// remove the session tokens for those methods
|
// remove the session tokens for those methods
|
||||||
func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
|
func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
|
||||||
isCurrentBasicAuthEnabled := !currentData[constants.EnvKeyDisableBasicAuthentication].(bool)
|
isCurrentBasicAuthEnabled := !currentData[constants.EnvKeyDisableBasicAuthentication].(bool)
|
||||||
|
isCurrentMobileBasicAuthEnabled := !currentData[constants.EnvKeyDisableMobileBasicAuthentication].(bool)
|
||||||
isCurrentMagicLinkLoginEnabled := !currentData[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
isCurrentMagicLinkLoginEnabled := !currentData[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
||||||
isCurrentAppleLoginEnabled := currentData[constants.EnvKeyAppleClientID] != nil && currentData[constants.EnvKeyAppleClientSecret] != nil && currentData[constants.EnvKeyAppleClientID].(string) != "" && currentData[constants.EnvKeyAppleClientSecret].(string) != ""
|
isCurrentAppleLoginEnabled := currentData[constants.EnvKeyAppleClientID] != nil && currentData[constants.EnvKeyAppleClientSecret] != nil && currentData[constants.EnvKeyAppleClientID].(string) != "" && currentData[constants.EnvKeyAppleClientSecret].(string) != ""
|
||||||
isCurrentFacebookLoginEnabled := currentData[constants.EnvKeyFacebookClientID] != nil && currentData[constants.EnvKeyFacebookClientSecret] != nil && currentData[constants.EnvKeyFacebookClientID].(string) != "" && currentData[constants.EnvKeyFacebookClientSecret].(string) != ""
|
isCurrentFacebookLoginEnabled := currentData[constants.EnvKeyFacebookClientID] != nil && currentData[constants.EnvKeyFacebookClientSecret] != nil && currentData[constants.EnvKeyFacebookClientID].(string) != "" && currentData[constants.EnvKeyFacebookClientSecret].(string) != ""
|
||||||
|
@ -34,6 +35,7 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
|
||||||
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) != ""
|
||||||
|
|
||||||
isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool)
|
isUpdatedBasicAuthEnabled := !updatedData[constants.EnvKeyDisableBasicAuthentication].(bool)
|
||||||
|
isUpdatedMobileBasicAuthEnabled := !updatedData[constants.EnvKeyDisableMobileBasicAuthentication].(bool)
|
||||||
isUpdatedMagicLinkLoginEnabled := !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
isUpdatedMagicLinkLoginEnabled := !updatedData[constants.EnvKeyDisableMagicLinkLogin].(bool)
|
||||||
isUpdatedAppleLoginEnabled := updatedData[constants.EnvKeyAppleClientID] != nil && updatedData[constants.EnvKeyAppleClientSecret] != nil && updatedData[constants.EnvKeyAppleClientID].(string) != "" && updatedData[constants.EnvKeyAppleClientSecret].(string) != ""
|
isUpdatedAppleLoginEnabled := updatedData[constants.EnvKeyAppleClientID] != nil && updatedData[constants.EnvKeyAppleClientSecret] != nil && updatedData[constants.EnvKeyAppleClientID].(string) != "" && updatedData[constants.EnvKeyAppleClientSecret].(string) != ""
|
||||||
isUpdatedFacebookLoginEnabled := updatedData[constants.EnvKeyFacebookClientID] != nil && updatedData[constants.EnvKeyFacebookClientSecret] != nil && updatedData[constants.EnvKeyFacebookClientID].(string) != "" && updatedData[constants.EnvKeyFacebookClientSecret].(string) != ""
|
isUpdatedFacebookLoginEnabled := updatedData[constants.EnvKeyFacebookClientID] != nil && updatedData[constants.EnvKeyFacebookClientSecret] != nil && updatedData[constants.EnvKeyFacebookClientID].(string) != "" && updatedData[constants.EnvKeyFacebookClientSecret].(string) != ""
|
||||||
|
@ -46,6 +48,10 @@ func clearSessionIfRequired(currentData, updatedData map[string]interface{}) {
|
||||||
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth)
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodBasicAuth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isCurrentMobileBasicAuthEnabled && !isUpdatedMobileBasicAuthEnabled {
|
||||||
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMobileBasicAuth)
|
||||||
|
}
|
||||||
|
|
||||||
if isCurrentMagicLinkLoginEnabled && !isUpdatedMagicLinkLoginEnabled {
|
if isCurrentMagicLinkLoginEnabled && !isUpdatedMagicLinkLoginEnabled {
|
||||||
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMagicLinkLogin)
|
memorystore.Provider.DeleteSessionForNamespace(constants.AuthRecipeMethodMagicLinkLogin)
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,11 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
|
if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
|
||||||
|
// verify if phone number is unique
|
||||||
|
if _, err := db.Provider.GetUserByPhoneNumber(ctx, strings.TrimSpace(refs.StringValue(params.PhoneNumber))); err == nil {
|
||||||
|
log.Debug("user with given phone number already exists")
|
||||||
|
return nil, errors.New("user with given phone number already exists")
|
||||||
|
}
|
||||||
user.PhoneNumber = params.PhoneNumber
|
user.PhoneNumber = params.PhoneNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,8 +159,14 @@ func UpdateProfileResolver(ctx context.Context, params model.UpdateProfileInput)
|
||||||
isBasicAuthDisabled = true
|
isBasicAuthDisabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isMobileBasicAuthDisabled, err := memorystore.Provider.GetBoolStoreEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("Error getting mobile basic auth disabled: ", err)
|
||||||
|
isBasicAuthDisabled = true
|
||||||
|
}
|
||||||
|
|
||||||
if params.NewPassword != nil && params.ConfirmNewPassword != nil {
|
if params.NewPassword != nil && params.ConfirmNewPassword != nil {
|
||||||
if isBasicAuthDisabled {
|
if isBasicAuthDisabled || isMobileBasicAuthDisabled {
|
||||||
log.Debug("Cannot update password as basic authentication is disabled")
|
log.Debug("Cannot update password as basic authentication is disabled")
|
||||||
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
|
return res, fmt.Errorf(`basic authentication is disabled for this instance`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,11 @@ func UpdateUserResolver(ctx context.Context, params model.UpdateUserInput) (*mod
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
|
if params.PhoneNumber != nil && refs.StringValue(user.PhoneNumber) != refs.StringValue(params.PhoneNumber) {
|
||||||
|
// verify if phone number is unique
|
||||||
|
if _, err := db.Provider.GetUserByPhoneNumber(ctx, strings.TrimSpace(refs.StringValue(params.PhoneNumber))); err == nil {
|
||||||
|
log.Debug("user with given phone number already exists")
|
||||||
|
return nil, errors.New("user with given phone number already exists")
|
||||||
|
}
|
||||||
user.PhoneNumber = params.PhoneNumber
|
user.PhoneNumber = params.PhoneNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
58
server/test/mobile_login_test.go
Normal file
58
server/test/mobile_login_test.go
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mobileLoginTests(t *testing.T, s TestSetup) {
|
||||||
|
t.Helper()
|
||||||
|
t.Run(`should login via mobile`, func(t *testing.T) {
|
||||||
|
_, ctx := createContext(s)
|
||||||
|
email := "mobile_login." + s.TestInfo.Email
|
||||||
|
phoneNumber := "2234567890"
|
||||||
|
signUpRes, err := resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
Email: refs.NewStringRef(email),
|
||||||
|
PhoneNumber: phoneNumber,
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, signUpRes)
|
||||||
|
assert.Equal(t, email, signUpRes.User.Email)
|
||||||
|
assert.Equal(t, phoneNumber, refs.StringValue(signUpRes.User.PhoneNumber))
|
||||||
|
assert.True(t, strings.Contains(signUpRes.User.SignupMethods, constants.AuthRecipeMethodMobileBasicAuth))
|
||||||
|
assert.Len(t, strings.Split(signUpRes.User.SignupMethods, ","), 1)
|
||||||
|
|
||||||
|
res, err := resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{
|
||||||
|
PhoneNumber: phoneNumber,
|
||||||
|
Password: "random_test",
|
||||||
|
})
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, res)
|
||||||
|
|
||||||
|
// Should fail for email login
|
||||||
|
res, err = resolvers.LoginResolver(ctx, model.LoginInput{
|
||||||
|
Email: email,
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Nil(t, res)
|
||||||
|
|
||||||
|
res, err = resolvers.MobileLoginResolver(ctx, model.MobileLoginInput{
|
||||||
|
PhoneNumber: phoneNumber,
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, res.AccessToken)
|
||||||
|
assert.NotEmpty(t, res.IDToken)
|
||||||
|
|
||||||
|
cleanData(email)
|
||||||
|
})
|
||||||
|
}
|
85
server/test/mobile_signup_test.go
Normal file
85
server/test/mobile_signup_test.go
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/authorizerdev/authorizer/server/constants"
|
||||||
|
"github.com/authorizerdev/authorizer/server/graph/model"
|
||||||
|
"github.com/authorizerdev/authorizer/server/memorystore"
|
||||||
|
"github.com/authorizerdev/authorizer/server/refs"
|
||||||
|
"github.com/authorizerdev/authorizer/server/resolvers"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mobileSingupTest(t *testing.T, s TestSetup) {
|
||||||
|
t.Helper()
|
||||||
|
t.Run(`should complete the signup with mobile and check duplicates`, func(t *testing.T) {
|
||||||
|
_, ctx := createContext(s)
|
||||||
|
email := "mobile_basic_auth_signup." + s.TestInfo.Email
|
||||||
|
res, err := resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
Email: refs.NewStringRef(email),
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password + "s",
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "invalid password")
|
||||||
|
assert.Nil(t, res)
|
||||||
|
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
Email: refs.NewStringRef(email),
|
||||||
|
Password: "test",
|
||||||
|
ConfirmPassword: "test",
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "invalid password")
|
||||||
|
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, true)
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
Email: refs.NewStringRef(email),
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "singup disabled")
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableSignUp, false)
|
||||||
|
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication, true)
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
Email: refs.NewStringRef(email),
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "singup disabled")
|
||||||
|
memorystore.Provider.UpdateEnvVariable(constants.EnvKeyDisableMobileBasicAuthentication, false)
|
||||||
|
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
PhoneNumber: " ",
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "invalid mobile")
|
||||||
|
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
PhoneNumber: "test",
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NotNil(t, err, "invalid mobile")
|
||||||
|
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
PhoneNumber: "1234567890",
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEmpty(t, res.AccessToken)
|
||||||
|
assert.Equal(t, "1234567890@authorizer.dev", res.User.Email)
|
||||||
|
|
||||||
|
res, err = resolvers.MobileSignupResolver(ctx, &model.MobileSignUpInput{
|
||||||
|
PhoneNumber: "1234567890",
|
||||||
|
Password: s.TestInfo.Password,
|
||||||
|
ConfirmPassword: s.TestInfo.Password,
|
||||||
|
})
|
||||||
|
assert.Error(t, err, "user exists")
|
||||||
|
|
||||||
|
cleanData(email)
|
||||||
|
cleanData("1234567890@authorizer.dev")
|
||||||
|
})
|
||||||
|
}
|
|
@ -111,6 +111,8 @@ func TestResolvers(t *testing.T) {
|
||||||
// user resolvers tests
|
// user resolvers tests
|
||||||
loginTests(t, s)
|
loginTests(t, s)
|
||||||
signupTests(t, s)
|
signupTests(t, s)
|
||||||
|
mobileSingupTest(t, s)
|
||||||
|
mobileLoginTests(t, s)
|
||||||
forgotPasswordTest(t, s)
|
forgotPasswordTest(t, s)
|
||||||
resendVerifyEmailTests(t, s)
|
resendVerifyEmailTests(t, s)
|
||||||
resetPasswordTest(t, s)
|
resetPasswordTest(t, s)
|
||||||
|
|
|
@ -31,7 +31,7 @@ func testEndpointTest(t *testing.T, s TestSetup) {
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, res)
|
assert.NotNil(t, res)
|
||||||
assert.GreaterOrEqual(t, int64(201), *res.HTTPStatus)
|
assert.GreaterOrEqual(t, *res.HTTPStatus, int64(200))
|
||||||
assert.NotEmpty(t, res.Response)
|
assert.NotEmpty(t, res.Response)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user