Skip to content

Custom callbackUrl within (custom) provider config not set #4568

@frankfoster

Description

@frankfoster

Environment

System:
OS: Windows 10 10.0.19042
CPU: (4) x64 Intel(R) Xeon(R) CPU E5-2697 v3 @ 2.60GHz
Memory: 9.92 GB / 16.00 GB
Binaries:
Node: 16.14.2 - ~\AppData\Local\Volta\tools\image\node\16.14.2\node.EXE
Yarn: 1.22.18 - ~\AppData\Local\Volta\tools\image\yarn\1.22.18\bin\yarn.CMD
npm: 8.5.0 - ~\AppData\Local\Volta\tools\image\node\16.14.2\npm.CMD
Browsers:
Edge: Spartan (44.19041.1266.0), Chromium (101.0.1210.39)
Internet Explorer: 11.0.19041.1566
npmPackages:
next: ^12.1.5 => 12.1.5
next-auth: ^4.3.3 => 4.3.3

Reproduction URL

unfortunately the code is not public

Describe the issue

Description

Hi there, we are using next-auth with a custom provider (see config below) on a custom node server (like so: #531 (comment)) in order to use next-auth on nextjs static generated pages (SSG). Unfortunately we have to use a custom callback URL pattern in order to get this running which is not working properly. What we tried so far is setting the custom URL as callbackUrl parameter (within the provider config) and handling the redirect stuff (custom callback URL <-> /api/auth/*) on our node server.

Provider config:

export const providerConfig = {  
    id: "xyz",
    name: "XYZ",
    type: "oauth",
    version: "2.0",
    wellKnown: "[...]/.well-known/openid-configuration",
    authorization: {
      params: {
        scope:
          "openid profile offline_access customer ACR_Level_10 ACR_Level_20 ACR_Level_30",
        code_challenge_method: "S256",
        protocol: "oauth2",
        access_type: "",
        response_type: "code",
        // not necessary if options -> callbackUrl is fixed
        redirect_uri: `${process.env.NEXTAUTH_URL}/oauth2/callback`,
      },
    },
    clientId: "xyz_id",
    checks: ["pkce", "state"],
    idToken: true,
    client: {
      token_endpoint_auth_method: "none",
      // see: https://github.com/nextauthjs/next-auth/issues/3559 in order to change expected algorithm
      authorization_signed_response_alg: "ES384",
      id_token_signed_response_alg: "ES384",
    },
    options: {
      // Dev hint: works only if following library code has changed
      // file: /node_modules/next-auth/core/lib/provider.js; line: 23 ff
      // move method parameter '...userOptions' to 3rd place
      // @ts-ignore
      callbackUrl: `${process.env.NEXTAUTH_URL}/oauth2/callback`,
    },
    profile(profile) {
      return {
        id: profile.sub,
        email: profile.authenEmail,
      };
    },
  };

Server.ts (only relevant part)

const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());

var corsOptions = {
  origin: true,
  credentials: true
}

app.use(cors(corsOptions));

(async () => {
  await server.start();
  server.applyMiddleware({ app });

  app.use((req, res, next) => {
    // Fill in the "nextauth" [catch all route parameter](https://nextjs.org/docs/routing/dynamic-routes#catch-all-routes)
    req.query.nextauth = req.url.slice(authBaseUrl.length).replace(/\?.*/, "").split("/");

      // @ts-ignore
    return NextAuth(req, res, {
      providers: [providerConfig],
      secret: "...",
      debug: true,
    });
  });

  app.listen({ port: 4200 }, () =>
    
  );
})();

Error message

After filling out user credentials the generated code verifier and challenge should be validated. But in this case the callbackURL is not the configured one.

[next-auth][error][OAUTH_CALLBACK_ERROR]
https://next-auth.js.org/errors#oauth_callback_error invalid_request (Invalid or missing redirect URI) {
  error: {
    message: 'invalid_request (Invalid or missing redirect URI)',
    stack: 'OPError: invalid_request (Invalid or missing redirect URI)\n' +
      '    at processResponse (\\node_modules\\openid-client\\lib\\helpers\\process_response.js:38:13)\n' +
      '    at Client.grant (\\node_modules\\openid-client\\lib\\client.js:1347:22)\n' +
      '    at processTicksAndRejections (node:internal/process/task_queues:96:5)\n' +
      '    at async Client.callback (\\node_modules\\openid-client\\lib\\client.js:474:24)\n' +
      '    at async oAuthCallback (\\node_modules\\next-auth\\core\\lib\\oauth\\callback.js:112:16)\n' +
      '    at async Object.callback (\\node_modules\\next-auth\\core\\routes\\callback.js:50:11)\n' +
      '    at async NextAuthHandler (\\node_modules\\next-auth\\core\\index.js:139:28)\n' +
      '    at async NextAuthNextHandler (\\node_modules\\next-auth\\next\\index.js:21:19)',
    name: 'OPError'
  },
  providerId: '...',
  message: 'invalid_request (Invalid or missing redirect URI)'
}
[next-auth][error][CALLBACK_OAUTH_ERROR]
https://next-auth.js.org/errors#callback_oauth_error invalid_request (Invalid or missing redirect URI) OPError: invalid_request (Invalid or missing redirect URI)
    at processResponse (\node_modules\openid-client\lib\helpers\process_response.js:38:13)
    at Client.grant (\node_modules\openid-client\lib\client.js:1347:22)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Client.callback (\node_modules\openid-client\lib\client.js:474:24)
    at async oAuthCallback (\node_modules\next-auth\core\lib\oauth\callback.js:112:16)
    at async Object.callback (\node_modules\next-auth\core\routes\callback.js:50:11)
    at async NextAuthHandler (\node_modules\next-auth\core\index.js:139:28)
    at async NextAuthNextHandler (\node_modules\next-auth\next\index.js:21:19) {
  name: 'OAuthCallbackError',
  code: undefined
}

The (quick) fix

Setting the callbackURL within the provider config is not working. What I figured out so far is: moving method parameter '...userOptions' to 3rd place within the following next-auth code snippet will keep the configured callbackURL instead of overriding it.

return merge(defaultOptions, {
...userOptions,
signinUrl: `${url}/signin/${userOptions?.id ?? rest.id}`,
callbackUrl: `${url}/callback/${userOptions?.id ?? rest.id}`,
})

How to reproduce

<SessionProvider basePath="http://localhost:4200/api/auth" session={pageProps.session} refetchInterval={0}>
  <Layout>
    <Component {...pageProps} />
  </Layout>
</SessionProvider>

Expected behavior

Correct (configured) callbackURL is added before triggering /api/auth/callback/<idp_id> in order to validate code verifier and challenge. Keep mind that we have to use a certain callbackURL to meet the IDP specification.

Metadata

Metadata

Assignees

No one assigned

    Labels

    coreRefers to `@auth/core`

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions