Protect API Routes
Learn how to use auth middleware to protect your API routes from unauthenticated access.
In this section, you'll configure the auth middleware you set up earlier to automatically protect your API routes. When an unauthenticated user tries to access a protected API route, they'll receive a 401 Unauthorized response.
Add Protected APIs to Auth Middleware
Update your requireAuth configuration in src/wristband.ts to specify which API routes require authentication:
// src/wristband.ts
//
// ... existing wristbandAuth and sessionOptions config ...
//
export const requireAuth = wristbandAuth.createMiddlewareAuth({
authStrategies: ['SESSION'],
sessionConfig: {
sessionOptions,
sessionEndpoint: '/api/auth/session'
},
protectedPages: ['/', '/dashboard', '/settings(.*)'],
protectedApis: [
'/api/v1/orders', // Protects only /api/v1/orders route
'/api/v1/products/(.*)', // Protects all /api/v1/products/* routes
],
});Now, if somebody tries to call a protected API without a valid session, a 401 Unauthorized response will be returned.
Manual API Route Protection (Optional)
If you need more granular control or custom handling for specific API routes, you can manually check the session in your API route handler instead of relying solely on middleware.
Note: Middleware protection alone is typically sufficient for most use cases.
// src/app/api/v1/orders/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getRequestSession } from 'src/wristband';
export async function GET(request: NextRequest) {
const session = await getRequestSession(request);
// Return 401 if not authenticated
if (!session.isAuthenticated) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// Your API logic here using session data
return NextResponse.json({
message: 'Order data retrieved',
userId: session.userId,
tenantId: session.tenantId,
});
}Handling 401 Responses in Frontend Code
When your frontend makes calls to APIs protected by the requireAuth middleware, 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.
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 about 10 hours ago
Your frontend and backend should now have proper authentication checks in place. Let's run some final tests to ensure everything is working.