next-auth icon indicating copy to clipboard operation
next-auth copied to clipboard

callbackUrl not working when signIn with apple

Open quypb opened this issue 3 years ago • 14 comments

Description 🐜

When I sign in with apple or google I want to navigate back to current page (the page when click sigin button). It's work with google and but when I sign in with apple, it's always navigate to home page.

Hope that everyone can help me fix this bug. Thank you so much.

How to reproduce ☕️

Here is the next-auth config image

And the function handle signin. image image

Environment 🖥

"next-auth": "^3.25.0", "next": "^10.2.0",

System: OS: macOS 11.4 CPU: (8) x64 Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz Memory: 363.25 MB / 16.00 GB Shell: 5.8 - /bin/zsh Binaries: Node: 14.15.0 - ~/.nvm/versions/node/v14.15.0/bin/node Yarn: 1.22.10 - /usr/local/bin/yarn npm: 6.14.8 - ~/.nvm/versions/node/v14.15.0/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman Browsers: Chrome: 91.0.4472.77 Safari: 14.1.1

quypb avatar Jun 03 '21 16:06 quypb

You don't need to define the callbackUrl if you only want to return to the same page, it's the default behaviour already. It sounds strange though that it works for one provider but not the other.

I'm wondering if this section is relevant, have you seen it?: https://next-auth.js.org/providers/apple#testing

Aside from that, any good reason for using useSecureCookies: false? Hope it's not in production, because it is a security risk. I would also not expose the idToken to the client through the session callback like that. Curious what you are trying to achieve with it. 🤔

balazsorban44 avatar Jun 04 '21 07:06 balazsorban44

@balazsorban44 About useSecureCookies, I use it for testing only. I've checked the logs in callbacks: redirect function. The current url still be keep when we navigate from webpage to apple authorize page. But when we navigate back to webpage it auto reset to root url.

quypb avatar Jun 04 '21 13:06 quypb

@balazsorban44 I think it related to this lines. Because I see that the callback cookies has reset to baseUrl when navigating from apple authorize page to my website.

https://github.com/nextauthjs/next-auth/blob/71f63117a9576d22f8958c6ee9492a09e21b39a6/src/server/lib/callback-url-handler.js#L27-L30

quypb avatar Jun 04 '21 17:06 quypb

I had similar issues with azureb2c, this might offer a temporary alternative for testing until issue is fixed 👇🏾

https://github.com/nextauthjs/next-auth/issues/1542#issuecomment-812409291

innowhat avatar Aug 06 '21 03:08 innowhat

I also have the same issue with apple login.

I have the same login flow with facebook , google , which run ok but only apple doesn't..

kidmysoul avatar Sep 01 '21 12:09 kidmysoul

I was able to fix the issue in azureb2c by adjusting the response_mode value in the AuthorizationUrl from form_post to query

Examples : authorizationUrl: https://${tenantName}.b2clogin.com/${tenantName}.onmicrosoft.com/${loginFlow}/oauth2/v2.0/authorize?response_type=code+id_token+token&response_mode=query,

Hope this helps

innowhat avatar Sep 01 '21 13:09 innowhat

Thank you @innowhat for the workaround, worked fine with Apple. However setting the response_mode to query doesn't allow any scope to be used to retrieve user info, sadly (although at this time scopes are also broken for Apple login)

gentlementlegen avatar Mar 07 '22 17:03 gentlementlegen

I'm experiencing this issue too. @FernandVEYRIER @innowhat - How can I use your response_mode workaround? Would I need to fork the repo and then edit packages/next-auth/src/providers/apple.ts?

KristenWilde avatar Apr 12 '22 13:04 KristenWilde

Hi @KristenWilde, I have never used apple as a provider so cant really tell if the work around applies there as well. Anyways, you could try overriding your apple provider while using the 'query' response_mode, and if works then perhaps you could raise a PR for a fix.

Here is an example of how it could look like, hope this helps.

export default NextAuth({
  providers: [
    {
      id: 'apple',
      name: 'Apple',
      type: 'oauth',
      version: '2.0',
      wellKnown: 'https://appleid.apple.com/.well-known/openid-configuration',
      authorization: {
        // note we use 'query' instead of 'form_post' here
        params: { scope: 'name email', response_mode: 'query' },
      },
      checks: ['pkce'],
      idToken: true,
      profile(profile) {
           ...
        }
      },
      options: {
        clientId: '',
        clientSecret: '',

        /**
   * Apple requires the client secret to be a JWT. You can generate one using the following script:
   * https://bal.so/apple-gen-secret
   * 
   * Read more: [Creating the Client Secret
](https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens#3262048)
   */
      },
    },
  ],
  ...
})

