React + Fetch - Set Authorization Header for API Requests if User Logged In
This is a quick example of how to automatically set the HTTP Authorization
header for requests sent with fetch()
from React to an API when the user is authenticated.
The code snippets in this tutorial are from a React + Recoil JWT Auth tutorial I posted recently, to see the code running in a live demo app check out React + Recoil - JWT Authentication Tutorial & Example.
Recoil is used in the example to store the current authenticated user in the auth
shared state object, but Recoil isn't required if your React app uses another way to store the user's logged in state such as Redux or RxJS etc. The only requirement is that you can check if the user is logged in from the authHeader()
function in the fetch wrapper below.
Fetch Wrapper with Set Authorization Header
The fetch wrapper is a lightweight wrapper around the native browser fetch()
function used to simplify the code for making HTTP requests by automatically setting the HTTP auth header, parsing JSON response data and handling errors. It returns an object with methods for get
, post
, put
and delete
requests.
The authHeader()
function is used to automatically add a JWT auth token to the HTTP Authorization
header of the request if the user is logged in and the request is to the application API url (process.env.REACT_APP_API_URL
).
With the fetch wrapper a POST
request can be made as simply as this: fetchWrapper.post(url, body);
. It's called in the example app by user actions for login and to fetch all users.
import { useRecoilState } from 'recoil';
import { history } from '_helpers';
import { authAtom } from '_state';
export { useFetchWrapper };
function useFetchWrapper() {
const [auth, setAuth] = useRecoilState(authAtom);
return {
get: request('GET'),
post: request('POST'),
put: request('PUT'),
delete: request('DELETE')
};
function request(method) {
return (url, body) => {
const requestOptions = {
method,
headers: authHeader(url)
};
if (body) {
requestOptions.headers['Content-Type'] = 'application/json';
requestOptions.body = JSON.stringify(body);
}
return fetch(url, requestOptions).then(handleResponse);
}
}
// helper functions
function authHeader(url) {
// return auth header with jwt if user is logged in and request is to the api url
const token = auth?.token;
const isLoggedIn = !!token;
const isApiUrl = url.startsWith(process.env.REACT_APP_API_URL);
if (isLoggedIn && isApiUrl) {
return { Authorization: `Bearer ${token}` };
} else {
return {};
}
}
function handleResponse(response) {
return response.text().then(text => {
const data = text && JSON.parse(text);
if (!response.ok) {
if ([401, 403].includes(response.status) && auth?.token) {
// auto logout if 401 Unauthorized or 403 Forbidden response returned from api
localStorage.removeItem('user');
setAuth(null);
history.push('/login');
}
const error = (data && data.message) || response.statusText;
return Promise.reject(error);
}
return data;
});
}
}
User Actions
The user actions object returned by the useUserActions()
hook function contains methods for login, logout and fetching all users. It handles communication between the React app and the backend api for everything related to users, and also handles Recoil state update operations for users and auth atoms. HTTP requests to the API are sent with the fetch wrapper.
The getAll()
method is called from a secure page in the React example app after the user has logged in, so the fetch wrapper automatically sets the HTTP Authorization
header of the request to the JWT token of the authenticated user.
The login()
method is called from the public login page when the user is not yet logged in, so the authHeader()
function of the fetch wrappper doesn't set the authorization header of the request.
import { useSetRecoilState } from 'recoil';
import { history, useFetchWrapper } from '_helpers';
import { authAtom, usersAtom } from '_state';
export { useUserActions };
function useUserActions () {
const baseUrl = `${process.env.REACT_APP_API_URL}/users`;
const fetchWrapper = useFetchWrapper();
const setAuth = useSetRecoilState(authAtom);
const setUsers = useSetRecoilState(usersAtom);
return {
login,
logout,
getAll
}
function login(username, password) {
return fetchWrapper.post(`${baseUrl}/authenticate`, { username, password })
.then(user => {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('user', JSON.stringify(user));
setAuth(user);
// get return url from location state or default to home page
const { from } = history.location.state || { from: { pathname: '/' } };
history.push(from);
});
}
function logout() {
// remove user from local storage, set auth state to null and redirect to login page
localStorage.removeItem('user');
setAuth(null);
history.push('/login');
}
function getAll() {
return fetchWrapper.get(baseUrl).then(setUsers);
}
}
Need Some React Help?
Search fiverr for freelance React developers.
Follow me for updates
When I'm not coding...
Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!