Skip to content

fix(gotrue): allow TOTP MFA enrollment without an issuer#1501

Open
AndroidPoet wants to merge 2 commits into
supabase:mainfrom
AndroidPoet:fix/gotrue-mfa-enroll-optional-issuer
Open

fix(gotrue): allow TOTP MFA enrollment without an issuer#1501
AndroidPoet wants to merge 2 commits into
supabase:mainfrom
AndroidPoet:fix/gotrue-mfa-enroll-optional-issuer

Conversation

@AndroidPoet

Copy link
Copy Markdown
Contributor

What

GoTrueMFAApi.enroll() no longer requires an issuer when enrolling a TOTP factor. The canonical call now works:

final res = await supabase.auth.mfa.enroll(); // factorType defaults to totp

Why

issuer is documented as optional for TOTP (/// [issuer] : Domain which the user is enrolled with (TOTP only).) and is optional in supabase-js, but the argument validation made it mandatory:

if (factorType == FactorType.totp && issuer != null) {
  body['issuer'] = issuer;
} else if (factorType == FactorType.phone && phone != null) {
  body['phone'] = phone;
} else {
  throw ArgumentError('Invalid arguments, expected an issuer for totp ...');
}

When a TOTP factor is enrolled without an issuer, both if branches are false, so it falls through to the else and throws ArgumentError synchronously — before any request is sent. The standard mfa.enroll() therefore always failed unless an issuer was passed.

This was an unintended regression from #1188 (Add phone mfa enrollment), which introduced the combined branch. The existing enroll totp integration test always passes issuer: 'MyFriend', so it never exercised the no-issuer path.

The fix separates the factor-type handling so TOTP forwards issuer only when provided, while phone enrollment keeps its existing requirement that a phone number is supplied.

Not a breaking change

  • TOTP enrollment with an issuer behaves exactly as before (the value is still sent).
  • Phone enrollment is unchanged and still throws ArgumentError when phone is omitted (covered by the existing enroll phone requires phone number test).
  • Only the previously-broken TOTP-without-issuer path changes: it now succeeds instead of throwing.

Tests

Added packages/gotrue/test/mfa_enroll_test.dart, an offline test using a recording BaseClient that inspects the outgoing request body:

  • enroll() reaches the network and sends no issuer (previously threw ArgumentError).
  • enroll(issuer: 'MyApp') forwards the issuer.
  • enroll(factorType: FactorType.phone) without a phone still throws ArgumentError.

@AndroidPoet AndroidPoet requested a review from a team as a code owner July 1, 2026 04:59
Comment thread packages/gotrue/lib/src/gotrue_mfa_api.dart Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants