redux-refresh-token
Extension to your API middleware to refresh access tokens when a request hits a 401 response (access token expired).
Introduction
If you use transient (short-lived) OAuth tokens for authentication then these will expire all the time. However, instead of logging the user out every time the token expires it is much better to simply request a new token using the refresh token.
If you use Redux you are surely using an API middleware for requesting an API. You might roll your own, use the one from the real-world example or a 3rd party like agraboso's redux-api-middleware. I use the latter - you should give it a try. It is great.
This library provides a function you can plug into your API call. If the API call returns a 401 response then your access token probably expired. This library will try to refresh the token. Whilst refreshing it will queue up all API calls. If the refresh was successful it will retry all the queued calls. If it was not successful it will log out the user.
Prerequisites
Your API middleware must return FSA-style responses. There is a great description about flux-standard-actions here. You want the quick run down? Your middleware must return actions like this.
Successful response (status range 200-299)
type: "ACTION" payload: // API response
Error response (everything else)
type: "ACTION" error: true payload: status: 401 // Http status code
This is the most important thing. redux-refresh-token will look for the error
property and will look for the status
to determine whether
or not it should try a refresh. It will always attempt a refresh on 401
status codes. Everything else will just be ignored.
Installation
You will need to install a reducer under the key tokenRefresh
. If you want to change the key
you have to pass the refreshReducerKey
setting to attemptRefresh
.
const store =
So you probably have some API middlware in your code that ends a long the lines of this below
return )
Now replace it with
; // Middleware code skipped for breweity return // This step will convert fetch's response into a FSA style action// This is needed in the attempt method
API
The attemptRefresh
has various parameters to adjust to different types of API middleware.
failure (action creator) (required)
Should be an actionCreator. This action will be dispatched whenever the refresh failed. Usually this would be a logout action.
An example could be
const LOGOUT_REQUEST = 'LOGOUT_REQUEST'const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS'const LOGOUT_FAILURE = 'LOGOUT_FAILURE' const logout = CALL_API: endpoint: '/logout' method: 'POST' types: LOGOUT_REQUEST LOGOUT_SUCCESS LOGOUT_FAILURE
isRefreshCall (function(action, refreshAction))
When refreshing it is important to determine whether or not a failed action is an attempt to refresh the access token. Because the library will attempt to refresh all 401's, if the refresh call returns 401 and we do not check if successfully we are stuck in an infinite loop.
The default behaviour is to check like below
return action["Call API"].endpoint === refreshAction["Call API"].endpoint;
refreshActionCreator (action creator) (required)
An action creator that creates the action that will request the API for a new token.
Example
const TOKEN_REFRESH_REQUEST = 'TOKEN_REFRESH_REQUEST'const TOKEN_REFRESH_SUCCESS = 'TOKEN_REFRESH_SUCCESS'const TOKEN_REFRESH_FAILURE = 'TOKEN_REFRESH_FAILURE' const attemptTokenRefresh = CALL_API: endpoint: '/login/refresh' method: 'POST' types: TOKEN_REFRESH_REQUEST TOKEN_REFRESH_SUCCESS TOKEN_REFRESH_FAILURE
refreshReducerKey (string)
By default the reducer should be installed under the key tokenRefresh
but you can
change the default setting using this key.
setAccessTokenActionCreator (action creator)
An action creator used to set a new access token in the redux store state.
The default creator is given below
const SET_ACCESS_TOKEN = 'SET_ACCESS_TOKEN' const setAccessToken = type: SET_ACCESS_TOKEN access_token expires_in
token (string) (required)
The current access token from the redux store state.
Tests
npm test
License
The MIT License (MIT). Please see License File for more information.