Skip to content
Docs
Usage guide
Refreshing credentials

Refreshing Credentials

next-firebase-auth-edge provides three different functions for updating user credentials after changes to the user token structure (e.g., adding new user claims).

Refresh Credentials in Middleware

To refresh credentials in Next.js Middleware (opens in a new tab) after updating the user token, use the refreshCredentials function from next-firebase-auth-edge/lib/next/cookies.

middleware.ts
import type {NextRequest} from 'next/server';
import {authMiddleware} from 'next-firebase-auth-edge';
import {refreshCredentials} from 'next-firebase-auth-edge/lib/next/cookies';
 
const commonOptions = {
  apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX',
  cookieName: 'AuthToken',
  cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'],
  cookieSerializeOptions: {
    path: '/',
    httpOnly: true,
    secure: false, // Set this to true on HTTPS environments
    sameSite: 'strict' as const,
    maxAge: 12 * 60 * 60 * 24 // twelve days
  },
  serviceAccount: {
    projectId: 'your-firebase-project-id',
    clientEmail:
      'firebase-adminsdk-nnw48@your-firebase-project-id.iam.gserviceaccount.com',
    privateKey: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n'
  }
};
 
export async function middleware(request: NextRequest) {
  return authMiddleware(request, {
    handleValidToken: async ({decodedToken}, headers) => {
      const shouldRefreshCredentials =
        await makeSomeComputationsToDeduceIfUserCredentialsShouldBeUpdated(
          decodedToken.uid
        );
 
      if (shouldRefreshCredentials) {
        return refreshCredentials(
          request,
          commonOptions,
          ({headers, tokens}) => {
            // Optionally perform additional verification on refreshed `tokens`...
 
            return NextResponse.next({
              request: {
                headers
              }
            });
          }
        );
      }
 
      return NextResponse.next({
        request: {
          headers
        }
      });
    },
    ...commonOptions
  });
}
 
export const config = {
  matcher: [
    '/',
    '/((?!_next|favicon.ico|api|.*\\.).*)',
    '/api/login',
    '/api/logout'
  ]
};

refreshCredentials

The refreshCredentials function is useful when you need to update user credentials after some asynchronous action that affects the user token structure (e.g., a cron job or event queue that updates custom claims).

In this example, makeSomeComputationsToDeduceIfUserCredentialsShouldBeUpdated is a fictional function used to quickly check if user credentials need updating. For example, it might check a distributed cache.

When you call refreshCredentials, it performs three actions:

  1. It generates a new token based on the existing credentials, including any updated claims.
  2. It allows the developer to create a new NextResponse with Modified Request Headers (opens in a new tab). Passing the modified request headers ensures that getTokens will return the fresh token within a single request.
  3. It updates the NextResponse with Set-Cookie headers that contain the latest credentials.

Here’s the function signature:

async function refreshCredentials(
  request: NextRequest,
  options: SetAuthCookiesOptions,
  responseFactory: (options: {
    headers: Headers;
    tokens: VerifiedTokens;
  }) => NextResponse | Promise<NextResponse>
): Promise<NextResponse>;

Response Factory Options

NameDescription
headersModified Request Headers (opens in a new tab). Passing these modified headers ensures that getTokens will return the updated token within a single request.
tokensA VerifiedTokens object, containing the values for idToken, refreshToken, and decodedIdToken. It also returns customToken if you passed enableCustomToken flag to authMiddleware.

Refresh Auth Cookies in API Route Handlers

To refresh authentication cookies after updating a user token in API Route Handlers (opens in a new tab), use refreshNextResponseCookies from next-firebase-auth-edge/lib/next/cookies.

import {NextResponse} from 'next/server';
import type { NextRequest } from 'next/server';
import {refreshNextResponseCookies} from 'next-firebase-auth-edge/lib/next/cookies';
import {getFirebaseAuth, getTokens} from 'next-firebase-auth-edge';
 
const commonOptions = {
  apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX',
  cookieName: 'AuthToken',
  cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'],
  cookieSerializeOptions: {
    path: '/',
    httpOnly: true,
    secure: false, // Set this to true on HTTPS environments
    sameSite: 'strict' as const,
    maxAge: 12 * 60 * 60 * 24 // twelve days
  },
  serviceAccount: {
    projectId: 'your-firebase-project-id',
    clientEmail:
      'firebase-adminsdk-nnw48@your-firebase-project-id.iam.gserviceaccount.com',
    privateKey: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n'
  }
};
 
const {setCustomUserClaims, getUser} = getFirebaseAuth({
  serviceAccount: commonOptions.serviceAccount,
  apiKey: commonOptions.apiKey
});
 
export async function POST(request: NextRequest) {
  const tokens = await getTokens(request.cookies, commonOptions);
 
  if (!tokens) {
    throw new Error('Cannot update custom claims of unauthenticated user');
  }
 
  await setCustomUserClaims(tokens.decodedToken.uid, {
    someCustomClaim: {
      updatedAt: Date.now()
    }
  });
 
  const user = await getUser(tokens.decodedToken.uid);
  const response = new NextResponse(
    JSON.stringify({
      customClaims: user.customClaims
    }),
    {
      status: 200,
      headers: {'content-type': 'application/json'}
    }
  );
 
  return refreshNextResponseCookies(request, response, commonOptions);
}

Refresh Auth Cookies in API Route Handlers with an ID Token Extracted from the Authorization Header

To refresh authentication cookies using the token string extracted from the Authorization header, use refreshNextResponseCookiesWithToken from next-firebase-auth-edge/lib/next/cookies.

import type {NextRequest} from 'next/server';
import {refreshNextResponseCookiesWithToken} from 'next-firebase-auth-edge/lib/next/cookies';
 
const commonOptions = {
  apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX',
  cookieName: 'AuthToken',
  cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'],
  cookieSerializeOptions: {
    path: '/',
    httpOnly: true,
    secure: false, // Set this to true on HTTPS environments
    sameSite: 'strict' as const,
    maxAge: 12 * 60 * 60 * 24 // twelve days
  },
  serviceAccount: {
    projectId: 'your-firebase-project-id',
    clientEmail:
      'firebase-adminsdk-nnw48@your-firebase-project-id.iam.gserviceaccount.com',
    privateKey: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n'
  }
};
 
export async function POST(request: NextRequest) {
  const token = request.headers.get('Authorization')?.split(' ')[1] ?? '';
 
  if (!token) {
    throw new Error('Unauthenticated');
  }
 
  return refreshNextResponseCookiesWithToken(
    token,
    request,
    response,
    commonOptions
  );
}

Refresh Auth Cookies in Pages Router API Routes

To refresh authentication cookies after updating a user token in API Routes (opens in a new tab), use refreshApiResponseCookies from next-firebase-auth-edge/lib/next/api.

import {NextApiRequest, NextApiResponse} from 'next';
import {refreshApiResponseCookies} from 'next-firebase-auth-edge/lib/next/api';
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  await refreshApiResponseCookies(req, res, {
    serviceAccount: {
      projectId: 'your-firebase-project-id',
      clientEmail:
        'firebase-adminsdk-nnw48@your-firebase-project-id.iam.gserviceaccount.com',
      privateKey:
        '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n'
    },
    apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX',
    cookieName: 'AuthToken',
    cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'],
    cookieSerializeOptions: {
      path: '/',
      httpOnly: true,
      secure: false, // Set this to true on HTTPS environments
      sameSite: 'strict' as const,
      maxAge: 12 * 60 * 60 * 24 // twelve days
    }
  });
 
  res.status(200).json({example: true});
}

Refresh Auth Cookies in Server Actions

To refresh authentication cookies after updating user credentials in Server Actions (opens in a new tab), use refreshServerCookies from next-firebase-auth-edge/lib/next/cookies.

'use server';
 
import {cookies, headers} from 'next/headers';
import {getTokens} from 'next-firebase-auth-edge';
import {refreshServerCookies} from 'next-firebase-auth-edge/lib/next/cookies';
 
const commonOptions = {
  apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX',
  cookieName: 'AuthToken',
  cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'],
  cookieSerializeOptions: {
    path: '/',
    httpOnly: true,
    secure: false, // Set this to true on HTTPS environments
    sameSite: 'strict' as const,
    maxAge: 12 * 60 * 60 * 24 // twelve days
  },
  serviceAccount: {
    projectId: 'your-firebase-project-id',
    clientEmail:
      'firebase-adminsdk-nnw48@your-firebase-project-id.iam.gserviceaccount.com',
    privateKey: '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n'
  }
};
 
export async function performServerAction() {
  // Since Next.js 15, `cookies` function returns a Promise, so we need to precede it with `await`.
  const tokens = await getTokens(await cookies(), commonOptions);
 
  if (!tokens) {
    throw new Error('Unauthenticated');
  }
 
  // headers() needs to be wrapped with new Headers() to work in Server Actions
  // Since Next.js 15, `cookies` and `headers` functions return a Promise, so we need to precede them with `await`.
  await refreshServerCookies(await cookies(), new Headers(await headers()), commonOptions);
}