From d970327ef70d1b03f8d7502277c4d6c93997ad78 Mon Sep 17 00:00:00 2001 From: Etienne Stalmans Date: Fri, 3 Apr 2026 10:09:04 +0200 Subject: [PATCH] feat: current password enforcement (auth) and docs (#43324) ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Feature and docs. ## What is the new feature? Adds a toggle to enforce current password checks for updating a user's password (auth) ## Summary by CodeRabbit * **New Features** * Added configurable option to require the current password when changing passwords. * Added configurable option to require recent reauthentication before allowing password changes. * **Documentation** * Added "Password security" guide sections documenting current-password verification and reauthentication safeguards, with usage examples. --------- Co-authored-by: Ivan Vasilov Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../content/guides/auth/password-security.mdx | 29 +++++++++++++++++++ .../Auth/AuthProvidersFormValidation.tsx | 7 ++++- .../lib/management-api-schema.d.ts | 2 ++ .../platform-kit-nextjs/lib/schemas/auth.ts | 7 +++++ packages/api-types/types/api.d.ts | 2 ++ packages/api-types/types/platform.d.ts | 2 ++ 6 files changed, 48 insertions(+), 1 deletion(-) diff --git a/apps/docs/content/guides/auth/password-security.mdx b/apps/docs/content/guides/auth/password-security.mdx index 4a9124eaa1f..479ff4955a5 100644 --- a/apps/docs/content/guides/auth/password-security.mdx +++ b/apps/docs/content/guides/auth/password-security.mdx @@ -32,6 +32,35 @@ Leaked password protection is available on the Pro Plan and above. +## Require reauthentication when changing password + +Users will need to be recently logged in to change their password without requiring reauthentication. (A user is considered recently logged in if the session was created within the last 24 hours.) If disabled, a user can change their password at any time. + +When enabled, a `nonce` will be sent to the user and this nonce must be validated before the a password change can occur. This can be triggered with the [reauthenticate()](/docs/reference/javascript/auth-reauthentication) API call. + +``` +const { error } = await supabase.auth.reauthenticate() +... +// send the nonce provided by the user with the password change +const { data, error } = await supabase.auth.updateUser({ + email: 'user@email.com', + nonce: `${nonce}`, + password: "new_super_strong_password" +}) +``` + +## Require current password when changing password + +Enforce that users supply their current password when trying to change the password. When enabled, the password change request will validate that the current password is correct before updating the user's password. + +``` +const { data, error } = await supabase.auth.updateUser({ + email: 'user@email.com', + current_password: "correct_current_password", + password: "new_super_strong_password" +}) +``` + ## Additional recommendations In addition to choosing suitable password strength settings and preventing the use of leaked passwords, consider asking your users to: diff --git a/apps/studio/components/interfaces/Auth/AuthProvidersFormValidation.tsx b/apps/studio/components/interfaces/Auth/AuthProvidersFormValidation.tsx index ab9cb817118..dbcf3888806 100644 --- a/apps/studio/components/interfaces/Auth/AuthProvidersFormValidation.tsx +++ b/apps/studio/components/interfaces/Auth/AuthProvidersFormValidation.tsx @@ -33,6 +33,12 @@ const PROVIDER_EMAIL = { If disabled, a user can change their password at any time.`, type: 'boolean', }, + SECURITY_UPDATE_PASSWORD_REQUIRE_CURRENT_PASSWORD: { + title: 'Require current password when updating', + description: `Requires that the user supplies their current password when changing their password. [Learn more](${DOCS_URL}/guides/auth/password-security#require-current-password-when-changing).`, + type: 'boolean', + isPaid: false, + }, PASSWORD_HIBP_ENABLED: { title: 'Prevent use of leaked passwords', description: `Rejects the use of known or easy to guess passwords on sign up or password change. Powered by the HaveIBeenPwned.org Pwned Passwords API. [Learn more](${DOCS_URL}/guides/auth/password-security#password-strength-and-leaked-password-protection)`, @@ -70,7 +76,6 @@ const PROVIDER_EMAIL = { }, ], }, - MAILER_OTP_EXP: { title: 'Email OTP expiration', type: 'number', diff --git a/apps/ui-library/registry/default/platform/platform-kit-nextjs/lib/management-api-schema.d.ts b/apps/ui-library/registry/default/platform/platform-kit-nextjs/lib/management-api-schema.d.ts index 132c76024ec..9a0bd43f95e 100644 --- a/apps/ui-library/registry/default/platform/platform-kit-nextjs/lib/management-api-schema.d.ts +++ b/apps/ui-library/registry/default/platform/platform-kit-nextjs/lib/management-api-schema.d.ts @@ -2493,6 +2493,7 @@ export interface components { security_manual_linking_enabled: boolean | null security_refresh_token_reuse_interval: number | null security_update_password_require_reauthentication: boolean | null + security_update_password_require_current_password: boolean | null sessions_inactivity_timeout: number | null sessions_single_per_user: boolean | null sessions_tags: string | null @@ -2591,6 +2592,7 @@ export interface components { | null security_manual_linking_enabled?: boolean | null security_update_password_require_reauthentication?: boolean | null + security_update_password_require_current_password?: boolean | null security_refresh_token_reuse_interval?: number | null mailer_otp_exp?: number mailer_otp_length?: number | null diff --git a/apps/ui-library/registry/default/platform/platform-kit-nextjs/lib/schemas/auth.ts b/apps/ui-library/registry/default/platform/platform-kit-nextjs/lib/schemas/auth.ts index 8e18f032fab..a26f18d845d 100644 --- a/apps/ui-library/registry/default/platform/platform-kit-nextjs/lib/schemas/auth.ts +++ b/apps/ui-library/registry/default/platform/platform-kit-nextjs/lib/schemas/auth.ts @@ -14,6 +14,7 @@ export const authFieldLabels: Record< mailer_autoconfirm: 'Confirm Email', mailer_secure_email_change_enabled: 'Secure Email Change', security_update_password_require_reauthentication: 'Secure Password Change', + security_update_password_require_current_password: 'Require Password Change', password_hibp_enabled: 'Prevent Leaked Passwords', password_min_length: 'Minimum Password Length', password_required_characters: { @@ -112,6 +113,12 @@ export const authEmailProviderSchema = z .describe( 'Users will need to be recently logged in to change their password without requiring reauthentication. (A user is considered recently logged in if the session was created within the last 24 hours.) If disabled, a user can change their password at any time.' ), + security_update_password_require_current_password: z + .boolean() + .optional() + .describe( + 'Users will need to provide their current password in order to change their password. Works alongside security_update_password_require_reauthentication and both can be enabled at the same time.' + ), password_hibp_enabled: z .boolean() .optional() diff --git a/packages/api-types/types/api.d.ts b/packages/api-types/types/api.d.ts index 89a5b3916fc..e0199788cd9 100644 --- a/packages/api-types/types/api.d.ts +++ b/packages/api-types/types/api.d.ts @@ -2317,6 +2317,7 @@ export interface components { security_refresh_token_reuse_interval: number | null security_sb_forwarded_for_enabled: boolean | null security_update_password_require_reauthentication: boolean | null + security_update_password_require_current_password: boolean | null sessions_inactivity_timeout: number | null sessions_single_per_user: boolean | null sessions_tags: string | null @@ -4063,6 +4064,7 @@ export interface components { security_refresh_token_reuse_interval?: number | null security_sb_forwarded_for_enabled?: boolean | null security_update_password_require_reauthentication?: boolean | null + security_update_password_require_current_password?: boolean | null sessions_inactivity_timeout?: number | null sessions_single_per_user?: boolean | null sessions_tags?: string | null diff --git a/packages/api-types/types/platform.d.ts b/packages/api-types/types/platform.d.ts index 6a6523ffa37..b63d459aedf 100644 --- a/packages/api-types/types/platform.d.ts +++ b/packages/api-types/types/platform.d.ts @@ -6985,6 +6985,7 @@ export interface components { SECURITY_REFRESH_TOKEN_REUSE_INTERVAL: number SECURITY_SB_FORWARDED_FOR_ENABLED: boolean SECURITY_UPDATE_PASSWORD_REQUIRE_REAUTHENTICATION: boolean + SECURITY_UPDATE_PASSWORD_REQUIRE_CURRENT_PASSWORD: boolean SESSIONS_INACTIVITY_TIMEOUT: number SESSIONS_SINGLE_PER_USER: boolean SESSIONS_TAGS: string @@ -10158,6 +10159,7 @@ export interface components { SECURITY_REFRESH_TOKEN_REUSE_INTERVAL?: number | null SECURITY_SB_FORWARDED_FOR_ENABLED?: boolean | null SECURITY_UPDATE_PASSWORD_REQUIRE_REAUTHENTICATION?: boolean | null + SECURITY_UPDATE_PASSWORD_REQUIRE_CURRENT_PASSWORD?: boolean | null SESSIONS_INACTIVITY_TIMEOUT?: number | null SESSIONS_SINGLE_PER_USER?: boolean | null SESSIONS_TAGS?: string | null