Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Callback url does not work when I set custom pages #882

Open
alimozdemir opened this issue Aug 23, 2024 · 0 comments
Open

Callback url does not work when I set custom pages #882

alimozdemir opened this issue Aug 23, 2024 · 0 comments
Labels
bug A bug that needs to be resolved pending An issue waiting for triage

Comments

@alimozdemir
Copy link

alimozdemir commented Aug 23, 2024

Environment

Reproduction

It is hard to reproduce this error without sharing the secrets.

Describe the bug

import { decode } from 'jsonwebtoken'
import AzureAdProvider from 'next-auth/providers/azure-ad'
import { NuxtAuthHandler } from '#auth'

async function callRefreshToken(accessToken: any) {
  const url = `https://login.microsoftonline.com/${process.env.AZURE_AD_TENANT_ID}/oauth2/v2.0/token`;
  const req = await fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body:
      `grant_type=refresh_token` +
      `&client_secret=${process.env.AZURE_AD_CLIENT_SECRET}` +
      `&refresh_token=${accessToken.refreshToken}` +
      `&client_id=${process.env.AZURE_AD_CLIENT_ID}`,
  });
  const res = await req.json();
  return res;
}

async function refreshAccessToken(accessToken: any) {
  try {
    console.log('Previous token expires at', new Date(accessToken.accessTokenExpires));
    console.log('Refreshing access token...');
    const msToken = await callRefreshToken(accessToken);
    console.log('New token received');
    setAccessToken(accessToken, msToken);
    console.log('Access token refreshed');
    console.log('Next token expires at', new Date(accessToken.accessTokenExpires));
    return accessToken;
  } catch (error) {
    console.error(error);
    return {
      ...accessToken,
      error: 'RefreshAccessTokenError',
    };
  }
}

// Persist the access_token in the encrypted JWT.
function setAccessToken(jwt: any, msToken: any) {
  if (!msToken) {
    return;
  }

  if (msToken.access_token) {
    const decoded = decode(msToken.access_token)
    jwt.accessToken = msToken.access_token;
    if (decoded && typeof decoded !== 'string')
      jwt.roles = decoded.roles;
  }

  if (msToken.expires_at)
    jwt.accessTokenExpires = msToken.expires_at * 1000;
  else if (msToken.expires_in)
    jwt.accessTokenExpires = Date.now() + msToken.expires_in * 1000;

  jwt.refreshToken = msToken.refresh_token;
}

export default NuxtAuthHandler({
  // A secret string you define, to ensure correct encryption
  secret: process.env.AUTH_APP_SECRET,
  pages: {
    signIn: '/auth/signIn',
    signOut: '/auth/signOut',
    error: '/auth/error',
    verifyRequest: '/auth/verifyRequest',
    newUser: '/auth/new-user'
  },
  callbacks: {
    async jwt({ token, account, profile }) {
      setAccessToken(token, account);

      if (token.accessTokenExpires && Date.now() < token.accessTokenExpires) {
        return token;
      }

      return refreshAccessToken(token);
    },
    async session({ session, token }) {
      // Make access token available on the client.
      session.roles = token.roles;

      return session;
    },
  },
  providers: [
    // @ts-expect-error You need to use .default here for it to work during SSR. May be fixed via Vite at some point
    AzureAdProvider.default({
      clientId: process.env.AZURE_AD_CLIENT_ID,
      clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
      tenantId: process.env.AZURE_AD_TENANT_ID,
      authorization: {
        params: {
          scope: `openid offline_access profile api://Boss-Dev/Admin`,
        },
      },
    })

  ]
})

nuxt config

  auth: {
    originEnvKey: 'NUXT_AUTH_ORIGIN',
    provider: {
      type: "authjs",
      defaultProvider: "azure-ad"
    },
    globalAppMiddleware: {
      isEnabled: true,
    },
    sessionRefresh: {
        enablePeriodically: 30000,
        enableOnWindowFocus: true,
    }
 },

When I remove custom pages and use the pages from the package, the callback url is working ok and redirects me to the intended page.

I think it might be somehow related to #857

Additional context

When I set custom pages it attaches callbackUrl to the query string but built-in pages do not add callbackUrl to the query string. e.g.

http://localhost:3000/auth/signIn?callbackUrl=http://localhost:3000/my-protected-data

http://localhost:3000/api/auth/signin

It might be related to #883, since that body (URLSearchParams) also contains callbackUrl

Logs

No response

@alimozdemir alimozdemir added bug A bug that needs to be resolved pending An issue waiting for triage labels Aug 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A bug that needs to be resolved pending An issue waiting for triage
Projects
None yet
Development

No branches or pull requests

1 participant