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

How to tell accessToken is set to null? #156

Closed
geraldnolan opened this issue May 24, 2020 · 9 comments
Closed

How to tell accessToken is set to null? #156

geraldnolan opened this issue May 24, 2020 · 9 comments
Labels
enhancement New feature or request question Ask how to do something or how something works stale Did not receive any activity for 60 days

Comments

@geraldnolan
Copy link
Contributor

Thanks for the project! I was testing out the new features today.
I was able to get it working with my custom IdentityServer.

 {
      id: 'IdentityServer4',
      name: 'IdentityServer4',
      type: 'oauth',
      version: '2.0',
      scope: 'profile openid email offline_access',
      params: { grant_type: 'authorization_code' },
      accessTokenUrl: process.env.IdentityServer4_URL + '/connect/token',
      requestTokenUrl: process.env.IdentityServer4_URL + '/connect/token',
      authorizationUrl: process.env.IdentityServer4_URL + '/connect/authorize?response_type=code',
      profileUrl: process.env.IdentityServer4_URL + '/connect/userinfo',
      profile: (profile) => {
        return {
          id: profile.sub,
          name: profile.name,
          email: profile.email,
        }
      },
      clientId: process.env.IdentityServer4_ID,
      clientSecret: process.env.IdentityServer4_SECRET
    },

On line 172 /src/server/lib/oauthcallback.js the accessToken is set to null. I was wondering why that is set to null?

There are a couple of issues with the model for a mysql database.

 accessToken: {
      type: 'text'
    },

  sessionExpires: {
      type: 'datetime'
    },

My question is how would one go about getting access to original accessToken to make calls to another micro service api? Also, I may have missed it in the documentation how would you refresh the token once it expired?

@geraldnolan geraldnolan changed the title IdentityServer4 accessToken IdentityServer4 accessToken to null May 24, 2020
@geraldnolan geraldnolan changed the title IdentityServer4 accessToken to null IdentityServer4 accessToken is set to null May 24, 2020
@LoriKarikari LoriKarikari added the question Ask how to do something or how something works label May 24, 2020
@iaincollins iaincollins added the bug Something isn't working label May 25, 2020
@iaincollins iaincollins added this to the 2.0 milestone May 25, 2020
@iaincollins
Copy link
Member

My question is how would one go about getting access to original accessToken to make calls to another micro service api? Also, I may have missed it in the documentation how would you refresh the token once it expired?

There isn't an API call to get the token yet, and there isn't one to use a refresh token to get a new access token. Currently folks will need to write their own logic to do this (i.e. look up the user by ID and query the table to get the access token themselves).

I would like to support this with /api routes out of the box, but it's not going to be ready in time for 2.0.

A thing that would be helpful in the interim is a document (a short writeup in markdown) that provides an example of creating an /api route to do this if anyone has time for that.

I actually have some good reference code for doing this with Google as an example if anyone is interested in that (been using it production for a couple of years with no issues).

@iaincollins
Copy link
Member

On line 172 /src/server/lib/oauthcallback.js the accessToken is set to null. I was wondering why that is set to null?

Hmm I don't know. Now there is a debug flag in the options, I could add in more debug statements into this function to make it easier to see the raw request/response.

