Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make recipe enabled booleans better #979

Open
8 tasks
sattvikc opened this issue Apr 9, 2024 · 3 comments
Open
8 tasks

Make recipe enabled booleans better #979

sattvikc opened this issue Apr 9, 2024 · 3 comments
Assignees
Labels
enhancement New feature or request

Comments

@sattvikc
Copy link
Collaborator

sattvikc commented Apr 9, 2024

馃悰 Bug Report

Changes to the core:

  • When a new tenant is created, we set all enabled booleans to true, and firstFactor array as. When a new tenant is created, we set all enabled boolean to true, and firstFactor undefined for public AND non public tenants.
    • EDIT: for non public tenants, we will set it to [] by default because:
      • Modifying the static list wont affect existing tenant config by default (other than the public tenant).
      • Via the UI there is no way to make a tenant have undefined as firstFactors, so it's weird that it starts of as undefined and then there is no way for the UI to go back to that state.
  • firstFactors array being empty vs not being set needs to be distinguished. firstFactor would be undefined for static config to take into affect.
  • requiredSecondaryFactor can remain the same as it is right now (no change needed)
  • For older CDI ->
    • if firstFactor.length > 0, then we only set those enabled flags
    • if firstFactor.length === 0, then we have all as false
    • if firstFactor is undefined, then we return the booleans as they are (needs to be communicated as a change to developers).

  • Add two booleans to tenant config:
    • firstFactorFromStaticConfigIfEmpty
    • thirdPartyProviderFromStaticConfigIfEmpty
  • For public tenant, they will be true, true by default:
    • If firstFactors is empty / undefined in the tenant config:
      • From dashboard, it will show static config
    • If firstFactor is not empty in tenant config:
      • It will show from firstFactor in tenant config
    • If in dashboard, you remove the last provider -> we set provider to undefined / empty, and this will actually remove it from the tenant cause that boolean should have been set to false. Or rather, our backend SDK api call will set this boolean to false, since there are no providers configured for this tenant by default.
    • If in dashboard, you disable the last first factor -> we set the firstFactors to undefined, and this will actually remove it from the tenant cause that boolean should have been set to false. Or rather, our backend SDK api call will set this boolean to false, since the firstfactor is by default undefined anyway.
  • In fact, if for any tenant (including public), we modify the firstFactors or the thirdparty config in any way, we will set these booleans to false for them automatically in the core. Even if it means they are setting the firstFactor to undefined. If the user also passes these booleans as part of the API call, then we set the value in the db to these booleans.

Backend SDK changes:

  • It will have to take into account firstFactorFromStaticConfigIfEmpty and thirdPartyProviderFromStaticConfigIfEmpty in its merging logic.
  • When creating / updating a tenant, we should remove the option for the enabled booleans from the function signature. The minimum config is still just tenant id.
  • New CDI support and not backwards compatible with older CDI
  • What will be the effect on the getLoginMethods API??? TODO
  • Change to dashboard logic??? TODO

Docs changes

  • We should remove enabled booleans from everywhere, and only show firstFactors usage

Migration of tenant config:

  • Table schema migrations -> add new columns to the tenant_configs table.
  • We considered doing a migration wherein we move the current tenant config -> enable all boolean + firstFactors array. But decided not to do cause such few people are using mfa at the moment anyway.
  • We set the value for firstFactorFromStaticConfigIfEmpty and thirdPartyProviderFromStaticConfigIfEmpty to true for ALL tenants since this is the current behaviour.

Things to note:

  • Given that all the enabled booleans are true now, it implies that users can create a secondary factor for any factor as long as the recipe for that is init on the backend sdk, and they have an active session.
  • There might be a few things in the backend SDK that rely on the fact that the core would have these booleans as false

Useful informations

(Write what happened. Add screenshots, stacktraces, videos, anything that can help)

