Protect Backend Endpoints
Learn how the auth middleware can be used to protect authenticated APIs.
Previously, during the Wristband SDK setup, we created an auth middleware named requireWristbandAuth. This section explains how to use it to ensure that protected endpoints are accessible only to authenticated users.
Using the Auth Middleware to Protect Endpoints
To protect an endpoint from unauthenticated access, add requireWristbandAuth as a dependency, as shown below
// src/routes/protected-routes.ts
import express from 'express';
import { requiresWristbandAuth } from '../wristband';
const router = express.Router();
// Apply the requiresWristbandAuth middleware to protect this route
router.get('/protected-api', requiresWristbandAuth, (req, res) => {
res.json({ message: 'This is a protected endpoint' });
});
export default router;Now, if somebody tries to call this API without a valid session, a 401 Unauthorized response will be returned.
Handling 401 Responses in Frontend Code
When your frontend makes calls to APIs protected by the require_session_auth dependency, the following error responses could come back:
401 Unauthorized: This response will be returned if the session is missing or invalid.
Your frontend needs to handle these error responses gracefully in order to ensure a smooth user experience. Below are common patterns for handling 401 errors in a JavaScript frontend.
Pattern 1: Use an Axios Interceptor
If you're using Axios, you can create a response interceptor to handle 401 error responses. In the example below, the user is redirected to the Login Endpoint if a 401 response is detected.
// api-client.ts
import axios from 'axios';
import { redirectToLogin } from '@wristband/react-client-auth';
const apiClient = axios.create({
baseURL: '<backend-apis-base-url>',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
withCredentials: true,
});
// If a 401 response is detected, redirect the user to your Login Endpoint.
const unauthorizedAccessInterceptor = (error: unknown) => {
if (axios.isAxiosError(error) && error.response?.status === 401) {
redirectToLogin('<your-login-endpoint-url>');
return;
}
return Promise.reject(error);
};
apiClient.interceptors.response.use(undefined, unauthorizedAccessInterceptor);
export { apiClient };
Pattern 2: Explicitly Catch Errors When Making API Calls
To handle 401 errors with more precision, you can explicitly catch them when calling your backend APIs. This allows for custom error-handling logic to be created for each API call.
import axios from 'axios';
import { redirectToLogin } from '@wristband/react-client-auth';
async function executeApiCall() {
try {
const response = await axios.get('<your-server-api-url>');
alert('Success!');
} catch (error: unknown) {
if (axios.isAxiosError(error) && error.response?.status === 401) {
redirectToLogin('<your-login-endpoint-url>');
} else {
console.error('Unexpected error:', error);
alert('Something went wrong!');
}
}
}
import { redirectToLogin } from '@wristband/react-client-auth';
function getCookie(name: string): string | null {
const match = document.cookie.match(new RegExp('(^|;\\s*)' + name + '=([^;]*)'));
return match ? decodeURIComponent(match[2]) : null;
}
async function executeApiCall() {
const csrfToken = getCookie('CSRF-TOKEN');
try {
const response = await fetch('/api/protected-endpoint', {
credentials: 'include',
headers: {
'X-CSRF-TOKEN': csrfToken ?? ''
}
});
if (!response.ok) {
if (response.status === 401 || response.status === 403) {
redirectToLogin('<your-login-endpoint-url>');
return;
}
const errorText = await response.text();
throw new Error(`HTTP error! status: ${response.status}, Message: ${errorText}`);
}
...
} catch (error) {
...
}
}Updated 3 days ago
Now that you've finished protecting your backend endpoints, let's run some final tests to ensure everything is working.