auth-ui: Password reset is not working
Bug report
I’m trying to set up password reset flow in my nextjs app with supabase and supabase auth ui. It’s not working and I’m struggling to understand the root cause.
Describe the bug
When a reset link is clicked, no password reset dialog is shown.
To Reproduce
Steps to reproduce the behavior, please provide code snippets or a repository:
- Instantiate a nextjs app with supabase and auth-ui
- Create a new page with the following content:
// LOCATED IN pages/auth-ui.jsx
import {
Auth,
// Import predefined theme
ThemeSupa,
} from '@supabase/auth-ui-react'
import {useSupabaseClient} from "@supabase/auth-helpers-react";
import Container from "@mui/material/Container";
const AuthUi = () => {
const supabase = useSupabaseClient();
return(
<Container maxWidth={"sm"}>
<Auth
supabaseClient={supabase}
appearance={{ theme: ThemeSupa }}
theme="dark"
redirectTo={`http://app.local/auth-ui`}
/>
</Container>
)
}
export default AuthUi
- Setup your auth settings in supabase:
Site URL: http://app.local
Redirect Url: http://app.local
Side note - I’m using http here since I have a local instance of my app on this redirect URL, so the certificate is not a concern.
- Using the AuthUI, generate an email for a password reset. The link in the email will be in the format of:
https://XXX.supabase.co/auth/v1/verify?token=XXX&type=recovery&redirect_to=http://app.local/auth-ui
- Click the link
- Auth flow will end up with the following path:
http:/app.local/auth-ui#
The user will remain signed in, but no reset password view will be shown.
Expected behavior
It works and doesn’t require users to debug this - it’s such a basic functionality, strange that it’s not working correctly by default.
Screenshots
If applicable, add screenshots to help explain your problem.
System information
- OS: [e.g. macOS, Windows] macos
- Browser (if applies) [e.g. chrome, safari] chrome
- Version of supabase-js: [e.g. 6.0.2]:
"@supabase/auth-helpers-nextjs": "^0.5.2",
"@supabase/auth-helpers-react": "^0.3.1",
"@supabase/auth-ui-react": "^0.2.6",
"@supabase/supabase-js": "^2.1.0",
- Version of Node.js: [e.g. 10.10.0]:
> node -v
v16.7.0
Additional context
If you’ll click the link second time, you’ll not get a proper error handle, instead, the redirect will look like this:
http://xxx.local/auth-ui#error=unauthorized_client&error_code=401&error_description=Email+link+is+invalid+or+has+expired
It’s quite clear that it should look like this (query, not an anchor):
http://xxx.local/auth-ui?error=unauthorized_client&error_code=401&error_description=Email+link+is+invalid+or+has+expired
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 20
- Comments: 42 (8 by maintainers)
I think the confusion arises because the Auth component is “half-smart”.
If you just drop it in, it lets you switch between all the different views, so it will already allow login, signup, and sending password reset links. Which is great! So it makes you think it Just Works.
But it doesn’t let you configure each of those views separately. You can’t customize
redirectToonly for the password reset link. If we could do that, for example, this would be easy to fix.So I think it’d be better either for it to be really dumb (not handle switching views with setAuthView, out-of-the-box), or smarter. Obviously I prefer the latter. 😃 Happy to help out with a PR if I hear some consensus about what to do.
Here to +1 to the fact that the Auth UI component is extremely misleading. Spent a decent chunk of time trying to use the component for my app, but instead kept uncovering limitations that make it a complete hassle to implement.
For those of you who happen to be reading this and are considering using Auth UI — don’t! Implement your own or use another service instead of this one since it’s half-baked as @mryechkin said.
The documentation should make it extremely clear that this is not a working solution. I went down this rabbit hole because the official documentation on Supabase’s site made it look like it was an appealing solution
To everyone in this thread I really appreciate the time you’ve all taken to explain the difficulties you are facing with the library and the lack of documentation which has led to these difficulties. I am taking it all into consideration as we formulate how to best fix these issues. I think the first step is to document how you would go about handling password reset as this is something that keeps on coming up and it differs per environment [server-side generated (SSG) and single page application (SPA)]. There is also scenarios where it may even work different in SPA environments too because in the case of you using a router in your SPA like React Router you would use the component similar to how you would use it in a SSG environment. I’ve added in the event listener in the auth-ui-react library to match that of the auth-ui-solid version, but this in effect is only useful in an SPA without a router setup.
A minimal repo for NextJS: https://github.com/chrisk-7777/supabase-reset-next-test
I’m intentionally avoiding the convenience helpers to keep the surface area small.
If
onAuthStateChangeis subscribed to within a root page (likeindex.tsx), or a sub page (likereset.tsx) then everything works fine, just with the same notes from my previous comment.Note: This is all SSG, no SSR.
@levity this is exactly why I opted to just use my own auth forms instead of relying on what feels like a half-baked solution with Auth UI. It would be great it it handled all the things like you said - but the fact that it doesn’t let us configure some things while also requiring to manually implement other things makes using this component an exercise in frustration, and not really worth the effort IMO.
Can you give an example of how you would do this with Auth UI? I can’t figure it out. This is the basic pattern I was expecting to work:
However, this won’t work with the password recovery links that Auth UI sends, because the user gets logged in and then the Auth UI doesn’t render. What else can I check to keep rendering Auth instead of MyContent, in order to update the password? It doesn’t seem like I can check
type=recoveryin the query params because something in the auth code changes the URL.@chrisk-7777 I ended up ditching the Auth UI library and just created my own Auth forms - much easier than trying to work around the gotchas in this library (see my comment here).
I wholeheartedly agree with this, and also find it quite strange that the “Forgot” form is included, but not the “Reset”. In my mind the two go hand-in-hand.
Yup… also agreed, and no it’s not just you - I was also quite confused when I started looking into this initially. It’s again the reason I opted to not use the provided UI library once I moved to Supabase v2, and created my own auth forms and the context provider.
BUMP @supabase where are you? Give us forgotPasswordRedirectUrl param. Simple fix. Thanks!
Any reason Supabase isn’t updating on this? I personally ran into a ton of issues, then by happenstance ran into another developer on a completely unrelated project running head first into the same brick walls I was at an event.
Not a good look for Supabase to show up at events as the problem child for something as pivotal as auth. End result is most people just go to Clerk.dev, and in turn probably go with Vercel’s Postgres over yours.
I’m pretty confused with how this feature is supposed to work. How do I distinguish between recovering a password and restoring the session in a client app? Using the React quickstart from the docs, the recovery link logs you in immediately and I don’t see a simple way to fix it.
I just want to come back and give an update here that this issue hasn’t been forgotten. I’m currently working on some docs to explain how this flow is supposed to work and then will create some examples with the Auth UI to show how it works.
I think where I’m most confused is that it presents itself as a fully baked component… There are no state change callback props. For example, if the “view” is changed in the component, and we are supposed to handle that separately, why is there no onViewChange callback? I see that maybe theres a hash added to the url but having a callback would be a lot more intuitive and clear about how the component can be handled - especially if we want to customize a specific view. There’s no way for me to handle, for example, onSignup vs onSignin or some sort of auth change type callback from that view component so I can send the user to an additional form for sign up details IF they just signed up. I understand that can be done by listening to auth helpers but i just think some callbacks from the auth ui would make setup a lot easier and more intuitive as to how you can handle it.
Hey folks I can see that there are still confusion around how this process works. I think one of the issue here is that folks think the Auth UI is supposed to be a smart component when in-fact it’s just a dumb component, it doesn’t do much more than provide you with a UI and make the API call, the rest is up to you the developer to handle. When doing a password reset flow you need to provide the page that the update password should happen on, on that page you can use the Auth UI component. You can take a look at the examples I’ve created here https://github.com/supabase-community/supabase-by-example/tree/main/reset-flow/auth-ui, note that you might see new component names being introduced like
ForgottenPasswordthese are just wrappers around theAuthcomponent that set theviewproperty to the correct state. These could have easily been theAuthcomponent with view property set toforgotten_password. You can see this component here https://github.com/supabase/auth-ui/blob/main/packages/react/src/components/Auth/ui/index.tsx#L93-L105I’ve created a very minimal example here: https://github.com/chrisk-7777/supabase-reset-test
It does “work”, but it doesn’t feel entirely intuitive or documented. Unless I’m missing something in the docs. I’ve read this dicusssion a half dozen times to really “get” what is going on.
Disclaimer, I’m new to Supabase and its ecosystem, but not new to authentication.
There were two key points that I initially missed:
Auth UI includes a “forget password” view, but not a “reset password” view. To me this was confusing. The confusion comes from my experience with other auth solutions like Auth0 and Laravel’s Sanctum/Fortify/Breeze - where a reset flow isn’t also a magic link / sign in combo. I can’t recall which one Firebase uses, I’ll check later. I noticed this recent PR, which is off the back of this confusion. But if anything, that makes it more confusing because someone (like myself) may conflate that to mean that “forgot” is “reset”. If the team is open to it, I would like to raise a PR saying that “reset password” view is excluded. The docs kind of hint to the user being signed in here but it doesn’t actually mention a session is started, just that a sign in event occurred. Maybe that is obvious to others, but reading around on various issues/discussions its not.
Within the React version of Auth UI, it never reaches the
update_passwordby itself (correct me if I’m wrong). So for the particular case of a post-forget-magic-link-loginPASSWORD_RECOVERYevent, we need to set some app level state, and manually set the view in consumer land. In hindsight, I guess this makes sense, it makes it handy to have that view available for general password updates, but its confusing thatviewis sometimes handled internally (swapping between login, register and forgot views), and sometimes handled externally (update password view). Maybe its just me?Bonus: One other thing that completely caught me off guard was
onAuthStateChangeshould be unregistered, like this, right? Again, I’m new to Supabase, but without unsubscribing, a component re-render will re-fire useEffect, and queue up multiple listeners - is that right? I bring it up because the documentation here outlines the subscribe occurring in auseEffectwithout any cleanup.Separately, I believe there is some NextJS funkiness going on. The same thing that @mryechkin is experiencing (sorry to @ you, but I’ve seen you pop up in nearly every password reset discussion/issue across supabase’s repo’s, and have helped me understand what is going on). As mentioned somewhere else, the “PASSWORD_RECOVERY” event isn’t fired, but is probably related to a clash with Next’ routing / rendering modes. I’ll try put together a minimal repo for that too.
None of this should be taken as criticism, I’m just trying to clarify my understanding after a day of going around in circles.
I made a PR that does what @levity describes and that works for me. You can see it here: #223 with my comment describing the desired reset password flow. But I must still be missing something regarding how to implement this flow without re-implementing a bunch of these components or even doing everything server-side. I would really appreciate pointers on how to get this working with the Auth components.
@chrisk-7777 good suggestions. I will add them to my list of todos and get the docs update to match this. Do note that there is an update password view, it’s just that you have to manually set the views with the Auth component.
You can see the individual component which just uses this view in the Auth component. https://github.com/supabase/auth-ui/blob/main/packages/react/src/components/Auth/ui/index.tsx#L107-L114
The provided Auth UI code just does not work whatsoever. It did not mention @supabase/auth-helpers-react. If you cannot provide any working example, why bother to release this?