TODO

  • How will this affect SaaS migration given that it's going to affect the master db and not the target db
    • When copying over master db info for a CUD, we will have to insert the two booleans as true in the sql query when migrating from older core to this new one.
  • Any changes required to the dashbaord / backend apis once this change is done in the context of the tenant screen?
  • Check that this case is fine
    1. create a tenant - now all toggles are off
    2. turn on otp-email in secondary factors -> this also enables passwordless recipe
    3. reload the tenant detail page -> turns on all passwordless factors in the first factors section (since firstFactors array is undefined at this point)
  • Initialising new recipe will enable login methods for all tenants by default - think about this
  • Test third party deletion (for both, public and non public tenant)
    1. there are 2 static configs defined: google and facebook
    2. Delete facebook using the dashboard, google will remain
    3. Delete google using the dashboard, now since this is the last provider, thirdParty login method gets disabled
    4. Now enable thirdParty login method
  • Check if golang and python SDKs require any changes
  • Check for docs changes, esp where it might be weirdly different for node and golang/python
    What providers should you see now? statically defined ones or the last provider that was deleted?
    It should start from no providers
  • Check that when creating a tenant, if the user forgets to add v2 and uses the inputs of v2, there are no undesired side effects. Make sure of this by extracting common function in the tenant creation handling.
@sattvikc sattvikc added the bug Something isn't working label Apr 9, 2024
@sattvikc sattvikc self-assigned this Apr 9, 2024
@rishabhpoddar rishabhpoddar added enhancement New feature or request and removed bug Something isn't working labels Apr 11, 2024
@rishabhpoddar
Copy link
Member

rishabhpoddar commented Apr 16, 2024

Using backend sdk with CDI 4.0 with new tenant creation using 4.0

When the backend SDK asks for tenant config, we will return the enabled booleans based on:

  • We should set firstFactorFromStaticConfigIfEmpty and thirdPartyProviderFromStaticConfigIfEmpty to true for ALL tenants here since it's using older CDI.
  • returned emaiPasswordEnabled = tenantConfig.emaiPasswordEnabled && ((firstFactors.length === 0 && firstFactorFromStaticConfigIfEmpty) || firstFactors.contains("emailpassword"))
  • returned thirdPartyEnabled = tenantConfig.thirdPartyEnabled && ((firstFactors.length === 0 && firstFactorFromStaticConfigIfEmpty) || firstFactors.contains("thirdparty"))
  • returned passwordlessEnabled = tenantConfig.passwordlessEnabled && ((firstFactors.length === 0 && firstFactorFromStaticConfigIfEmpty) || firstFactors.contains("otp-email") || firstFactor.contains("otp-phone") || ...)

Using backend sdk with CDI 4.0 with new tenant creation using 5.1 (new to be CDI)

NOTE: We have to tell users that the new CDI will be breaking in how you create tenants. Instead of passing enabled booleans, you need to pass in firstFactors array ONLY.
When the backend SDK asks for tenant config, we will return the enabled booleans based on:

  • returned emaiPasswordEnabled = tenantConfig.emaiPasswordEnabled && ((firstFactors.length === 0 && firstFactorFromStaticConfigIfEmpty) || firstFactors.contains("emailpassword"))
  • returned thirdPartyEnabled = tenantConfig.thirdPartyEnabled && ((firstFactors.length === 0 && firstFactorFromStaticConfigIfEmpty) || firstFactors.contains("thirdparty"))
  • returned passwordlessEnabled = tenantConfig.passwordlessEnabled && ((firstFactors.length === 0 && firstFactorFromStaticConfigIfEmpty) || firstFactors.contains("otp-email") || firstFactor.contains("otp-phone") || ...)
  • Whenever update a tenant in this case (5.1 cdi), we need to make all the enabled booleans true.

Using backend sdk with CDI 5.0 with new tenant creation using 5.0

  • We should set firstFactorFromStaticConfigIfEmpty and thirdPartyProviderFromStaticConfigIfEmpty to true for ALL tenants here since it's using older CDI.
  • returned emaiPasswordEnabled = tenantConfig.emaiPasswordEnabled && ((firstFactors.length === 0 && firstFactorFromStaticConfigIfEmpty) || firstFactors.contains("emailpassword"))
  • returned thirdPartyEnabled = tenantConfig.thirdPartyEnabled && ((firstFactors.length === 0 && firstFactorFromStaticConfigIfEmpty) || firstFactors.contains("thirdparty"))
  • returned passwordlessEnabled = tenantConfig.passwordlessEnabled && ((firstFactors.length === 0 && firstFactorFromStaticConfigIfEmpty) || firstFactors.contains("otp-email") || firstFactor.contains("otp-phone") || ...)
  • returned firstFactors = tenantConfig.firstFactors

Using backend sdk with CDI 5.0 with new tenant creation using 5.1 (new to be CDI)

