My problem is figuring out when to refresh the access token.
I have read that I should refresh the new access token before each request, but it says elsewhere that this is not recommended. So my question is whether I should refresh the access token before each request or send the request and after receiving the 401 Unauthorized status refresh the access token and retry the request to the specified resource.
You can get the expiry time from the access token (usually at a field called exp and is formatted as unix timestamp). So whenever you prepare sending a HTTP request to the resource server , you can check that if the access token is already expired or about to be expired very soon (e.g 60 seconds).
If yes, try to use the refresh token to get a new access token , and update the returned new access token and refresh token that are stored inside your app. Otherwise , just keep using the existing access token.
You can do either way, you know when you access token is about to expire and for example 1 minute before, you use the refresh token to get a new set of refresh/access tokens.
Doing it on a 401 is also an option but that means that you need to do an extra request and you also have some race-conditions to watch out for, as in many configurations you only allow a one-time use of a refresh token (you get a new refresh token each time). So with the 401 approach, you need to make sure you don't sent away many concurrent requests to get new tokens for the same user.
Related
I'm creating an app that integrates with several 3rd-party Oauth2 providers (think Zapier). The user adds a connection through Oauth2 which gives me a refresh token and access token and which I'm storing in a database.
What is the best practice to keep the access token fresh? Should I be running an async job (e.g. cron) that refreshes the access token every 30 minutes for every connection? If the user doesn't use my app for several days I'd like to still be able to access his 3rd-party data without having him to go through the Oauth2 consent.
What is the best practice to keep the access token fresh? Should I be running an async job (e.g. cron) that refreshes the access token every 30 minutes for every connection?
Not necessarily. Wait till your API call fails. Check for a proper response such as "401 Unauthorized" which hints your access token is invalidated/expired. Once this happens use refresh token to renew the access token. If refresh token fails, then you have to fall back again and ask user to login again.
A refresh token can have a varying life time. It can be from few days to few months. For example check Google's explanation mentioning long lived refresh tokens and possible expiry of them. Also check how Azure AD mention about configurations related to token lifetimes.
So user not using app for few days (ex:- leave it and return after weekend) can be handled through proper validity configurations of tokens lifetimes. But be mindful about threats that could occur from long-lived, unmanaged tokens (ex:- due to token stealing).
The Oauth website has a pretty informative answer
The “expires_in” value is the number of seconds that the access token
will be valid. It’s up to the service you’re using to decide how long
access tokens will be valid, and may depend on the application or the
organization’s own policies. You could use this timestamp to
preemptively refresh your access tokens instead of waiting for a
request with an expired token to fail. Some people like to get a new
access token shortly before the current one will expire in order to
save an HTTP request of an API call failing. While that is a perfectly
fine optimization, it doesn’t stop you from still needing to handle
the case where an API call fails if an access token expires before the
expected time. Access tokens can expire for many reasons, such as the
user revoking an app, or if the authorization server expires all
tokens when a user changes their password.
If you make an API request and the token has expired already, you’ll
get back a response indicating as such. You can check for this
specific error message, and then refresh the token and try the request
again.
TLDR: I would only refresh the token when a request fails
Once I've completed the OAuth flow by obtaining authorization from the user and then creating an access token, how do I obtain another token without asking the user for authorization again? I thought the user's account on Smartsheet would remember that they trusted the application, but that doesn't seem to be the case. I'm new to OAuth so I'm sorry if I'm missing something obvious.
Thanks!
Access tokens retrieved via the OAuth flow are valid only for a certain period of time -- you (i.e., your application) can refresh a token before it expires in order to prevent the end-user from having to provide authorization again.
When you issue a GET Token request to obtain an access token, the response contains not only the token itself, but also information to indicate how long the token is valid (the expires_in property indicates the number of seconds until the token expires) and a refresh_token property value that you'll need in order to refresh the token.
To prevent the user from having to provide authorization again, simply refresh the token before it expires, and then use the new (refreshed) token value in subsequent API requests. Note that each token you obtain (whether it's the original token or a refresh token) will always expire in a finite amount of time, thereby requiring that you refresh the token in order for your application to maintain user authorization.
I am implementing an oauth server using spring oauth. I notice that spring's implementation re issues the same access token if not expired from the token endpoint. However the behavior is different while refreshing access tokens. A new token is reissued each time, are there any concerns to keep in mind if I were to reissue the same un expired access token on receiving a valid refresh request.
The OAuth Spec section-6 specifies that:
The authorization server MAY issue a new refresh token, in which case
the client MUST discard the old refresh token and replace it with the
new refresh token. The authorization server MAY revoke the old
refresh token after issuing a new refresh token to the client. If a
new refresh token is issued, the refresh token scope MUST be
identical to that of the refresh token included by the client in the
request.
There does not seem to be a requirement that the access token is brand new.
I think the main concern is to ensure that you do not change the expiration date on an existing token. And that you correctly return to the client an accurate expires_in property which reflects when the token will expire.
In addition, it might make the semantics confusing for clients. The refresh is usually done when a token is expired, and the client wants a new one.
I can imagine some odd edge cases. A client could send a request to refresh a token a few seconds before it is expired (perfectly valid logic for a client), but still receive back the same token which is almost expired.
I'm developing a API to be used with my IOS App and I am curious on the best practice for using the refresh token in oAuth2. I am using the user password grant to generate a access token and refresh token.
If the token expires every 60 minutes then that means every 60 minutes the client will have to make 3 consecutive API calls: 1. use the access token to get the resource from the API, 2. api responds with a invalid token so we need to use the refresh token, 3. now that the token is refreshed we need to try the initial call again.
So, what I am wanting to know is if it's best to refresh the token just before it expires? Or is it better to generate a new access token once the API has responded with a expired token error?
Not sure there's a best practice as such, but it's certainly more efficient to refresh in advance as you then won't make requests that you can know will fail. The cost of the timer to refresh is much less than the cost of the network communication.
You still need handling for the token being invalid on any request as the server could invalidate the token for any number of other reasons, so this is really a 'how can I make this efficient and user friendly' than a 'can I remove some of my code' kind of thing. Handling the error response is the standard, refreshing in advance is the user friendly.
Be cautious about refreshing while you have in-flight requests and you could inadvertently cause a request to fail by invalidating its token...
I'm working with an API that uses OAuth2, provides an access token that expires in 3600 seconds, and provides a refresh token with it. Originally, I'd waited for an API call to fail in a way that indicated the access token was expired and then tried to refresh the access token using the refresh token. This has become problematic when the access token is expired and several API calls are made concurrently (each call separately triggers a refresh and most of the calls fail).
Would it be better to automatically refresh the access token using the refresh token after 3600 seconds? (Or 3599 seconds or 3601 seconds?) Is there a different paradigm I should be using for refreshing the access token?
Ideally, the client should have sufficient smarts to not use an expired access token. Fortunately the response from your OAuth AS's token endpoint should include the expires_in attribute to confirm that the expiry will be in 3600 seconds. E.g.:
{"token_type":"Bearer","expires_in":3600,"refresh_token":"p8BPdo01kkjh6fhatclD3wwBEQblm4kL4ctYRVlrHo","access_token":"9XebAAXeu6hQOAiwmOk8vdhRyUFV"}
Since this JSON response is generated by the server, there's a chance that the transmission back to the client has taken time, and thus the "expires_in" value may be smaller than it appears.
Given that, I'd recommend that you have some sort of buffer (say 5-10 seconds) before expiry to automatically use your refresh token to request a new access token.
I may have used the following scenario. There will be access failures due to access token validation error but those errors will be minimal.
App1 invokes the token api with password grant type and get the access token and refresh token pair (accto1/refto1)
App2 also do the same at the starting up of the execution (accto1/refto1)
When the access token is expired for App1, he may do the refresh token by invoking the token api with refresh token grant type and with his existing refresh token (refto1) and he will retrieve a new pair of access token and refresh token. (accto2/refto2)
When App2 also reaches the instance when his access token is expired, he will also try the refresh token grant with the refresh token he already has (refto1) but he will get an authorization error since that refresh token is now expired.
When either of the apps get this error then app needs to realize that someone else has refreshed the token so at this moment the app needs to make a call with the password grant to retrieve the new access token / refresh token pair in action. This time as in the example the App2 will also retrieve the same access token and refresh token pair that the App1 has previously received for his refresh token grant. (accto2/refto2)