Next-auth: Is it possible to signout from an API route?

Created on 17 Jul 2020  路  3Comments  路  Source: nextauthjs/next-auth

Is it supported to post a signout from an API route? I understand that signout needs access to the cookies so my initial assumption is no but I'm not sure if there's a recommended/supported way of passing these cookies between API routes. My use case is the login redirect is an api route that collects some additional verification data and then redirects the user based on that data. I've implemented a signout for the case where this validation fails like this (basically a copy/paste from the client side signin method):

const _logout = async (res: NextApiResponse, callbackUrl?: string) => {
  const csrf = await getCsrfToken();

  await fetch(`${process.env.NEXT_PUBLIC_SITE}/api/auth/signout`, {
    method: 'post',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: _encodedForm({
      csrfToken: csrf,
      callbackUrl: callbackUrl ? callbackUrl : process.env.NEXT_PUBLIC_SITE,
    }),
  });

// Added this for now since the signout callback doesn't seem to work
  res.status(302).setHeader('Location', callbackUrl ? callbackUrl : process.env.NEXT_PUBLIC_SITE);
  res.end();
};

The fetch call returns url: 'http://localhost:3000/api/auth/signout?csrf=true', status: 200, statusText: 'OK', so it seems successful but seeing the ?csrf=true leads me to believe there's an issue with the CSRF token validation given what I see here.
After some further digging I see that csrfTokenVerified is set to true here but only if req.cookies[cookies.csrfToken.name] exists, and I don't think this server-server request will have cookies so I'm guessing this is where this is failing.

Is what I'm attempting to do here possible?

  • [ ] Found the documentation helpful
  • [ ] Found documentation but was incomplete
  • [x] Could not find relevant documentation
  • [ ] Found the example project helpful
  • [x] Did not find the example project helpful
question

All 3 comments

Hi! So it turns out the CSRF Token function was poorly documented and that's why it's not working for you.

  • In v2 (the current production version) the getCsrfToken() function is browser side only.
  • In v3 (the current beta version) the getCsrfToken() function can be used both client and server side.

Note: The usage is slightly different when using it server side - as with getSession() you need to pass { req }


Inspired by this I updated the documentation for v3:

getCsrfToken()

  • Client Side: Yes
  • Server Side: Yes

The getCsrfToken() method returns the current Cross Site Request Forgery (CSRF Token) required to make POST requests (e.g. for signing in and signing out).

You likely only need to use this if you are not using the built-in signIn() and signOut() methods.

Client Side Example

async function myFunction() {
  const csrfToken = await getCsrfToken()
  /* ... */
}

Server Side Example

import { getCsrfToken } from 'next-auth/client'

export default async (req, res) => {
  const csrfToken = await getCsrfToken({ req })
  /* ... */
  res.end()
}

If you think it would be helpful, we could make the signOut() function in v3 work server side too!

e.g.

import { signOut } from 'next-auth/client'

export default async (req, res) => {
  const callbackUrl = 'https://example.com/some/path'
  await signOut({ req, res, callbackUrl })
  res.end()
}

My current use case is building this server-side redirect, which could probably be replaced by a more robust signin callback with additional options for responses instead of just true or false as we discussed in #373.

But I do think this would be helpful whether or not that sort of functionality makes it into V3!

Was this page helpful?
0 / 5 - 0 ratings