Protect Backend Endpoints

Learn to protect your API endpoints with Wristband's authentication middleware.

Utilize the requireWristbandAuth middleware, created during the initial setup, to restrict endpoint access exclusively to authenticated users. This section details how to apply the middleware to protect private API endpoints. Learn more about implementing this, as described on the Wristband documentation site.

Using the Auth Middleware to Protect Endpoints

Secure your endpoint from unauthenticated access by adding the requireWristbandAuth middleware:

// 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;

If an unauthenticated user attempts to access this API, the server will return a 401 Unauthorized status.

Handling 401 Responses in Frontend Code

If your frontend requests an endpoint protected by requireWristbandAuth without a valid session, the server will return this error response:

  • 401 Unauthorized: This response will be returned if the session is missing or invalid.

To ensure a smooth user experience, your frontend must handle this error properly. Below are the most common patterns for managing 401 errors in JavaScript.

Pattern 1: Use an Axios Interceptor

Implement an Axios response interceptor to manage 401 Unauthorized states. This example redirects the user to the login endpoint whenever a 401 response occurs.

// 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

Explicitly catching errors during individual API calls provides greater precision. This enables you to deploy unique error-handling logic for each endpoint rather than relying on a global handler.

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) {
    ...
  }
}

What’s Next

Now that you've finished protecting your backend endpoints, let's run some final tests to ensure everything is working.

Did this page help you?