21/ NextAuth + Strapi: Final pieces and conclusion
Tags: nextauth, strapi, nextjs
Published: 2024-04-01 16:37:13

There are some issues that we left unhandled, let's quickly go over them.

## Automatically signing in on reset password in NextAuth

In our auth flow, we added the forgot/reset password option for credentials. But, as our flow stands now, we prompt the user to sign in after resetting the password. This is acceptable but not ideal.

A successful password reset in `Strapi` actually returns the user object + a `Strapi token`. In other words, everything we need to sign the user in automatically. I delayed talking talking about this because we didn't have all the necessary pieces just yet! But we do now.

We can now use what we learned in the change username and change password functionality and apply it to reset password. That is, stop using `useFormState`. Call our server action in a submitHandler function, await the response from this server action and on success call the `useSession.update` function. What would we pass it? Everything you need to update the token.

Note: I didn't actually try this out so you may run into some problems. But, I'm pretty sure it can be done.

## Automatically signing in on email confirmation in NextAuth

When first signing up, the user receives an email confirmation request. Upon clicking the confirmation link the user gets a success message and is asked to sign in. Can we do this automatically?

Maybe, but we would have to seriously rework our component. First on the actual first _sign up_ we would have to integrate `NextAuth`. Our `Strapi` endpoint for signing up returns (on success) the user object but no token. So, we would have to put this user into the `NextAuth token`. I think you can listen for the trigger 'signup' inside the `jwt callback` for this.

It would also be necessary to use a second CredentialsProvider for _sign up_ and give it a unique ID. You can then call the `signIn` function with this ID, f.e.

```jsx
// not
signIn('credentials', ...)
// use ID
signIn('signin', ...)
signIn('signup', ...)
```

Inside this second CredentialsProvider (with id signup), you can then write an `authorize` function that calls the `Strapi` signup endpoint + handle errors and everything else that needs to be done.

The issue now is how to get the `Strapi token`. On email confirmation, the `Strapi` endpoint will not return the token but redirect the user. Also, we don't have a password to sign in with. (DO NOT send the password along any requests!)

And that is where I run aground. Maybe it can be done but I don't know how because I can't get to the `Strapi token`.

Also note that you would have to update your guarded components. No longer only checking `if(session)` but also something like `&& session.user.authorized`.

## Tokens and expiry in Strapi and NextAuth

We used a lot of tokens in our auth flow: `Strapi sign in token`, request reset token, reset password token, `NextAuth` token,... All of these tokens have expiry dates. This means that they are only valid within a certain period. I'm pretty sure the expiry date is encoded inside the token.

On top of that, tokens also can be invalidated but not expired. A good example of this is the password reset token. Once you've used it to reset a password, `Strapi` will invalidate it. This token will then be invalid even though the expiry date may not have been reached yet.

Note, I don't know how this works yet. I'm yet to study it. I only know bits and pieces but I do know it's a problem we have to deal with.

When our `NextAuth` token expires, the user will simply be signed out and will have to sign in again. No problems there. There are ways to automate this with f.e. GoogleProvider. On sign in, we leverage some `NextAuth` callbacks to request a new `NextAuth` token ... somehow. Not sure how but it is possible.

A more immediate problem is when our `NextAuth` token is still valid or hasn't expired but the `Strapi token` has. This would lead to a cascade of problems and very confusing error message. The user would still be logged in, yet `Strapi` would throw errors like 'invalid credentials' or something. That is a problem and I don't know how to solve this yet.

We already came across another problem. Upon changing our password, `Strapi` returned us a new `Strapi token`. We then updated the `NextAuth token` via the `useSession.update` method. But, what happened to the old token? Spoilers, it is still valid. This means that it could be used to access our app. So, again, something we would have to manage.

`Strapi` also has a block user option. You would have to look into this to find out what this means for the token.

That is pretty much all I know about this for the moment. Takeaway: handle token expiry.

## Final conclusion

We setup a complete auth using credentials and GoogleProvider in `Next` and `Strapi` using `NextAuth`. Contrary to some articles in the wild, this wasn't easy and it wasn't quick - if done right.

On top of that, we took some shortcuts. We avoided some problems by simplifying our app or choosing a basic auth flow. Building a production level auth flow will complicate things. Meeting design specs will complicate things even more.

There will be things you can't do. Partly due to `NextAuth`'s insufficient server code support but also just hard restrictions. Things `NextAuth` just can't do.

That being said, we did do a lot. We do having a fully functioning auth flow. One I hope I was able to explain clearly. It's important to get a feel for how `NextAuth` works. Feel the flow. Especially inside the `callbacks`. Besides this I tried to guide you through countless problems and how I managed to solve them. In the end this took up a lot of our time and I hope you learned from it.

Don't be shy to critique this. If you catch a mistake or a better solution, feel free to let me know in the comments.

Anymore on the way? As mentioned above, I still need to figure out how to handle token. Besides this I may do this series over with `NextAuth v5` once it comes out of beta. Not making any promises.

Hope you enjoyed this series. Comment and share if you liked it.

---

If you want to support my writing, you can [donate with paypal](https://www.paypal.com/donate/?hosted_button_id=4D78YQU4V5NEJ).