nextauthjs / next-auth

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

FusionAuth - Handle www-authenticate challenges as needed #8745

Open alex-fusionauth opened 1 year ago

alex-fusionauth commented 1 year ago

Provider type

FusionAuth

Environment

System: OS: macOS 13.4.1 CPU: (12) arm64 Apple M2 Pro Memory: 1.70 GB / 32.00 GB Shell: 5.9 - /bin/zsh Binaries: Node: 20.6.1 - /opt/homebrew/bin/node npm: 9.8.1 - /opt/homebrew/bin/npm pnpm: 8.7.6 - /opt/homebrew/bin/pnpm Browsers: Brave Browser: 117.1.58.129 Chrome: 117.0.5938.92 Safari: 16.5.1

"dependencies": { "@auth/core": "latest", "@auth/sveltekit": "latest" },

Reproduction URL

https://github.com/alex-fusionauth/fusionauth-sveltekit

Describe the issue

Trying to find why Auth.js is throwing TODO: Handle www-authenticate challenges as needed. It appears that in the package oauth4webapi the method parseWwwAuthenticateChallenges is called and brings back WWW-Authenticate header from the code grant response. This has scheme:'basic' listed which causes the error.

Origin of issue

    let challenges;
    if ((challenges = o.parseWwwAuthenticateChallenges(codeGrantResponse))) {
        for (const challenge of challenges) {
            console.log("challenge", challenge);
        }
        throw new Error("TODO: Handle www-authenticate challenges as needed");
    }

Should the user or FusionAuth be handling this somehow?

How to reproduce

You will need docker.

  1. run docker compose up -d
  2. cd complete-example
  3. copy .env.example to .env
  4. npm run dev
  5. click sing in button
  6. sign in using richard@example.com with password: password
image

Chooose provider while signing in

image

Error thrown:

