Search code examples
next.jsoauth-2.0openid-client

How to return to the previous page after login with authorization code flow?


After a successful login I have a handler the callback url - set by redirect_uri. There, I fetch the tokens and redirect the landing page, with the tokens set in the Set-Cookie handler. This is working fine, but ideally I could also redirect to the original page instead of the landing page.

Two - untested ideas - come to my mind, but both don't strike be as particular convincing: 1.) I could use the state parameter to pass the original url and receive it later, but that's not what it's there for. 2.) I could try to store the "recent_url" in the cookies and read it at my callback, which might be an overkill. Is there maybe a defined way to pass arbitrary data (or an "original url") via the authorization url which I receive in my callback? Or what's the common approach here?

For reference, here are the - simplified - code snippets:

At pages/api/auth/login.ts:

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const authUrl = await myOpenIdClient.getAuthorizationUrl({
    // ideally, I could pass the original url here to receive it in the callback
    prompt: 'login',
    redirect_uri:`${APP_URL}/api/auth/callback/token`
  });
  res.redirect(authUrl).end();
}

At pages/api/auth/callback/token.ts:

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const params = myOpenIdClient.callbackParams(req);
  const tokenSet = await myOpenIdClient.callback(`${APP_URL}/api/auth/callback/token`, params);
  setTokenCookies(req, res, tokenSet.access_token, tokenSet.refresh_token);
  // Here I'ld like to redirect to something more specific as APP_URL/my-prev-side
  res.redirect(APP_URL).end();
}

myOpenIdClient is an openid-client, and at the backend there's a node-oidc-provider.


Solution

  • This seems like a great use-case for a session cookie, with some data related to auth stored in the session. state is not ideal because you're supposed to validate that the received state is what you originally sent, so you'd still need to store your state value somewhere anyway.

    Some people do use the state parameter for this, but this it's intended use-case:

    https://datatracker.ietf.org/doc/html/rfc6749#section-10.12