NOTE: We have to tell users that the new CDI will be breaking in how you create tenants. Instead of passing enabled booleans, you need to pass in firstFactors array ONLY.

  • returned emaiPasswordEnabled = tenantConfig.emaiPasswordEnabled && ((firstFactors.length === 0 && firstFactorFromStaticConfigIfEmpty) || firstFactors.contains("emailpassword") || secondaryFactor.contains("emailpassword"))
  • returned thirdPartyEnabled = tenantConfig.thirdPartyEnabled && ((firstFactors.length === 0 && firstFactorFromStaticConfigIfEmpty) || firstFactors.contains("thirdparty") || secondaryFactor.contains("thirdparty"))
  • returned passwordlessEnabled = tenantConfig.passwordlessEnabled && ((firstFactors.length === 0 && firstFactorFromStaticConfigIfEmpty) || firstFactors.contains("otp-email") || firstFactor.contains("otp-phone"))
  • returned firstFactors = tenantConfig.firstFactors
  • Whenever update a tenant in this case (5.1 cdi), we need to make all the enabled booleans true.

Using backend sdk with CDI 5.1 (new CDI to be) with new tenant creation using 5.1 (new CDI to be)

  • returned emaiPasswordEnabled = tenantConfig.emaiPasswordEnabled
  • returned thirdPartyEnabled = tenantConfig.thirdPartyEnabled
  • returned passwordlessEnabled = tenantConfig.passwordlessEnabled
  • returned firstFactors = tenantConfig.firstFactors
  • returned firstFactorFromStaticConfigIfEmpty = tenantConfig.firstFactorFromStaticConfigIfEmpty
  • returned thirdPartyProviderFromStaticConfigIfEmpty = tenantConfig.thirdPartyProviderFromStaticConfigIfEmpty
  • Whenever update a tenant in this case (5.1 cdi), we need to make all the enabled booleans true.

Other changes:

  • On a per API level, we do not need to check for these enabled booleans anymore.

@sattvikc
Copy link
Collaborator Author

sattvikc commented May 8, 2024

Database state for tenant

Introduce new state [] (empty) for firstFactors and providers

{
    emailPasswordEnabled: boolean,
    passwordlessEnabled: boolean,
    thirdPartyEnabled: boolean,
    firstFactors?: null | string[], // null, empty, non-empty
    requiredSecondaryFactors: string[], // null, non-empty
    providers: null | Provider[] // null, empty, non-empty
}

Recipe enabled check in core

isEmailPasswordEnabled = emailPasswordEnabled || (firstFactors != null && firstFactors.includes('emailpassword')) || (requiredSecondaryFactors != null && requiredSecondaryFactors.includes('emailpassword'))
isThirdPartyEnabled = thirdPartyEnabled || (firstFactors != null && firstFactors.includes('thirdparty')) || (requiredSecondaryFactors != null && requiredSecondaryFactors.includes('thirdparty'))
isPasswordlessEnabled = passwordlessEnabled || (firstFactors != null && firstFactors.includesOneOf('otp-email', 'otp-phone', 'link-email', 'link-phone')) || (requiredSecondaryFactors != null && requiredSecondaryFactors.includesOneOf('otp-email', 'otp-phone', 'link-email', 'link-phone'))

In the above conditions, we have three parts with OR conditions:

  • the recipe enabled boolean: this lets public tenant to have all recipes enabled for any factor login
  • firstFactors: this is to let any tenant use a recipe if they are being used as a firstFactor, for the tenants created using the v2 API which does not modify the booleans
  • requiredSecondaryFactors: this is to let any tenant use a recipe if they are being used as a secondary factor, for the tenants created using the v2 API which does not modify the booleans

Note: v2 means new endpoint for create/update and get/list tenants

New v2 endpoints for create/update CUD/app/tenant and list cud/apps/tenants and get tenant

  • The existing APIs for these would be deprecated and a new set of APIs will be added using the /v2 suffix

Input for create/update tenant

{
  tenantId: string;
  firstFactors?: null | string[], // allows empty array
  requiredSecondaryFactors: null | string[], // does not allow empty array
  coreConfig: any,
}

Output of a tenant in get tenant or list tenants

{
  tenantId: string;
  firstFactors?: string[]; // undefined or empty or non-empty
  requiredSecondaryFactors?: string[]; // undefined or non-empty
  thirdParty: {
    providers?: Provider[]; // undefined or empty or non-empty
  };
  coreConfig: any;
}

