nextauthjs / next-auth

Authentication for the Web.
https://authjs.dev
ISC License
25.03k stars 3.54k forks source link

Incorrect tenant details even if tenantId is provided in provider options #12258

Open VishalRathoreSM opened 6 days ago

VishalRathoreSM commented 6 days ago

Environment

  System:
    OS: macOS 14.5
    CPU: (10) arm64 Apple M1 Pro
    Memory: 18.81 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.17.1 - ~/.nvm/versions/node/v18.17.1/bin/node
    Yarn: 1.22.17 - /usr/local/bin/yarn
    npm: 9.6.7 - ~/.nvm/versions/node/v18.17.1/bin/npm
    bun: 1.1.34 - ~/.nvm/versions/node/v18.17.1/bin/bun
    Watchman: 2023.01.16.00 - /usr/local/bin/watchman
  Browsers:
    Brave Browser: 131.1.73.89
    Chrome: 131.0.6778.70
    Safari: 17.5

Reproduction URL

https://github.com/FusionAuth/fusionauth-quickstart-javascript-nextjs-web

Describe the issue

export async function getAuthorizationUrl(query, options) {
  const { logger, provider } = options;

  let url = provider.authorization?.url;
  let as;

  // Falls back to authjs.dev if the user only passed params
  if (!url || url.host === 'authjs.dev' || true) {
    // If url is undefined, we assume that issuer is always defined
    // We check this in assert.ts
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    const issuer = new URL(provider.issuer);
    const discoveryResponse = await o.discoveryRequest(**issuer**);
    const as = await o.processDiscoveryResponse(issuer, discoveryResponse);
    if (!as.authorization_endpoint) {
      throw new TypeError(
        'Authorization server did not provide an authorization endpoint.'
      );
    }
    url = new URL(as.authorization_endpoint);

  }
  export async function discoveryRequest(issuerIdentifier, options) {
    if (!(issuerIdentifier instanceof URL)) {
        throw new TypeError('"issuerIdentifier" must be an instance of URL');
    }
    if (issuerIdentifier.protocol !== 'https:' && issuerIdentifier.protocol !== 'http:') {
        throw new TypeError('"issuer.protocol" must be "https:" or "http:"');
    }
    const url = new URL(issuerIdentifier.href);
    switch (options?.algorithm) {
        case undefined:
        case 'oidc':
            url.pathname = `${url.pathname}/.well-known/openid-configuration`.replace('//', '/');
            break;
        case 'oauth2':
            if (url.pathname === '/') {
                url.pathname = '.well-known/oauth-authorization-server';
            }
            else {
                url.pathname = `.well-known/oauth-authorization-server/${url.pathname}`.replace('//', '/');
            }
            break;
        default:
            throw new TypeError('"options.algorithm" must be "oidc" (default), or "oauth2"');
    }
    const headers = prepareHeaders(options?.headers);
    headers.set('accept', 'application/json');
    return (options?.[customFetch] || fetch)(url.href, {
        headers: Object.fromEntries(headers.entries()),
        method: 'GET',
        redirect: 'manual',
        signal: options?.signal ? signal(options.signal) : null,
    }).then(processDpopNonce);
}

As you can see above, we are passing issuer in discoveryRequest function which always results in response from the default tenant of our provider instead of the tenant whose id we have passed while configuring our provider. This can fetch incorrect authorization url from default tenant.

How to reproduce

  1. https://fusionauth.io/docs/quickstarts/quickstart-javascript-nextjs-web Follow this guide to setup
  2. Create one more tenant besides default tenant on fusionauth admin dashboard.
  3. Make some configuration different from default tenant.
  4. Pass this tenantId in options while configuring FusionAuthProvider
  5. export const fusionAuthProvider = FusionAuthProvider({
    issuer: fusionAuthIssuer,
    clientId: fusionAuthClientId,
    clientSecret: fusionAuthClientSecret,
    tenantId: fusionAuthTenantId,  ==> **here**
  6. Open local server on frontend and signIn
  7. You will get information from default tenant instead of the tenantId you have passed

Expected behavior

We should be passing provider.wellKnown in discoveryRequest function everywhere as it already takes its correct tenant well known url into account.