### Install and Run Locally Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/README.md Instructions for installing dependencies and running the development server for the next-firebase-auth-edge website. ```bash yarn install yarn dev ``` -------------------------------- ### Install next-firebase-auth-edge with pnpm Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/README.md Use this command to install the library using pnpm. ```shell pnpm add next-firebase-auth-edge ``` -------------------------------- ### Install next-firebase-auth-edge with yarn Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/README.md Use this command to install the library using yarn. ```shell yarn add next-firebase-auth-edge ``` -------------------------------- ### Install next-firebase-auth-edge with npm Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/README.md Use this command to install the library using npm. ```shell npm install next-firebase-auth-edge ``` -------------------------------- ### Run Development Server Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/examples/next-typescript-starter/README.md Start the Next.js development server using npm or yarn. ```bash npm run dev # or yarn dev ``` -------------------------------- ### Run Development Server Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/examples/next-typescript-minimal/README.md Commands to start the Next.js development server using different package managers. ```bash npm run dev # or yarn dev # or pnpm dev # or bun dev ``` -------------------------------- ### Use redirectToHome Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/redirect-functions.mdx Example of using `redirectToHome` to redirect the user to the home page ('/'). ```typescript redirectToHome(request); ``` -------------------------------- ### Example AuthContext Implementation Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/getting-started/auth-context.mdx Implement a custom AuthContext using React's createContext. This example defines the User and AuthContextValue interfaces and creates the AuthContext and useAuth hook. ```tsx import {createContext, useContext} from 'react'; import {UserInfo} from 'firebase/auth'; import {Claims} from 'next-firebase-auth-edge/auth/claims'; export interface User extends UserInfo { emailVerified: boolean; customClaims: Claims; } export interface AuthContextValue { user: User | null; } export const AuthContext = createContext({ user: null }); export const useAuth = () => useContext(AuthContext); ``` -------------------------------- ### Use redirectToPath Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/redirect-functions.mdx Example of using `redirectToPath` to redirect to '/dashboard' and clear search parameters. ```typescript redirectToPath(request, '/dashboard', {shouldClearSearchParams: true}); ``` -------------------------------- ### Refresh Credentials in Proxy/Middleware Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/refresh-credentials.mdx This example demonstrates how to use the `refreshCredentials` function within a Next.js proxy or middleware to update user credentials when necessary. It shows the integration with `authMiddleware` and how to handle token refreshes. ```APIDOC ## refreshCredentials ### Description 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). It performs three actions: 1. Generates a new token based on the existing credentials, including any updated claims. 2. Allows the developer to create a new `NextResponse` with [Modified Request Headers](https://vercel.com/templates/next.js/edge-functions-modify-request-header). Passing the modified request headers ensures that `getTokens` will return the fresh token within **a single request**. 3. Updates the `NextResponse` with `Set-Cookie` headers that contain the latest credentials. ### Function Signature ```typescript async function refreshCredentials( request: NextRequest, options: SetAuthCookiesOptions, responseFactory: (options: { headers: Headers; tokens: VerifiedCookies; metadata: Metadata; }) => NextResponse | Promise ): Promise; ``` ### Example Usage in Proxy/Middleware ```tsx filename="proxy.ts" import type {NextRequest} from 'next/server'; import {authMiddleware} from 'next-firebase-auth-edge'; import {refreshCredentials} from 'next-firebase-auth-edge/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 proxy(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' ] }; ``` ``` -------------------------------- ### Implement RootLayout with AuthProvider Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/getting-started/layout.mdx This example demonstrates how to create a RootLayout React Server Component that fetches user tokens from cookies using `getTokens`, transforms them into a user object, and passes it to the `AuthProvider` client component. Note the handling of `cookies()` which is asynchronous in Next.js 15 and synchronous in Next.js 14. ```tsx import { filterStandardClaims } from "next-firebase-auth-edge/auth/claims"; import { Tokens, getTokens } from "next-firebase-auth-edge"; import { cookies } from "next/headers"; import { User } from "./AuthContext"; import { AuthProvider } from "./AuthProvider"; const toUser = ({ decodedToken }: Tokens): User => { const { uid, email, picture: photoURL, email_verified: emailVerified, phone_number: phoneNumber, name: displayName, source_sign_in_provider: signInProvider, } = decodedToken; const customClaims = filterStandardClaims(decodedToken); return { uid, email: email ?? null, displayName: displayName ?? null, photoURL: photoURL ?? null, phoneNumber: phoneNumber ?? null, emailVerified: emailVerified ?? false, providerId: signInProvider, customClaims, }; }; export default async function RootLayout({ children, }: { children: JSX.Element }) { // Since Next.js 15, `cookies()` returns a Promise and must be preceded with `await`. // In Next.js 14, `cookies()` is synchronous — use `getTokens(cookies(), ...)` without `await` on `cookies()`. const tokens = await getTokens(await cookies(), { apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX', cookieName: 'AuthToken', cookieSignatureKeys: [ 'Key-Should-Be-at-least-32-bytes-in-length' ], 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 user = tokens ? toUser(tokens) : null; return (
{children}
); } ``` -------------------------------- ### Basic authMiddleware Usage in proxy.ts Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/getting-started/middleware.mdx Demonstrates the basic setup for authMiddleware in a Next.js proxy configuration. Ensure to replace placeholder values with your actual Firebase project details and keys. For HTTPS environments, set `secure` to true in `cookieSerializeOptions`. ```tsx import type { NextRequest } from "next/server"; import { authMiddleware } from "next-firebase-auth-edge"; export async function proxy(request: NextRequest) { return authMiddleware(request, { loginPath: "/api/login", logoutPath: "/api/logout", 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: "lax" 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 const config = { matcher: ["/api/login", "/api/logout", "/", "/((?!_next|favicon.ico|api|.*\\.).*)"], }; ``` -------------------------------- ### Get Tokens with Firebase Hosting Configuration Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/firebase-hosting.mdx Retrieve authentication tokens using `getTokens` by specifying the `cookieName` as `__session` when running within the Firebase Hosting environment. This example demonstrates server component usage. ```typescript import { getTokens } from "next-firebase-auth-edge"; const tokens = await getTokens(context.req.cookies, { apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX', cookieName: '__session', cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'], 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", }, }); ``` -------------------------------- ### Configure Auth Middleware for Firebase Hosting Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/firebase-hosting.mdx Set the `cookieName` to `__session` when initializing `authMiddleware` to ensure compatibility with Firebase Hosting's cookie restrictions. This setup is for `proxy.ts`. ```typescript import { NextRequest, NextResponse } from "next/server"; import { authMiddleware } from "next-firebase-auth-edge"; export async function proxy(request: NextRequest) { return authMiddleware(request, { cookieName: "__session", // This needs to be "__session" to work inside Firebase Hosting loginPath: "/api/login", logoutPath: "/api/logout", apiKey: "XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX", cookieSignatureKeys: ["Key-Should-Be-at-least-32-bytes-in-length"], cookieSerializeOptions: { path: "/", httpOnly: true, secure: false, sameSite: "lax" as const, maxAge: 12 * 60 * 60 * 24, }, 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 const config = { matcher: ["/api/login", "/api/logout", "/", "/((?!_next|favicon.ico|api|.*\.).*)"], }; ``` -------------------------------- ### Initialize getFirebaseAuth with Service Account Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/advanced-usage.mdx Import and initialize `getFirebaseAuth` with your Firebase project's API key and service account credentials. This setup provides access to various server-side authentication methods. ```tsx import {getFirebaseAuth} from 'next-firebase-auth-edge'; const { getCustomIdAndRefreshTokens, verifyIdToken, createCustomToken, handleTokenRefresh, getUser, getUserByEmail, createUser, updateUser, deleteUser, verifyAndRefreshExpiredIdToken, setCustomUserClaims } = getFirebaseAuth({ apiKey: 'YOUR FIREBASE API KEY', 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' } }); ``` -------------------------------- ### Access Custom Metadata from Cookies Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/middleware.mdx Retrieve custom metadata, like user roles, stored in cookies using the getTokens function. This example demonstrates accessing the 'roles' metadata after it has been set by the authMiddleware. ```tsx const { metadata: {roles} } = await getTokens(await cookies(), authConfig); ``` -------------------------------- ### Using getTokens in Next.js API Route Handler Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/app-router-api-routes.mdx This example shows how to retrieve authentication tokens within a Next.js API route handler using the `getTokens` function. Ensure your Firebase service account credentials and cookie configuration are correctly set. ```tsx import { NextRequest, NextResponse } from "next/server"; import { getTokens } from "next-firebase-auth-edge"; export async function GET(request: NextRequest) { const tokens = await getTokens(request.cookies, { apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX', cookieName: 'AuthToken', cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'], 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' } }); if (!tokens) { throw new Error("Unauthenticated"); } const headers: Record = { "Content-Type": "application/json", }; const response = new NextResponse( JSON.stringify({ tokens, }), { status: 200, headers, } ); return response; } ``` -------------------------------- ### updateUser Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/advanced-usage.mdx Updates an existing user by uid and returns the updated UserRecord. See Firebase’s Update a user documentation for request examples. ```APIDOC ## updateUser ### Description Updates an existing user by `uid` and returns the updated `UserRecord`. See Firebase’s [Update a user](https://firebase.google.com/docs/auth/admin/manage-users#update_a_user) documentation for request examples. ### Method `updateUser(uid: string, request: UpdateRequest) => Promise` ``` -------------------------------- ### Configure Firebase Emulators Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/examples/next-typescript-starter/README.md Environment variables for connecting to Firebase Authentication and Firestore emulators. Ensure these are uncommented in your .env.local file. ```shell NEXT_PUBLIC_AUTH_EMULATOR_HOST=localhost:9099 NEXT_PUBLIC_FIRESTORE_EMULATOR_HOST=8080 FIREBASE_AUTH_EMULATOR_HOST=127.0.0.1:9099 ``` -------------------------------- ### Firestore Database Rules for User Counters Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/examples/next-typescript-starter/README.md Example Firestore rules to validate user access for updating 'user-counters' collection. Ensures only the authenticated user can modify their own counter. ```json rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /user-counters/{document} { allow read, write: if request.auth.uid == resource.data.id; } } } ``` -------------------------------- ### Root Layout for AuthProvider Initialization Source: https://context7.com/awinogrodzki/next-firebase-auth-edge/llms.txt Initializes the AuthProvider in the root layout by fetching user tokens from cookies. The user object is constructed from decoded tokens. ```tsx import { cookies } from 'next/headers'; import { getTokens } from 'next-firebase-auth-edge'; import { AuthProvider } from './auth/AuthProvider'; import { authConfig } from '@/config/server-config'; export default async function RootLayout({ children }: { children: React.ReactNode }) { const tokens = await getTokens(await cookies(), authConfig); const user = tokens ? { ...tokens.decodedToken, customClaims: tokens.decodedToken as any } : null; return ( {children} ); } ``` -------------------------------- ### Get Tokens for Cloud Run Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/cloud-run.mdx Retrieve authentication tokens within a Google Cloud Run environment. This function automatically uses credentials from the environment when `serviceAccount` is not provided. ```typescript import { getTokens } from "next-firebase-auth-edge"; const tokens = await getTokens(context.req.cookies, { apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX', cookieName: 'AuthToken', cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'], }); ``` -------------------------------- ### Import redirectToLogin Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/redirect-functions.mdx Import the `redirectToLogin` helper function from the library. ```typescript import {redirectToLogin} from 'next-firebase-auth-edge'; ``` -------------------------------- ### Integrate with next-intl Middleware Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/middleware.mdx Combine `authMiddleware` with `next-intl` middleware by returning the `intlMiddleware` from the `handleValidToken`, `handleInvalidToken`, and `handleError` callbacks. This ensures proper routing and localization after authentication checks. ```ts import type {NextRequest} from 'next/server'; import createIntlMiddleware from 'next-intl/middleware'; import {authMiddleware} from 'next-firebase-auth-edge'; const intlMiddleware = createIntlMiddleware({ locales: ['en', 'pl'], defaultLocale: 'en' }); export async function proxy(request: NextRequest) { return authMiddleware(request, { // ... handleValidToken: async (tokens) => { return intlMiddleware(request); }, handleInvalidToken: async (reason) => { return intlMiddleware(request); }, handleError: async (error) => { return intlMiddleware(request); } }); } ``` -------------------------------- ### Get Valid ID Token on Client-Side Source: https://context7.com/awinogrodzki/next-firebase-auth-edge/llms.txt Use this client-side helper to ensure a non-expired ID token. It calls the refresh token endpoint only when necessary. Requires the refresh endpoint to be enabled in your middleware. ```typescript import { getValidIdToken } from 'next-firebase-auth-edge/next/client'; // serverIdToken is the `token` string returned from getTokens() in a Server Component export async function fetchProtectedData(serverIdToken: string) { const idToken = await getValidIdToken({ serverIdToken, refreshTokenUrl: '/api/refresh-token' }); const response = await fetch('https://api.example.com/protected', { headers: { Authorization: `Bearer ${idToken}` } }); if (!response.ok) { throw new Error('API request failed'); } return response.json(); } ``` -------------------------------- ### Import redirectToHome Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/redirect-functions.mdx Import the `redirectToHome` helper function from the library. ```typescript import {redirectToHome} from 'next-firebase-auth-edge'; ``` -------------------------------- ### Create and Verify App Check Tokens Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/app-check.mdx Create an App Check token using createToken with an appId and optional createTokenOptions. Verify the token using verifyToken with the token and optional verifyTokenOptions. ```typescript const appId = "your-app-id"; // Optional const createTokenOptions = { ttlMillis: 3600 * 1000, }; const token = await createToken(appId, createTokenOptions); // Optional const verifyTokenOptions = { currentDate: new Date(), }; const response = await verifyToken(token, verifyTokenOptions); ``` -------------------------------- ### Page Component to Render Login Form Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/getting-started/login-with-server-action.mdx A Server Component that imports and renders the `LoginPage` client component, passing the `loginAction` Server Action as a prop. ```tsx import LoginPage from './LoginPage'; import {loginAction} from './login'; export default function Page() { return ; } ``` -------------------------------- ### Get and Validate Tokens in App Router API Routes Source: https://context7.com/awinogrodzki/next-firebase-auth-edge/llms.txt Utilize `getTokens` within App Router API Route Handlers by accessing cookies from the `NextRequest` object. Handles unauthenticated responses with a 401 status. ```ts import { NextRequest, NextResponse } from 'next/server'; import { getTokens } from 'next-firebase-auth-edge'; export async function GET(request: NextRequest) { const tokens = await getTokens(request.cookies, { apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX', cookieName: 'AuthToken', cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'], 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' } }); if (!tokens) { return new NextResponse('Unauthenticated', { status: 401 }); } return NextResponse.json({ uid: tokens.decodedToken.uid, email: tokens.decodedToken.email }); } ``` -------------------------------- ### Redirect helper functions Source: https://context7.com/awinogrodzki/next-firebase-auth-edge/llms.txt Convenience wrappers around NextResponse.redirect for common auth-related routing patterns used in middleware callbacks. ```APIDOC ## Redirect helper functions ### Description Three convenience wrappers around `NextResponse.redirect` for common auth-related routing patterns used in middleware callbacks: `redirectToLogin`, `redirectToHome`, and `redirectToPath`. ### Usage ```ts import { redirectToLogin, redirectToHome, redirectToPath } from 'next-firebase-auth-edge'; // Redirect to /login, but skip redirect for public paths and regex patterns const loginRedirect = redirectToLogin(request, { path: '/login', publicPaths: ['/login', '/register', /^\/blog\/(.+)/] }); // Redirect to /login only when the requested path matches privatePaths const loginRedirectPrivate = redirectToLogin(request, { path: '/login', privatePaths: ['/dashboard', /^\/settings\/.+/] }); // Redirect to / const homeRedirect = redirectToHome(request); // Redirect to an arbitrary path, clearing query params const dashboardRedirect = redirectToPath(request, '/dashboard', { shouldClearSearchParams: true }); ``` ``` -------------------------------- ### Get and Validate Tokens in Pages Router API Routes and getServerSideProps Source: https://context7.com/awinogrodzki/next-firebase-auth-edge/llms.txt Employ `getApiRequestTokens` for Pages Router API Routes and `getServerSideProps` by passing the `req` object. Returns null for unauthenticated requests, responding with a 401 status. ```ts import type { NextApiRequest, NextApiResponse } from 'next'; import { getApiRequestTokens } from 'next-firebase-auth-edge'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const tokens = await getApiRequestTokens(req, { apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX', cookieName: 'AuthToken', cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'], 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' } }); if (!tokens) { return res.status(401).json({ error: 'Unauthenticated' }); } return res.status(200).json({ uid: tokens.decodedToken.uid }); } // Usage in getServerSideProps: // import { GetServerSidePropsContext } from 'next'; // export async function getServerSideProps(context: GetServerSidePropsContext) { // const tokens = await getApiRequestTokens(context.req, commonOptions); // return { props: { tokens } }; // } ``` -------------------------------- ### Get Valid Custom Token for Client SDK Usage Source: https://context7.com/awinogrodzki/next-firebase-auth-edge/llms.txt Obtain a custom token for client-side Firebase SDKs like Firestore. This function works similarly to getValidIdToken but returns a custom token. Requires `enableCustomToken: true` in `authMiddleware`. ```typescript import { getAuth } from 'firebase/auth'; import { signInWithCustomToken } from 'firebase/auth'; import { getValidCustomToken } from 'next-firebase-auth-edge/next/client'; export async function initFirebaseClientSession(serverCustomToken: string) { const customToken = await getValidCustomToken({ serverCustomToken, refreshTokenUrl: '/api/refresh-token' }); if (!customToken) { throw new Error('Could not obtain a valid custom token'); } const auth = getAuth(); const { user } = await signInWithCustomToken(auth, customToken); return user; } ``` -------------------------------- ### Middleware Options Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/middleware.mdx These options allow you to customize the behavior of the authentication middleware. ```APIDOC ## Options | Name | Optional | Type | Default | Description | |---|---|---|---|---| | `authorizationHeaderName` | Optional | `string` | `Authorization` | The name of the authorization header expected by the login endpoint. | | `checkRevoked` | Optional | `boolean` | `false` | If `true`, validates the token against the Firebase server on every request. Unless there's a specific need, it's usually better not to use this. | | `handleValidToken` | Optional | `(tokens: { token: string, decodedToken: DecodedIdToken, customToken?: string }, headers: Headers) => Promise` | `NextResponse.next()` | Called when a valid token is received. Should return a promise resolving with `NextResponse`. It's passed modified request `headers` as a second parameter, which, if forwarded with `NextResponse.next({ request: { headers } })`, prevents re-verification of the token in subsequent calls, improving response times. | | `handleInvalidToken` | Optional | `(reason: InvalidTokenReason) => Promise` | `NextResponse.next()` | Called when a request is unauthenticated (either missing credentials or has invalid credentials). Can be used to redirect users to a specific page. The `reason` argument can be one of `MISSING_CREDENTIALS`, `MISSING_REFRESH_TOKEN`, `MALFORMED_CREDENTIALS`, `INVALID_SIGNATURE`, `INVALID_KID` or `INVALID_CREDENTIALS`. See the [handleInvalidToken section](/docs/errors#handleinvalidtoken) for details on each reason. | | `handleError` | Optional | `(error: AuthError) => Promise` | `NextResponse.next()` | Called when an unhandled error occurs during authentication. By default, the app will render, but you can customize error handling here. See the [handleError section](/docs/errors#handleerror) for more information on possible errors. | | `getMetadata` | Optional | `(tokens: TokenSet) => Promise` | N/A | Called when user signs in or the credentials are refreshed. Can be used to load user data from external sources and save it inside the cookies. Metadata can be accessed using `metadata` property returned by [getTokens](/docs/usage/server-components). | ``` -------------------------------- ### Auth Redirect Helper Functions Source: https://context7.com/awinogrodzki/next-firebase-auth-edge/llms.txt Convenience wrappers for common auth-related routing patterns in middleware. These functions simplify redirect logic for login, home, or arbitrary paths. ```typescript import { redirectToLogin, redirectToHome, redirectToPath } from 'next-firebase-auth-edge'; // Redirect to /login, but skip redirect for public paths and regex patterns const loginRedirect = redirectToLogin(request, { path: '/login', publicPaths: ['/login', '/register', /^\/blog\/(.+)/] }); // Redirect to /login only when the requested path matches privatePaths const loginRedirectPrivate = redirectToLogin(request, { path: '/login', privatePaths: ['/dashboard', /^\/settings\/.+/] }); // Redirect to / const homeRedirect = redirectToHome(request); // Redirect to an arbitrary path, clearing query params const dashboardRedirect = redirectToPath(request, '/dashboard', { shouldClearSearchParams: true }); ``` -------------------------------- ### Configure authMiddleware for Next.js Proxy Source: https://context7.com/awinogrodzki/next-firebase-auth-edge/llms.txt Set up the `authMiddleware` in `proxy.ts` to protect routes, manage session cookies, and handle authentication flows. Configure paths, API endpoints, keys, and service account details. Customize behavior for valid tokens, invalid tokens, and errors. ```tsx import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { authMiddleware, redirectToHome, redirectToLogin } from 'next-firebase-auth-edge'; const PUBLIC_PATHS = ['/register', '/login', '/reset-password']; export async function proxy(request: NextRequest) { return authMiddleware(request, { loginPath: '/api/login', logoutPath: '/api/logout', apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX', cookieName: 'AuthToken', cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'], cookieSerializeOptions: { path: '/', httpOnly: true, secure: true, // Set to false on non-HTTPS environments sameSite: 'lax' 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' }, enableMultipleCookies: true, // Splits session into 4 cookies to avoid 4096-byte limit checkRevoked: false, // Set true to validate against Firebase on every request debug: false, handleValidToken: async ({ token, decodedToken }, headers) => { // Redirect authenticated users away from public pages if (PUBLIC_PATHS.includes(request.nextUrl.pathname)) { return redirectToHome(request); } // Pass modified headers to enable token verification caching in getTokens return NextResponse.next({ request: { headers } }); }, handleInvalidToken: async (reason) => { console.info('Missing or malformed credentials', { reason }); return redirectToLogin(request, { path: '/login', publicPaths: PUBLIC_PATHS }); }, handleError: async (error) => { console.error('Unhandled authentication error', { error }); return redirectToLogin(request, { path: '/login', publicPaths: PUBLIC_PATHS }); } }); } export const config = { matcher: [ '/api/login', '/api/logout', '/', '/((?!_next|favicon.ico|api|.*\.)*)' ] }; ``` -------------------------------- ### Initialize App Check with Service Account and Tenant ID Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/app-check.mdx Use the getAppCheck function from 'next-firebase-auth-edge/app-check' to initialize App Check. Provide serviceAccount details and optionally a tenantId for multi-tenancy. ```typescript import { getAppCheck } from "next-firebase-auth-edge/app-check"; // Optional in authenticated Google Cloud Run environment. Otherwise required. const serviceAccount = { projectId: "firebase-project-id", privateKey: "firebase service account private key", clientEmail: "firebase service account client email", }; // Optional. Specify if your project supports multi-tenancy // https://cloud.google.com/identity-platform/docs/multi-tenancy-authentication const tenantId = "You tenant id"; const { createToken, verifyToken } = getAppCheck({ serviceAccount, tenantId }); ``` -------------------------------- ### Get and Validate Tokens in Server Components Source: https://context7.com/awinogrodzki/next-firebase-auth-edge/llms.txt Use `getTokens` within Server Components to extract and validate session cookies. Returns null if unauthenticated or credentials expired. Requires API key, cookie name, signature keys, and service account details. ```tsx import { getTokens } from 'next-firebase-auth-edge'; import { cookies } from 'next/headers'; import { notFound } from 'next/navigation'; export default async function ProfilePage() { const tokens = await getTokens(await cookies(), { apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX', cookieName: 'AuthToken', cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'], 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' } }); if (!tokens) { return notFound(); // or redirect to login } const { token, decodedToken, customToken, metadata } = tokens; return (

Welcome, {decodedToken.email}

UID: {decodedToken.uid}

{metadata &&
{JSON.stringify(metadata, null, 2)}
}
); } ``` -------------------------------- ### Configure authMiddleware with Advanced Options Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/middleware.mdx Configure the authMiddleware with various options like login/logout paths, API keys, cookie settings, service account details, and custom token handling. It also includes handlers for valid tokens, invalid tokens, and errors, along with metadata retrieval and token refresh. ```tsx import {NextResponse} from 'next/server'; import type {NextRequest} from 'next/server'; import { authMiddleware, redirectToHome, redirectToLogin } from 'next-firebase-auth-edge'; const PUBLIC_PATHS = ['/register', '/login', '/reset-password']; export async function proxy(request: NextRequest) { return authMiddleware(request, { loginPath: '/api/login', logoutPath: '/api/logout', 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: 'lax' 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' }, enableMultipleCookies: true, enableCustomToken: false, debug: true, tenantId: 'your-tenant-id', checkRevoked: true, authorizationHeaderName: 'Authorization', dynamicCustomClaimsKeys: ['someCustomClaim'], handleValidToken: async ({token, decodedToken}, headers) => { // Authenticated user should not be able to access /login, /register and /reset-password routes if (PUBLIC_PATHS.includes(request.nextUrl.pathname)) { return redirectToHome(request); } return NextResponse.next({ request: { headers } }); }, handleInvalidToken: async (reason) => { console.info('Missing or malformed credentials', {reason}); return redirectToLogin(request, { path: '/login', publicPaths: PUBLIC_PATHS }); }, handleError: async (error) => { console.error('Unhandled authentication error', {error}); return redirectToLogin(request, { path: '/login', publicPaths: PUBLIC_PATHS }); }, getMetadata: async (tokens: TokenSet) => { // Here you can load any data related to the user // The data will be saved in cookies and can be accessed using `getTokens` function. // Note: The cookie size is limited, so keep the data compact return {uid: tokens.decodedIdToken.uid, timestamp: new Date().getTime()}; }, enableTokenRefreshOnExpiredKidHeader: true }); } export const config = { matcher: [ '/api/login', '/api/logout', '/', '/((?!_next|favicon.ico|api|.*\.)*)' ] }; ``` -------------------------------- ### Get Valid Custom Token for Firebase Auth Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/client-side-apis.mdx The `getValidCustomToken` function provides a valid custom token, essential for using Firebase's `signInWithCustomToken`. It works with the refresh token endpoint to ensure the token is current and only calls the endpoint when the token has expired. This function requires the server-side custom token obtained from `getTokens`. ```typescript export async function signInWithServerCustomToken(serverCustomToken: string) { const auth = getAuth(getFirebaseApp()); const customToken = await getValidCustomToken({ serverCustomToken, refreshTokenUrl: '/api/refresh-token' }); if (!customToken) { throw new Error('Invalid custom token'); } return signInWithCustomToken(auth, customToken); } ``` -------------------------------- ### createUser Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/advanced-usage.mdx Creates a new user and returns the UserRecord. Refer to Firebase’s Create a user documentation for details on the request structure. ```APIDOC ## createUser ### Description Creates a new user and returns the `UserRecord`. Refer to Firebase’s [Create a user](https://firebase.google.com/docs/auth/admin/manage-users#create_a_user) documentation for details on the request structure. ### Method `createUser(request: CreateRequest) => Promise` ``` -------------------------------- ### Get Valid ID Token for External API Calls Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/client-side-apis.mdx Use `getValidIdToken` to retrieve the latest valid ID token, ensuring it's up-to-date before making external API calls. This function efficiently checks token validity and only calls the refresh token endpoint if necessary. It requires the server-side ID token obtained from `getTokens`. ```typescript import {getValidIdToken} from 'next-firebase-auth-edge/next/client'; export async function fetchSomethingFromExternalApi(serverIdToken: string) { const idToken = await getValidIdToken({ serverIdToken, refreshTokenUrl: '/api/refresh-token' }); return fetch('https://some-external-api.com/api/example', { method: 'GET', headers: { Authorization: `Bearer ${idToken}` } }); } ``` -------------------------------- ### Import redirectToPath Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/redirect-functions.mdx Import the `redirectToPath` helper function from the library. ```typescript import {redirectToPath} from 'next-firebase-auth-edge'; ``` -------------------------------- ### getFirebaseAuth Initialization Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/advanced-usage.mdx Initialize `getFirebaseAuth` with your Firebase project configuration to access server-side authentication methods. ```APIDOC ## getFirebaseAuth The `getFirebaseAuth` function provides several server-side methods to manage more advanced authentication scenarios. ```tsx import {getFirebaseAuth} from 'next-firebase-auth-edge'; const { getCustomIdAndRefreshTokens, verifyIdToken, createCustomToken, handleTokenRefresh, getUser, getUserByEmail, createUser, updateUser, deleteUser, verifyAndRefreshExpiredIdToken, setCustomUserClaims } = getFirebaseAuth({ apiKey: 'YOUR FIREBASE API KEY', 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' } }); ``` ### Options | Name | Type | Required? | | ---------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | apiKey | `string` | **Required** | | serviceAccount | `{ projectId: string; clientEmail: string; privateKey: string }` | Optional (required unless in [Google Cloud Run](https://cloud.google.com/run) environment) | | tenantId | `string` | Optional | | serviceAccountId | `string` | Optional | ``` -------------------------------- ### redirectToLogin with Private Paths Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/redirect-functions.mdx Use `redirectToLogin` to redirect to a sign-in page, only redirecting if the request matches specified private paths. ```typescript redirectToLogin(request, { path: '/sign-in', privatePaths: ['/dashboard', /^\/settings\/(\w+)/] }); ``` -------------------------------- ### redirectToLogin with Public Paths Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/redirect-functions.mdx Use `redirectToLogin` to redirect to a sign-in page, skipping the redirect if the request matches specified public paths. ```typescript redirectToLogin(request, { path: '/sign-in', publicPaths: ['/sign-in', '/register', /^\/post\/(\w+)/] }); ``` -------------------------------- ### Implement AuthProvider Component Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/getting-started/auth-provider.mdx Use this component to wrap your application or specific sections to provide user data via AuthContext. It accepts a 'user' prop and 'children', rendering the AuthContext.Provider with the provided user value. ```tsx 'use client'; import * as React from 'react'; import {AuthContext, User} from './AuthContext'; export interface AuthProviderProps { user: User | null; children: React.ReactNode; } export const AuthProvider: React.FunctionComponent = ({ user, children }) => { return ( {children} ); }; ``` -------------------------------- ### Composing Auth Middleware with Next-Intl Source: https://context7.com/awinogrodzki/next-firebase-auth-edge/llms.txt Integrates next-firebase-auth-edge's authMiddleware with next-intl's createIntlMiddleware. Handles valid, invalid, and error token scenarios by invoking the intlMiddleware. ```tsx import type { NextRequest } from 'next/server'; import createIntlMiddleware from 'next-intl/middleware'; import { authMiddleware } from 'next-firebase-auth-edge'; const intlMiddleware = createIntlMiddleware({ locales: ['en', 'fr', 'de'], defaultLocale: 'en' }); export async function proxy(request: NextRequest) { return authMiddleware(request, { loginPath: '/api/login', logoutPath: '/api/logout', apiKey: 'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX', cookieName: 'AuthToken', cookieSignatureKeys: ['Key-Should-Be-at-least-32-bytes-in-length'], cookieSerializeOptions: { path: '/', httpOnly: true, secure: true, sameSite: 'lax' as const, maxAge: 86400 * 12 }, 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' }, handleValidToken: async () => intlMiddleware(request), handleInvalidToken: async () => intlMiddleware(request), handleError: async () => intlMiddleware(request) }); } export const config = { matcher: ['/', '/((?!_next|api|.*\.).*)', '/api/login', '/api/logout'] }; ``` -------------------------------- ### Enable Custom Token Authentication Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/docs/pages/docs/usage/middleware.mdx Enable custom token authentication by setting `enableCustomToken` to `true` within the `authMiddleware` options. This is recommended to be used with `enableMultipleCookies` to manage potential cookie size increases. ```tsx return authMiddleware(request, { enableCustomToken: true // ...other options }); ``` -------------------------------- ### AuthContext and AuthProvider for User State Source: https://context7.com/awinogrodzki/next-firebase-auth-edge/llms.txt Defines a React context and provider to share user state across client components. Requires UserInfo and custom Claims types. ```tsx import { createContext, useContext } from 'react'; import type { UserInfo } from 'firebase/auth'; import type { Claims } from 'next-firebase-auth-edge/auth/claims'; export interface User extends UserInfo { emailVerified: boolean; customClaims: Claims; } export const AuthContext = createContext<{ user: User | null }>({ user: null }); export const useAuth = () => useContext(AuthContext); ``` ```tsx 'use client'; import * as React from 'react'; import { AuthContext, User } from './AuthContext'; export function AuthProvider({ user, children }: { user: User | null; children: React.ReactNode }) { return {children}; } ``` -------------------------------- ### Configure Firebase App Check Source: https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/examples/next-typescript-starter/README.md Environment variables required for Firebase App Check integration. Replace placeholders with your actual App Check key and App ID. ```shell NEXT_PUBLIC_FIREBASE_APP_CHECK_KEY=XXxxxxXxXXXXXXXxxxXxxxXXXxxXXXXxxxxxXX_X NEXT_PUBLIC_FIREBASE_APP_ID=x:xxxxxxxxxxxx:web:xxxxxxxxxxxxxxxxxxxxxx ```