Using Backend CDI 4.0, Create/Update tenant using core CDI 4.0

  • Tenants are created using recipe booleans
  • In creation of Tenant,
    • firstFactors is set to null, providers is set to null
    • For public tenant, all recipe booleans are enabled by default
    • For non-public tenant, all recipe booleans are disabled by default
  • While updating a tenant:
    • Update booleans as per input
  • While returning a tenant:
    • Reasoning
      • When creating or updating tenant using CDI 4.0, firstFactors will always remain null and effectively, the returned boolean value is same as what is set in the db
    • Return:
      • emailPasswordEnabled = (firstFactors == null && emailPasswordEnabled) || (firstFactors != null && firstFactors.includes('emailpassword'))
      • thirdPartyEnabled = (firstFactors == null && thirdPartyEnabled) || (firstFactors != null && firstFactors.includes('thirdparty'))
      • passwordlessEnabled = (firstFactors == null && passwordlessEnabled) || (firstFactors != null && firstFactors.includesOneOf('otp-email', 'otp-phone', 'link-email', 'link-phone'))
      • providers = providers !== [] ? providers : null

Using Backend CDI 4.0, Create/Update tenant using core CDI 5.0

  • Tenants are created using recipe booleans + firstFactors
  • During creation of tenant,
    • Reasoning:
      • If the user doesn't provide firstFactors, most likely the user is coming from previous version of CDI, so we set firstFactors to be null which technically means that the SDK config will be used. When firstFactors is null, the boolean is effectively what is in the db.
      • If the user providers firstFactors in the input, then more likely, it's from MFA use. In that case, if backend is using CDI 4.0, which does not support MFA, technically, firstFactors determine the login methods that are enabled for the SDK. So, firstFactors takes the priority over the value of the boolean itself.
    • Behaviour:
      • firstFactors (if not provided) is set to null, providers is set to null
      • For public tenant, all recipe booleans are enabled by default
      • For non-public tenant, all recipe booleans are disabled by default
  • During updation of tenant,
    • Update firstFactor to empty array is not allowed
    • Update boolean or firstFactor as per input
  • While returning a tenant:
    • Reasoning:
      • if firstFactors is null, then booleans are effectively what is in the db
      • if firstFactors is set to non-empty list, then they are considered for the state of the boolean because the CDI 4.0 does not support MFA, and technically it is a first factor only
    • Return:
      • emailPasswordEnabled = (firstFactors == null && emailPasswordEnabled) || (firstFactors != null && firstFactors.includes('emailpassword'))
      • thirdPartyEnabled = (firstFactors == null && thirdPartyEnabled) || (firstFactors != null && firstFactors.includes('thirdparty'))
      • passwordlessEnabled = (firstFactors == null && passwordlessEnabled) || (firstFactors != null && firstFactors.includesOneOf('otp-email', 'otp-phone', 'link-email', 'link-phone'))
      • providers = providers !== [] ? providers : null

Edge cases:

  • If passwordless was enabled explicitly and not added to firstFactors, then passwordless will be shown as disabled for CD 4.0. This is a correct behaviour because the passwordless would have been enabled for second factor, which is unavailable in 4.0

Using Backend CDI 4.0, Create/Update tenant using core CDI 5.1 (v2)

  • Tenants are created using firstFactors/requiredSecondaryFactors. No recipe enable booleans are present in the input/output.
  • During creation of tenant,
    • Reasoning:
      • For public tenant, having firstFactors = null and all recipes enabled, keeps everything available to the SDK. No core modifications will be required for public tenant to use any feature on the SDK.
      • For non-public tenant, the tenant will have nothing enabled by default. The user will need to enable things that are necessary for that tenant. For eg, firstFactors and requiredSecondaryFactors.
    • Behaviour:
      • For public tenant, all recipe booleans are enabled by default, firstFactors is set to null
      • For non-public tenant, all recipe booleans are disabled by default, firstFactors is set to []
  • During updation of tenant,
    • Update firstFactors to empty array is allowed
    • firstFactors as per input
    • There will be no recipe enable booleans in the input
  • While returning a tenant:
    • Reasoning:
      • We don't consider requiredSecondaryFactors in the boolean state because CDI 4.0 doesn't support MFA and only first factors needs to be actually considered.
    • Return:
      • emailPasswordEnabled = (firstFactors == null && emailPasswordEnabled) || (firstFactors != null && firstFactors.includes('emailpassword'))
      • thirdPartyEnabled = (firstFactors == null && thirdPartyEnabled) || (firstFactors != null && firstFactors.includes('thirdparty'))
      • passwordlessEnabled = (firstFactors == null && passwordlessEnabled) || (firstFactors != null && firstFactors.includesOneOf('otp-email', 'otp-phone', 'link-email', 'link-phone'))
      • providers = providers !== [] ? providers : null

