Challenges

Add Social Authentication

Save the User in a Datastore

Using JWT to manage the login session is a viable option for us. But we need to save the user in a datastore after the sign-in process. Here's how we are going to do that:

  • In the signIn callback, we will save the user in a datastore
  • Then it'll return a userId which we can use to get the user later on
  • We will store this userId inside the JWT token
  • Then, when creating the session, we will use this userId to get the actual user from the DB
  • After that, we will create a session object, which we can get using the useSession React hook.
// This is how the session object looks like
{
    user: {
        id: 'userId',
        github: {
            avatar: 'https://avatar.url',
            login: 'my-github-login',
            name: 'My Name'
        }
    }
}

Let's do this:

šŸ‘‹ Here we will be working on the pages/api/auth/[...nextauth].js file.

First, import following functions:

import { saveUser, getUser } from '../../../lib/data'

Then replace the callbacks.signIn function with this:

callbacks.signIn = async function signIn(user, account, metadata) {
  const emailRes = await fetch('https://api.github.com/user/emails', {
    headers: {
      'Authorization': `token ${account.accessToken}`
    }
  })
  const emails = await emailRes.json()
  const primaryEmail = emails.find(e => e.primary).email;

  const githubUser = {
    id: metadata.id,
    login: metadata.login,
    name: metadata.name,
    email: primaryEmail,
    avatar: user.image
  }

  user.id = await saveUser('github', githubUser)
  return true;
}
šŸ’” Now we do not set the email into the user object. Instead, we save the user and add user.id.

Add the following jwt callback as well:

callbacks.jwt = async function jwt(token, user) {
  if (user) {
    token = {id: user.id}
  }

  return token
}
šŸ’” With this, we only keep user.id inside the token.

Finally, add the session callback:

callbacks.session = async function session(session, token) {
  const dbUser = await getUser(token.id)
  if (!dbUser) {
    return null
  }
  
  session.user = {
    id: dbUser.id,
    github: {
      avatar: dbUser.github.avatar,
      login: dbUser.github.login,
      name: dbUser.github.name
    }
  }
  
  return session
}
šŸ’” As you can see, we get the user from the token.id and use it to create the session object.

Let's verify these changes:

  • Kill the currently running app
  • Start the app again with yarn dev
  • Login again
Q: Which of the following statements is a false one?
authenticating...

šŸ™ We need your help

We need your help to keep maintain & add new content to this course. Here's how you can support us: