Go back

Confirm email with Djoser in a Next.js app

I find authentication flows intriguing to work on — to be honest!

And I love how this project has opened my mind to see how things work on a larger scale. The task at hand was for me to implement the "confirm email" auth flow.

For the first time, I wasn't aloof about what to do and how to implement this with Next.js. Why? I had already worked on something similar — and failed while doing so — previously.

One could also say that I've read a bit about what most responses from the API I'll be interacting with are like. A common pattern involves sending an email — containing a clickable link — to the user with a unique id and a token that verifies their account/email address.

Here's what a typical "confirm email" link will look like. Yours may be different.

https://example.com/auth/confirm-email/Mw/bui50h-476924d8c76af469d7128c8b19d536c2

Agreeing on a route for the URL

The important segments of the link above are the uid, Mw, and the token, bui50h-476924d8c76af469d7128c8b19d536c2.

How you decide to structure the route is left to you and your backend team. I remember jumping on calls with our backend folks a couple of times so we could agree on the URL structure, so I could create a corresponding route for it.

The backend service we used for this is Djoser, a Django-based library for authentication and all in between.

When that was all settled I went on to create the /confirm-email route.

Handling dynamic routes

As I said previously, the uid and token segments of the URL are important because no "confirm email" link is ever the same, they're all unique.

Next.js provides a way to handle dynamic route segments and to improve the whole experience, one could tap into the capabilities of useRouter() to read the values in the URL.

Since these segments of the URL are dynamic, I went on to create them accordingly with the [] notation like so

.
└── pages/
    └── auth/
        └── confirm-email/
            └── [uid]/
                  └── [token].tsx

One thing to notice is how the [uid] in the snippet above is a folder that contains the token file, which is where would be ideal for you to render any markup and access the URL segment values as slugs.

Confirming an email address

The next thing on my list after structuring the route was to find a way to get the uid and token from the URL, when the user clicks on it from their email, so I can send a GET request to the API endpoint confirming their info.

This is possible with useRouter

import { useRouter } from 'next/router'
 
const ConfirmEmailPage = () => {
  const router = useRouter()
  const { uid, token } = router.query
 
  return (
    <>
      <p>just a little moment...</p>
    </>
  )
}
 
export default ConfirmEmailPage

To make things easier for myself, I wrote a custom data hook — useConfirmEmail() — with SWR to carry out this action. You can learn more about them here

const confirmationStatus = useConfirmEmail(
  typeof uid === 'string' ? uid : '',
  typeof token === 'string' ? token : ''
)
const { error, isLoading } = confirmationStatus

If the request has no error and it isn't being fetched/running, render a confirmation message.

import { useRouter } from 'next/router'
 
const ConfirmEmailPage = () => {
  const router = useRouter()
  const { uid, token } = router.query
 
  const confirmationStatus = useConfirmEmail(
    typeof uid === 'string' ? uid : '',
    typeof token === 'string' ? token : ''
  )
  const { error, isLoading } = confirmationStatus
 
  return (
    <>
      {!error && !isLoading ? (
        <p>Welcome aboard!</p>
      ) : (
        <p>just a little moment. please wait...</p>
      )}
    </>
  )
}
 
export default ConfirmEmailPage

Although other approaches may abound, this is what worked for me. Let me know how it goes when you try it.