Using Backend CDI 5.0, Create/Update tenant using core CDI 5.0

  • Tenants are created using recipe booleans + firstFactors
  • During creation of tenant,
    • firstFactors (if not provided) is set to null, providers is set to null
    • For public tenant, all recipe booleans are enabled by default
    • For non-public tenant, all recipe booleans are disabled by default
  • During updation of tenant,
    • Update firstFactor to empty array is not allowed
    • Update boolean or firstFactor as per input
  • While returning a tenant:
    • Reasoning:
      • Replicating 5.0 behaviour as is
      • 5.0 doesn't have empty state for firstFactors and providers. So, empty state is considered as null, which will effectively use the static config from SDK.
      • we also consider firstFactors and requiredSecondaryFactors here because, in 5.0, you can't include emailpassword in firstFactor without having emailPasswordEnabled set to true.
    • Return:
      • emailPasswordEnabled = emailPasswordEnabled || (firstFactors != null && firstFactors.includes('emailpassword')) || (requiredSecondaryFactors != null && requiredSecondaryFactors.includes('emailpassword'))
      • thirdPartyEnabled = thirdPartyEnabled || (firstFactors != null && firstFactors.includes('thirdparty')) || (requiredSecondaryFactors != null && requiredSecondaryFactors.includes('thirdparty'))
      • passwordlessEnabled = passwordlessEnabled || (firstFactors != null && firstFactors.includesOneOf('otp-email', 'otp-phone', 'link-email', 'link-phone')) || (requiredSecondaryFactors != null && requiredSecondaryFactors.includesOneOf('otp-email', 'otp-phone', 'link-email', 'link-phone'))
      • firstFactors = firstFactors !== [] ? firstFactors : null
      • providers = providers !== [] ? providers : null

Using Backend CDI 5.0, Create/Update tenant using core CDI 5.1 (v2)

  • Tenants are created using firstFactors/requiredSecondaryFactors. No recipe enable booleans are present in the input/output.
  • During creation of tenant,
    • Reasoning:
      • Already explained
    • Behaviour:
      • For public tenant, all recipe booleans are enabled by default, firstFactors is set to null
      • For non-public tenant, all recipe booleans are disabled by default, firstFactors is set to []
  • During updation of tenant,
    • Update firstFactors to empty array is allowed
    • Update boolean or firstFactors as per input
  • While returning a tenant:
    • Reasoning:
      • Since in 5.1 (v2), there are no boolean inputs, the effective value for them is based on the firstFactors and requiredSecondaryFactors value in the core
    • Return:
      • emailPasswordEnabled = emailPasswordEnabled || (firstFactors != null && firstFactors.includes('emailpassword')) || (requiredSecondaryFactors != null && requiredSecondaryFactors.includes('emailpassword'))
      • thirdPartyEnabled = thirdPartyEnabled || (firstFactors != null && firstFactors.includes('thirdparty')) || (requiredSecondaryFactors != null && requiredSecondaryFactors.includes('thirdparty'))
      • passwordlessEnabled = passwordlessEnabled || (firstFactors != null && firstFactors.includesOneOf('otp-email', 'otp-phone', 'link-email', 'link-phone')) || (requiredSecondaryFactors != null && requiredSecondaryFactors.includesOneOf('otp-email', 'otp-phone', 'link-email', 'link-phone'))
    • firstFactors = firstFactors !== [] ? firstFactors : null
    • providers = providers !== [] ? providers : null

Using Backend CDI 5.1 (v2), Create/Update tenant using core CDI 5.1 (v2)

  • Tenants are created using firstFactors/requiredSecondaryFactors. No recipe enable booleans are present in the input/output.
  • During creation of tenant,
    • For public tenant, all recipe booleans are enabled by default, firstFactors is set to null
    • For non-public tenant, all recipe booleans are disabled by default, firstFactors is set to []
  • During updation of tenant,
    • Update firstFactors to empty array is allowed
    • Update boolean or firstFactors as per input
  • While returning a tenant:
    • firstFactors = firstFactors
    • requiredSecondaryFactors = requiredSecondaryFactors
    • providers = providers