image
challenge { scheme: 'basic', parameters: {} }
[auth][error][CallbackRouteError]: Read more at https://errors.authjs.dev#callbackrouteerror
[auth][cause]: Error: TODO: Handle www-authenticate challenges as needed
    at handleOAuth (file:///Users/afa/dev/inversoft/fusionauth/fusionauth-quickstart-javascript-sveltekit-web/complete-application/node_modules/@auth/sveltekit/node_modules/@auth/core/lib/oauth/callback.js:69:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Module.callback (file:///Users/afa/dev/inversoft/fusionauth/fusionauth-quickstart-javascript-sveltekit-web/complete-application/node_modules/@auth/sveltekit/node_modules/@auth/core/lib/routes/callback.js:20:41)
    at async AuthInternal (file:///Users/afa/dev/inversoft/fusionauth/fusionauth-quickstart-javascript-sveltekit-web/complete-application/node_modules/@auth/sveltekit/node_modules/@auth/core/lib/index.js:65:38)
    at async Proxy.Auth (file:///Users/afa/dev/inversoft/fusionauth/fusionauth-quickstart-javascript-sveltekit-web/complete-application/node_modules/@auth/sveltekit/node_modules/@auth/core/index.js:100:30)
    at async Module.respond (/Users/afa/dev/inversoft/fusionauth/fusionauth-quickstart-javascript-sveltekit-web/complete-application/node_modules/@sveltejs/kit/src/runtime/server/respond.js:282:20)
    at async file:///Users/afa/dev/inversoft/fusionauth/fusionauth-quickstart-javascript-sveltekit-web/complete-application/node_modules/@sveltejs/kit/src/exports/vite/dev/index.js:510:22
[auth][details]: {
  "provider": "fusionauth"
}

Expected behavior

There should be no error. Login should continue as the AuthToken is good.

alex-fusionauth commented 1 year ago

Just a note I am the DevRel at FusionAuth, happy to work through how to make this valid.

marckustech commented 1 year ago

I've been dealing with this Discord provider issue for, like, a whole day now. The weird thing is, when I use it, I don't even get an error message or anything. I just get sent to this http://localhost:3000/api/auth/error?error= page, and there are no errors in the URL or in my logs.

The crazy part is, when I deploy it on Vercel, it works perfectly fine. This situation seriously sucks! image

ThangHuuVu commented 11 months ago

This is a part that we haven't tacked in the core package. If you are willing to contribute a PR, I'm happy to take a look @alex-fusionauth . It would solve the issue not only for FusionAuth but for all auth providers which return WWWAuthenticateChallenge

sohnemann commented 10 months ago

Tried to implement Auth.js with SvelteKit and got stuck here also. Any idea what to look for?

hardylr commented 10 months ago

Same here. I tried to implement Auth.js with SvelteKit using Okta and got stuck here also. How do we handle WWWAuthenticateChallenge?

dhadrien commented 10 months ago

Hey @ThangHuuVu, I am also having the issue with the Notion provider fyi

hardylr commented 10 months ago

I managed to get Auth.js working with SvelteKit and Okta. Seems like you do not need to set a clientSecret when using Okta when setting token_endpoint_auth_method: "none". Hope this helps.

export const handle = SvelteKitAuth({
  providers: [
    Okta({
          clientId: OKTA_CLIENT_ID,
          //clientSecret: OKTA_CLIENT_SECRET, // DO NOT SET!
          //https://github.com/nextauthjs/next-auth/issues/3540#issuecomment-1021807328
          issuer: OKTA_ISSUER,
          checks: ["pkce", "state"],
          client: {
            token_endpoint_auth_method: "none",
          }          
        }) as Provider
  ]  
})
luis815 commented 8 months ago

Hi everyone!

Not sure if this would help anyone, but I resolved a careless mistake from my end for an error like the above (SvelteKit and Discord):

challenge {
  scheme: 'basic',
  parameters: { error: 'invalid_client', error_description: '' }
}
[auth][error] CallbackRouteError: Read more at https://errors.authjs.dev#callbackrouteerror
[auth][cause]: Error: TODO: Handle www-authenticate challenges as needed

The "invalid_client" error indicated that client secret was incorrect.

Cheers!

UlasCanAk commented 8 months ago

Hey everyone, running in this same exact issue no matter what I do. Is there any solution to this? I tried following this guide: https://fusionauth.io/docs/quickstarts/quickstart-javascript-nextjs-web#authentication and I'm getting

` challenge { scheme: 'basic', parameters: {} } [auth][error][CallbackRouteError]: Read more at https://errors.authjs.dev#callbackrouteerror [auth][cause]: Error: TODO: Handle www-authenticate challenges as needed

"provider": "fusionauth" } `

I also tried setting token_endpoint_auth_method to "none" and "client_secret_basic", none of them worked sadly.

I also get an "Invalid URL" error when trying to configure the Provider as it's shown in the guide. Instead I have to provide the authorization and token endpoint manually:

authorization: `https://${env.FUSIONAUTH_ISSUER}/oauth2/authorize`,
token: `https://${env.FUSIONAUTH_ISSUER}/oauth2/token`,

I'm on 5.0.0-beta.2 of next-auth and 0.20.0 of @auth/core.

Thank you!

alex-fusionauth commented 8 months ago

Hey everyone, running in this same exact issue no matter what I do. Is there any solution to this? I tried following this guide: https://fusionauth.io/docs/quickstarts/quickstart-javascript-nextjs-web#authentication and I'm getting

challenge { scheme: 'basic', parameters: {} } [auth][error][CallbackRouteError]: Read more at https://errors.authjs.dev#callbackrouteerror [auth][cause]: Error: TODO: Handle www-authenticate challenges as needed [auth][details]: { "provider": "fusionauth" }

I also tried setting token_endpoint_auth_method to "none" and "client_secret_basic", none of them worked sadly.

I also get an "Invalid URL" error when trying to configure the Provider as it's shown in the guide. Instead I have to provide the authorization and token endpoint manually:

authorization: `https://${env.FUSIONAUTH_ISSUER}/oauth2/authorize`,
token: `https://${env.FUSIONAUTH_ISSUER}/oauth2/token`,

I'm on 5.0.0-beta.2 of next-auth and 0.20.0 of @auth/core.

Thank you!

@UlasCanAk This looks like it is a config issue within fusionauth, might be better to post on our community forum or if you ping me on our Slack I can help you directly https://fusionauth.io/community

firebotQL commented 8 months ago

From my understanding, the WWW-Authenticate header should only be included in a 401 response and not with other statuses, as per the specification in the linked RFC.

I'm wondering why we'd have to include this in a 200 response. It would be great to get some clarification on this from @alex-fusionauth or any other FusionAuth devs.

In the meantime, I've provided a solution (FusionAuth provider with config for v5 next-auth@beta) to remove the header from within the response. This should help avoid the challenge exception users have been having in this thread, and allow the rest of the auth process to proceed smoothly:

Fusionauth({
      clientId: process.env.FUSIONAUTH_CLIENT_ID,
      clientSecret: process.env.FUSIONAUTH_CLIENT_SECRET,
      tenantId: process.env.FUSIONAUTH_TENANT_ID,
      issuer: process.env.FUSIONAUTH_ISSUER,
      userinfo: process.env.FUSIONAUTH_OAUTH_USERINFO_ENDPOINT,
      authorization: {
        url: process.env.FUSIONAUTH_OAUTH_AUTHORIZE_ENDPOINT,
        params: {
          scope: "offline_access",
        },
      },
      token: {
        url: process.env.FUSIONAUTH_OAUTH_TOKEN_ENDPOINT,
        conform: async (response: Response) => {
          if (response.status === 401) return response;

          const newHeaders = Array.from(response.headers.entries())
            .filter(([key]) => key.toLowerCase() !== "www-authenticate")
            .reduce((headers, [key, value]) => (headers.append(key, value), headers), new Headers());

          return new Response(response.body, {
            status: response.status,
            statusText: response.statusText,
            headers: newHeaders,
          });
        },
      },
    }),
robotdan commented 7 months ago

Thanks @firebotQL - I can speak on behalf of FusionAuth.

In section 4.1 of RFC 7235 where it describes that when a 401 is returned this header must be added, it also says the server may respond with this header for other responses. It isn't explicit, but this sounds like it is ok to return this header on a 200 as well.

A server MAY generate a WWW-Authenticate header field in other response messages to indicate that supplying credentials (or different credentials) might affect the response.

My guess is that is why we are always returning it. This statement in the RFC isn't exactly crystal clear if "other response messages" means other response codes than 401 or something else. If I have the correct understanding (I may not) of "other messages", would it be safe to ignore this header unless the status code is also a 401?

I will do some additional research, and we can revisit our current behavior to see if there was any historical reason to always write this header, or if we just made an assumption that it was ok to always return it.

Thank you for adding this work around while we investigate further! Much appreciated.

I opened this issue in FusionAuth to investigate and track as well.

alex-fusionauth commented 4 months ago

I have added a new Issue/PR to update FusionAuth defaults to better represent our needs. Users should be able to override as they see fit. We can back out the token.conform once it is merged into the core release.

Issue: https://github.com/nextauthjs/next-auth/issues/10867 PR: https://github.com/nextauthjs/next-auth/issues/10868