@logto/schemas 1.43.0 → 1.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/alterations/1.44.0-1788946735-add-saml-authn-request-config.ts +18 -0
- package/alterations/1.44.0-1789000000-extend-user-id-length.ts +61 -0
- package/alterations/1.45.0-1791531333-add-tenant-viewer-role.ts +38 -0
- package/alterations-js/1.44.0-1788946735-add-saml-authn-request-config.js +14 -0
- package/alterations-js/1.44.0-1789000000-extend-user-id-length.js +47 -0
- package/alterations-js/1.45.0-1791531333-add-tenant-viewer-role.js +32 -0
- package/lib/consts/experience.d.ts +3 -0
- package/lib/consts/experience.js +3 -0
- package/lib/consts/index.d.ts +1 -0
- package/lib/consts/index.js +1 -0
- package/lib/consts/license.d.ts +222 -0
- package/lib/consts/license.js +81 -0
- package/lib/consts/license.test.d.ts +1 -0
- package/lib/consts/license.test.js +96 -0
- package/lib/consts/oidc.d.ts +15 -1
- package/lib/consts/oidc.js +11 -0
- package/lib/consts/oidc.test.d.ts +1 -0
- package/lib/consts/oidc.test.js +15 -0
- package/lib/consts/subscriptions.d.ts +13 -1
- package/lib/consts/subscriptions.js +12 -0
- package/lib/db-entries/aggregated-daily-active-user.js +2 -2
- package/lib/db-entries/application-access-control-user-relation.js +2 -2
- package/lib/db-entries/application-user-consent-organization.js +2 -2
- package/lib/db-entries/cimd-grant-organization.js +2 -2
- package/lib/db-entries/daily-active-user.js +2 -2
- package/lib/db-entries/oidc-session-extension.js +2 -2
- package/lib/db-entries/organization-invitation.js +4 -4
- package/lib/db-entries/organization-role-user-relation.js +2 -2
- package/lib/db-entries/organization-user-relation.js +2 -2
- package/lib/db-entries/personal-access-token.js +2 -2
- package/lib/db-entries/saml-application-config.d.ts +4 -2
- package/lib/db-entries/saml-application-config.js +5 -1
- package/lib/db-entries/secret.js +2 -2
- package/lib/db-entries/subject-token.js +2 -2
- package/lib/db-entries/trusted-device.js +2 -2
- package/lib/db-entries/user-geo-location.js +2 -2
- package/lib/db-entries/user-sign-in-country.js +2 -2
- package/lib/db-entries/user-sso-identity.js +2 -2
- package/lib/db-entries/user.js +2 -2
- package/lib/db-entries/users-role.js +2 -2
- package/lib/db-entries/verification-record.js +2 -2
- package/lib/db-entries/verification-status.js +2 -2
- package/lib/foundations/jsonb-types/captcha.d.ts +47 -1
- package/lib/foundations/jsonb-types/captcha.js +20 -0
- package/lib/foundations/jsonb-types/hooks.d.ts +0 -3
- package/lib/foundations/jsonb-types/hooks.js +2 -6
- package/lib/foundations/jsonb-types/saml-application-configs.d.ts +23 -0
- package/lib/foundations/jsonb-types/saml-application-configs.js +16 -0
- package/lib/foundations/jsonb-types/saml-application-configs.test.js +24 -1
- package/lib/types/authentication-context.d.ts +224 -0
- package/lib/types/authentication-context.js +238 -0
- package/lib/types/authentication-context.test.d.ts +1 -0
- package/lib/types/authentication-context.test.js +186 -0
- package/lib/types/cookie.d.ts +4 -0
- package/lib/types/cookie.js +6 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.js +1 -0
- package/lib/types/interactions.d.ts +161 -0
- package/lib/types/interactions.js +23 -0
- package/lib/types/log/interaction.d.ts +15 -2
- package/lib/types/log/interaction.js +5 -0
- package/lib/types/logto-config/index.d.ts +47 -0
- package/lib/types/logto-config/index.js +1 -0
- package/lib/types/logto-config/jwt-customizer.d.ts +92 -0
- package/lib/types/saml-application.d.ts +55 -1
- package/lib/types/saml-application.js +7 -1
- package/lib/types/sign-in-experience.d.ts +11 -7
- package/lib/types/sign-in-experience.js +2 -2
- package/lib/types/ssr.d.ts +2 -0
- package/lib/types/system.d.ts +57 -5
- package/lib/types/system.js +36 -0
- package/lib/types/system.test.d.ts +1 -0
- package/lib/types/system.test.js +26 -0
- package/lib/types/tenant-organization.d.ts +4 -2
- package/lib/types/tenant-organization.js +6 -2
- package/lib/types/tenant-organization.test.d.ts +1 -0
- package/lib/types/tenant-organization.test.js +16 -0
- package/lib/types/user-sessions.d.ts +156 -0
- package/lib/types/verification-records/code-verification.d.ts +17 -0
- package/lib/types/verification-records/code-verification.js +1 -0
- package/lib/utils/management-api.d.ts +5 -0
- package/lib/utils/management-api.js +7 -1
- package/lib/utils/oidc-private-key.test.js +44 -0
- package/package.json +7 -7
- package/tables/aggregated_daily_active_users.sql +1 -1
- package/tables/application_access_control_user_relations.sql +1 -1
- package/tables/application_user_consent_organizations.sql +1 -1
- package/tables/cimd_grant_organizations.sql +1 -1
- package/tables/daily_active_users.sql +1 -1
- package/tables/oidc_session_extensions.sql +1 -1
- package/tables/organization_invitations.sql +2 -2
- package/tables/organization_role_user_relations.sql +1 -1
- package/tables/organization_user_relations.sql +1 -1
- package/tables/personal_access_tokens.sql +1 -1
- package/tables/saml_application_configs.sql +1 -0
- package/tables/secrets.sql +1 -1
- package/tables/subject_tokens.sql +1 -1
- package/tables/trusted_devices.sql +1 -1
- package/tables/user_geo_locations.sql +1 -1
- package/tables/user_sign_in_countries.sql +1 -1
- package/tables/user_sso_identities.sql +1 -1
- package/tables/users.sql +1 -1
- package/tables/users_roles.sql +1 -1
- package/tables/verification_records.sql +1 -1
- package/tables/verification_statuses.sql +1 -1
- package/LICENSE +0 -373
|
@@ -3,6 +3,7 @@ export var CaptchaType;
|
|
|
3
3
|
(function (CaptchaType) {
|
|
4
4
|
CaptchaType["RecaptchaEnterprise"] = "RecaptchaEnterprise";
|
|
5
5
|
CaptchaType["Turnstile"] = "Turnstile";
|
|
6
|
+
CaptchaType["Cap"] = "Cap";
|
|
6
7
|
})(CaptchaType || (CaptchaType = {}));
|
|
7
8
|
export var RecaptchaEnterpriseMode;
|
|
8
9
|
(function (RecaptchaEnterpriseMode) {
|
|
@@ -21,8 +22,27 @@ export const recaptchaEnterpriseConfigGuard = z.object({
|
|
|
21
22
|
projectId: z.string(),
|
|
22
23
|
domain: z.string().optional(),
|
|
23
24
|
mode: z.nativeEnum(RecaptchaEnterpriseMode).optional(),
|
|
25
|
+
scoreThreshold: z.number().min(0).max(1).optional(),
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Config of a self-hosted Cap Standalone instance.
|
|
29
|
+
*
|
|
30
|
+
* @see https://capjs.js.org/guide/standalone/
|
|
31
|
+
*/
|
|
32
|
+
export const capConfigGuard = z.object({
|
|
33
|
+
type: z.literal(CaptchaType.Cap),
|
|
34
|
+
/** The public base URL of the Cap Standalone instance, e.g. `https://cap.example.com`. */
|
|
35
|
+
endpoint: z
|
|
36
|
+
.string()
|
|
37
|
+
.url()
|
|
38
|
+
.refine((value) => ['http:', 'https:'].includes(new URL(value).protocol), {
|
|
39
|
+
message: 'The endpoint must be an HTTP(S) URL.',
|
|
40
|
+
}),
|
|
41
|
+
siteKey: z.string(),
|
|
42
|
+
secretKey: z.string(),
|
|
24
43
|
});
|
|
25
44
|
export const captchaConfigGuard = z.discriminatedUnion('type', [
|
|
26
45
|
turnstileConfigGuard,
|
|
27
46
|
recaptchaEnterpriseConfigGuard,
|
|
47
|
+
capConfigGuard,
|
|
28
48
|
]);
|
|
@@ -33,9 +33,6 @@ type CustomDataHookMutableSchema = `${Exclude<DataHookSchema, DataHookSchema.Tru
|
|
|
33
33
|
type DataHookPropertyUpdateEvent = `${CustomDataHookMutableSchema}.${DataHookDetailMutationType.Updated}`;
|
|
34
34
|
export type ExceptionHookEvent = 'Identifier.Lockout' | 'Message.RateLimited' | 'Grant.LimitExceeded';
|
|
35
35
|
export type DataHookEvent = BasicDataHookEvent | DataHookPropertyUpdateEvent;
|
|
36
|
-
/** Data hook events that are available only while their feature is under development. */
|
|
37
|
-
export declare const devFeatureHookEvents: readonly ["TrustedDevice.Created", "TrustedDevice.Deleted"];
|
|
38
|
-
export type DevFeatureHookEvent = (typeof devFeatureHookEvents)[number];
|
|
39
36
|
/** The hook event values that can be registered. */
|
|
40
37
|
export declare const hookEvents: readonly [InteractionHookEvent.PostRegister, InteractionHookEvent.PostSignIn, InteractionHookEvent.PostSignInAdaptiveMfaTriggered, InteractionHookEvent.PostResetPassword, "User.Created", "User.Deleted", "User.Data.Updated", "User.SuspensionStatus.Updated", "TrustedDevice.Created", "TrustedDevice.Deleted", "Role.Created", "Role.Deleted", "Role.Data.Updated", "Role.Scopes.Updated", "Scope.Created", "Scope.Deleted", "Scope.Data.Updated", "Organization.Created", "Organization.Deleted", "Organization.Data.Updated", "Organization.Membership.Updated", "OrganizationRole.Created", "OrganizationRole.Deleted", "OrganizationRole.Data.Updated", "OrganizationRole.Scopes.Updated", "OrganizationScope.Created", "OrganizationScope.Deleted", "OrganizationScope.Data.Updated", "Identifier.Lockout", "Message.RateLimited", "Grant.LimitExceeded"];
|
|
41
38
|
/** The type of hook event values that can be registered. */
|
|
@@ -34,11 +34,6 @@ var DataHookDetailMutationType;
|
|
|
34
34
|
(function (DataHookDetailMutationType) {
|
|
35
35
|
DataHookDetailMutationType["Updated"] = "Updated";
|
|
36
36
|
})(DataHookDetailMutationType || (DataHookDetailMutationType = {}));
|
|
37
|
-
/** Data hook events that are available only while their feature is under development. */
|
|
38
|
-
export const devFeatureHookEvents = Object.freeze([
|
|
39
|
-
'TrustedDevice.Created',
|
|
40
|
-
'TrustedDevice.Deleted',
|
|
41
|
-
]);
|
|
42
37
|
/** The hook event values that can be registered. */
|
|
43
38
|
export const hookEvents = Object.freeze([
|
|
44
39
|
InteractionHookEvent.PostRegister,
|
|
@@ -49,7 +44,8 @@ export const hookEvents = Object.freeze([
|
|
|
49
44
|
'User.Deleted',
|
|
50
45
|
'User.Data.Updated',
|
|
51
46
|
'User.SuspensionStatus.Updated',
|
|
52
|
-
|
|
47
|
+
'TrustedDevice.Created',
|
|
48
|
+
'TrustedDevice.Deleted',
|
|
53
49
|
'Role.Created',
|
|
54
50
|
'Role.Deleted',
|
|
55
51
|
'Role.Data.Updated',
|
|
@@ -49,6 +49,29 @@ export declare const samlEncryptionGuard: z.ZodEffects<z.ZodObject<{
|
|
|
49
49
|
certificate?: string | undefined;
|
|
50
50
|
}>;
|
|
51
51
|
export type SamlEncryption = z.input<typeof samlEncryptionGuard>;
|
|
52
|
+
/** Authentication and request-signature policy for a SAML application. */
|
|
53
|
+
export declare const samlAuthnRequestConfigGuard: z.ZodEffects<z.ZodObject<{
|
|
54
|
+
forceAuthn: z.ZodOptional<z.ZodBoolean>;
|
|
55
|
+
requireSignedAuthnRequests: z.ZodOptional<z.ZodBoolean>;
|
|
56
|
+
signingCertificate: z.ZodOptional<z.ZodString>;
|
|
57
|
+
}, "strip", z.ZodTypeAny, {
|
|
58
|
+
forceAuthn?: boolean | undefined;
|
|
59
|
+
requireSignedAuthnRequests?: boolean | undefined;
|
|
60
|
+
signingCertificate?: string | undefined;
|
|
61
|
+
}, {
|
|
62
|
+
forceAuthn?: boolean | undefined;
|
|
63
|
+
requireSignedAuthnRequests?: boolean | undefined;
|
|
64
|
+
signingCertificate?: string | undefined;
|
|
65
|
+
}>, {
|
|
66
|
+
forceAuthn?: boolean | undefined;
|
|
67
|
+
requireSignedAuthnRequests?: boolean | undefined;
|
|
68
|
+
signingCertificate?: string | undefined;
|
|
69
|
+
}, {
|
|
70
|
+
forceAuthn?: boolean | undefined;
|
|
71
|
+
requireSignedAuthnRequests?: boolean | undefined;
|
|
72
|
+
signingCertificate?: string | undefined;
|
|
73
|
+
}>;
|
|
74
|
+
export type SamlAuthnRequestConfig = z.infer<typeof samlAuthnRequestConfigGuard>;
|
|
52
75
|
export declare enum NameIdFormat {
|
|
53
76
|
/** Uses unique and persistent identifiers for the user. */
|
|
54
77
|
Persistent = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
|
|
@@ -28,6 +28,22 @@ export const samlEncryptionGuard = z
|
|
|
28
28
|
return z.NEVER;
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
|
+
/** Authentication and request-signature policy for a SAML application. */
|
|
32
|
+
export const samlAuthnRequestConfigGuard = z
|
|
33
|
+
.object({
|
|
34
|
+
forceAuthn: z.boolean().optional(),
|
|
35
|
+
requireSignedAuthnRequests: z.boolean().optional(),
|
|
36
|
+
signingCertificate: z.string().trim().min(1).optional(),
|
|
37
|
+
})
|
|
38
|
+
.superRefine(({ requireSignedAuthnRequests, signingCertificate }, ctx) => {
|
|
39
|
+
if (requireSignedAuthnRequests && !signingCertificate) {
|
|
40
|
+
ctx.addIssue({
|
|
41
|
+
code: z.ZodIssueCode.custom,
|
|
42
|
+
path: ['signingCertificate'],
|
|
43
|
+
message: '`signingCertificate` is required when `requireSignedAuthnRequests` is `true`',
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
31
47
|
export var NameIdFormat;
|
|
32
48
|
(function (NameIdFormat) {
|
|
33
49
|
/** Uses unique and persistent identifiers for the user. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { samlEncryptionGuard } from './saml-application-configs.js';
|
|
2
|
+
import { samlEncryptionGuard, samlAuthnRequestConfigGuard } from './saml-application-configs.js';
|
|
3
3
|
describe('samlEncryptionGuard', () => {
|
|
4
4
|
// Test valid configurations
|
|
5
5
|
it('should pass when encryption is disabled', () => {
|
|
@@ -47,3 +47,26 @@ describe('samlEncryptionGuard', () => {
|
|
|
47
47
|
}
|
|
48
48
|
});
|
|
49
49
|
});
|
|
50
|
+
describe('samlAuthnRequestConfigGuard', () => {
|
|
51
|
+
it('keeps the per-application force-login setting', () => {
|
|
52
|
+
expect(samlAuthnRequestConfigGuard.parse({ forceAuthn: true })).toEqual({ forceAuthn: true });
|
|
53
|
+
});
|
|
54
|
+
it('allows default session reuse', () => {
|
|
55
|
+
expect(samlAuthnRequestConfigGuard.parse({})).toEqual({});
|
|
56
|
+
});
|
|
57
|
+
it('rejects a non-boolean force-login setting', () => {
|
|
58
|
+
expect(samlAuthnRequestConfigGuard.safeParse({ forceAuthn: 'true' }).success).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
describe('signed AuthnRequest policy', () => {
|
|
62
|
+
it('requires a signing certificate when signatures are required', () => {
|
|
63
|
+
expect(samlAuthnRequestConfigGuard.safeParse({ requireSignedAuthnRequests: true }).success).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
it('keeps the configured trust certificate', () => {
|
|
66
|
+
const config = { requireSignedAuthnRequests: true, signingCertificate: 'certificate' };
|
|
67
|
+
expect(samlAuthnRequestConfigGuard.parse(config)).toEqual(config);
|
|
68
|
+
});
|
|
69
|
+
it.each(['', ' '])('rejects an empty certificate: %j', (signingCertificate) => {
|
|
70
|
+
expect(samlAuthnRequestConfigGuard.safeParse({ signingCertificate }).success).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The authoritative vocabulary for the authentication context Logto records on a sign-in or
|
|
3
|
+
* step-up: the supported Authentication Context Class Reference (ACR) values, their satisfaction
|
|
4
|
+
* relation, and the Authentication Methods References (AMR) each verification contributes.
|
|
5
|
+
*
|
|
6
|
+
* @see {@link https://openid.net/specs/openid-connect-core-1_0.html#IDToken | OpenID Connect Core `acr` / `amr`}
|
|
7
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc8176.html | RFC 8176 Authentication Method Reference Values}
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { VerificationType } from './verification-records/verification-type.js';
|
|
11
|
+
/** The Logto-defined ACR values. Only these can be requested through `acr_values`. */
|
|
12
|
+
export declare enum LogtoAcr {
|
|
13
|
+
/**
|
|
14
|
+
* At least one active factor that Logto can directly verify: password, the user's primary
|
|
15
|
+
* email / phone verification code, or an enrolled MFA factor. Social and enterprise SSO never
|
|
16
|
+
* satisfy this class.
|
|
17
|
+
*/
|
|
18
|
+
FirstFactor = "urn:logto:acr:1fa",
|
|
19
|
+
/**
|
|
20
|
+
* A Logto-verifiable {@link LogtoAcr.FirstFactor} context plus an `mfa`-class record from a
|
|
21
|
+
* different factor, or WebAuthn / passkey with required user verification alone.
|
|
22
|
+
*/
|
|
23
|
+
Mfa = "urn:logto:acr:mfa"
|
|
24
|
+
}
|
|
25
|
+
/** The ACR values advertised in Discovery as `acr_values_supported`, in the provider order. */
|
|
26
|
+
export declare const logtoAcrValues: readonly [LogtoAcr.FirstFactor, LogtoAcr.Mfa];
|
|
27
|
+
/** Whether a value, e.g. one of the requested `acr_values` or a session `acr`, is a Logto ACR. */
|
|
28
|
+
export declare const isLogtoAcr: (value: unknown) => value is LogtoAcr;
|
|
29
|
+
/**
|
|
30
|
+
* Whether an achieved ACR, e.g. the `acr` recorded on the OIDC session, satisfies a required
|
|
31
|
+
* class. An achieved value that is not a Logto ACR, including an absent one, satisfies nothing.
|
|
32
|
+
*/
|
|
33
|
+
export declare const acrSatisfies: (achieved: unknown, required: LogtoAcr) => boolean;
|
|
34
|
+
/** How Experience handles a login prompt that carries a requested authentication context. */
|
|
35
|
+
export declare enum AuthenticationContextMode {
|
|
36
|
+
/**
|
|
37
|
+
* An authenticated OIDC session exists but does not satisfy the request: the subject is pinned
|
|
38
|
+
* from the session and the interaction asks only for the missing assurance.
|
|
39
|
+
*/
|
|
40
|
+
StepUp = "stepUp"
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The authentication context the OIDC interaction policy writes into the login prompt details
|
|
44
|
+
* when the authorization request carries supported `acr_values`. Experience reads it at
|
|
45
|
+
* interaction creation; `interactions.url` routes on {@link RequestedAuthenticationContext.mode}.
|
|
46
|
+
*/
|
|
47
|
+
export type RequestedAuthenticationContext = {
|
|
48
|
+
/** The supported classes from `acr_values`, in the caller's order. */
|
|
49
|
+
requestedAcrValues: LogtoAcr[];
|
|
50
|
+
/**
|
|
51
|
+
* The first requested class, the minimum the interaction must reach. Present only in step-up
|
|
52
|
+
* mode; a sign-in without a session applies the same selection rule once the user is identified.
|
|
53
|
+
*/
|
|
54
|
+
selectedAcr?: LogtoAcr;
|
|
55
|
+
/** Present only when an authenticated session pins the subject. */
|
|
56
|
+
mode?: AuthenticationContextMode;
|
|
57
|
+
};
|
|
58
|
+
export declare const requestedAuthenticationContextGuard: z.ZodObject<{
|
|
59
|
+
requestedAcrValues: z.ZodArray<z.ZodNativeEnum<typeof LogtoAcr>, "many">;
|
|
60
|
+
selectedAcr: z.ZodOptional<z.ZodNativeEnum<typeof LogtoAcr>>;
|
|
61
|
+
mode: z.ZodOptional<z.ZodNativeEnum<typeof AuthenticationContextMode>>;
|
|
62
|
+
}, "strip", z.ZodTypeAny, {
|
|
63
|
+
requestedAcrValues: LogtoAcr[];
|
|
64
|
+
mode?: AuthenticationContextMode | undefined;
|
|
65
|
+
selectedAcr?: LogtoAcr | undefined;
|
|
66
|
+
}, {
|
|
67
|
+
requestedAcrValues: LogtoAcr[];
|
|
68
|
+
mode?: AuthenticationContextMode | undefined;
|
|
69
|
+
selectedAcr?: LogtoAcr | undefined;
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* The login prompt details that carry a {@link RequestedAuthenticationContext}. Absent when the
|
|
73
|
+
* authorization request carried no supported `acr_values`.
|
|
74
|
+
*/
|
|
75
|
+
export type LoginPromptAuthenticationContextDetails = {
|
|
76
|
+
authenticationContext?: RequestedAuthenticationContext;
|
|
77
|
+
};
|
|
78
|
+
export declare const loginPromptAuthenticationContextDetailsGuard: z.ZodObject<{
|
|
79
|
+
authenticationContext: z.ZodOptional<z.ZodObject<{
|
|
80
|
+
requestedAcrValues: z.ZodArray<z.ZodNativeEnum<typeof LogtoAcr>, "many">;
|
|
81
|
+
selectedAcr: z.ZodOptional<z.ZodNativeEnum<typeof LogtoAcr>>;
|
|
82
|
+
mode: z.ZodOptional<z.ZodNativeEnum<typeof AuthenticationContextMode>>;
|
|
83
|
+
}, "strip", z.ZodTypeAny, {
|
|
84
|
+
requestedAcrValues: LogtoAcr[];
|
|
85
|
+
mode?: AuthenticationContextMode | undefined;
|
|
86
|
+
selectedAcr?: LogtoAcr | undefined;
|
|
87
|
+
}, {
|
|
88
|
+
requestedAcrValues: LogtoAcr[];
|
|
89
|
+
mode?: AuthenticationContextMode | undefined;
|
|
90
|
+
selectedAcr?: LogtoAcr | undefined;
|
|
91
|
+
}>>;
|
|
92
|
+
}, "strip", z.ZodTypeAny, {
|
|
93
|
+
authenticationContext?: {
|
|
94
|
+
requestedAcrValues: LogtoAcr[];
|
|
95
|
+
mode?: AuthenticationContextMode | undefined;
|
|
96
|
+
selectedAcr?: LogtoAcr | undefined;
|
|
97
|
+
} | undefined;
|
|
98
|
+
}, {
|
|
99
|
+
authenticationContext?: {
|
|
100
|
+
requestedAcrValues: LogtoAcr[];
|
|
101
|
+
mode?: AuthenticationContextMode | undefined;
|
|
102
|
+
selectedAcr?: LogtoAcr | undefined;
|
|
103
|
+
} | undefined;
|
|
104
|
+
}>;
|
|
105
|
+
/**
|
|
106
|
+
* The AMR values Logto emits. All except {@link AuthenticationMethodReference.Federated} are
|
|
107
|
+
* registered in RFC 8176; `fed` is the de facto industry value for authentication delegated to an
|
|
108
|
+
* upstream identity provider and is the only unregistered value Logto emits.
|
|
109
|
+
*/
|
|
110
|
+
export declare enum AuthenticationMethodReference {
|
|
111
|
+
/** Password-based authentication. */
|
|
112
|
+
Password = "pwd",
|
|
113
|
+
/** One-time password: email verification code, TOTP, backup code, or one-time token. */
|
|
114
|
+
Otp = "otp",
|
|
115
|
+
/** Verification code delivered by SMS. */
|
|
116
|
+
Sms = "sms",
|
|
117
|
+
/** Proof-of-possession of a key, e.g. WebAuthn. */
|
|
118
|
+
ProofOfPossession = "pop",
|
|
119
|
+
/** User presence / verification by the authenticator, e.g. WebAuthn user verification. */
|
|
120
|
+
UserPresence = "user",
|
|
121
|
+
/** Multiple-factor authentication; appended whenever the achieved ACR is {@link LogtoAcr.Mfa}. */
|
|
122
|
+
Mfa = "mfa",
|
|
123
|
+
/** Federated authentication assertion from a social or enterprise SSO provider. */
|
|
124
|
+
Federated = "fed"
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The role a proof can fill when proofs are combined into an ACR. This is not the ACR a proof
|
|
128
|
+
* reaches on its own: any proof with a class reaches {@link LogtoAcr.FirstFactor} alone, and the
|
|
129
|
+
* class only decides which side of the pair the proof can stand on when
|
|
130
|
+
* {@link LogtoAcr.Mfa} is derived. That level needs a `1fa`-role proof and an `mfa`-role proof of
|
|
131
|
+
* two different factors, so two `mfa`-class factors, such as a TOTP and a backup code, never reach
|
|
132
|
+
* it together.
|
|
133
|
+
*/
|
|
134
|
+
export declare enum AuthenticationFactorClass {
|
|
135
|
+
/** Fills the `1fa` role: a password or a primary email / phone code. */
|
|
136
|
+
FirstFactor = "1fa",
|
|
137
|
+
/**
|
|
138
|
+
* Fills the `mfa` role: TOTP, a backup code or an MFA email / phone code. Alone it reaches
|
|
139
|
+
* {@link LogtoAcr.FirstFactor}; paired with a `1fa`-role proof of a different factor it reaches
|
|
140
|
+
* {@link LogtoAcr.Mfa}.
|
|
141
|
+
*/
|
|
142
|
+
Mfa = "mfa",
|
|
143
|
+
/**
|
|
144
|
+
* Fills both roles by itself, so it reaches {@link LogtoAcr.Mfa} alone: a user-verified WebAuthn
|
|
145
|
+
* authenticator is possession plus user verification in one act. Kept as a class rather than a
|
|
146
|
+
* special case on the factor so that every "can fill this role" check stays a class comparison
|
|
147
|
+
* and this table stays the single place that decides.
|
|
148
|
+
*/
|
|
149
|
+
Both = "both"
|
|
150
|
+
}
|
|
151
|
+
/** Classify a verification type; see {@link authenticationFactorClasses}. */
|
|
152
|
+
export declare const getAuthenticationFactorClass: (type: VerificationType) => AuthenticationFactorClass | undefined;
|
|
153
|
+
/**
|
|
154
|
+
* The factor a verification record is a proof of. Repeated proofs of one factor count once, and
|
|
155
|
+
* {@link LogtoAcr.Mfa} needs a `1fa`-class and an `mfa`-class proof of two different factors: a
|
|
156
|
+
* one-time token and an MFA email code are two proofs of the same mailbox, not two factors.
|
|
157
|
+
*/
|
|
158
|
+
export declare enum AuthenticationFactor {
|
|
159
|
+
Password = "password",
|
|
160
|
+
Email = "email",
|
|
161
|
+
Phone = "phone",
|
|
162
|
+
Totp = "totp",
|
|
163
|
+
BackupCode = "backupCode",
|
|
164
|
+
WebAuthn = "webAuthn",
|
|
165
|
+
Federated = "federated"
|
|
166
|
+
}
|
|
167
|
+
/** The factor a verification type is a proof of; see {@link authenticationFactors}. */
|
|
168
|
+
export declare const getAuthenticationFactor: (type: VerificationType) => AuthenticationFactor;
|
|
169
|
+
/** The AMR values a verification type contributes; see {@link authenticationMethodReferences}. */
|
|
170
|
+
export declare const getAuthenticationMethodReferences: (type: VerificationType) => readonly AuthenticationMethodReference[];
|
|
171
|
+
/**
|
|
172
|
+
* Build the `amr` claim from the references each counted proof contributes and the ACR they
|
|
173
|
+
* achieved: the union in first-seen order, with `mfa` always last, present whenever a proof carries
|
|
174
|
+
* it (WebAuthn) or the achieved ACR is {@link LogtoAcr.Mfa}.
|
|
175
|
+
*/
|
|
176
|
+
export declare const buildAuthenticationMethodReferences: (references: Iterable<readonly AuthenticationMethodReference[]>, achievedAcr?: LogtoAcr) => AuthenticationMethodReference[];
|
|
177
|
+
/**
|
|
178
|
+
* Why a proof was recorded: the touchpoint that consumed the credential. Aggregation into `acr` /
|
|
179
|
+
* `amr` ignores the role; it exists for the MFA gate and for step-up freshness, and never reaches
|
|
180
|
+
* a token.
|
|
181
|
+
*/
|
|
182
|
+
export declare enum AuthenticationProofRole {
|
|
183
|
+
/** `createUser()` created the account from the record. */
|
|
184
|
+
Create = "create",
|
|
185
|
+
/** `identifyUser()` identified the user with the record. */
|
|
186
|
+
Identify = "identify",
|
|
187
|
+
/** The credential or factor was written to the account by this interaction. */
|
|
188
|
+
Bind = "bind",
|
|
189
|
+
/** An MFA challenge was answered with the record. */
|
|
190
|
+
Mfa = "mfa"
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* A proof that the identified user authenticated in the interaction, recorded at the single
|
|
194
|
+
* touchpoint that consumed the credential. What counts is decided where the interaction relies on
|
|
195
|
+
* the credential, never by inspecting verification records afterwards.
|
|
196
|
+
*/
|
|
197
|
+
export type AuthenticationProof = {
|
|
198
|
+
/** The verification record id, or `password` for a password established through the profile. */
|
|
199
|
+
id: string;
|
|
200
|
+
factor: AuthenticationFactor;
|
|
201
|
+
/** Absent for a federated proof, which contributes `fed` to AMR and nothing to the ACR. */
|
|
202
|
+
class?: AuthenticationFactorClass;
|
|
203
|
+
amr: AuthenticationMethodReference[];
|
|
204
|
+
role: AuthenticationProofRole;
|
|
205
|
+
};
|
|
206
|
+
export declare const authenticationProofGuard: z.ZodObject<{
|
|
207
|
+
id: z.ZodString;
|
|
208
|
+
factor: z.ZodNativeEnum<typeof AuthenticationFactor>;
|
|
209
|
+
class: z.ZodOptional<z.ZodNativeEnum<typeof AuthenticationFactorClass>>;
|
|
210
|
+
amr: z.ZodArray<z.ZodNativeEnum<typeof AuthenticationMethodReference>, "many">;
|
|
211
|
+
role: z.ZodNativeEnum<typeof AuthenticationProofRole>;
|
|
212
|
+
}, "strip", z.ZodTypeAny, {
|
|
213
|
+
id: string;
|
|
214
|
+
role: AuthenticationProofRole;
|
|
215
|
+
factor: AuthenticationFactor;
|
|
216
|
+
amr: AuthenticationMethodReference[];
|
|
217
|
+
class?: AuthenticationFactorClass | undefined;
|
|
218
|
+
}, {
|
|
219
|
+
id: string;
|
|
220
|
+
role: AuthenticationProofRole;
|
|
221
|
+
factor: AuthenticationFactor;
|
|
222
|
+
amr: AuthenticationMethodReference[];
|
|
223
|
+
class?: AuthenticationFactorClass | undefined;
|
|
224
|
+
}>;
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The authoritative vocabulary for the authentication context Logto records on a sign-in or
|
|
3
|
+
* step-up: the supported Authentication Context Class Reference (ACR) values, their satisfaction
|
|
4
|
+
* relation, and the Authentication Methods References (AMR) each verification contributes.
|
|
5
|
+
*
|
|
6
|
+
* @see {@link https://openid.net/specs/openid-connect-core-1_0.html#IDToken | OpenID Connect Core `acr` / `amr`}
|
|
7
|
+
* @see {@link https://www.rfc-editor.org/rfc/rfc8176.html | RFC 8176 Authentication Method Reference Values}
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { VerificationType } from './verification-records/verification-type.js';
|
|
11
|
+
/** The Logto-defined ACR values. Only these can be requested through `acr_values`. */
|
|
12
|
+
export var LogtoAcr;
|
|
13
|
+
(function (LogtoAcr) {
|
|
14
|
+
/**
|
|
15
|
+
* At least one active factor that Logto can directly verify: password, the user's primary
|
|
16
|
+
* email / phone verification code, or an enrolled MFA factor. Social and enterprise SSO never
|
|
17
|
+
* satisfy this class.
|
|
18
|
+
*/
|
|
19
|
+
LogtoAcr["FirstFactor"] = "urn:logto:acr:1fa";
|
|
20
|
+
/**
|
|
21
|
+
* A Logto-verifiable {@link LogtoAcr.FirstFactor} context plus an `mfa`-class record from a
|
|
22
|
+
* different factor, or WebAuthn / passkey with required user verification alone.
|
|
23
|
+
*/
|
|
24
|
+
LogtoAcr["Mfa"] = "urn:logto:acr:mfa";
|
|
25
|
+
})(LogtoAcr || (LogtoAcr = {}));
|
|
26
|
+
/** The ACR values advertised in Discovery as `acr_values_supported`, in the provider order. */
|
|
27
|
+
export const logtoAcrValues = Object.freeze([LogtoAcr.FirstFactor, LogtoAcr.Mfa]);
|
|
28
|
+
const logtoAcrSet = new Set(logtoAcrValues);
|
|
29
|
+
/** Whether a value, e.g. one of the requested `acr_values` or a session `acr`, is a Logto ACR. */
|
|
30
|
+
export const isLogtoAcr = (value) => typeof value === 'string' && logtoAcrSet.has(value);
|
|
31
|
+
/**
|
|
32
|
+
* The classes each Logto ACR satisfies. Satisfaction is this explicit map, never the provider's
|
|
33
|
+
* exact match: {@link LogtoAcr.Mfa} is a {@link LogtoAcr.FirstFactor} context plus more, so it
|
|
34
|
+
* satisfies both classes, while {@link LogtoAcr.FirstFactor} satisfies only itself.
|
|
35
|
+
*/
|
|
36
|
+
const satisfiedAcrs = Object.freeze({
|
|
37
|
+
[LogtoAcr.FirstFactor]: [LogtoAcr.FirstFactor],
|
|
38
|
+
[LogtoAcr.Mfa]: [LogtoAcr.Mfa, LogtoAcr.FirstFactor],
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Whether an achieved ACR, e.g. the `acr` recorded on the OIDC session, satisfies a required
|
|
42
|
+
* class. An achieved value that is not a Logto ACR, including an absent one, satisfies nothing.
|
|
43
|
+
*/
|
|
44
|
+
export const acrSatisfies = (achieved, required) => isLogtoAcr(achieved) && satisfiedAcrs[achieved].includes(required);
|
|
45
|
+
/** How Experience handles a login prompt that carries a requested authentication context. */
|
|
46
|
+
export var AuthenticationContextMode;
|
|
47
|
+
(function (AuthenticationContextMode) {
|
|
48
|
+
/**
|
|
49
|
+
* An authenticated OIDC session exists but does not satisfy the request: the subject is pinned
|
|
50
|
+
* from the session and the interaction asks only for the missing assurance.
|
|
51
|
+
*/
|
|
52
|
+
AuthenticationContextMode["StepUp"] = "stepUp";
|
|
53
|
+
})(AuthenticationContextMode || (AuthenticationContextMode = {}));
|
|
54
|
+
export const requestedAuthenticationContextGuard = z.object({
|
|
55
|
+
requestedAcrValues: z.nativeEnum(LogtoAcr).array(),
|
|
56
|
+
selectedAcr: z.nativeEnum(LogtoAcr).optional(),
|
|
57
|
+
mode: z.nativeEnum(AuthenticationContextMode).optional(),
|
|
58
|
+
});
|
|
59
|
+
export const loginPromptAuthenticationContextDetailsGuard = z.object({
|
|
60
|
+
authenticationContext: requestedAuthenticationContextGuard.optional(),
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* The AMR values Logto emits. All except {@link AuthenticationMethodReference.Federated} are
|
|
64
|
+
* registered in RFC 8176; `fed` is the de facto industry value for authentication delegated to an
|
|
65
|
+
* upstream identity provider and is the only unregistered value Logto emits.
|
|
66
|
+
*/
|
|
67
|
+
export var AuthenticationMethodReference;
|
|
68
|
+
(function (AuthenticationMethodReference) {
|
|
69
|
+
/** Password-based authentication. */
|
|
70
|
+
AuthenticationMethodReference["Password"] = "pwd";
|
|
71
|
+
/** One-time password: email verification code, TOTP, backup code, or one-time token. */
|
|
72
|
+
AuthenticationMethodReference["Otp"] = "otp";
|
|
73
|
+
/** Verification code delivered by SMS. */
|
|
74
|
+
AuthenticationMethodReference["Sms"] = "sms";
|
|
75
|
+
/** Proof-of-possession of a key, e.g. WebAuthn. */
|
|
76
|
+
AuthenticationMethodReference["ProofOfPossession"] = "pop";
|
|
77
|
+
/** User presence / verification by the authenticator, e.g. WebAuthn user verification. */
|
|
78
|
+
AuthenticationMethodReference["UserPresence"] = "user";
|
|
79
|
+
/** Multiple-factor authentication; appended whenever the achieved ACR is {@link LogtoAcr.Mfa}. */
|
|
80
|
+
AuthenticationMethodReference["Mfa"] = "mfa";
|
|
81
|
+
/** Federated authentication assertion from a social or enterprise SSO provider. */
|
|
82
|
+
AuthenticationMethodReference["Federated"] = "fed";
|
|
83
|
+
})(AuthenticationMethodReference || (AuthenticationMethodReference = {}));
|
|
84
|
+
/**
|
|
85
|
+
* The role a proof can fill when proofs are combined into an ACR. This is not the ACR a proof
|
|
86
|
+
* reaches on its own: any proof with a class reaches {@link LogtoAcr.FirstFactor} alone, and the
|
|
87
|
+
* class only decides which side of the pair the proof can stand on when
|
|
88
|
+
* {@link LogtoAcr.Mfa} is derived. That level needs a `1fa`-role proof and an `mfa`-role proof of
|
|
89
|
+
* two different factors, so two `mfa`-class factors, such as a TOTP and a backup code, never reach
|
|
90
|
+
* it together.
|
|
91
|
+
*/
|
|
92
|
+
export var AuthenticationFactorClass;
|
|
93
|
+
(function (AuthenticationFactorClass) {
|
|
94
|
+
/** Fills the `1fa` role: a password or a primary email / phone code. */
|
|
95
|
+
AuthenticationFactorClass["FirstFactor"] = "1fa";
|
|
96
|
+
/**
|
|
97
|
+
* Fills the `mfa` role: TOTP, a backup code or an MFA email / phone code. Alone it reaches
|
|
98
|
+
* {@link LogtoAcr.FirstFactor}; paired with a `1fa`-role proof of a different factor it reaches
|
|
99
|
+
* {@link LogtoAcr.Mfa}.
|
|
100
|
+
*/
|
|
101
|
+
AuthenticationFactorClass["Mfa"] = "mfa";
|
|
102
|
+
/**
|
|
103
|
+
* Fills both roles by itself, so it reaches {@link LogtoAcr.Mfa} alone: a user-verified WebAuthn
|
|
104
|
+
* authenticator is possession plus user verification in one act. Kept as a class rather than a
|
|
105
|
+
* special case on the factor so that every "can fill this role" check stays a class comparison
|
|
106
|
+
* and this table stays the single place that decides.
|
|
107
|
+
*/
|
|
108
|
+
AuthenticationFactorClass["Both"] = "both";
|
|
109
|
+
})(AuthenticationFactorClass || (AuthenticationFactorClass = {}));
|
|
110
|
+
/**
|
|
111
|
+
* The class each verification type contributes: `1fa`-class, `mfa`-class, `both`, or `undefined`
|
|
112
|
+
* for social / enterprise SSO, which contribute `fed` to AMR but nothing to the ACR.
|
|
113
|
+
*
|
|
114
|
+
* The record is keyed by every {@link VerificationType}, so a new type fails at compile time until
|
|
115
|
+
* it is mapped here. Logto requires user verification for every WebAuthn ceremony, registration and
|
|
116
|
+
* authentication alike, so a verified WebAuthn record is user-verified by construction.
|
|
117
|
+
*/
|
|
118
|
+
const authenticationFactorClasses = Object.freeze({
|
|
119
|
+
[VerificationType.Password]: AuthenticationFactorClass.FirstFactor,
|
|
120
|
+
[VerificationType.EmailVerificationCode]: AuthenticationFactorClass.FirstFactor,
|
|
121
|
+
[VerificationType.PhoneVerificationCode]: AuthenticationFactorClass.FirstFactor,
|
|
122
|
+
[VerificationType.OneTimeToken]: AuthenticationFactorClass.FirstFactor,
|
|
123
|
+
// A password established by a registration; it is a proof once `createUser()` consumes it.
|
|
124
|
+
[VerificationType.NewPasswordIdentity]: AuthenticationFactorClass.FirstFactor,
|
|
125
|
+
[VerificationType.TOTP]: AuthenticationFactorClass.Mfa,
|
|
126
|
+
[VerificationType.MfaEmailVerificationCode]: AuthenticationFactorClass.Mfa,
|
|
127
|
+
[VerificationType.MfaPhoneVerificationCode]: AuthenticationFactorClass.Mfa,
|
|
128
|
+
[VerificationType.BackupCode]: AuthenticationFactorClass.Mfa,
|
|
129
|
+
[VerificationType.WebAuthn]: AuthenticationFactorClass.Both,
|
|
130
|
+
[VerificationType.SignInPasskey]: AuthenticationFactorClass.Both,
|
|
131
|
+
[VerificationType.Social]: undefined,
|
|
132
|
+
[VerificationType.EnterpriseSso]: undefined,
|
|
133
|
+
});
|
|
134
|
+
/** Classify a verification type; see {@link authenticationFactorClasses}. */
|
|
135
|
+
export const getAuthenticationFactorClass = (type) => authenticationFactorClasses[type];
|
|
136
|
+
/**
|
|
137
|
+
* The factor a verification record is a proof of. Repeated proofs of one factor count once, and
|
|
138
|
+
* {@link LogtoAcr.Mfa} needs a `1fa`-class and an `mfa`-class proof of two different factors: a
|
|
139
|
+
* one-time token and an MFA email code are two proofs of the same mailbox, not two factors.
|
|
140
|
+
*/
|
|
141
|
+
export var AuthenticationFactor;
|
|
142
|
+
(function (AuthenticationFactor) {
|
|
143
|
+
AuthenticationFactor["Password"] = "password";
|
|
144
|
+
AuthenticationFactor["Email"] = "email";
|
|
145
|
+
AuthenticationFactor["Phone"] = "phone";
|
|
146
|
+
AuthenticationFactor["Totp"] = "totp";
|
|
147
|
+
AuthenticationFactor["BackupCode"] = "backupCode";
|
|
148
|
+
AuthenticationFactor["WebAuthn"] = "webAuthn";
|
|
149
|
+
AuthenticationFactor["Federated"] = "federated";
|
|
150
|
+
})(AuthenticationFactor || (AuthenticationFactor = {}));
|
|
151
|
+
/** Keyed by every {@link VerificationType}, so a new type fails at compile time until mapped. */
|
|
152
|
+
const authenticationFactors = Object.freeze({
|
|
153
|
+
[VerificationType.Password]: AuthenticationFactor.Password,
|
|
154
|
+
[VerificationType.NewPasswordIdentity]: AuthenticationFactor.Password,
|
|
155
|
+
[VerificationType.EmailVerificationCode]: AuthenticationFactor.Email,
|
|
156
|
+
[VerificationType.MfaEmailVerificationCode]: AuthenticationFactor.Email,
|
|
157
|
+
[VerificationType.OneTimeToken]: AuthenticationFactor.Email,
|
|
158
|
+
[VerificationType.PhoneVerificationCode]: AuthenticationFactor.Phone,
|
|
159
|
+
[VerificationType.MfaPhoneVerificationCode]: AuthenticationFactor.Phone,
|
|
160
|
+
[VerificationType.TOTP]: AuthenticationFactor.Totp,
|
|
161
|
+
[VerificationType.BackupCode]: AuthenticationFactor.BackupCode,
|
|
162
|
+
[VerificationType.WebAuthn]: AuthenticationFactor.WebAuthn,
|
|
163
|
+
[VerificationType.SignInPasskey]: AuthenticationFactor.WebAuthn,
|
|
164
|
+
[VerificationType.Social]: AuthenticationFactor.Federated,
|
|
165
|
+
[VerificationType.EnterpriseSso]: AuthenticationFactor.Federated,
|
|
166
|
+
});
|
|
167
|
+
/** The factor a verification type is a proof of; see {@link authenticationFactors}. */
|
|
168
|
+
export const getAuthenticationFactor = (type) => authenticationFactors[type];
|
|
169
|
+
/**
|
|
170
|
+
* The AMR values a single verification type contributes, per the step-up tech design. The record
|
|
171
|
+
* is keyed by every {@link VerificationType}, so a new type fails at compile time until it is
|
|
172
|
+
* mapped here.
|
|
173
|
+
*
|
|
174
|
+
* The trailing `mfa` marker for an achieved {@link LogtoAcr.Mfa} is added by
|
|
175
|
+
* {@link buildAuthenticationMethodReferences}, not here; WebAuthn carries it inherently because a
|
|
176
|
+
* user-verified passkey is a multi-factor authenticator on its own.
|
|
177
|
+
*/
|
|
178
|
+
const authenticationMethodReferences = Object.freeze({
|
|
179
|
+
[VerificationType.Password]: [AuthenticationMethodReference.Password],
|
|
180
|
+
[VerificationType.NewPasswordIdentity]: [AuthenticationMethodReference.Password],
|
|
181
|
+
[VerificationType.EmailVerificationCode]: [AuthenticationMethodReference.Otp],
|
|
182
|
+
[VerificationType.OneTimeToken]: [AuthenticationMethodReference.Otp],
|
|
183
|
+
[VerificationType.TOTP]: [AuthenticationMethodReference.Otp],
|
|
184
|
+
[VerificationType.MfaEmailVerificationCode]: [AuthenticationMethodReference.Otp],
|
|
185
|
+
[VerificationType.BackupCode]: [AuthenticationMethodReference.Otp],
|
|
186
|
+
[VerificationType.PhoneVerificationCode]: [AuthenticationMethodReference.Sms],
|
|
187
|
+
[VerificationType.MfaPhoneVerificationCode]: [AuthenticationMethodReference.Sms],
|
|
188
|
+
[VerificationType.WebAuthn]: [
|
|
189
|
+
AuthenticationMethodReference.ProofOfPossession,
|
|
190
|
+
AuthenticationMethodReference.UserPresence,
|
|
191
|
+
AuthenticationMethodReference.Mfa,
|
|
192
|
+
],
|
|
193
|
+
[VerificationType.SignInPasskey]: [
|
|
194
|
+
AuthenticationMethodReference.ProofOfPossession,
|
|
195
|
+
AuthenticationMethodReference.UserPresence,
|
|
196
|
+
AuthenticationMethodReference.Mfa,
|
|
197
|
+
],
|
|
198
|
+
[VerificationType.Social]: [AuthenticationMethodReference.Federated],
|
|
199
|
+
[VerificationType.EnterpriseSso]: [AuthenticationMethodReference.Federated],
|
|
200
|
+
});
|
|
201
|
+
/** The AMR values a verification type contributes; see {@link authenticationMethodReferences}. */
|
|
202
|
+
export const getAuthenticationMethodReferences = (type) => authenticationMethodReferences[type];
|
|
203
|
+
/**
|
|
204
|
+
* Build the `amr` claim from the references each counted proof contributes and the ACR they
|
|
205
|
+
* achieved: the union in first-seen order, with `mfa` always last, present whenever a proof carries
|
|
206
|
+
* it (WebAuthn) or the achieved ACR is {@link LogtoAcr.Mfa}.
|
|
207
|
+
*/
|
|
208
|
+
export const buildAuthenticationMethodReferences = (references, achievedAcr) => {
|
|
209
|
+
const flattened = [...references].flat();
|
|
210
|
+
const hasMfa = achievedAcr === LogtoAcr.Mfa || flattened.includes(AuthenticationMethodReference.Mfa);
|
|
211
|
+
return [
|
|
212
|
+
...new Set(flattened.filter((reference) => reference !== AuthenticationMethodReference.Mfa)),
|
|
213
|
+
...(hasMfa ? [AuthenticationMethodReference.Mfa] : []),
|
|
214
|
+
];
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* Why a proof was recorded: the touchpoint that consumed the credential. Aggregation into `acr` /
|
|
218
|
+
* `amr` ignores the role; it exists for the MFA gate and for step-up freshness, and never reaches
|
|
219
|
+
* a token.
|
|
220
|
+
*/
|
|
221
|
+
export var AuthenticationProofRole;
|
|
222
|
+
(function (AuthenticationProofRole) {
|
|
223
|
+
/** `createUser()` created the account from the record. */
|
|
224
|
+
AuthenticationProofRole["Create"] = "create";
|
|
225
|
+
/** `identifyUser()` identified the user with the record. */
|
|
226
|
+
AuthenticationProofRole["Identify"] = "identify";
|
|
227
|
+
/** The credential or factor was written to the account by this interaction. */
|
|
228
|
+
AuthenticationProofRole["Bind"] = "bind";
|
|
229
|
+
/** An MFA challenge was answered with the record. */
|
|
230
|
+
AuthenticationProofRole["Mfa"] = "mfa";
|
|
231
|
+
})(AuthenticationProofRole || (AuthenticationProofRole = {}));
|
|
232
|
+
export const authenticationProofGuard = z.object({
|
|
233
|
+
id: z.string().min(1),
|
|
234
|
+
factor: z.nativeEnum(AuthenticationFactor),
|
|
235
|
+
class: z.nativeEnum(AuthenticationFactorClass).optional(),
|
|
236
|
+
amr: z.nativeEnum(AuthenticationMethodReference).array().min(1),
|
|
237
|
+
role: z.nativeEnum(AuthenticationProofRole),
|
|
238
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|