(As per comments in that file, it needs refactoring a bit, as the code in there has grown a little wild, but I'm reluctant to get to that too soon as subtle changes can break things for some providers.)

@iaincollins
Copy link
Member

There are a couple of issues with the model for a mysql database.

accessToken: {
type: 'text'
},

sessionExpires: {
type: 'datetime'
},

Thanks! I'm going to be looking at this today. I'm not sure what the problem is, if you have any background on it that would be great. Probably worth raising as a separate issue so can more easily discuss/track progress.

@iaincollins
Copy link
Member

Update: Both the properties above have now been updated to resolve issues with them for 2.0.

I'm not sure why the 'accessToken' would be null on the service, and can't say without having access to debug the calls.

It might be appropriate to look at improving debug messages in 2.1 to make it easier to view requests and responses to make debugging issues like this easier.

@iaincollins iaincollins modified the milestones: 2.0, 2.1 May 26, 2020
@iaincollins iaincollins changed the title IdentityServer4 accessToken is set to null How to tell accessToken is set to null? May 26, 2020
@iaincollins iaincollins added enhancement New feature or request and removed bug Something isn't working labels May 26, 2020
@geraldnolan
Copy link
Contributor Author

There isn't an API call to get the token yet, and there isn't one to use a refresh token to get a new access token. Currently folks will need to write their own logic to do this (i.e. look up the user by ID and query the table to get the access token themselves).

I would like to support this with /api routes out of the box, but it's not going to be ready in time for 2.0.

A thing that would be helpful in the interim is a document (a short writeup in markdown) that provides an example of creating an /api route to do this if anyone has time for that.

I actually have some good reference code for doing this with Google as an example if anyone is interested in that (been using it production for a couple of years with no issues).

@iaincollins Can you point me to your reference code? I'll take a stab at it.

@iaincollins
Copy link
Member

Oh thanks!

It's not an open source project (it's in a private repo of my small company) but sharing the code below! Hopefully makes sense out of context.

It looks like I'm using the Google API here, and I think best to create an option for a refresh access REST token endpoint (if needed) instead of pulling in the actual Google API (as pulling in a load of provider specific APIs would bloat the module quite quickly).

Not sure if it is endpoint as is used for auth or if it's worthing having a new property in provider profile (that seems like the way to go?)

// @TODO Account credentials should be stored with User object not session
// (so that one account can have more than one active session)
const updateGoogleAccessTokens = (session) => {
  return new Promise((resolve, reject) => {
    if (!session || !session.session || !session.session.google || !session.session.google.refreshToken)
      return resolve(session)
              
    // If we have an expory date for the token and it's still good then we don't
    // need to get a new one. We compare the time with 5 minutes before actual
    // expiry to allow for clock drift between hosts.
    if (session.session.google.accessTokenExpires &&
        (session.session.google.accessTokenExpires - 60000 * 5) > new Date().getTime())
      return resolve(session)

   // Create oAuth2 client instance using our credentials and the users tokens
    const oauth2Client = new google.auth.OAuth2(
      process.env.GOOGLE_ID,
      process.env.GOOGLE_SECRET
    )

    oauth2Client.setCredentials({
      access_token: session.session.google.accessToken || null,
      refresh_token: session.session.google.refreshToken
    })

    oauth2Client.refreshAccessToken((err, tokens) => {
      if (err) {
        console.error("Using Google RefreshToken to get new AccessToken failed\n", err)
        return reject()
      }
 
      session.session.google.refreshToken = tokens.refresh_token
      session.session.google.accessToken = tokens.access_token
      session.session.google.accessTokenExpires = tokens.expiry_date
      
      session.save(err => {
        if (err) return reject(err)
        return resolve(session)
      })
    })
    
  })
}

@simonbbyrne
Copy link

@iaincollins Would it possible to show an example of this in the context of the nextAuth callbacks? I'm thinking that the expiry check and access token fetching can be done in the jwt callback?

@stale
Copy link

stale bot commented Dec 5, 2020

Hi there! It looks like this issue hasn't had any activity for a while. It will be closed if no further activity occurs. If you think your issue is still relevant, feel free to comment on it to keep ot open. Thanks!

@stale stale bot added the stale Did not receive any activity for 60 days label Dec 5, 2020
@stale
Copy link

stale bot commented Dec 12, 2020

Hi there! It looks like this issue hasn't had any activity for a while. To keep things tidy, I am going to close this issue for now. If you think your issue is still relevant, just leave a comment and I will reopen it. (Read more at #912) Thanks!

@stale stale bot closed this as completed Dec 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Ask how to do something or how something works stale Did not receive any activity for 60 days
Projects
None yet
Development

No branches or pull requests

4 participants