Note: this only applies to next-auth4 or later

innowhat avatar Apr 12 '22 18:04 innowhat

Hi @KristenWilde, I have never used apple as a provider so cant really tell if the work around applies there as well. Anyways, you could try overriding your apple provider while using the 'query' response_mode, and if works then perhaps you could raise a PR for a fix.

Here is an example of how it could look like, hope this helps.

export default NextAuth({
  providers: [
    {
      id: 'apple',
      name: 'Apple',
      type: 'oauth',
      version: '2.0',
      wellKnown: 'https://appleid.apple.com/.well-known/openid-configuration',
      authorization: {
        // note we use 'query' instead of 'form_post' here
        params: { scope: 'name email', response_mode: 'query' },
      },
      checks: ['pkce'],
      idToken: true,
      profile(profile) {
           ...
        }
      },
      options: {
        clientId: '',
        clientSecret: '',

        /**
   * Apple requires the client secret to be a JWT. You can generate one using the following script:
   * https://bal.so/apple-gen-secret
   * 
   * Read more: [Creating the Client Secret
](https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens#3262048)
   */
      },
    },
  ],
  ...
})

Note: this only applies to next-auth4 or later

From my experience the scope doesn't work when setting the response_mode to query., and Apple denies the login. Removing the scope parameter fixes the problem.

gentlementlegen avatar Apr 14 '22 22:04 gentlementlegen

Thanks @FernandVEYRIER and @innowhat! I am using an older version of next-auth, but it was easy to change the response_mode and remove the scope in the Providers.Apple config.

Providers.Apple({
        clientId: process.env.APPLE_ID,
        clientSecret: { ... },
        authorizationUrl:
          'https://appleid.apple.com/auth/authorize?response_type=code&id_token&response_mode=query', 
})

This worked for signing in and redirecting, but unfortunately my app doesn't work without the user's name and email.

KristenWilde avatar Apr 22 '22 18:04 KristenWilde

We got the Apple redirect working by changing the cookie config for the callbackUrl. sameSite: 'lax' was a problem so we added this to our config:

 cookies: {
  callbackUrl: {
      name: `__Secure-next-auth.callback-url`,
      options: {
        httpOnly: false,
        sameSite: 'none',
        path: '/',
        secure: true,
      },
    },

(still using next-auth version 3).

KristenWilde avatar Aug 11 '22 07:08 KristenWilde

@KristenWilde Thank you!

I think this fixed the root cause of the issue: missing cookies on a request coming in from https://appleid.apple.com/ to /api/auth/callback/apple.

Before adding your cookie config to next-auth options, that request looked like this (no cookies):

referer: https://appleid.apple.com/
url: /api/auth/callback/apple
method: POST
cookies: {}
body:  {
  code: 'some-code-here'
}

and after (with callback-url cookie):

referer: https://appleid.apple.com/
url: /api/auth/callback/apple
method: POST
cookies: {
  '__Secure-next-auth.callback-url': 'https://example.com/send-me-here
 }
 body: {
   code: 'some-code-here'
 }

This cookie value is then used as a redirect url, and user is successfully redirected to the path specified in signIn call:

  signIn("apple", {
    callbackUrl: "/send-me-here",
  })

And this is how my NextAuthOptions looks like now:

export const authOptions: NextAuthOptions = {
  cookies: {
    callbackUrl: {
      name: `__Secure-next-auth.callback-url`,
      options: {
        httpOnly: false,
        sameSite: "none",
        path: "/",
        secure: true,
      },
    },
  },
  providers: [
    Apple({
      authorization: {
        params: {
          scope: "name email",
          response_mode: "form_post",
          response_type: "code",
        },
      },
      clientId: process.env.APPLE_ID,
      clientSecret: "some-secret-here",
    }),
  ]
}        

Before finding out this fix I was going to submit the pull request where I added callbackUrl in NextAuthOptions. Then this callbackUrl would be used instead of url.origin as fallback in case when there is no callbackUrl in cookies, body or query params in requests coming in to /api/auth/callback/.

senad87 avatar Aug 18 '22 13:08 senad87

I tested locally. It seems using signIn like this solves the problem. In your Apple Login Button onClick

onClick={() => {
  signIn( 'apple', 
    { callbackUrl: "https://<your-redirect-url>" },
    { redirect_uri: "https://<your-redirect-url>" });
}}

Edit: But not works if you don't apply api/auth/callback/apple to end of your url, And with that, It does not working again. Edit2: @senad87 's solution works perfect 👌 Thanks.

muhammedogz avatar Aug 23 '22 19:08 muhammedogz