Edge cases

  • To be able to use a secondary factor, the user will need to add the factor to the requiredSecondaryFactors

DB schema changes

  • isFirstFactorsNull and isThirdPartyProvidersNull are added to the tenant config table
  • both the booleans are true by default, and ignored if there is a value in the firstFactors or providers field
  • when updating firstFactors to non-null value, isFirstFactorsNull is set to false
  • when adding/removing thirdparty providers, isThirdPartyProvidersNull is set to false

Migrating for 5.0 -> 5.1

  • the 2 new columns are added with default value true to tenant_configs table
    • this carry forwards null state of firstFactors and providers

From dashboard point of view

For migrated tenant from 4.0

firstFactors

  • firstFactors will be set to null, so in the dashboard we show all available factors based on how SDK is initialised
  • Toggling any of the factors will update the firstFactors field
  • On further updates on firstFactors, the firstFactors will never get to the null state

thirdParty providers

  • providers will be set to null, so we show all statically defined providers
  • Adding or deleting a provider will result in a non-empty value in core
  • Any further updates on providers will never result in providers to be set to null

For migrated tenant from 5.0

firstFactors

  • if firstFactors was null, then same rules as 4.0 tenant will apply
  • On further updates on firstFactors, the firstFactors will never get to the null state

thirdParty providers

  • if providers was null, then same rules as 4.0 tenant will apply
  • Any further updates on providers will never result in providers to be set to null

Tenants on 5.1

  • While creating a tenant, firstFactors and providers are set to []

Use cases

  1. Using MFA with static config of firstFactors and requiredSecondary factors

    With Core migrated, but the SDK is not updated yet:

    The tenants have firstFactors set to null, which will remain as is post migration. This also means that the user would have enabled necessary recipes that are being used.

    • Effectively, core will allow all the enabled recipes, letting the first factor and secondary factors as expected.
    • Old deprecated API will return null for firstFactors and then SDK will use the static config as expected.

    With core migratied and the SDK updated:

    • the v2 APIs will still return null for firstFactors and effectively static config will be used
  2. Using MFA with firstFactors and requiredSecondaryFactors configured in the tenant

    With Core migrated, but the SDK is not updated yet:

    • firstFactors and requiredSecondaryFactors will return values as is and effectively they will be used in the SDK.
    • Core does not care about the recipe booleans and will allow all factors specified in firstFactors and requiredSecondaryFactors

    With core migratied and the SDK updated:

    • the v2 APIs will also return the same values as is and effectively they will be used in the SDK.
  3. Using dashboard to create new tenants, but there are also existing tenants and Backend is still on an older CDI:

    First Factors

    • The tenants created in 4.0 will have firstFactors set to null. Effectively this will use the static config. On switching any of the toggles, firstFactors will be updated and it will never get to null state from the dashboard.
      • if backend is using CDI 4.0, booleans will be based on the firstFactors since it's no more set to null. Original booleans will be ignored.
      • if backend is using CDI 5.0:
        • if using backend SDK, it does not depend on booleans, so the SDK will use the firstFactors as is
        • else, the recipe boolean set to true effectively means the recipe could be used for either first factor or the secondary factors. It should not be used as a first factor.
      • if backend is using CDI 5.1 and using deprecated APIs:
        • the behaviour will be same as 5.0
    • The tenants created using 5.0 with firstFactors and the recipe booleans, we only show first factors in the dashboard. Toggling any of it will only update the firstFactors and leave the booleans as is.
      • Backend behaviours will be similar to what is explained in the previous point

    Secondary Factors

    • The tenants created in 4.0 will have requiredSecondaryFactors set to null. Toggling them will update the requiredSecondaryFactors
      • if backend is using CDI 4.0, secondary factors aren't considered for anything
      • if backend is using CDI 5.0:
        • if using backend SDK, it does not depend on the booleans. just the value of requiredSecondaryFactors is considered.
        • else, the recipe boolean will show up as true if the factor is present in the requiredSecondaryFactors
      • if backend is using CDI 5.1 and using the deprecated APIs:
        • the behaviour will be same as 5.0
      • The tenants created using 5.0 with requiredSecondaryFactors and the recipe booleans, we only show secondary factors in the dashboard. Toggling any of it will only update the requiredSecondaryFactors and leave the booleans as is.
        • Backend behaviours will be similar to what is explained in the previous point

    Creation of new tenants

    • The new tenants will have firstFactors set to [] by default. Which means, all the first factors will be disabled by default. Toggling them just updates the firstFactors array. It will never get to null state.
      • For backend using CDI 4.0, the booleans will be based on firstFactors

