Open rmshin opened 4 months ago
Have you found a fix? I am getting [AuthApiError: Error confirm email]
when using the js sdk for the same purpose, when confirming the new email (the old one works fine when using verifyOtp).
hey @Kraktoos , not sure I understand your issue as your errors look a bit different to mine. Are you confirming the new email via OTP as well? What I did as a workaround/fix is essentially:
verifyOTP
with old email + OTP code from old emailAuthException
. I simply catch this error and ignore it. verifyOTP
with new email + OTP code from new emailHope that helps!
I'm able to reproduce this against the local setup. My scenario is slightly different than above:
final emailId = Uuid().v4();
final email = '$emailId@example.com';
await auth.signInAnonymously();
await auth.updateUser(
UserAttributes(email: email),
emailRedirectTo: 'https:localhost/a',
);
await auth.verifyOTP(
type: OtpType.emailChange, token: token, email: email);
This raises the following exception:
AuthException(message: Only the token_hash and type should be provided, statusCode: 400, errorCode: validation_failed)
And corresponding error in the container log:
{"component":"api","error":"400: Only the token_hash and type should be provided","level":"info","method":"POST","msg":"400: Only the token_hash and type should be provided","path":"/verify","referer":"http://127.0.0.1:3000","remote_addr":"192.168.65.1","request_id":"d8d3d2a2-cac8-4b0a-9381-a78df66efb2b","time":"2024-09-09T04:52:56Z"}
These lines prevent us from submitting what appears to be a valid request:
Removing that assertion and making the request without the email succeeds:
await auth.verifyOTP(
type: OtpType.emailChange,
tokenHash: tokenHash,
);
Not sure what a proper fix looks like, but if someone else runs into this you can use this hack to get around it: https://github.com/ryanhanks-bestow/supabase-flutter/tree/hack-fix-verify-otp
# in your pubspec
dependency_overrides:
gotrue:
git:
url: https://github.com/ryanhanks-bestow/supabase-flutter
ref: hack-fix-verify-otp
path: packages/gotrue
Bug report
Describe the bug
As per the Supabase docs, the default behaviour when a user requests an email change is that a confirmation email is sent to both the old and new email addresses of the user.
For the case where an OTP code is used instead of a confirmation link, the user receives two distinct OTP codes to each of their given email addresses. Both these codes must subsequently be verified via the
verifyOTP
API in order for the email change to take effect.However, at least in the
supabase-flutter
client, calling this endpoint with a valid OTP token raises anAuthException
. This is due to the following code snippet withinverifyOTP
defined ingotrue_client.dart
:Here the function expects a successful user session to be returned within the
/verify
API response, but in the case of secure email change the returned response is:Essentially, the current implementation of
verifyOtp
doesn't account for the two-step verification flow of email change via OTP.To Reproduce
Steps to reproduce the behavior, please provide code snippets or a repository:
Email Templates
for email change within Supabase dashboard to send{{ .Token }}
rather than{{ .ConfirmationUrl }}
.updateUser
API:verifyOtp
:AuthException
is raised:verifyOTP
is called with the wrong code, anAuthRetryableFetchException
is raised due to a server 500 response:Expected behavior
When a user is requesting an secure email change via OTP, calling
verifyOTP
with a correct first token should not result in anAuthException
. Instead, confirmation of the successful verification should be returned so the client can relay the appropriate feedback to the user.Providing an incorrect code, on the other hand, should return a meaningful error message about the invalid code rather than a generic
AuthRetryableFetchException
.Screenshots
System information
Additional context
According to the logs shown within the Supabase dashboard, the issue of 500 responses being returned from
/verify
when the wrong OTP token is sent seems to stem from a runtime panic somewhere in the server logic. See screenshots for additional details, and the below raw output of the event log: