Protect Server Actions

Learn how to protect your Server Actions so only authenticated users can execute them.

Server Actions bypass the Next.js middleware/proxy (and thus bypass our auth middleware), so you must perform authentication checks directly within the Server Action.

Create Server Action Auth Helper Function

First, add the requireServerActionAuth() function to your src/wristband.ts file. This function can be used to perform authentication checks within Server Actions.

// src/wristband.ts

import { NextRequest } from 'next/server';
import {
  createWristbandAuth,
  getReadOnlySessionFromCookies,
  getSessionFromRequest,
  NextJsCookieStore,
  SessionOptions,
} from '@wristband/nextjs-auth';

export const wristbandAuth = createWristbandAuth({
  clientId: '<WRISTBAND_CLIENT_ID>',
  clientSecret: '<WRISTBAND_CLIENT_SECRET>',
  wristbandApplicationVanityDomain: '<WRISTBAND_APPLICATION_VANITY_DOMAIN>',
});

const sessionOptions: SessionOptions = {
  secrets: '<your-generated-secret>'
};

export function getRequestSession(request: NextRequest) {
  return getSessionFromRequest(request, sessionOptions);
}

export const requireAuth = wristbandAuth.createMiddlewareAuth({
  authStrategies: ['SESSION'],
  sessionConfig: { sessionOptions, sessionEndpoint: '/api/auth/session' },
  protectedPages: ['/', '/dashboard', '/settings(.*)'],
});

export function getServerComponentSession(cookieStore: NextJsCookieStore) {
  return getReadOnlySessionFromCookies(cookieStore, sessionOptions);
}

// NEW: Helper function for performing authentication checkes within Server Actions.
export const requireServerActionAuth = wristbandAuth.appRouter.createServerActionAuth({
  sessionOptions
});

Add Authentication Checks to Server Actions

Use the requireServerActionAuth() helper function at the start of any Server Action that requires authentication. Calling this function returns a response that can be used to check if the user is authenticated. If the user is authenticated, it also returns their session.

// src/app/actions/fetch-tenant.ts

'use server';

import { cookies } from 'next/headers';
import { requireServerActionAuth } from 'src/wristband';

export async function fetchTenant() {
  const cookieStore = await cookies();
  const { authenticated, session } = await requireServerActionAuth(cookieStore);

  // Check authentication
  if (!authenticated) {
    return { error: 'You are not authenticated. Please log in again.' };
  }

  // Access session data
  const { accessToken, tenantId } = session;
  
  // Make authenticated API call
  const url = `https://${'your-wristband-app-vanity-domain'}/api/v1/tenants/${tenantId}`;
  const response = await fetch(url, {
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    }
  });

  if (!response.ok) {
    return { error: 'Failed to fetch tenant data.' };
  }

  const tenant = await response.json();
  return { data: tenant };
}


What’s Next

Next, let's protect your API routes so only authenticated requests can access them.