react-relay-network-modern
Version:
Network Layer for React Relay and Express (Batch Queries, AuthToken, Logging, Retry)
63 lines (62 loc) • 2.07 kB
JavaScript
/* eslint-disable no-param-reassign, arrow-body-style, dot-notation */
import { isFunction } from '../utils';
import RRNLError from '../RRNLError';
export class RRNLAuthMiddlewareError extends RRNLError {
constructor(msg) {
super(msg);
this.name = 'RRNLAuthMiddlewareError';
}
}
export default function authMiddleware(opts) {
const {
token: tokenOrThunk,
tokenRefreshPromise,
allowEmptyToken = false,
prefix = 'Bearer ',
header = 'Authorization'
} = opts || {};
let tokenRefreshInProgress = null;
return next => async req => {
try {
// $FlowFixMe
const token = await (isFunction(tokenOrThunk) ? tokenOrThunk(req) : tokenOrThunk);
if (!token && tokenRefreshPromise && !allowEmptyToken) {
throw new RRNLAuthMiddlewareError('Empty token');
}
if (token) {
req.fetchOpts.headers[header] = `${prefix}${token}`;
}
const res = await next(req);
return res;
} catch (e) {
if (e && tokenRefreshPromise) {
if (e.message === 'Empty token' || e.res && e.res.status === 401) {
if (tokenRefreshPromise) {
if (!tokenRefreshInProgress) {
tokenRefreshInProgress = Promise.resolve(tokenRefreshPromise(req, e.res)).then(newToken => {
tokenRefreshInProgress = null;
return newToken;
}).catch(err => {
tokenRefreshInProgress = null;
throw err;
});
}
return tokenRefreshInProgress.then(newToken => {
if (!newToken && !allowEmptyToken) {
throw new RRNLAuthMiddlewareError('Empty token');
}
const newReq = req.clone();
if (newToken) {
newReq.fetchOpts.headers[header] = `${prefix}${newToken}`;
} else {
delete newReq.fetchOpts.headers[header];
}
return next(newReq); // re-run query with new token
});
}
}
}
throw e;
}
};
}