OAuth access_token refresh techniques - reactjs

I'm implementing OAuth in my React / Redux ( Or other Flux based state management ) application, And i'm struggling to find good information on "pro's vs cons" of various access_token extension methods.
1) Intercept 401 responses
One option would be to intercept API requests (E.g using "fetch-intercept" package) and detect any 401 HTTP code responses.
In the case we 401 we build logic to retrieve a new access_token, and then replay the previous request.
Replay could be handled via dispatching an INVALID_TOKEN action in the 401 handler, catching these through middle-ware, Which would then replay the action before the INVALID_TOKEN action occurred.
Pros
Full visibility of auth failure related actions are visible ( Therefore we could replay auth related bugs using time travel debugging )
2) Detecting out of date access_token at time of API call
Another method would be at the time of sending any request, decode our access_token and check if we need to refresh it soon ( And if so do so ).
Again some sort of middle-ware would be the best option for this solution. We could intercept all actions and before dispatching it first check we have a valid access_token.
Pros
Doesn't need to hit the server just to receive a 401 response we could have instead preempted it
Cons
More complicated logic to queue the requests whilst we're refreshing a token, before finally replaying them once it's been correctly refreshed
3) Polling method
Upon login, see how long it is until the token expires and set a timeout to refresh the access_token just before then
Pros
Simplest option ( Especially when retrofitting an app with lost of existing request logic )
Any additional options or pro's vs cons for each method would be appreciated, so perhaps I can create an exhaustive list here for those starting out

Related

Best practices for refreshing JWT in SPA?

Hi I'm developing a React app that communicates with an Express API. I'm trying to implement JWT authentication but I don't know what should happen when the jwt expires. It not seems very user friendly if the user is logged out when the token expires.
Should I use refresh tokens? As it says in the node-jsonwebtoken package documentation (jsonwebtoken). This may not be the best approach.
Should I create a new jwt in every request to the server? If the user reads an article for a long time without doing any request, he is going to be logged out.
Maybe I'm wrong and the best practice is using a big expiration time and let the user be logged out. If this is the case what would be a reasonable time?
Thanks!
A pattern commonly used along with refresh tokens is to follow a workflow along the lines of:
Some API call / resource returns with a 401, alerting that the token has expired, this sometimes is accompanied by a reason, e.g. Expired token, invalid token
Create a reference to the API call that failed, to retry later
Attempt to refresh the token with the refresh_token
If the refresh works, go ahead and perform the queued API call again
If the refresh fails, the user will need to log in again
You can also use the above approach to queue multiple failed requests, in the event that multiple calls fails whilst a refresh is taking place.
Coupled with a decent expiry time, which really depends on your application, this has proven to be a robust solution in the past for me.
An alternative approach would be to implement a 'heartbeat' API call that updates the user's token periodically whilst they are on the site, however this may come with side effects that may not be desired.

Oauth2. Asynchronous refresh_token calls

We have a client which communicates with a server secured by OAuth2.
As implementing tokens flow we have faced a problem. When page loads, there are few components that make calls to different secured endpoints.
There is a situation when access token is expired so all requests get error and try to refresh it. So we have few asynchronous requests.
Is there an approach to deal with such situation?
Our client is written on React JS.
There are a number of solutions to this.
One solution would be to create something like a TokenService.
Before you fire any http call, you work with this service and check if you have a valid token. This is easy since when you create the token you get back information on how long the token is valid for. You store that somewhere and before you fire a call you check if you are still in the validity window. If you are then you fire the http call, if you are not then you request another and update the stored one with the new one. Once this is done then you fire your http call with the valid token.
If you don't want to manage this complexity then you could simply request a new token for every request and you're done. You use each token for one call and that's it really.
You could also use the refresh tokens functionality if you have that implemented, so if your token expires, you simply refresh it and move on

React-Redux Strategies for Refreshing Cognito IdToken

I'm using the following combination of packages:
react
redux
react-cognito
react-router (v4)
redux-saga
(and I'll disclaim that I'm pretty new with all of these)
Currently I have a PrivateRoute component which will check (and refresh if necessary) an expired IdToken on route changes. This works well.
My problem is if the browser is open past token expiry to a PrivateRoute which is polling my API and sending along the IdToken in its 'Authorization' header. The API will start returning 401.
Options I've Thought of:
Act on API Error
I could catch the 401 error and dispatch an action to refresh the token, but
if there is any issue refreshing the token I wind up in an infinite loop hammering AWS, so need some logic to catch and prevent this. Perhaps redirect to login route if refresh fails?
I then need to add complexity to all my private API calls throughout my app to have this logic, and re-do the requested API call upon successful refresh.
Pre-empt API Error
To me it makes more sense to separate API calls and keeping the auth token valid. Considering react-cognito stores the token expiry time in cognito.user.signInUserSession.idToken.payload.exp, maybe it is possible to pre-empt the API call and expiry.
How to best do this though? At login a refresh action could be 'scheduled' using setTimeout for (currentTime - expiryTime - someBuffer) seconds in the future.
I'm assuming (haven't verified) AWS will let you refresh an IdToken before it expires. I don't want to wait until afterwards else some API calls may have already failed.
are there concerns with using setTimeout with a timeout that may be up to 1 hour long?
Alternatively I could set something up to poll cognito.user.signInUserSession.idToken.payload.exp frequently to detect and refresh an almost-expired token?
Any suggestions?

Start Redux/React Polling after Login

I'm new to Redux, this is a best practice question.
I have a server that i'm logging my app into, on a successful Login i'm returned a tokenId and an expiry time for that token.
tokenId is attached to subsequent API requests to ensure my sessions is valid. Before the expiry time is exceeded i'm required to send a request which generate a new tokenId.
Where is the best place to poll token regeneration? I believe calling an Action from a Reducer is against best practices.

Resend REST Call in Restangular after JWT Refresh

I am currently working on a web application that uses a JWT for authentication on all REST calls. The problem we are having is when a customer is performing an action needing a REST call and the JWT is expired, for whatever reason. At that point it kicks back a 401 response, as it should.
The functionality I am looking for is some way to intercept the 401 error, refresh the JWT, and retry the request without sending errors to the user.
The application runs on AngularJS and uses Restangular to handle all of the rest calls. So far I have been looking closely at the setErrorInterceptor as outlined here and at the Restangular documentation. Using a version of that posted code, I could successfully resend the request and in the .then() portion I had a successful response. However, it seems from the documentation that this method can only return false or true, so I couldn't get at it.
At the moment we have a timer that basically compares the jwt expiration time to the current system time and refreshes the jwt when there are 60 seconds left before expiration. This caused issues when the user's system clock was off compared to the server clock, resulting in a token not being refreshed because the application thought there was more time.
A solution to that specifically would be something like getting the system time, comparing to server time and creating an offset variable, but that doesn't cover all the bases for things that could go wrong. On another topic, checking the JWT before every request is not feasible.
Is there a way within Restangular's interceptors to accomplish the error interception and resending? If not, are there ways outside of it?

Resources