auth
auth copied to clipboard
Auth: Inconsistent Password Reset redirect_to URLs Between Custom Domains and .web.app
Bug report
- [x] I confirm this is a bug with Supabase, not with my own application.
- [x] I confirm I have searched the Docs, GitHub Discussions, and Discord.
Describe the bug
Password reset redirect URL handling is inconsistent between Firebase-hosted .web.app domains and custom domains. When using a custom domain, Supabase doesn't include the hash fragment (/#/reset-callback) in the redirect_to URL, though it does include it for .web.app domains.
To Reproduce
- Set up a Flutter web app with Supabase auth and hash-based routing
- Deploy to Firebase hosting (gets a .web.app domain)
- Add a custom domain to the Firebase hosting
- Configure Supabase with both domains:
Site URL: https://custom-domain.com Redirect URLs: https://custom-domain.com/#/reset-callback - Request password reset using the same app code on both domains
Expected URLs in reset email:
- .web.app domain:
https://[project].supabase.co/auth/v1/verify?token=[token]&type=recovery&redirect_to=https://[project-id].web.app/#/reset-callback
- Custom domain:
https://[project].supabase.co/auth/v1/verify?token=[token]&type=recovery&redirect_to=https://custom-domain.com/#/reset-callback
Actual URLs:
- .web.app domain (correct):
https://[project].supabase.co/auth/v1/verify?token=[token]&type=recovery&redirect_to=https://[project-id].web.app/#/reset-callback
- Custom domain (incorrect):
https://[project].supabase.co/auth/v1/verify?token=[token]&type=recovery&redirect_to=https://custom-domain.com/
Expected behavior
Supabase should include the hash fragment (/#/reset-callback) in the redirect URL consistently for both .web.app and custom domains when it's specified in the Redirect URLs configuration.
System information
- OS: Windows 11
- Browser: Chrome 121
- Framework: Flutter Web
- supabase_flutter: ^2.6.0
Additional context
Currently requires a JavaScript workaround to handle the redirect properly on custom domains:
<script>
window.addEventListener("load", function () {
var search = window.location.search;
var hash = window.location.hash;
if (window.location.href.includes('custom-domain.com/') &&
search.includes('type=recovery') &&
search.includes('token') &&
!hash.includes('reset-callback')) {
window.location.replace('/#/reset-callback' + search);
}
});
</script>
This workaround shouldn't be necessary if the redirect URL was handled consistently.