Environment: This is code I'm trying to implement on top of the tried and tested React-boilerplate. While this boilerplate is wonderful, it doesn't contain authentication. I'm trying to implement my own authentication logic in a way that meshes with the existing logic of the boilerplate.
Context:
I have a service/utility function that is used to send the server requests with a JWT authentication header and return its response.
Goal:
I'm trying to implement logic where when a request is made using an expired token, the access token is automatically refreshed before the request is sent to the server.
What's stopping me:
I have a saga that handles the access token refresh. It works perfectly when it is called from within a container. But because this is a service, it is unaware of the redux store. For this reason I am unable to dispatch actions.
The react-boilerplate structure works by injecting reducers and sagas on the fly. This means I'd need to inject the authentication saga and reducer from within the service (kinda feels wrong no?). However, the saga and reducer injectors are React side-effects and can, therefore, only be used inside of React components.
I feel like the task I'm trying to achieve is quite trivial (and I'm sure it was implementing a million times already), and yet, I can't think of a solution that doesn't seem to go against the entire logic of why use Redux or Sagas to begin with.
Can anyone offer some insights? In the attached image, the red text is the part I'm struggling to implement
See code below:
/**
* Requests a URL, returning a promise
*
* @param {string} url The URL we want to request
* @param {object} [options] The options we want to pass to "fetch".
*
* @return {object} The response data
*/
export default function request( url, options ) {
const token = makeSelectAccessToken();
if (!token) throw new Error('No access token found.');
// Refresh access token if it's expired.
if (new Date(token.expires) - Date.now() <= 0) {
// TODO: Attempt to use refresh token to get new access token before continuing
/** dispatch(REFRESH_ACCESS_TOKEN) **/
// PROBLEM: can't dispatch actions because the store is not exposed to this service.
// Secondary challenge: Can't inject Saga or Reducer because the React-boilerplate injectors are React side-effects.
}
options = {
...options,
Authorization: `Bearer ${token.token}`, // Adding the JWT token to the request
};
return fetch(url, options)
}