@sattvikc
Copy link
Collaborator Author

database states

enabled booleans
for latest node SDK: filtering out the first and second factors that have boolean set to false
for py/go SDK: frontend uses subset of this as first factors based on what is initialised in the frontend static config

firstFactors
null:
for latest node SDK: use backend static config. It will throw an error on frontend if all the recipes from this array are not initialised
for py/go SDK: implies all recipe booleans are true
[]:
for latest node SDK: no login allowed
for py/go SDK: all enabled booleans are false
["emailpassword", "thirdparty"]:
for latest node SDK: it means we use subset of this based on which recipe is initialised in the backend static config. This will overwrite mfa.init(firstFactors) It will throw an error on frontend if all the recipes from this array are not initialised
for py/go SDK: only enabled booleans associated with the factors are true, rest false. What is rendered on frontend is subset of this based on which recipe is initialised in the frontend static config

requiredSecondaryFactors
null:
for latest node SDK: MFA is not enabled
for py/go SDK: not applicable
["otp-phone"]:
for latest node SDK: enables subset based on backend SDK initialised recipes (check with Mihaly)
for py/go SDK: not applicable

providers
TODO

create or update in v4.0

create public tenant

Intention

  • All recipes are enabled by default and the frontend static config gets used
  • If the backend SDK makes calls to any recipe APIs is allowed

effect on enabledBoolean

  • all boolean set to true
    effect on firstFactors
  • firstFactors set to all factors
    effect on core APIs
  • core will allow all APIs
    effect on thirdParty providers array
  • no effect

create non-public tenant

Intention

  • All recipes are disabled by default
  • If the backend SDK makes calls to any recipe APIs is disallowed

effect on enabledBoolean

  • all boolean set to false
    effect on firstFactors
  • firstFactors set to []
    effect on core APIs
  • core will block all APIs
    effect on thirdParty providers array
  • no effect

{ emailPasswordEnabled: true }

Intention

  • Enable emailpassword as a first factor for the tenant
  • If the backend SDK makes calls to emailPassword APIs, it should be allowed in the core

effect on enabledBoolean

  • emailPassword boolean set to true
    effect on firstFactors
  • modify firstFactors to add emailpassword to it
    effect on core APIs
  • core will allow emailpassword APIs
    effect on thirdParty providers array
  • no effect

{ emailPasswordEnabled: false }

Intention

  • Disable emailpassword as a first factor for the tenant
  • If all the booleans are false, it means the user has disabled login for the tenant entirely
  • EmailPassword APIs are blocked by the core

effect on enabledBoolean

  • emailPassword boolean set to false
    effect on firstFactors
  • if firstFactors is null
    • if all booleans are false, set firstFactors = []
    • else add factors that have boolean as true
  • if firstFactors is []
    • do nothing
  • else
    • remove emailpassword from firstFactors (if it exists). if firstFactors becomes empty, leave it empty
      effect on core APIs
  • core will block emailpassword APIs
    effect on thirdParty providers array
  • no effect

similarly for thirdparty and passwordless

create or update in v5.0

create public tenant (same as v4)

Intention

  • All recipes are enabled by default for firstFactor or secondFactor depending on backend static config
  • If the backend SDK makes calls to any recipe APIs is allowed

effect on enabledBoolean

  • all boolean set to true
    effect on firstFactors
  • firstFactors set to all factors
    effect on core APIs
  • core will allow all APIs
    effect on thirdParty providers array
  • no effect

create non-public tenant (same as v4)

Intention

  • All recipes are disabled by default
  • If the backend SDK makes calls to any recipe APIs is disallowed

effect on enabledBoolean

  • all boolean set to false
    effect on firstFactors
  • firstFactors set to []
    effect on core APIs
  • core will block all APIs
    effect on thirdParty providers array
  • no effect

{ emailPasswordEnabled: true }

Intention

  • If the backend SDK makes calls to emailPassword APIs, it should be allowed in the core
  • let the sdk use emailpassword as either first or second factor

effect on enabledBoolean

  • emailPassword boolean set to true
    effect on firstFactors
  • do not modify
    effect on core APIs
  • core will allow emailpassword APIs
    effect on thirdParty providers array
  • no effect

