nextauthjs / next-auth

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

Cognito callback fails when using social idp #6865

Closed half2me closed 1 year ago

half2me commented 1 year ago

Provider type

Cognito

Environment

System: OS: macOS 13.2.1 CPU: (10) arm64 Apple M1 Max Memory: 2.95 GB / 32.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 19.7.0 - /opt/homebrew/bin/node npm: 9.5.0 - /opt/homebrew/bin/npm Browsers: Chrome: 110.0.5481.177 Firefox: 101.0 Safari: 16.3

Reproduction URL

https://sveltekit-authjs-houdini.pages.dev/

Describe the issue

I'm using SvelteKit and cognito login. Everything works as expected when I login using cognito with a regular email/pw combination. But, if I enable social login on cognito, and try to login with that, when it redirects me to my oauth callback, I get the following error from auth.js on the server:

[auth][error][CallbackRouteError]: Read more at https://errors.authjs.dev#callbackrouteerror
[auth][cause]: OperationProcessingError: unexpected ID Token "nonce" claim value
    at Module.processAuthorizationCodeOpenIDResponse (file:///.../node_modules/oauth4webapi/build/index.js:1016:23)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async handleOAuth (file:///.../node_modules/@auth/sveltekit/node_modules/@auth/core/lib/oauth/callback.js:79:24)
    at async Module.callback (file:///.../node_modules/@auth/sveltekit/node_modules/@auth/core/lib/routes/callback.js:14:41)
    at async AuthInternal (file:///.../node_modules/@auth/sveltekit/node_modules/@auth/core/lib/index.js:64:38)
    at async Proxy.Auth (file:///.../node_modules/@auth/sveltekit/node_modules/@auth/core/index.js:100:30)
    at async Module.respond (/node_modules/@sveltejs/kit/src/runtime/server/respond.js:248:20)
    at async file:///.../node_modules/@sveltejs/kit/src/exports/vite/dev/index.js:501:22
[auth][details]: {
  "provider": "cognito"
}
Screenshot 2023-03-03 at 00 18 55

After selecting a social login, I get redirected to: http://localhost:5173/auth/error?error=CallbackRouteError

Screenshot 2023-03-03 at 00 19 19

How to reproduce

The source is available here: https://github.com/half2me/sveltekit-authjs-houdini If you login/register with a normal username and password, it works. If you try to login with social, it fails.

Expected behavior

It should work just like username/password

half2me commented 1 year ago

Strangely enough if I go back and try again a second time, by clicking the login button, it immediately signs me in without even asking me which user to login as. (Clearly the user is already authenticated on cognito) So on subsequent tries this works fine. I'm not sure why it won't work on the first try.

half2me commented 1 year ago

@balazsorban44 I added a link to the full source code, along with a live deployed version of the site which produces this exact error that I've mentioned. What else should I provide?

balazsorban44 commented 1 year ago

Sorry, didn't see the source code link. :facepalm: Thanks!

half2me commented 1 year ago

Sorry, didn't see the source code link. Thanks!

no problem, let me know if you need any more details. This is quite an important issue for me, as its blocking our usage of Auth.js

half2me commented 1 year ago

@balazsorban44 is there anything more I can provide for this? This is quite urgent for us to fix.

balazsorban44 commented 1 year ago

Note that Auth.js is experimental currently. I'm sorry if it's urgent, the source code is public though. Feel free to have a look. šŸ™šŸ’š

From the error message, your IDP sent back a nonce in the ID token, even though the provider was not configured to do so.

So it might actually be a configuration issue rather than a bug, but I haven't looked at it closer yet.

balazsorban44 commented 1 year ago

If you do not provide a nonce value in your request, Amazon Cognito automatically generates and validates a nonce when you authenticate through a third-party identity provider, then adds it as a nonce claim to the ID token

https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-id-token.html

So apparently Cognito returns this nonce value even if it's not configured. This is not an Auth.js bug, just Cognito being a bit too eager.

You can add checks: ["nonce", "pkce"] to your provider config to force a matching nonce value.

https://authjs.dev/reference/core/providers#checks

half2me commented 1 year ago

@balazsorban44 thank you so much!

half2me commented 1 year ago

@balazsorban44 can we please reopen this issue? This does not fix it for me. Infact, when making this change, now the auth doesn't work at all. Always giving me:

[auth][error][CallbackRouteError]: Read more at https://errors.authjs.dev#callbackrouteerror
[auth][cause]: OperationProcessingError: unexpected ID Token "nonce" claim value
    at Module.processAuthorizationCodeOpenIDResponse (file:///.../sveltekit-authjs-houdini/node_modules/oauth4webapi/build/index.js:1034:23)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async handleOAuth (file:///.../sveltekit-authjs-houdini/node_modules/@auth/core/lib/oauth/callback.js:79:24)
    at async Module.callback (file:///.../sveltekit-authjs-houdini/node_modules/@auth/core/lib/routes/callback.js:14:41)
    at async AuthInternal (file:///.../sveltekit-authjs-houdini/node_modules/@auth/core/lib/index.js:64:38)
    at async Proxy.Auth (file:///.../sveltekit-authjs-houdini/node_modules/@auth/core/index.js:100:30)
    at async Module.respond (/node_modules/@sveltejs/kit/src/runtime/server/respond.js:248:20)
    at async file:///.../sveltekit-authjs-houdini/node_modules/@sveltejs/kit/src/exports/vite/dev/index.js:505:22
[auth][details]: {
  "provider": "cognito"
}

You can see in the same code I had before, this latest commit: https://github.com/half2me/sveltekit-authjs-houdini/commit/f4009e5ec84b6002aed59efd259d1040bb515ed0

Login now completely fails. I add this: checks: ['nonce', 'pkce']

half2me commented 1 year ago

Looks like others are facing this same issue though: https://github.com/nextauthjs/next-auth/discussions/3551

balazsorban44 commented 1 year ago

Unfortunately, I don't have a Cognito setup so I cannot dig deeper into this. In any case, Cognito should not send a nonce back if it's not required to do so. :thinking:

Could you check with checks: ["nonce"] only to see if that worked? We've had some issues with setting multiple cookies, maybe related to that. Check if the nonce cookie is created, as well as the authorization URL contains a nonce=value parameter when logging in.

After which, we should be comparing the id_token nonce value with the one saved in the cookie.

The error message you show says that we did not create a nonce cookie so the one sent in id_token should not exist.

half2me commented 1 year ago

@balazsorban44 I checked with checks: ["nonce"] and instead of just failing with social signIn, it fails now for any kind of signin. Same error:

[auth][error][CallbackRouteError]: Read more at https://errors.authjs.dev#callbackrouteerror
[auth][cause]: OperationProcessingError: unexpected ID Token "nonce" claim value

The next-auth.nonce cookie is created. The authorization url does have the nonce included and looks like this:

https://sveltekit-authjs-houdini.auth.eu-west-2.amazoncognito.com/oauth2/authorize?response_type=code&client_id=6kmf5kg4618mrndk5t0avrt34r&redirect_uri=http%3A%2F%2Flocalhost%3A5173%2Fauth%2Fcallback%2Fcognito&nonce=CBn-y3UYSmG-s43S7ySLIVwVpP83CF81pEtEpdQRY7A&scope=openid+profile+email

After clicking login, I get redirected back to my app at this url:

http://localhost:5173/auth/callback/cognito?code=334c18a1-68cb-484c-960b-9375bfbb8a6b

And that gives me the 302 to http://localhost:5173/auth/error?error=CallbackRouteError

half2me commented 1 year ago

@balazsorban44 from what I can tell, looking at the call stack: core/lib/oauth/callback.js has this:

if (provider.type === "oidc") {
        const result = await o.processAuthorizationCodeOpenIDResponse(as, client, codeGrantResponse);
        ...
}

The expectedNonce parameter is not set, which will default to undefined causing the issue.

half2me commented 1 year ago

@balazsorban44 I spent an hour today stepping through the code with the debugger. This seems to be a combination of two separate things. First, Cognito includes the nonce in the claims, when using social login, even if not requested to do so.

So the answer should be as simple as adding checks: ['pkce', 'nonce'] to the code. Unfortunately this nonce here is not respected and always treated as an error if returned in the claims. The processAuthorizationCodeOpenIDResponse expects a parameter: expectedNonce. This parameter is never set. It is always undefined therefore the code will never work.

So I don't understand, this fixes my problem right here: https://github.com/nextauthjs/next-auth/blob/99ca67f1cff24d77330ff662acf7aa57dd5793e7/packages/core/src/lib/oauth/callback.ts#L138

But I have the latest version of @auth/core and this line doesn't exist on my version v0.5.1

Okay, so this seems to be fixed in master but not in @auth/core. Should I be using a different version? I'm a bit confused about the versioning.

half2me commented 1 year ago

Just found the PR fixing this #6998 ... wish I had seen it earlier šŸ¤¦