Connected App - avoiding a limit on a number of issued tokens + token expiration

  • We have configured our web application to use OAuth2 with our SFDC Connected App. The connected app is configured to never expire the refresh token unless manually revoked. When an admin connects the Connected App to our web application it stores the refresh token received so that we can communicate with SFDC's APIs on behalf of that user later one. "Offline_access" and "refresh_token" are properly set on scope for that admin login page.

    The application will work throughout the day just fine but then suddenly returns the response below when attempting to retrieve a new access token using the stored refresh token.

    {"error_description":"expired access/refresh token","error":"invalid_grant"}

    I've looked over many settings and everything seems to be configured to never expire the refresh token. Are there other usages that can cause them to expire? Can using it too many times from our servers to request an access token cause it to expire? Are you supposed to refresh the refresh token?

    What is the recovery process once this happens? Right now the only solution we have is for the user to reauthorize the app which is a really bad scenario to be in as all communication attempts in the meantime just die.

    We also have normal users (non admin) who OAuth into a web app via our Connected App. Should we not be requesting "offline_access" and "refresh_token" in scope for normal users who just need to authenticate? We tried asking for nothing and bare minimums too but they don't seem to have an effect.

    I've seen hints from other questions here that say you can only ask for 5 refresh tokens before the last ones expire. We've tried signing in as an admin and user dozens of times to reproduce the issue but we can't trigger the problem. Are there other IP address restrictions or things we could look into as well?

    This may be related as well. When does the Use Count highlighted here increase? What does that number represent? Every successful OAuth exchange or only when certain refresh tokens or offline access are also requested? Is there a limit?

    Connected App User's Usage

    UPDATE - Feb 9 2015

    I checked the User Session Information tab after signing in with OAuth and I can see the newly created OAuth2 session there. The Valid Until definitely seems to be correlated to the 15min Timeout Value set for the account. I am under the impression that this value will expire the requested AccessToken and not the RefreshToken for the user.

    I can also confirm that using the RefreshToken after the Valid Until date has passed will reset the Valid Until date and give me a new session valid for 15 more minutes. Also, OAuth2 sessions do not seem to be associated with a parent session.

    User Session Information

    UPDATE - Feb 10 2015

    We were finally been able to reproduce the issue but I still do not understand the behavior we're seeing. To reproduce the issue I had to perform 4 consecutive logins using OAuth without performing a request for an AccessToken using the RefreshToken. On the 4th sign in we noticed that the Use Count would drop for some high number (10+ in our case) down to 4. But why 4? Here's what we've been able to deduce.

    Requesting an AccessToken/Session using the RefreshToken will always increase the Use Count but will not add a new session row in the Session Management list. You can perform this request as many times as you want. It has no effect on the currently assigned RefreshToken.

    Authenticating a user with OAuth seems to always add a new session row in the Session Management list. It will also increase the Use Count up to 4, but no higher. 4 seems to be some sort of magic number here. SFDC seems to create a new session for each successful authentication even if it's for the same user and the previous one hasn't expired yet. Once you pass 4 it seems to invalidate all your previous sessions and tokens.

    What's interesting is if you sign in 2 times, then programatically request an AccessToken/Session using the RefreshToken, then sign in an additional 2 more times you don't experience the issue. Using the RefreshToken has some effect on the current outstanding sessions for the user and will give you 4 more successful sign ins.

    Is this normal behavior? Should re-authenticating over and over again really create brand new sessions each time for the same user? Could this be because I'm not actually signing out via OAuth for each attempt? Does SFDC think that I'm signing in from different devices and there is a limit of 4 concurrent sessions?

    UPDATE - Feb 13 2015

    It looks like calling the revoke API between each sign in has no effect. I signed in as a user, signed out and called revoke to remove the access token from SF and repeated this 5 times. I can see the OAuth Session disappear from the Session Management list but on the 5th sign in the refresh token once again expired (and the Use Count on the Connected Apps OAuth Usage page once again dropped down to a static 4).

    It looks like my only option is to perform a Token Refresh after every single sign in.

    Did you increase the timeout in the session settings? Setup -> Security Controls -> Session Settings?

    A long shot perhaps, but have a look under Setup > Security Controls > Session Management > User Session Information. It lists both the Sessions and the parent Session Ids. Some big assumptions, but I'd guess that expiring the parent session also expires the child sessions. I'm not sure how the refresh token ties into a parent session. My wild guess would be the admin explicitly expiring the parent session, which also invalidates the refresh token. Of course, I could be way off the mark here.

    @EricSSH, wouldn't increasing the Timeout Value under Session Settings only increase the duration of the received AccessToken and not the RefreshToken? I believe an AccessToken is just a SF SessionID. I want to use my original RefreshToken to request a fresh AccessToken which will then be used to make other API calls to SFDC on behalf of that user. My problem seems to be that the RefreshToken itself is expiring.

    I think you need to keep the refresh token and swap it with the access token in order to keep the the session active.

    Re: your most recent update comment, I'm pretty sure the limit for concurrent sessions is 5 per user. 1 web session + 4 active OAuth tokens would put you at the limit.

    @JonathanHersh One thing that wasn't mentioned is that this is only related to the person who connected to the app. If Person A authorizes the connected app and then OAuths a bunch of times without requesting a refresh token the connected app's refresh token invalidates. If Person B OAuths a bunch of times everything is fine. Connected App authorization and OAuth authorization are connected, which is dangerous because an admin OAuthing a bunch could potentially crash an entire connected app for the org and not even realize it. This requires the admin to go back and reauth the connected app.

    How often are you facing this error?

    Also, can you confirm what do you see under Permitted Users in Connected Apps -> Manage

    As described above, this issue happens after every 5 successful sign-ins using OAuth. Permitted Users is set to: "All users may self-authorize". Refresh Token Policy is set to: "Refresh token is valid until revoked".

    I am wondering how your users authenticate to your app. I'm curious to see if each time a user authenticates if you are then requesting a new token even though there is an existing token out there that would be eligible to be used hence incrementing the counter. On your user model of your app are you storing the Salesforce token and refresh token?

  • metadaddy

    metadaddy Correct answer

    6 years ago

    I see you've discovered most of this for yourself, but I had this drafted, so I thought I'd post it also, in case it fills in any gaps.

    From the docs on connected apps:

    An application may be listed more than once. Each time you grant access to an application, it obtains a new access token. Requests for refresh tokens increase the Use Count displayed for the application. You must grant access to your Salesforce data from each device that you use, for example, from both a laptop and a desktop computer. The default limit is five access tokens for each application. Newer applications (using the OAuth 2.0 protocol) are automatically approved for additional devices after you've granted access once. OAuth 2.0 applications can be listed more than once. Each row in the table represents a unique grant, so if an application requests multiple tokens with different scopes, you’ll see the same application multiple times.

    A given user may only have 5 access tokens authorized for a given connected app. Since each refresh token can potentially issue an access token, they are counted in that total. The way to think about this is that only the most recent 5 authorizations are valid. When the user goes through login the sixth time, the oldest authorization is invalidated and that refresh token will no longer work.

    How do you manage this? Don't ask for a refresh token if you're not going to use it. Don't use the same connected app for interactive and 'batch' operations. If you want to keep a refresh token around, then create a connected app for that purpose, and use a different one for login.

    Finally, consider using the JWT Bearer Token flow rather than holding on to a refresh token obtained interactively. It will give you much more predictable behavior.

    This is a better answer than the accepted answer because it provides guidance on how to work around the problem. I'm using omniauth in a Rails app and each time the user had to 'log into my app' using the OAuth flow, a new refresh_token was issued -- after the 5th login, the refresh_token that I had socked away after the 1st login was invalidated. This is a big drag. Not to mention how confusing it looks in the User's OAuth Apps list -- the same app is listed a zillion times:

License under CC-BY-SA with attribution

Content dated before 7/24/2021 11:53 AM