{ emailPasswordEnabled: false }

Intention

  • EmailPassword is disabled entirely (cannot be used as either first or second factor)
  • EmailPassword APIs are blocked by the core

effect on enabledBoolean

  • emailPassword boolean set to false
    effect on firstFactors
  • if firstFactors is null
    • do not modify
  • if firstFactors is []
    • do nothing
  • else
    • remove emailpassword from firstFactors (if it exists). if firstFactors becomes empty, leave it empty (do not throw an error)
      effect on core APIs
  • core will block emailpassword APIs
    effect on thirdParty providers array
  • no effect

{ firstFactors: null }

Intention

  • To use backend static config (mfa.init(firstfactors) or initialized recipes) for firstFactors for the tenant

effect on enabledBoolean

  • enable all booleans. Note: if the user is returning 'otp-phone' in the getMFAReqForAuth and the user disabled it using passwordlessEnabled = false, then we are re-enabling. This ok because the right way to disable 'otp-phone' is not return in the getMFAReqForAuth override.
    effect on firstFactors
  • set firstFactors to null
    effect on core APIs
  • core will allow all APIs
    effect on thirdParty providers array
  • no effect

{ firstFactors: ["otp-phone"] }

Intention

  • To allow only otp-phone as first factor and no other first factor for the tenant
  • Ignore Mfa.init(firstFactors) and initialized recipes in the backend SDK and use this value instead

effect on enabledBoolean

  • enable passwordless (we wont error out as it causes friction)
    effect on firstFactors
  • set firstFactors to ['otp-phone']
    effect on core APIs
  • core will allow all APIs
    effect on thirdParty providers array
  • no effect

{ emailPasswordEnabled: true, firstFactors: null, requiredSecondaryFactors: null }

  • This means that emailPassword is being enabled for either first factor or second factor
  • core should allow emailpassword APIs
  • get in v4.0 should return emailPasswordEnabled true
  • get in v5.0 should return as per the update
  • get in v5.1 (v2 API) ???

{ requiredSecondaryFactors: null }

  • This means that any factor that is enabled can be used as a secondary factor
  • get in v4.0 no booleans should get flipped because of this [rare case]
  • get in v5.0 should return requiredSecondaryFactors: null and rest as is
  • get in v5.1 (v2 API) should return requiredSecondaryFactors: null (discuss) and firstFactors as is

{ requiredSecondaryFactors : [...]}

  • This means some factors are being enabled as secondary factors
  • get in v4.0 no booleans should get flipped because of this [rare case]
  • get in v5.0 should return requiredSecondaryFactors: [...], rest as is
  • get in v5.1 (v2 API) should return requiredSecondaryFactors: [...] + (factors from enabled recipes - firstFactors) (discuss)

create or update in v5.1 (v2 API)

{ firstFactors: null }

  • This means that all firstFactors are to be enabled
  • core allows all recipe APIs
  • get in v4.0 should return all the booleans as true
  • get in v5.0 should return all the booleans as true and firstFactors: null
  • get in v5.1 (v2 API) should return firstFactors: null and secondaryFactors as is

{ firstFactors: ['emailpassword']}

  • This means that only emailpassword is enabled as firstFactor
  • core should allow emailpassword APIs
  • get in v4.0 should return only emailPasswordEnabled: true
  • get in v5.0 should return emailPasswordEnabled: true and firstFactors: ['emailpassword'] other booleans can be true based on the secondary factors
  • get in v5.1 (v2 API) return as is

{ firstFactors: [] }

  • This means that all recipes are disabled for firstFactor
  • core blocks all recipes (unless requiredSecondaryFactors contains some factors). probably we should not allow setting requiredSecondaryFactors if firstFactors == []
  • get in v4.0 should return all the booleans as false
  • get in v5.0 may return some booleans true based on secondaryFactors
  • get in v5.1 (v2 API) should return firstFactors: [] and secondaryFactors as is

{ requiredSecondaryFactors: ['emailpassword'] }

  • This means that emailpassword maybe used as a secondary factor
  • core allows emailpassword APIs
  • get in v4.0 should not be affected by this
  • get in v5.0 should have emailPasswordEnabled: true and rest as is
  • get in v5.1 (v2 API) should return requiredSecondaryFactors: ['emailpassword'] and rest as is

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants