@logto/schemas 1.40.0 → 1.41.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.
Files changed (73) hide show
  1. package/alterations/1.41.0-1779864280-add-password-expiration-policy.ts +23 -0
  2. package/alterations/1.41.0-1779864281-add-is-password-expired-to-users.ts +18 -0
  3. package/alterations/1.41.0-1780358400-drop-oidc-model-instances-legacy-grant-id-index.ts +25 -0
  4. package/alterations/1.41.0-1780381219-add-username-policy.ts +41 -0
  5. package/alterations/1.41.0-1780643665-set-sign-up-profile-fields-default.ts +20 -0
  6. package/alterations/1.41.0-1780906060-add-verification-code-policy.ts +19 -0
  7. package/alterations/1.41.0-1781689400-add-sentinel-activities-created-at-index.ts +25 -0
  8. package/alterations/1.41.0-1782354362-set-admin-account-center-profile-fields.ts +28 -0
  9. package/alterations/1.41.0-1782375106-cover-service-logs-tenant-type-index-with-created-at.ts +36 -0
  10. package/alterations-js/1.41.0-1779864280-add-password-expiration-policy.js +19 -0
  11. package/alterations-js/1.41.0-1779864281-add-is-password-expired-to-users.js +14 -0
  12. package/alterations-js/1.41.0-1780358400-drop-oidc-model-instances-legacy-grant-id-index.js +21 -0
  13. package/alterations-js/1.41.0-1780381219-add-username-policy.js +37 -0
  14. package/alterations-js/1.41.0-1780643665-set-sign-up-profile-fields-default.js +16 -0
  15. package/alterations-js/1.41.0-1780906060-add-verification-code-policy.js +15 -0
  16. package/alterations-js/1.41.0-1781689400-add-sentinel-activities-created-at-index.js +21 -0
  17. package/alterations-js/1.41.0-1782354362-set-admin-account-center-profile-fields.js +23 -0
  18. package/alterations-js/1.41.0-1782375106-cover-service-logs-tenant-type-index-with-created-at.js +32 -0
  19. package/lib/consts/experience.d.ts +2 -0
  20. package/lib/consts/experience.js +2 -0
  21. package/lib/consts/index.d.ts +2 -0
  22. package/lib/consts/index.js +2 -0
  23. package/lib/consts/message-rate-limit.d.ts +65 -0
  24. package/lib/consts/message-rate-limit.js +29 -0
  25. package/lib/consts/message-rate-limit.test.d.ts +1 -0
  26. package/lib/consts/message-rate-limit.test.js +20 -0
  27. package/lib/consts/verification-code.d.ts +10 -0
  28. package/lib/consts/verification-code.js +10 -0
  29. package/lib/db-entries/sign-in-experience.d.ts +10 -4
  30. package/lib/db-entries/sign-in-experience.js +13 -1
  31. package/lib/db-entries/user.d.ts +5 -1
  32. package/lib/db-entries/user.js +8 -0
  33. package/lib/foundations/jsonb-types/account-centers.d.ts +3 -0
  34. package/lib/foundations/jsonb-types/account-centers.js +1 -0
  35. package/lib/foundations/jsonb-types/hooks.d.ts +4 -4
  36. package/lib/foundations/jsonb-types/hooks.js +1 -0
  37. package/lib/foundations/jsonb-types/sentinel.d.ts +16 -1
  38. package/lib/foundations/jsonb-types/sentinel.js +15 -0
  39. package/lib/foundations/jsonb-types/sign-in-experience.d.ts +74 -2
  40. package/lib/foundations/jsonb-types/sign-in-experience.js +19 -0
  41. package/lib/foundations/jsonb-types/sign-in-experience.test.js +49 -1
  42. package/lib/foundations/jsonb-types/users.d.ts +9 -0
  43. package/lib/foundations/jsonb-types/users.js +1 -0
  44. package/lib/seeds/account-center.js +1 -0
  45. package/lib/seeds/sign-in-experience.js +1 -0
  46. package/lib/seeds/sign-in-experience.test.js +5 -1
  47. package/lib/types/consent.d.ts +8 -0
  48. package/lib/types/custom-profile-fields.d.ts +4 -0
  49. package/lib/types/hook.d.ts +2 -2
  50. package/lib/types/interactions.js +3 -1
  51. package/lib/types/logto-config/index.d.ts +69 -4
  52. package/lib/types/logto-config/index.js +12 -0
  53. package/lib/types/logto-config/index.test.js +25 -1
  54. package/lib/types/logto-config/inline-hook.d.ts +76 -0
  55. package/lib/types/logto-config/inline-hook.js +25 -0
  56. package/lib/types/logto-config/jwt-customizer.d.ts +133 -1
  57. package/lib/types/logto-config/jwt-customizer.js +14 -0
  58. package/lib/types/saml-application.d.ts +3 -0
  59. package/lib/types/saml-application.js +3 -0
  60. package/lib/types/sign-in-experience.d.ts +9 -0
  61. package/lib/types/ssr.d.ts +11 -0
  62. package/lib/types/user-assets.d.ts +10 -0
  63. package/lib/types/user-assets.js +17 -0
  64. package/lib/types/user-sessions.d.ts +231 -5
  65. package/lib/types/user-sessions.js +5 -0
  66. package/lib/types/user.d.ts +15 -0
  67. package/lib/types/user.js +1 -0
  68. package/package.json +8 -8
  69. package/tables/oidc_model_instances.sql +0 -8
  70. package/tables/sentinel_activities.sql +4 -0
  71. package/tables/service_logs.sql +2 -2
  72. package/tables/sign_in_experiences.sql +15 -2
  73. package/tables/users.sql +7 -0
@@ -1,4 +1,4 @@
1
- import { Color, Branding, LanguageInfo, SignIn, SignUp, SocialSignIn, ConnectorTargets, CustomContent, CustomUiAssets, CustomUiCsp, PartialPasswordPolicy, Mfa, AdaptiveMfa, CaptchaPolicy, SentinelPolicy, EmailBlocklistPolicy, ForgotPasswordMethods, PasskeySignIn, SignUpProfileFields, GeneratedSchema } from './../foundations/index.js';
1
+ import { Color, Branding, LanguageInfo, SignIn, SignUp, SocialSignIn, ConnectorTargets, CustomContent, CustomUiAssets, CustomUiCsp, PartialPasswordPolicy, Mfa, AdaptiveMfa, CaptchaPolicy, SentinelPolicy, EmailBlocklistPolicy, VerificationCodePolicy, ForgotPasswordMethods, PasskeySignIn, SignUpProfileFields, PasswordExpirationPolicy, UsernamePolicy, GeneratedSchema } from './../foundations/index.js';
2
2
  import { AgreeToTermsPolicy, SignInMode } from './custom-types.js';
3
3
  /**
4
4
  *
@@ -35,10 +35,13 @@ export type CreateSignInExperience = {
35
35
  captchaPolicy?: CaptchaPolicy;
36
36
  sentinelPolicy?: SentinelPolicy;
37
37
  emailBlocklistPolicy?: EmailBlocklistPolicy;
38
+ verificationCodePolicy?: VerificationCodePolicy;
38
39
  forgotPasswordMethods?: ForgotPasswordMethods | null;
39
40
  passkeySignIn?: PasskeySignIn;
40
- /** Nullable by design: null keeps legacy full-catalog behavior and [] collects no custom profile fields. */
41
+ /** Nullable by design: null keeps legacy full-catalog behavior, and new rows default to [] to collect no custom profile fields. */
41
42
  signUpProfileFields?: SignUpProfileFields | null;
43
+ passwordExpiration?: PasswordExpirationPolicy;
44
+ usernamePolicy?: UsernamePolicy;
42
45
  };
43
46
  export type SignInExperience = {
44
47
  tenantId: string;
@@ -70,10 +73,13 @@ export type SignInExperience = {
70
73
  captchaPolicy: CaptchaPolicy;
71
74
  sentinelPolicy: SentinelPolicy;
72
75
  emailBlocklistPolicy: EmailBlocklistPolicy;
76
+ verificationCodePolicy: VerificationCodePolicy;
73
77
  forgotPasswordMethods: ForgotPasswordMethods | null;
74
78
  passkeySignIn: PasskeySignIn;
75
- /** Nullable by design: null keeps legacy full-catalog behavior and [] collects no custom profile fields. */
79
+ /** Nullable by design: null keeps legacy full-catalog behavior, and new rows default to [] to collect no custom profile fields. */
76
80
  signUpProfileFields: SignUpProfileFields | null;
81
+ passwordExpiration: PasswordExpirationPolicy;
82
+ usernamePolicy: UsernamePolicy;
77
83
  };
78
- export type SignInExperienceKeys = 'tenantId' | 'id' | 'color' | 'branding' | 'hideLogtoBranding' | 'languageInfo' | 'termsOfUseUrl' | 'privacyPolicyUrl' | 'agreeToTermsPolicy' | 'signIn' | 'signUp' | 'socialSignIn' | 'socialSignInConnectorTargets' | 'signInMode' | 'customCss' | 'customContent' | 'customUiAssets' | 'customUiCsp' | 'passwordPolicy' | 'mfa' | 'adaptiveMfa' | 'singleSignOnEnabled' | 'supportEmail' | 'supportWebsiteUrl' | 'unknownSessionRedirectUrl' | 'captchaPolicy' | 'sentinelPolicy' | 'emailBlocklistPolicy' | 'forgotPasswordMethods' | 'passkeySignIn' | 'signUpProfileFields';
84
+ export type SignInExperienceKeys = 'tenantId' | 'id' | 'color' | 'branding' | 'hideLogtoBranding' | 'languageInfo' | 'termsOfUseUrl' | 'privacyPolicyUrl' | 'agreeToTermsPolicy' | 'signIn' | 'signUp' | 'socialSignIn' | 'socialSignInConnectorTargets' | 'signInMode' | 'customCss' | 'customContent' | 'customUiAssets' | 'customUiCsp' | 'passwordPolicy' | 'mfa' | 'adaptiveMfa' | 'singleSignOnEnabled' | 'supportEmail' | 'supportWebsiteUrl' | 'unknownSessionRedirectUrl' | 'captchaPolicy' | 'sentinelPolicy' | 'emailBlocklistPolicy' | 'verificationCodePolicy' | 'forgotPasswordMethods' | 'passkeySignIn' | 'signUpProfileFields' | 'passwordExpiration' | 'usernamePolicy';
79
85
  export declare const SignInExperiences: GeneratedSchema<SignInExperienceKeys, CreateSignInExperience, SignInExperience, 'sign_in_experiences', 'sign_in_experience'>;
@@ -1,6 +1,6 @@
1
1
  // THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2
2
  import { z } from 'zod';
3
- import { colorGuard, brandingGuard, languageInfoGuard, signInGuard, signUpGuard, socialSignInGuard, connectorTargetsGuard, customContentGuard, customUiAssetsGuard, customUiCspGuard, partialPasswordPolicyGuard, mfaGuard, adaptiveMfaGuard, captchaPolicyGuard, sentinelPolicyGuard, emailBlocklistPolicyGuard, forgotPasswordMethodsGuard, passkeySignInGuard, signUpProfileFieldsGuard } from './../foundations/index.js';
3
+ import { colorGuard, brandingGuard, languageInfoGuard, signInGuard, signUpGuard, socialSignInGuard, connectorTargetsGuard, customContentGuard, customUiAssetsGuard, customUiCspGuard, partialPasswordPolicyGuard, mfaGuard, adaptiveMfaGuard, captchaPolicyGuard, sentinelPolicyGuard, emailBlocklistPolicyGuard, verificationCodePolicyGuard, forgotPasswordMethodsGuard, passkeySignInGuard, signUpProfileFieldsGuard, passwordExpirationPolicyGuard, usernamePolicyGuard } from './../foundations/index.js';
4
4
  import { AgreeToTermsPolicy, SignInMode } from './custom-types.js';
5
5
  const createGuard = z.object({
6
6
  tenantId: z.string().max(21).optional(),
@@ -31,9 +31,12 @@ const createGuard = z.object({
31
31
  captchaPolicy: captchaPolicyGuard.optional(),
32
32
  sentinelPolicy: sentinelPolicyGuard.optional(),
33
33
  emailBlocklistPolicy: emailBlocklistPolicyGuard.optional(),
34
+ verificationCodePolicy: verificationCodePolicyGuard.optional(),
34
35
  forgotPasswordMethods: forgotPasswordMethodsGuard.nullable().optional(),
35
36
  passkeySignIn: passkeySignInGuard.optional(),
36
37
  signUpProfileFields: signUpProfileFieldsGuard.nullable().optional(),
38
+ passwordExpiration: passwordExpirationPolicyGuard.optional(),
39
+ usernamePolicy: usernamePolicyGuard.optional(),
37
40
  });
38
41
  const guard = z.object({
39
42
  tenantId: z.string().max(21),
@@ -64,9 +67,12 @@ const guard = z.object({
64
67
  captchaPolicy: captchaPolicyGuard,
65
68
  sentinelPolicy: sentinelPolicyGuard,
66
69
  emailBlocklistPolicy: emailBlocklistPolicyGuard,
70
+ verificationCodePolicy: verificationCodePolicyGuard,
67
71
  forgotPasswordMethods: forgotPasswordMethodsGuard.nullable(),
68
72
  passkeySignIn: passkeySignInGuard,
69
73
  signUpProfileFields: signUpProfileFieldsGuard.nullable(),
74
+ passwordExpiration: passwordExpirationPolicyGuard,
75
+ usernamePolicy: usernamePolicyGuard,
70
76
  });
71
77
  export const SignInExperiences = Object.freeze({
72
78
  table: 'sign_in_experiences',
@@ -100,9 +106,12 @@ export const SignInExperiences = Object.freeze({
100
106
  captchaPolicy: 'captcha_policy',
101
107
  sentinelPolicy: 'sentinel_policy',
102
108
  emailBlocklistPolicy: 'email_blocklist_policy',
109
+ verificationCodePolicy: 'verification_code_policy',
103
110
  forgotPasswordMethods: 'forgot_password_methods',
104
111
  passkeySignIn: 'passkey_sign_in',
105
112
  signUpProfileFields: 'sign_up_profile_fields',
113
+ passwordExpiration: 'password_expiration',
114
+ usernamePolicy: 'username_policy',
106
115
  },
107
116
  fieldKeys: [
108
117
  'tenantId',
@@ -133,9 +142,12 @@ export const SignInExperiences = Object.freeze({
133
142
  'captchaPolicy',
134
143
  'sentinelPolicy',
135
144
  'emailBlocklistPolicy',
145
+ 'verificationCodePolicy',
136
146
  'forgotPasswordMethods',
137
147
  'passkeySignIn',
138
148
  'signUpProfileFields',
149
+ 'passwordExpiration',
150
+ 'usernamePolicy',
139
151
  ],
140
152
  createGuard,
141
153
  guard,
@@ -24,7 +24,9 @@ export type CreateUser = {
24
24
  logtoConfig?: JsonObject;
25
25
  mfaVerifications?: MfaVerifications;
26
26
  isSuspended?: boolean;
27
+ isPasswordExpired?: boolean;
27
28
  lastSignInAt?: number | null;
29
+ passwordUpdatedAt?: number | null;
28
30
  createdAt?: number;
29
31
  updatedAt?: number;
30
32
  };
@@ -47,9 +49,11 @@ export type User = {
47
49
  logtoConfig: JsonObject;
48
50
  mfaVerifications: MfaVerifications;
49
51
  isSuspended: boolean;
52
+ isPasswordExpired: boolean;
50
53
  lastSignInAt: number | null;
54
+ passwordUpdatedAt: number | null;
51
55
  createdAt: number;
52
56
  updatedAt: number;
53
57
  };
54
- export type UserKeys = 'tenantId' | 'id' | 'username' | 'primaryEmail' | 'primaryPhone' | 'passwordEncrypted' | 'passwordEncryptionMethod' | 'name' | 'avatar' | 'profile' | 'applicationId' | 'identities' | 'customData' | 'logtoConfig' | 'mfaVerifications' | 'isSuspended' | 'lastSignInAt' | 'createdAt' | 'updatedAt';
58
+ export type UserKeys = 'tenantId' | 'id' | 'username' | 'primaryEmail' | 'primaryPhone' | 'passwordEncrypted' | 'passwordEncryptionMethod' | 'name' | 'avatar' | 'profile' | 'applicationId' | 'identities' | 'customData' | 'logtoConfig' | 'mfaVerifications' | 'isSuspended' | 'isPasswordExpired' | 'lastSignInAt' | 'passwordUpdatedAt' | 'createdAt' | 'updatedAt';
55
59
  export declare const Users: GeneratedSchema<UserKeys, CreateUser, User, 'users', 'user'>;
@@ -19,7 +19,9 @@ const createGuard = z.object({
19
19
  logtoConfig: jsonObjectGuard.optional(),
20
20
  mfaVerifications: mfaVerificationsGuard.optional(),
21
21
  isSuspended: z.boolean().optional(),
22
+ isPasswordExpired: z.boolean().optional(),
22
23
  lastSignInAt: z.number().nullable().optional(),
24
+ passwordUpdatedAt: z.number().nullable().optional(),
23
25
  createdAt: z.number().optional(),
24
26
  updatedAt: z.number().optional(),
25
27
  });
@@ -40,7 +42,9 @@ const guard = z.object({
40
42
  logtoConfig: jsonObjectGuard,
41
43
  mfaVerifications: mfaVerificationsGuard,
42
44
  isSuspended: z.boolean(),
45
+ isPasswordExpired: z.boolean(),
43
46
  lastSignInAt: z.number().nullable(),
47
+ passwordUpdatedAt: z.number().nullable(),
44
48
  createdAt: z.number(),
45
49
  updatedAt: z.number(),
46
50
  });
@@ -64,7 +68,9 @@ export const Users = Object.freeze({
64
68
  logtoConfig: 'logto_config',
65
69
  mfaVerifications: 'mfa_verifications',
66
70
  isSuspended: 'is_suspended',
71
+ isPasswordExpired: 'is_password_expired',
67
72
  lastSignInAt: 'last_sign_in_at',
73
+ passwordUpdatedAt: 'password_updated_at',
68
74
  createdAt: 'created_at',
69
75
  updatedAt: 'updated_at',
70
76
  },
@@ -85,7 +91,9 @@ export const Users = Object.freeze({
85
91
  'logtoConfig',
86
92
  'mfaVerifications',
87
93
  'isSuspended',
94
+ 'isPasswordExpired',
88
95
  'lastSignInAt',
96
+ 'passwordUpdatedAt',
89
97
  'createdAt',
90
98
  'updatedAt',
91
99
  ],
@@ -20,6 +20,7 @@ export declare const accountCenterFieldControlGuard: z.ZodObject<{
20
20
  social: z.ZodOptional<z.ZodNativeEnum<typeof AccountCenterControlValue>>;
21
21
  customData: z.ZodOptional<z.ZodNativeEnum<typeof AccountCenterControlValue>>;
22
22
  mfa: z.ZodOptional<z.ZodNativeEnum<typeof AccountCenterControlValue>>;
23
+ passkey: z.ZodOptional<z.ZodNativeEnum<typeof AccountCenterControlValue>>;
23
24
  session: z.ZodOptional<z.ZodNativeEnum<typeof AccountCenterControlValue>>;
24
25
  }, "strip", z.ZodTypeAny, {
25
26
  name?: AccountCenterControlValue | undefined;
@@ -32,6 +33,7 @@ export declare const accountCenterFieldControlGuard: z.ZodObject<{
32
33
  social?: AccountCenterControlValue | undefined;
33
34
  customData?: AccountCenterControlValue | undefined;
34
35
  mfa?: AccountCenterControlValue | undefined;
36
+ passkey?: AccountCenterControlValue | undefined;
35
37
  session?: AccountCenterControlValue | undefined;
36
38
  }, {
37
39
  name?: AccountCenterControlValue | undefined;
@@ -44,6 +46,7 @@ export declare const accountCenterFieldControlGuard: z.ZodObject<{
44
46
  social?: AccountCenterControlValue | undefined;
45
47
  customData?: AccountCenterControlValue | undefined;
46
48
  mfa?: AccountCenterControlValue | undefined;
49
+ passkey?: AccountCenterControlValue | undefined;
47
50
  session?: AccountCenterControlValue | undefined;
48
51
  }>;
49
52
  export type AccountCenterFieldControl = z.infer<typeof accountCenterFieldControlGuard>;
@@ -22,6 +22,7 @@ export const accountCenterFieldControlGuard = z
22
22
  social: z.nativeEnum(AccountCenterControlValue),
23
23
  customData: z.nativeEnum(AccountCenterControlValue),
24
24
  mfa: z.nativeEnum(AccountCenterControlValue),
25
+ passkey: z.nativeEnum(AccountCenterControlValue),
25
26
  session: z.nativeEnum(AccountCenterControlValue),
26
27
  })
27
28
  .partial();
@@ -30,14 +30,14 @@ declare enum DataHookDetailMutationType {
30
30
  type BasicDataHookEvent = `${DataHookSchema}.${DataHookBasicMutationType}`;
31
31
  type CustomDataHookMutableSchema = `${DataHookSchema}.Data` | `${DataHookSchema.User}.SuspensionStatus` | `${DataHookSchema.Role}.Scopes` | `${DataHookSchema.Organization}.Membership` | `${DataHookSchema.OrganizationRole}.Scopes`;
32
32
  type DataHookPropertyUpdateEvent = `${CustomDataHookMutableSchema}.${DataHookDetailMutationType.Updated}`;
33
- export type ExceptionHookEvent = 'Identifier.Lockout';
33
+ export type ExceptionHookEvent = 'Identifier.Lockout' | 'Message.RateLimited';
34
34
  export type DataHookEvent = BasicDataHookEvent | DataHookPropertyUpdateEvent;
35
35
  /** The hook event values that can be registered. */
36
- export declare const hookEvents: readonly [InteractionHookEvent.PostRegister, InteractionHookEvent.PostSignIn, InteractionHookEvent.PostSignInAdaptiveMfaTriggered, InteractionHookEvent.PostResetPassword, "User.Created", "User.Deleted", "User.Data.Updated", "User.SuspensionStatus.Updated", "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"];
36
+ export declare const hookEvents: readonly [InteractionHookEvent.PostRegister, InteractionHookEvent.PostSignIn, InteractionHookEvent.PostSignInAdaptiveMfaTriggered, InteractionHookEvent.PostResetPassword, "User.Created", "User.Deleted", "User.Data.Updated", "User.SuspensionStatus.Updated", "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"];
37
37
  /** The type of hook event values that can be registered. */
38
38
  export type HookEvent = (typeof hookEvents)[number];
39
- export declare const hookEventGuard: z.ZodEnum<[InteractionHookEvent.PostRegister, InteractionHookEvent.PostSignIn, InteractionHookEvent.PostSignInAdaptiveMfaTriggered, InteractionHookEvent.PostResetPassword, "User.Created", "User.Deleted", "User.Data.Updated", "User.SuspensionStatus.Updated", "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"]>;
40
- export declare const hookEventsGuard: z.ZodArray<z.ZodEnum<[InteractionHookEvent.PostRegister, InteractionHookEvent.PostSignIn, InteractionHookEvent.PostSignInAdaptiveMfaTriggered, InteractionHookEvent.PostResetPassword, "User.Created", "User.Deleted", "User.Data.Updated", "User.SuspensionStatus.Updated", "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"]>, "many">;
39
+ export declare const hookEventGuard: z.ZodEnum<[InteractionHookEvent.PostRegister, InteractionHookEvent.PostSignIn, InteractionHookEvent.PostSignInAdaptiveMfaTriggered, InteractionHookEvent.PostResetPassword, "User.Created", "User.Deleted", "User.Data.Updated", "User.SuspensionStatus.Updated", "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"]>;
40
+ export declare const hookEventsGuard: z.ZodArray<z.ZodEnum<[InteractionHookEvent.PostRegister, InteractionHookEvent.PostSignIn, InteractionHookEvent.PostSignInAdaptiveMfaTriggered, InteractionHookEvent.PostResetPassword, "User.Created", "User.Deleted", "User.Data.Updated", "User.SuspensionStatus.Updated", "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"]>, "many">;
41
41
  export type HookEvents = z.infer<typeof hookEventsGuard>;
42
42
  export declare const interactionHookEventGuard: z.ZodNativeEnum<typeof InteractionHookEvent>;
43
43
  /**
@@ -62,6 +62,7 @@ export const hookEvents = Object.freeze([
62
62
  'OrganizationScope.Deleted',
63
63
  'OrganizationScope.Data.Updated',
64
64
  'Identifier.Lockout',
65
+ 'Message.RateLimited',
65
66
  ]);
66
67
  export const hookEventGuard = z.enum(hookEvents);
67
68
  export const hookEventsGuard = hookEventGuard.array();
@@ -39,7 +39,22 @@ export declare enum SentinelActivityAction {
39
39
  /**
40
40
  * The subject tries to pass a backup code MFA verification.
41
41
  */
42
- MfaBackupCode = "MfaBackupCode"
42
+ MfaBackupCode = "MfaBackupCode",
43
+ /**
44
+ * A verification code is sent to the target (email/phone), e.g. sign-in,
45
+ * register, forgot-password, or identifier-binding codes.
46
+ *
47
+ * Used by the message rate limit to throttle sends, distinct from the
48
+ * failure-based lockout actions above.
49
+ */
50
+ VerificationCodeSend = "VerificationCodeSend",
51
+ /**
52
+ * A non-verification-code message is sent to the target (email/phone),
53
+ * e.g. an organization invitation.
54
+ *
55
+ * Used by the message rate limit to throttle sends.
56
+ */
57
+ MessageSend = "MessageSend"
43
58
  }
44
59
  export declare const sentinelActivityActionGuard: z.ZodNativeEnum<typeof SentinelActivityAction>;
45
60
  export type SentinelActivityPayload = Record<string, unknown>;
@@ -42,6 +42,21 @@ export var SentinelActivityAction;
42
42
  * The subject tries to pass a backup code MFA verification.
43
43
  */
44
44
  SentinelActivityAction["MfaBackupCode"] = "MfaBackupCode";
45
+ /**
46
+ * A verification code is sent to the target (email/phone), e.g. sign-in,
47
+ * register, forgot-password, or identifier-binding codes.
48
+ *
49
+ * Used by the message rate limit to throttle sends, distinct from the
50
+ * failure-based lockout actions above.
51
+ */
52
+ SentinelActivityAction["VerificationCodeSend"] = "VerificationCodeSend";
53
+ /**
54
+ * A non-verification-code message is sent to the target (email/phone),
55
+ * e.g. an organization invitation.
56
+ *
57
+ * Used by the message rate limit to throttle sends.
58
+ */
59
+ SentinelActivityAction["MessageSend"] = "MessageSend";
45
60
  })(SentinelActivityAction || (SentinelActivityAction = {}));
46
61
  export const sentinelActivityActionGuard = z.nativeEnum(SentinelActivityAction);
47
62
  export const sentinelActivityPayloadGuard = z.record(z.unknown());
@@ -193,6 +193,7 @@ export declare const signInGuard: z.ZodObject<{
193
193
  }[];
194
194
  }>;
195
195
  export type SignIn = z.infer<typeof signInGuard>;
196
+ export { defaultUsernamePolicy, usernamePolicyGuard, type UsernamePolicy } from '@logto/core-kit';
196
197
  export type SocialSignIn = {
197
198
  /**
198
199
  * If account linking should be performed when a user signs in with a social identity that is new
@@ -359,11 +360,33 @@ export declare const sentinelPolicyGuard: z.ZodObject<{
359
360
  lockoutDuration?: number | undefined;
360
361
  }>;
361
362
  /**
362
- * Email blocklist policy.
363
+ * Verification code policy.
363
364
  *
364
365
  * @remarks
365
- * This policy is used to block specific email addresses or domains from signing up.
366
+ * This policy controls the expiration duration and maximum retry attempts for verification codes.
366
367
  */
368
+ export type VerificationCodePolicy = {
369
+ /**
370
+ * The duration in seconds that a verification code remains valid.
371
+ * @default 600 (10 minutes)
372
+ */
373
+ expirationDuration?: number;
374
+ /**
375
+ * Maximum number of failed verification attempts allowed before the code is invalidated.
376
+ * @default 10
377
+ */
378
+ maxRetryAttempts?: number;
379
+ };
380
+ export declare const verificationCodePolicyGuard: z.ZodObject<{
381
+ expirationDuration: z.ZodOptional<z.ZodNumber>;
382
+ maxRetryAttempts: z.ZodOptional<z.ZodNumber>;
383
+ }, "strip", z.ZodTypeAny, {
384
+ expirationDuration?: number | undefined;
385
+ maxRetryAttempts?: number | undefined;
386
+ }, {
387
+ expirationDuration?: number | undefined;
388
+ maxRetryAttempts?: number | undefined;
389
+ }>;
367
390
  export type EmailBlocklistPolicy = {
368
391
  blockDisposableAddresses?: boolean;
369
392
  blockSubaddressing?: boolean;
@@ -441,4 +464,53 @@ export declare const signUpProfileFieldsGuard: z.ZodArray<z.ZodObject<{
441
464
  name: string;
442
465
  }>, "many">;
443
466
  export type SignUpProfileFields = z.infer<typeof signUpProfileFieldsGuard>;
467
+ /**
468
+ * Password lifecycle policy for configuring password expiration and rotation.
469
+ *
470
+ * @remarks
471
+ * This policy is evaluated server-side during sign-in (after local password verification) to determine
472
+ * whether the user's password has expired.
473
+ *
474
+ * If the password age >= `validPeriodDays`, the sign-in is blocked and the user must reset their
475
+ * password before continuing.
476
+ */
477
+ export type PasswordExpirationPolicy = {
478
+ /**
479
+ * Whether the password expiration policy is enabled.
480
+ * @default false
481
+ */
482
+ enabled?: false;
483
+ } | {
484
+ enabled: true;
485
+ /**
486
+ * Number of days a password is valid before it expires and the user is
487
+ * forced to reset it on sign-in.
488
+ */
489
+ validPeriodDays: number;
490
+ /**
491
+ * Epoch milliseconds when the policy was enabled. Used as the expiry anchor for users
492
+ * that have no `passwordUpdatedAt` (e.g. legacy accounts), so enabling the policy grants
493
+ * them a full valid period instead of expiring them against their account creation date.
494
+ */
495
+ enabledAt?: number;
496
+ };
497
+ export declare const passwordExpirationPolicyGuard: z.ZodUnion<[z.ZodObject<{
498
+ enabled: z.ZodOptional<z.ZodLiteral<false>>;
499
+ }, "strip", z.ZodTypeAny, {
500
+ enabled?: false | undefined;
501
+ }, {
502
+ enabled?: false | undefined;
503
+ }>, z.ZodObject<{
504
+ enabled: z.ZodLiteral<true>;
505
+ validPeriodDays: z.ZodNumber;
506
+ enabledAt: z.ZodOptional<z.ZodNumber>;
507
+ }, "strip", z.ZodTypeAny, {
508
+ enabled: true;
509
+ validPeriodDays: number;
510
+ enabledAt?: number | undefined;
511
+ }, {
512
+ enabled: true;
513
+ validPeriodDays: number;
514
+ enabledAt?: number | undefined;
515
+ }>]>;
444
516
  export { customUiCspGuard, type CustomUiCsp } from '@logto/core-kit';
@@ -62,6 +62,9 @@ export const signInGuard = z.object({
62
62
  })
63
63
  .array(),
64
64
  });
65
+ // The username policy is owned by @logto/core-kit (like passwordPolicyGuard) so core, experience,
66
+ // and console share one source of truth; re-exported here for the `@use UsernamePolicy` column.
67
+ export { defaultUsernamePolicy, usernamePolicyGuard } from '@logto/core-kit';
65
68
  export const socialSignInGuard = z.object({
66
69
  automaticAccountLinking: z.boolean().optional(),
67
70
  skipRequiredIdentifiers: z.boolean().optional(),
@@ -120,6 +123,10 @@ export const sentinelPolicyGuard = z.object({
120
123
  maxAttempts: z.number().optional(),
121
124
  lockoutDuration: z.number().optional(),
122
125
  });
126
+ export const verificationCodePolicyGuard = z.object({
127
+ expirationDuration: z.number().int().min(60).max(3600).optional(),
128
+ maxRetryAttempts: z.number().int().min(1).max(100).optional(),
129
+ });
123
130
  export const emailBlocklistPolicyGuard = z.object({
124
131
  blockDisposableAddresses: z.boolean().optional(),
125
132
  blockSubaddressing: z.boolean().optional(),
@@ -142,4 +149,16 @@ export const signUpProfileFieldItemGuard = z.object({
142
149
  name: z.string(),
143
150
  });
144
151
  export const signUpProfileFieldsGuard = z.array(signUpProfileFieldItemGuard);
152
+ // Intentionally not `.strict()` for backward compatibility: legacy rows may carry removed fields
153
+ // (e.g. `reminderPeriodDays`), which are stripped on parse instead of rejected.
154
+ export const passwordExpirationPolicyGuard = z.union([
155
+ z.object({
156
+ enabled: z.literal(false).optional(),
157
+ }),
158
+ z.object({
159
+ enabled: z.literal(true),
160
+ validPeriodDays: z.number().int().min(1),
161
+ enabledAt: z.number().int().nonnegative().optional(),
162
+ }),
163
+ ]);
145
164
  export { customUiCspGuard } from '@logto/core-kit';
@@ -1,5 +1,5 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { customUiCspGuard } from './sign-in-experience.js';
2
+ import { customUiCspGuard, passwordExpirationPolicyGuard } from './sign-in-experience.js';
3
3
  describe('customUiCspGuard', () => {
4
4
  it.each([
5
5
  {},
@@ -16,3 +16,51 @@ describe('customUiCspGuard', () => {
16
16
  expect(customUiCspGuard.safeParse({ imgSrc: ['https://example.com'] }).success).toBe(false);
17
17
  });
18
18
  });
19
+ describe('passwordExpirationPolicyGuard', () => {
20
+ it.each([
21
+ [{}, {}],
22
+ [{ enabled: false }, { enabled: false }],
23
+ ])('accepts disabled policy %p', (value, expected) => {
24
+ expect(passwordExpirationPolicyGuard.parse(value)).toEqual(expected);
25
+ });
26
+ it('accepts enabled policy with a valid period', () => {
27
+ expect(passwordExpirationPolicyGuard.parse({
28
+ enabled: true,
29
+ validPeriodDays: 30,
30
+ })).toEqual({
31
+ enabled: true,
32
+ validPeriodDays: 30,
33
+ });
34
+ });
35
+ it('accepts enabled policy with an enabledAt timestamp', () => {
36
+ expect(passwordExpirationPolicyGuard.parse({
37
+ enabled: true,
38
+ validPeriodDays: 30,
39
+ enabledAt: 1_700_000_000_000,
40
+ })).toEqual({
41
+ enabled: true,
42
+ validPeriodDays: 30,
43
+ enabledAt: 1_700_000_000_000,
44
+ });
45
+ });
46
+ it('strips unknown keys from legacy rows (e.g. the removed reminderPeriodDays)', () => {
47
+ expect(passwordExpirationPolicyGuard.parse({
48
+ enabled: true,
49
+ validPeriodDays: 30,
50
+ reminderPeriodDays: 5,
51
+ })).toEqual({
52
+ enabled: true,
53
+ validPeriodDays: 30,
54
+ });
55
+ });
56
+ it.each([
57
+ { enabled: true },
58
+ { enabled: true, validPeriodDays: 0 },
59
+ { enabled: true, validPeriodDays: 1.5 },
60
+ { enabled: true, reminderPeriodDays: 5 },
61
+ { enabled: true, validPeriodDays: 30, enabledAt: -1 },
62
+ { enabled: true, validPeriodDays: 30, enabledAt: 1.5 },
63
+ ])('rejects invalid policy %p', (value) => {
64
+ expect(passwordExpirationPolicyGuard.safeParse(value).success).toBe(false);
65
+ });
66
+ });
@@ -150,6 +150,7 @@ export declare const baseMfaVerification: {
150
150
  };
151
151
  export declare const mfaVerificationTotp: z.ZodObject<{
152
152
  key: z.ZodString;
153
+ lastUsedTimeStep: z.ZodOptional<z.ZodNumber>;
153
154
  id: z.ZodString;
154
155
  createdAt: z.ZodString;
155
156
  lastUsedAt: z.ZodOptional<z.ZodString>;
@@ -159,12 +160,14 @@ export declare const mfaVerificationTotp: z.ZodObject<{
159
160
  id: string;
160
161
  key: string;
161
162
  createdAt: string;
163
+ lastUsedTimeStep?: number | undefined;
162
164
  lastUsedAt?: string | undefined;
163
165
  }, {
164
166
  type: MfaFactor.TOTP;
165
167
  id: string;
166
168
  key: string;
167
169
  createdAt: string;
170
+ lastUsedTimeStep?: number | undefined;
168
171
  lastUsedAt?: string | undefined;
169
172
  }>;
170
173
  export type MfaVerificationTotp = z.infer<typeof mfaVerificationTotp>;
@@ -244,6 +247,7 @@ export declare const mfaVerificationBackupCode: z.ZodObject<{
244
247
  export type MfaVerificationBackupCode = z.infer<typeof mfaVerificationBackupCode>;
245
248
  export declare const mfaVerificationGuard: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
246
249
  key: z.ZodString;
250
+ lastUsedTimeStep: z.ZodOptional<z.ZodNumber>;
247
251
  id: z.ZodString;
248
252
  createdAt: z.ZodString;
249
253
  lastUsedAt: z.ZodOptional<z.ZodString>;
@@ -253,12 +257,14 @@ export declare const mfaVerificationGuard: z.ZodDiscriminatedUnion<"type", [z.Zo
253
257
  id: string;
254
258
  key: string;
255
259
  createdAt: string;
260
+ lastUsedTimeStep?: number | undefined;
256
261
  lastUsedAt?: string | undefined;
257
262
  }, {
258
263
  type: MfaFactor.TOTP;
259
264
  id: string;
260
265
  key: string;
261
266
  createdAt: string;
267
+ lastUsedTimeStep?: number | undefined;
262
268
  lastUsedAt?: string | undefined;
263
269
  }>, z.ZodObject<{
264
270
  rpId: z.ZodOptional<z.ZodString>;
@@ -333,6 +339,7 @@ export declare const mfaVerificationGuard: z.ZodDiscriminatedUnion<"type", [z.Zo
333
339
  export type MfaVerification = z.infer<typeof mfaVerificationGuard>;
334
340
  export declare const mfaVerificationsGuard: z.ZodArray<z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
335
341
  key: z.ZodString;
342
+ lastUsedTimeStep: z.ZodOptional<z.ZodNumber>;
336
343
  id: z.ZodString;
337
344
  createdAt: z.ZodString;
338
345
  lastUsedAt: z.ZodOptional<z.ZodString>;
@@ -342,12 +349,14 @@ export declare const mfaVerificationsGuard: z.ZodArray<z.ZodDiscriminatedUnion<"
342
349
  id: string;
343
350
  key: string;
344
351
  createdAt: string;
352
+ lastUsedTimeStep?: number | undefined;
345
353
  lastUsedAt?: string | undefined;
346
354
  }, {
347
355
  type: MfaFactor.TOTP;
348
356
  id: string;
349
357
  key: string;
350
358
  createdAt: string;
359
+ lastUsedTimeStep?: number | undefined;
351
360
  lastUsedAt?: string | undefined;
352
361
  }>, z.ZodObject<{
353
362
  rpId: z.ZodOptional<z.ZodString>;
@@ -40,6 +40,7 @@ export const mfaVerificationTotp = z.object({
40
40
  type: z.literal(MfaFactor.TOTP),
41
41
  ...baseMfaVerification,
42
42
  key: z.string(),
43
+ lastUsedTimeStep: z.number().int().nonnegative().optional(),
43
44
  });
44
45
  export const webAuthnTransportGuard = z.enum([
45
46
  'usb',
@@ -27,4 +27,5 @@ export const createAdminTenantAccountCenter = () => Object.freeze({
27
27
  customData: AccountCenterControlValue.Edit,
28
28
  mfa: AccountCenterControlValue.Edit,
29
29
  },
30
+ profileFields: [{ name: 'name' }, { name: 'avatar' }],
30
31
  });
@@ -42,6 +42,7 @@ export const createDefaultSignInExperience = (forTenantId, isCloud) => Object.fr
42
42
  customCss: null,
43
43
  customContent: {},
44
44
  customUiAssets: null,
45
+ signUpProfileFields: null,
45
46
  passwordPolicy: {},
46
47
  mfa: {
47
48
  factors: [],
@@ -19,9 +19,13 @@ describe('createAdminTenantSignInExperience', () => {
19
19
  expect(row.tenantId).toBe(adminTenantId);
20
20
  });
21
21
  });
22
- describe('createDefaultSignInExperience (unchanged contract)', () => {
22
+ describe('createDefaultSignInExperience', () => {
23
23
  it('still has a two-parameter signature and seeds an empty passwordPolicy', () => {
24
24
  const row = createDefaultSignInExperience('some-tenant-id', false);
25
25
  expect(row.passwordPolicy).toEqual({});
26
26
  });
27
+ it('keeps legacy null signUpProfileFields for seeded default tenants', () => {
28
+ const row = createDefaultSignInExperience('some-tenant-id', false);
29
+ expect(row.signUpProfileFields).toBeNull();
30
+ });
27
31
  });
@@ -68,6 +68,7 @@ export declare const publicUserInfoGuard: z.ZodObject<Pick<{
68
68
  id: string;
69
69
  key: string;
70
70
  createdAt: string;
71
+ lastUsedTimeStep?: number | undefined;
71
72
  lastUsedAt?: string | undefined;
72
73
  } | {
73
74
  type: import("../index.js").MfaFactor.WebAuthn;
@@ -95,6 +96,7 @@ export declare const publicUserInfoGuard: z.ZodObject<Pick<{
95
96
  id: string;
96
97
  key: string;
97
98
  createdAt: string;
99
+ lastUsedTimeStep?: number | undefined;
98
100
  lastUsedAt?: string | undefined;
99
101
  } | {
100
102
  type: import("../index.js").MfaFactor.WebAuthn;
@@ -119,7 +121,9 @@ export declare const publicUserInfoGuard: z.ZodObject<Pick<{
119
121
  lastUsedAt?: string | undefined;
120
122
  })[]>;
121
123
  isSuspended: z.ZodType<boolean, z.ZodTypeDef, boolean>;
124
+ isPasswordExpired: z.ZodType<boolean, z.ZodTypeDef, boolean>;
122
125
  lastSignInAt: z.ZodType<number | null, z.ZodTypeDef, number | null>;
126
+ passwordUpdatedAt: z.ZodType<number | null, z.ZodTypeDef, number | null>;
123
127
  createdAt: z.ZodType<number, z.ZodTypeDef, number>;
124
128
  updatedAt: z.ZodType<number, z.ZodTypeDef, number>;
125
129
  }, "name" | "id" | "username" | "avatar" | "primaryEmail" | "primaryPhone">, "strip", z.ZodTypeAny, {
@@ -667,6 +671,7 @@ export declare const consentInfoResponseGuard: z.ZodObject<{
667
671
  id: string;
668
672
  key: string;
669
673
  createdAt: string;
674
+ lastUsedTimeStep?: number | undefined;
670
675
  lastUsedAt?: string | undefined;
671
676
  } | {
672
677
  type: import("../index.js").MfaFactor.WebAuthn;
@@ -694,6 +699,7 @@ export declare const consentInfoResponseGuard: z.ZodObject<{
694
699
  id: string;
695
700
  key: string;
696
701
  createdAt: string;
702
+ lastUsedTimeStep?: number | undefined;
697
703
  lastUsedAt?: string | undefined;
698
704
  } | {
699
705
  type: import("../index.js").MfaFactor.WebAuthn;
@@ -718,7 +724,9 @@ export declare const consentInfoResponseGuard: z.ZodObject<{
718
724
  lastUsedAt?: string | undefined;
719
725
  })[]>;
720
726
  isSuspended: z.ZodType<boolean, z.ZodTypeDef, boolean>;
727
+ isPasswordExpired: z.ZodType<boolean, z.ZodTypeDef, boolean>;
721
728
  lastSignInAt: z.ZodType<number | null, z.ZodTypeDef, number | null>;
729
+ passwordUpdatedAt: z.ZodType<number | null, z.ZodTypeDef, number | null>;
722
730
  createdAt: z.ZodType<number, z.ZodTypeDef, number>;
723
731
  updatedAt: z.ZodType<number, z.ZodTypeDef, number>;
724
732
  }, "name" | "id" | "username" | "avatar" | "primaryEmail" | "primaryPhone">, "strip", z.ZodTypeAny, {