Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to set accessToken in signIn callback #894

Closed
3 of 5 tasks
larsfoll opened this issue Dec 1, 2020 · 7 comments
Closed
3 of 5 tasks

Unable to set accessToken in signIn callback #894

larsfoll opened this issue Dec 1, 2020 · 7 comments
Labels
question Ask how to do something or how something works

Comments

@larsfoll
Copy link

larsfoll commented Dec 1, 2020

Your question
Unable to set accessToken in signIn callback

What are you trying to do
I'm trying to add an accessToken to the session object coming from a custom backend.
When the user signs in we fetch an accessToken from a custom backend in the signIn callback.
Still in the signIn callback we set the accessToken on the user user.accessToken = data.authToken.

In the jwt callback we check for a user, if present we add the accessToken from the user - at this stage we do not have the fetched accessToken anymore as a result we can't access it in the session either.

  callbacks: {
    signIn: async (user: CurrentUser, account) => {
      try {
        const response = await fetch(
          `${SERVER_URL}/api/account/auth-token?accountId=${account.id}`,
        );
        if (!response.ok) {
          throw new Error('Failed to generate token.');
        }
        const data = await response.json();
        user.accessToken = data.authToken;
        return Promise.resolve(true);
      } catch (error) {
        return Promise.reject('/');
      }
    },
    jwt: async (token, user: CurrentUser) => {
      if (user) {
        token = {
          id: user.id,
          accessToken: user.accessToken || 'NO TOKEN FOUND',
        };
      }
      return Promise.resolve(token);
    },
    session: async (session: Session, token: any) => {
      session.accessToken = token.accessToken;
      session.user.id = token.id;
      return Promise.resolve(session);
    },
  },

Feedback
I followed the referred to example but to no avail. Is it possible the referred to document is outdated and this is no longer possible? Staring at it for quite a while, am I missing something obvious? Thanks in advance!

  • Found the documentation helpful
  • Found documentation but was incomplete
  • Could not find relevant documentation
  • Found the example project helpful
  • Did not find the example project helpful
@larsfoll larsfoll added the question Ask how to do something or how something works label Dec 1, 2020
@balazsorban44
Copy link
Member

balazsorban44 commented Dec 1, 2020

Hi there!

You could fetch the access token in the jwt callback as well. In addition to user, you will also get the account in jwt, if it's the first time jwt is called.
It's the third parameter. 🙂

From your example, it looks like you only need the account ID. I am curious though, do you take other measures to get hold of an access token besides sending an account ID? please prove me wrong but from your code example, it looks like I could get an excess token for a user, if I know their ID.

A standard way of getting an access token is using OAuth authorization flow, which next-auth supports out of the box, if your Identity Provider is OAuth compliant.

Relevant documentation:

https://auth0.com/docs/flows/authorization-code-flow (example)

https://next-auth.js.org/configuration/callbacks#jwt-callback

@larsfoll
Copy link
Author

larsfoll commented Dec 1, 2020

Hi,

Thanks already, getting the token in the jwt callback indeed works.

No that's still a big flaw, Azure AD B2C is being used.
I guess following these docs I should be able to retrieve the access tokens.

Thanks!

@balazsorban44
Copy link
Member

balazsorban44 commented Dec 1, 2020

https://docs.microsoft.com/en-us/azure/active-directory-b2c/authorization-code-flow#2-get-an-access-token
Looking at this, you can actually configure next-auth to receive your token at sign-in automatically.

You should be able to configure it with a custom provider's accesstoken url https://next-auth.js.org/configuration/providers#using-a-custom-provider

Keep an eye on #809 ;)

@larsfoll
Copy link
Author

larsfoll commented Dec 1, 2020

Great to hear that this'll be a built-in provider! 👏

At the moment my custom provider works like a charm, except getting the accessToken doesn't seem to work yet.
I presume this should be returned in the account?
Current example of what gets returned

  account: {
    provider: 'azureb2c',
    type: 'oauth',
    id: '10299'-3904....,
    refreshToken: 'eyJr.....',
    accessToken: undefined,
    accessTokenExpires: null
  },

I'll go over the steps again , probably missed something.

Provider:

    {
      id: 'azureb2c',
      name: 'Azure B2C',
      type: 'oauth',
      version: '2.0',
      scope: 'offline_access openid',
      params: {
        grant_type: 'authorization_code',
      },
      accessTokenUrl: `https://${TENANT_NAME}.b2clogin.com/${TENANT_NAME}.onmicrosoft.com/oauth2/v2.0/token?p=${USER_FLOW}`,
      authorizationUrl: `https://${TENANT_NAME}.b2clogin.com/${TENANT_NAME}.onmicrosoft.com/oauth2/v2.0/authorize?p=${USER_FLOW}&nonce=defaultNonce&response_type=code+id_token&prompt=login&response_mode=form_post`,
      profileUrl: 'https://graph.microsoft.com/oidc/userinfo',
      profile: (profile) => {
        return {
          id: profile.oid,
          firstName: profile.given_name,
          lastName: profile.family_name,
          email: profile?.emails?.[0],
        };
      },
      clientId: CLIENT_ID,
      clientSecret: CLIENT_SECRET,
      idToken: true,
      state: false,
    },
  session: {
    jwt: true,
  },
  jwt: {
    secret: JWT_SECRET,
  },

@balazsorban44
Copy link
Member

You can try adding debug: true to your NextAuth config, for a more verbose logging, maybe it will be easier to detect where the accessToken disappears. If it is there at a point, it means the token gets lost in NextAuth, in that case it is a bug.

If you are comfortable with the OAUTH spec, you can try re-playing the steps of an authentication from Postman, and see that the access_token actually gets sent where it needs to be, or is it a configuration issue in your Azure setup. If that is the case, the error is not in next-auth.

@larsfoll
Copy link
Author

larsfoll commented Dec 2, 2020

Jep the debug is very helpful, I'm not getting the accessToken back at all from azure.
The problem of not getting the accessToken back is referenced in this issue as well. So as far as I'm concerned this issue can be closed.
Big thanks already!

@larsfoll larsfoll closed this as completed Dec 2, 2020
@longfellowone
Copy link

longfellowone commented Feb 20, 2022

Hi there!

You could fetch the access token in the jwt callback as well. In addition to user, you will also get the account in jwt, if it's the first time jwt is called. It's the third parameter. 🙂

From your example, it looks like you only need the account ID. I am curious though, do you take other measures to get hold of an access token besides sending an account ID? please prove me wrong but from your code example, it looks like I could get an excess token for a user, if I know their ID.

A standard way of getting an access token is using OAuth authorization flow, which next-auth supports out of the box, if your Identity Provider is OAuth compliant.

Relevant documentation:

https://auth0.com/docs/flows/authorization-code-flow (example)

https://next-auth.js.org/configuration/callbacks#jwt-callback

You mention fetching the token in the jwt() callback. How do I deal with errors in this callback?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Ask how to do something or how something works
Projects
None yet
Development

No branches or pull requests

3 participants