resetPasswordForEmail + MFA: Cannot update password due to AAL2 requirement
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 38/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- go
- Domain
- authentication, security
Research direction
Start by tracing the resetPasswordForEmail() recovery flow through the session used by updateUser({ password }), then inspect how MFA and AAL2 requirements are applied. Confirm whether the reported 401 is intended and identify the appropriate documented flow or clarification for password resets when MFA is enabled.
Written by the indexing model from the issue text.
Description
Bug report
- I confirm this is a bug with Supabase, not with my own application.
- I confirm I have searched the Docs, GitHub Discussions, and Discord.
Describe the bug
When I initiate a password reset using supabase.auth.resetPasswordForEmail(email), the user receives the reset link and is redirected correctly. However, when trying to update the password using supabase.auth.updateUser({ password }), Supabase responds with a 401 Unauthorized error, stating that AAL2 is required.
Context
- The user has MFA enabled (TOTP or SMS).
- The session obtained from the recovery link works (getSession() returns a valid session).
- However, the session is AAL1, and Supabase rejects the password update due to AAL2 not being satisfied.
- Calling setSession() does not resolve the issue.
Expected behavior
When using resetPasswordForEmail(), I would expect that the session obtained from the recovery link allows the user to reset their password — even if MFA is enabled — since the reset link was securely sent via email.
If this is not intended, it would be great to have:
- A workaround or documented flow to support password reset when MFA is enabled.
- Clarification in the docs that resetPasswordForEmail() cannot be used if MFA is active unless the user also completes MFA.
Steps to Reproduce
- Enable MFA for a user.
- Trigger resetPasswordForEmail().
- Click on the recovery link and set the session.
- Try calling updateUser({ password }).
- Receive a 401 with AAL2 required.
Could you please clarify:
- Is this the expected behavior?
- If so, how should developers allow users to reset passwords when MFA is enabled?
More info:
Error and logs from Supabase Auth Logs dashboard:
{
"event_message": "{\"component\":\"api\",\"error\":\"401: AAL2 session is required to update email or password when MFA is enabled.\",\"level\":\"info\",\"method\":\"PUT\",\"msg\":\"401: AAL2 session is required to update email or password when MFA is enabled.\",\"path\":\"/user\",\"referer\":\"http://localhost:4200/\",\"remote_addr\":\"XXX\",\"request_id\":\"945dfb2d4397ed16-MXP\",\"time\":\"2025-05-26T14:32:18Z\"}",
"id": "077d00dc-95d2-461c-a014-b94f75e457c9",
"metadata": [
{
"host": "db-qdevaaylziztqvcidnmk",
"component": "api",
"_SYSTEMD_CGROUP": null,
"grant_type": null,
"request_id": "945dfb2d4397ed16-MXP",
"mail_from": null,
"message": null,
"_SOURCE_REALTIME_TIMESTAMP": null,
"PRIORITY": null,
"_AUDIT_LOGINUID": null,
"panic": null,
"metering": null,
"UNIT": null,
"event": null,
"SYSLOG_FACILITY": null,
"msg": "401: AAL2 session is required to update email or password when MFA is enabled.",
"mail_type": null,
"EXECUTABLE": null,
"user_id": null,
"_CMDLINE": null,
"action": null,
"auth_event": [],
"level": "info",
"_PID": null,
"path": "/user",
"duration": null,
"_COMM": null,
"sso_provider_id": null,
"header": null,
"_MACHINE_ID": null,
"login_method": null,
"_STREAM_ID": null,
"source_type": null,
"_LINE_BREAK": null,
"_EXE": null,
"_AUDIT_SESSION": null,
"_TRANSPORT": null,
"x_forwarded_proto": null,
"time": null,
"mail_to": null,
"_GID": null,
"stack": null,
"x_forwarded_host": null,
"saml_entity_id": null,
"status": null,
"_UID": null,
"valid_until": null,
"method": "PUT",
"CODE_FILE": null,
"remote_addr": "XXX",
"provider": null,
"_SYSTEMD_UNIT": null,
"issuer": null,
"error": "401: AAL2 session is required to update email or password when MFA is enabled.",
"client_id": null,
"MESSAGE_ID": null,
"url": null,
"referer": "http://localhost:4200/",
"_SYSTEMD_INVOCATION_ID": null,
"CODE_FUNC": null,
"_BOOT_ID": null,
"INVOCATION_ID": null,
"__MONOTONIC_TIMESTAMP": null,
"timestamp": null,
"__REALTIME_TIMESTAMP": null,
"CODE_LINE": null,
"_SYSTEMD_SLICE": null,
"count": null,
"instance_id": null,
"args": [],
"SYSLOG_IDENTIFIER": null,
"metadata": [],
"_CAP_EFFECTIVE": null,
"factor_id": null,
"_SELINUX_CONTEXT": null,
"expires_in": null,
"version": null,
"project": null
}
],
"timestamp": 1748269938000000
}
- Dominant language
- Go
- Stars
- 2.6k
- Forks
- 764
- Avg merge
- 5d 3h
- Merged PRs (30d)
- 39
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from supabase/auth
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
Difficulty 1/5 Under an hour Newbie friendliness 86/100
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Similar issues
-
optimization optimization:agents-md-curator
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
githubnext/gh-aw-cao#13143 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
blinklabs-io/bursa#904 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
yanet-platform/ipfw-go#129 ·
-
bug confmap/provider/googlesecretmanagerprovider needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
open-telemetry/opentelemetry-collector-contrib#51273 · 2 comments ·
-
bug: AI Gateway client filter lists "Unknown" twice when NULL and literal Unknown clients coexist Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 90/100