main a3721a8b460a cached
295 files
606.8 KB
177.4k tokens
588 symbols
1 requests
Download .txt
Showing preview only (680K chars total). Download the full file or copy to clipboard to get everything.
Repository: ensite-in/next-firebase-auth-edge
Branch: main
Commit: a3721a8b460a
Files: 295
Total size: 606.8 KB

Directory structure:
gitextract_erfprbrg/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       ├── main.yml
│       └── release.yml
├── .gitignore
├── .husky/
│   ├── commit-msg
│   └── pre-commit
├── .npmignore
├── .releaserc.yaml
├── .swcrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── commitlint.config.js
├── docs/
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── README.md
│   ├── components/
│   │   ├── Chip.tsx
│   │   ├── CommunityLink.tsx
│   │   ├── Example.tsx
│   │   ├── FeaturePanel.tsx
│   │   ├── Footer.tsx
│   │   ├── FooterLink.tsx
│   │   ├── FooterSeparator.tsx
│   │   ├── Hero.tsx
│   │   ├── HeroCode.tsx
│   │   ├── Link.tsx
│   │   ├── LinkButton.tsx
│   │   ├── Section.tsx
│   │   ├── Steps.module.css
│   │   ├── Steps.tsx
│   │   └── Wrapper.tsx
│   ├── config.js
│   ├── next-env.d.ts
│   ├── next-sitemap.config.js
│   ├── next.config.js
│   ├── package.json
│   ├── pages/
│   │   ├── _app.tsx
│   │   ├── _document.tsx
│   │   ├── _meta.json
│   │   ├── docs/
│   │   │   ├── _meta.json
│   │   │   ├── app-check.mdx
│   │   │   ├── emulator.mdx
│   │   │   ├── errors.mdx
│   │   │   ├── faq.mdx
│   │   │   ├── getting-started/
│   │   │   │   ├── _meta.json
│   │   │   │   ├── auth-context.mdx
│   │   │   │   ├── auth-provider.mdx
│   │   │   │   ├── index.mdx
│   │   │   │   ├── layout.mdx
│   │   │   │   ├── login-page.mdx
│   │   │   │   ├── login-with-server-action.mdx
│   │   │   │   ├── logout-with-server-action.mdx
│   │   │   │   └── middleware.mdx
│   │   │   └── usage/
│   │   │       ├── _meta.json
│   │   │       ├── advanced-usage.mdx
│   │   │       ├── app-router-api-routes.mdx
│   │   │       ├── client-side-apis.mdx
│   │   │       ├── cloud-run.mdx
│   │   │       ├── debug-mode.mdx
│   │   │       ├── domain-restriction.mdx
│   │   │       ├── firebase-hosting.mdx
│   │   │       ├── get-server-side-props.mdx
│   │   │       ├── index.mdx
│   │   │       ├── middleware.mdx
│   │   │       ├── pages-router-api-routes.mdx
│   │   │       ├── redirect-functions.mdx
│   │   │       ├── refresh-credentials.mdx
│   │   │       ├── remove-credentials.mdx
│   │   │       └── server-components.mdx
│   │   ├── examples/
│   │   │   └── index.mdx
│   │   └── index.mdx
│   ├── postcss.config.js
│   ├── prettier.config.js
│   ├── public/
│   │   └── favicon/
│   │       └── site.webmanifest
│   ├── services/
│   │   ├── BrowserTracker.tsx
│   │   └── ServerTracker.tsx
│   ├── styles.css
│   ├── tailwind.config.js
│   ├── theme.config.tsx
│   └── tsconfig.json
├── eslint.config.mjs
├── examples/
│   ├── next-typescript-minimal/
│   │   ├── .eslintrc.json
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── app/
│   │   │   ├── HomePage.tsx
│   │   │   ├── globals.css
│   │   │   ├── layout.tsx
│   │   │   ├── login/
│   │   │   │   └── page.tsx
│   │   │   ├── page.tsx
│   │   │   └── register/
│   │   │       └── page.tsx
│   │   ├── config.ts
│   │   ├── firebase.ts
│   │   ├── middleware.ts
│   │   ├── next.config.mjs
│   │   ├── package.json
│   │   ├── postcss.config.js
│   │   ├── tailwind.config.ts
│   │   └── tsconfig.json
│   └── next-typescript-starter/
│       ├── .dockerignore
│       ├── .firebaserc
│       ├── .gitignore
│       ├── Dockerfile
│       ├── README.md
│       ├── api/
│       │   └── index.ts
│       ├── app/
│       │   ├── actions/
│       │   │   ├── login.ts
│       │   │   ├── refresh-cookies.ts
│       │   │   └── user-counters.ts
│       │   ├── api/
│       │   │   ├── check-email-verification/
│       │   │   │   └── route.ts
│       │   │   ├── custom-claims/
│       │   │   │   └── route.ts
│       │   │   ├── test-app-check/
│       │   │   │   └── route.ts
│       │   │   ├── token-test/
│       │   │   │   └── route.ts
│       │   │   └── user-counters/
│       │   │       └── route.ts
│       │   ├── auth/
│       │   │   ├── AuthContext.ts
│       │   │   ├── AuthProvider.tsx
│       │   │   └── firebase.ts
│       │   ├── firebase.ts
│       │   ├── globals.css
│       │   ├── layout.module.css
│       │   ├── layout.tsx
│       │   ├── login/
│       │   │   ├── LoginPage.tsx
│       │   │   ├── firebase.ts
│       │   │   ├── login.module.css
│       │   │   └── page.tsx
│       │   ├── page.module.css
│       │   ├── page.tsx
│       │   ├── profile/
│       │   │   ├── UserProfile/
│       │   │   │   ├── UserProfile.module.css
│       │   │   │   ├── UserProfile.tsx
│       │   │   │   ├── index.ts
│       │   │   │   ├── user-counters-server.ts
│       │   │   │   └── user-counters.ts
│       │   │   ├── page.module.css
│       │   │   └── page.tsx
│       │   ├── register/
│       │   │   ├── RegisterPage.tsx
│       │   │   ├── firebase.ts
│       │   │   ├── page.tsx
│       │   │   └── register.module.css
│       │   ├── reset-password/
│       │   │   ├── ResetPasswordPage.module.css
│       │   │   ├── ResetPasswordPage.tsx
│       │   │   ├── firebase.ts
│       │   │   └── page.tsx
│       │   └── shared/
│       │       ├── redirect.ts
│       │       ├── useRedirectAfterLogin.ts
│       │       ├── useRedirectParam.ts
│       │       └── user.ts
│       ├── app-check/
│       │   └── index.ts
│       ├── config/
│       │   ├── client-config.ts
│       │   └── server-config.ts
│       ├── eslint.config.mjs
│       ├── firebase.json
│       ├── next-env.d.ts
│       ├── next.config.js
│       ├── package.json
│       ├── pages/
│       │   └── api/
│       │       └── tokens.ts
│       ├── proxy.ts
│       ├── tsconfig.json
│       └── ui/
│           ├── Badge/
│           │   ├── Badge.module.css
│           │   ├── Badge.tsx
│           │   └── index.ts
│           ├── Button/
│           │   ├── Button.module.css
│           │   ├── Button.tsx
│           │   └── index.ts
│           ├── ButtonGroup/
│           │   ├── ButtonGroup.module.css
│           │   ├── ButtonGroup.tsx
│           │   └── index.ts
│           ├── Card/
│           │   ├── Card.module.css
│           │   ├── Card.tsx
│           │   └── index.ts
│           ├── FormError/
│           │   ├── FormError.module.css
│           │   ├── FormError.tsx
│           │   └── index.ts
│           ├── HomeLink/
│           │   ├── HomeLink.module.css
│           │   ├── HomeLink.tsx
│           │   └── index.ts
│           ├── IconButton/
│           │   ├── IconButton.module.css
│           │   ├── IconButton.tsx
│           │   └── index.ts
│           ├── Input/
│           │   ├── Input.module.css
│           │   ├── Input.tsx
│           │   └── index.ts
│           ├── MainTitle/
│           │   ├── MainTitle.module.css
│           │   ├── MainTitle.tsx
│           │   └── index.ts
│           ├── PasswordForm/
│           │   ├── PasswordForm.module.css
│           │   ├── PasswordForm.tsx
│           │   └── index.ts
│           ├── Switch/
│           │   ├── Switch.module.css
│           │   ├── Switch.tsx
│           │   ├── index.ts
│           │   └── vars.css
│           ├── classNames.ts
│           └── icons/
│               ├── HiddenIcon.tsx
│               ├── HomeIcon.tsx
│               ├── LoadingIcon.tsx
│               ├── VisibleIcon.tsx
│               ├── icons.module.css
│               └── index.ts
├── jest.config.js
├── jest.setup.ts
├── package.json
├── prettier.config.js
├── src/
│   ├── app-check/
│   │   ├── api-client.ts
│   │   ├── index.ts
│   │   ├── test/
│   │   │   └── app-check.integration.test.ts
│   │   ├── token-generator.ts
│   │   ├── token-verifier.ts
│   │   └── types.ts
│   ├── auth/
│   │   ├── auth-request-handler.ts
│   │   ├── claims.ts
│   │   ├── credential.ts
│   │   ├── custom-token/
│   │   │   ├── index.test.ts
│   │   │   └── index.ts
│   │   ├── default-credential.ts
│   │   ├── error.ts
│   │   ├── firebase.ts
│   │   ├── index.ts
│   │   ├── jwt/
│   │   │   ├── consts.ts
│   │   │   ├── crypto-signer.ts
│   │   │   ├── sign.test.ts
│   │   │   ├── sign.ts
│   │   │   ├── verify.test.ts
│   │   │   └── verify.ts
│   │   ├── rotating-credential.test.ts
│   │   ├── rotating-credential.ts
│   │   ├── signature-verifier.test.ts
│   │   ├── signature-verifier.ts
│   │   ├── test/
│   │   │   ├── create-custom-token.integration.test.ts
│   │   │   ├── no-matching-kid.integration.test.ts
│   │   │   ├── session-cookie.test.ts
│   │   │   ├── set-custom-user-claims.integration.test.ts
│   │   │   ├── user.integration.test.ts
│   │   │   └── verify-token.integration.test.ts
│   │   ├── token-generator.ts
│   │   ├── token-verifier.ts
│   │   ├── types.ts
│   │   ├── user-record.ts
│   │   ├── utils.ts
│   │   └── validator.ts
│   ├── debug/
│   │   └── index.ts
│   ├── index.ts
│   └── next/
│       ├── api.ts
│       ├── client.ts
│       ├── cookies/
│       │   ├── AuthCookies.test.ts
│       │   ├── AuthCookies.ts
│       │   ├── builder/
│       │   │   ├── CookieBuilder.ts
│       │   │   ├── CookieBuilderFactory.ts
│       │   │   ├── MultipleCookieBuilder.test.ts
│       │   │   ├── MultipleCookieBuilder.ts
│       │   │   ├── SingleCookieBuilder.test.ts
│       │   │   └── SingleCookieBuilder.ts
│       │   ├── expiration/
│       │   │   ├── CombinedCookieExpiration.ts
│       │   │   ├── CookieExpiration.ts
│       │   │   ├── CookieExpirationFactory.test.ts
│       │   │   ├── CookieExpirationFactory.ts
│       │   │   ├── MultipleCookieExpiration.test.ts
│       │   │   ├── MultipleCookieExpiration.ts
│       │   │   ├── SingleCookieExpiration.test.ts
│       │   │   └── SingleCookieExpiration.ts
│       │   ├── index.test.ts
│       │   ├── index.ts
│       │   ├── parser/
│       │   │   ├── CookieParser.ts
│       │   │   ├── CookieParserFactory.test.ts
│       │   │   ├── CookieParserFactory.ts
│       │   │   ├── CookiesProvider.ts
│       │   │   ├── MultipleCookiesParser.test.ts
│       │   │   ├── MultipleCookiesParser.ts
│       │   │   ├── ObjectCookiesProvider.ts
│       │   │   ├── RequestCookiesProvider.test.ts
│       │   │   ├── RequestCookiesProvider.ts
│       │   │   ├── SingleCookieParser.test.ts
│       │   │   └── SingleCookieParser.ts
│       │   ├── remover/
│       │   │   ├── CombinedCookieRemover.ts
│       │   │   ├── CookieRemover.ts
│       │   │   ├── CookieRemoverFactory.test.ts
│       │   │   ├── CookieRemoverFactory.ts
│       │   │   ├── MultipleCookieRemover.test.ts
│       │   │   ├── MultipleCookieRemover.ts
│       │   │   └── SingleCookieRemover.ts
│       │   ├── setter/
│       │   │   ├── CookieSetter.ts
│       │   │   ├── CookieSetterFactory.ts
│       │   │   ├── HeadersCookieSetter.test.ts
│       │   │   ├── HeadersCookieSetter.ts
│       │   │   ├── NextApiResponseHeadersCookieSetter.ts
│       │   │   ├── RequestCookieSetter.test.ts
│       │   │   └── RequestCookieSetter.ts
│       │   └── types.ts
│       ├── metadata.ts
│       ├── middleware.ts
│       ├── refresh-token.ts
│       ├── tokens.ts
│       └── utils.ts
├── tsconfig.base.json
├── tsconfig.browser.json
├── tsconfig.esm.json
├── tsconfig.json
└── tsconfig.test.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
github: awinogrodzki

================================================
FILE: .github/workflows/main.yml
================================================
name: Main

on:
  pull_request:
    paths:
      - "**"
      - "!*.md"
      - "!**/*.md"
      - "!.gitignore"

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  FIREBASE_API_KEY: AIzaSyAXYgJha6lO_L4qfWpnhf3KijeKYDhuFzQ
  FIREBASE_PROJECT_ID: next-firebase-auth-edge-demo
  FIREBASE_ADMIN_CLIENT_EMAIL: ${{ secrets.FIREBASE_ADMIN_CLIENT_EMAIL }}
  FIREBASE_ADMIN_PRIVATE_KEY: ${{ secrets.FIREBASE_ADMIN_PRIVATE_KEY }}
  FIREBASE_AUTH_TENANT_ID: ${{ secrets.FIREBASE_AUTH_TENANT_ID }}
  FIREBASE_APP_CHECK_KEY: ${{ secrets.FIREBASE_APP_CHECK_KEY }}
  FIREBASE_APP_ID: ${{ secrets.FIREBASE_APP_ID }}
jobs:
  install:
    name: Install dependencies
    timeout-minutes: 10
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 22
        uses: actions/setup-node@v4
        with:
          cache: "yarn"
          cache-dependency-path: yarn.lock
          node-version: 22
      - name: Cache node_modules
        uses: actions/cache@v4
        with:
          path: |
            node_modules
          key: ${{ runner.os }}-node_modules-cache-v2-${{ hashFiles('./yarn.lock') }}-${{github.sha}}
          restore-keys: |
            ${{ runner.os }}-node_modules-cache-v2-${{ hashFiles('./yarn.lock') }}-
      - run: yarn install

  build:
    name: Build packages
    timeout-minutes: 15
    needs: install
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 22
        uses: actions/setup-node@v4
        with:
          node-version: 22
      - name: Cache node_modules
        uses: actions/cache@v4
        with:
          path: |
            node_modules
          key: ${{ runner.os }}-node_modules-cache-v2-${{ hashFiles('./yarn.lock') }}-${{github.sha}}
      - name: Cache build
        uses: actions/cache@v4
        with:
          path: |
            lib
          key: ${{ runner.os }}-build-cache-v2-${{ github.ref_name }}-${{github.sha}}
          restore-keys: |
            ${{ runner.os }}-build-cache-v2-${{ github.ref_name }}-
      - run: yarn build

  lint:
    name: Lint packages
    timeout-minutes: 10
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 22
        uses: actions/setup-node@v4
        with:
          node-version: 22
      - name: Cache node_modules
        uses: actions/cache@v4
        with:
          path: |
            node_modules
          key: ${{ runner.os }}-node_modules-cache-v2-${{ hashFiles('./yarn.lock') }}-${{github.sha}}
      - run: yarn lint

  tests:
    name: Tests
    timeout-minutes: 15
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 22
        uses: actions/setup-node@v4
        with:
          node-version: 22
      - name: Cache node_modules
        uses: actions/cache@v4
        with:
          path: |
            node_modules
          key: ${{ runner.os }}-node_modules-cache-v2-${{ hashFiles('./yarn.lock') }}-${{github.sha}}
      - name: Cache build
        uses: actions/cache@v4
        with:
          path: |
            lib
          key: ${{ runner.os }}-build-cache-v2-${{ github.ref_name }}-${{github.sha}}
      - run: yarn test


================================================
FILE: .github/workflows/release.yml
================================================
name: Release

env:
  FIREBASE_API_KEY: AIzaSyAXYgJha6lO_L4qfWpnhf3KijeKYDhuFzQ
  FIREBASE_PROJECT_ID: next-firebase-auth-edge-demo
  FIREBASE_ADMIN_CLIENT_EMAIL: ${{ secrets.FIREBASE_ADMIN_CLIENT_EMAIL }}
  FIREBASE_ADMIN_PRIVATE_KEY: ${{ secrets.FIREBASE_ADMIN_PRIVATE_KEY }}
  FIREBASE_AUTH_TENANT_ID: ${{ secrets.FIREBASE_AUTH_TENANT_ID }}
  FIREBASE_APP_CHECK_KEY: ${{ secrets.FIREBASE_APP_CHECK_KEY }}
  FIREBASE_APP_ID: ${{ secrets.FIREBASE_APP_ID }}

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

on:
  push:
    branches: [main, canary]
    paths:
      - "**"
      - "!*.md"
      - "!**/*.md"
      - "!.gitignore"

jobs:
  install:
    name: Install dependencies
    timeout-minutes: 10
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 22
        uses: actions/setup-node@v4
        with:
          cache: "yarn"
          cache-dependency-path: yarn.lock
          node-version: 22
      - name: Cache node_modules
        uses: actions/cache@v4
        with:
          path: |
            node_modules
          key: ${{ runner.os }}-node_modules-cache-v2-${{ hashFiles('./yarn.lock') }}-${{github.sha}}
          restore-keys: |
            ${{ runner.os }}-node_modules-cache-v2-${{ hashFiles('./yarn.lock') }}-
      - run: yarn install

  build:
    name: Build packages
    timeout-minutes: 15
    needs: install
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 22
        uses: actions/setup-node@v4
        with:
          node-version: 22
      - name: Cache node_modules
        uses: actions/cache@v4
        with:
          path: |
            node_modules
          key: ${{ runner.os }}-node_modules-cache-v2-${{ hashFiles('./yarn.lock') }}-${{github.sha}}
      - name: Cache build
        uses: actions/cache@v4
        with:
          path: |
            lib
            browser
            esm
          key: ${{ runner.os }}-build-cache-v2-${{ github.ref_name }}-${{github.sha}}
          restore-keys: |
            ${{ runner.os }}-build-cache-v2-${{ github.ref_name }}-
      - run: yarn build

  semantic-release:
    if: "!contains(github.event.head_commit.message, '[skip ci]')"

    name: Semantic Release
    runs-on: ubuntu-latest
    needs:
      - build
    permissions:
      contents: write
      id-token: write

    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 22
        uses: actions/setup-node@v4
        with:
          node-version: 22
      - name: Cache node_modules
        uses: actions/cache@v4
        with:
          path: |
            node_modules
          key: ${{ runner.os }}-node_modules-cache-v2-${{ hashFiles('./yarn.lock') }}-${{github.sha}}
      - name: Cache build
        uses: actions/cache@v4
        with:
          path: |
            lib
            browser
            esm
          key: ${{ runner.os }}-build-cache-v2-${{ github.ref_name }}-${{github.sha}}
          restore-keys: |
            ${{ runner.os }}-build-cache-v2-${{ github.ref_name }}-

      - name: Release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: npx semantic-release





================================================
FILE: .gitignore
================================================
node_modules
.vscode
yarn-error.log
.yarn
.next
.env


tmp
package-lock.json
coverage
webpack-stats.json
.turbo
.DS_Store
.idea
*.log
dist
.fleet
.history

#dist
lib
browser
esm
cjs


================================================
FILE: .husky/commit-msg
================================================
npx --no -- commitlint --edit "${1}"


================================================
FILE: .husky/pre-commit
================================================
yarn test
yarn lint --fix
yarn check-circular-imports
git add --all


================================================
FILE: .npmignore
================================================
.env
.env.dist
examples
src
!lib
!browser
!esm

================================================
FILE: .releaserc.yaml
================================================
plugins:
  - "@semantic-release/commit-analyzer"
  - "@semantic-release/release-notes-generator"
  - "@semantic-release/changelog"
  - "@semantic-release/npm"
  - "@semantic-release/git"
  - - "@semantic-release/github"
    - successComment: false
      failTitle: false

branches:
  - main
  - name: canary
    prerelease: true


================================================
FILE: .swcrc
================================================
{
  "jsc": {
     "parser": {
        "syntax": "typescript",
        "decorators": true
     },
     "transform": {
        "legacyDecorator": true,
        "decoratorMetadata": true
     }
  }
}

================================================
FILE: CHANGELOG.md
================================================
# [1.12.0](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.11.5...v1.12.0) (2026-02-26)


### Bug Fixes

* **release:** update canary release after rebase ([f80caf1](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f80caf15dde88da8164bcef3be643a60c4380065))


### Features

* **next:** support Next.js 16 ([7f69f89](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/7f69f893223fdd2297563d408601999890b079b6))

# [1.12.0-canary.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.11.5...v1.12.0-canary.1) (2026-02-26)


### Bug Fixes

* **release:** update canary release after rebase ([f80caf1](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f80caf15dde88da8164bcef3be643a60c4380065))


### Features

* **next:** support Next.js 16 ([7f69f89](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/7f69f893223fdd2297563d408601999890b079b6))

## [1.11.5](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.11.4...v1.11.5) (2026-02-16)


### Bug Fixes

* update node version to 22 in github workflows ([ce45f99](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/ce45f99daa167e1871ba3794937ad9f10aafa850))

## [1.11.4](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.11.3...v1.11.4) (2026-02-16)


### Bug Fixes

* another attempt to fix semantic release ([1397c7b](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/1397c7b880a0bc158fcbd79fb034f63c9ac2c1dd))

## [1.11.3](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.11.2...v1.11.3) (2026-02-16)


### Bug Fixes

* insignificant change to trigger and test release flow ([d90764d](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d90764d956cf7c0d8a727afaefb27610cae76859))
* trigger release to test semantic release integration ([e5dd2f0](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/e5dd2f0909920262d53b0ae27765fbe1f336b7ff))

## [1.11.2](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.11.1...v1.11.2) (2026-02-16)


### Bug Fixes

* upgrade semantic release version to support provenance mode ([a37975b](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/a37975b403791671f10a96d8508fa3d72b7ef903))
* use provenance with semantic release ([d2031e5](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d2031e5875606a8c73201174cd52af0546fe612e))

## [1.11.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.11.0...v1.11.1) (2025-09-14)


### Bug Fixes

* remove cookie verification warning ([910808e](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/910808ea03dcf0da986218ae56182bc1f265d17d))

# [1.11.0](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.10.1...v1.11.0) (2025-08-21)


### Bug Fixes

* **refresh-token:** respond with 401: Unauthorized when verify fails with InvalidTokenError ([cf84cec](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/cf84cecf77ae14bbadf5c1441abe74a2e0c65b58))


### Features

* **enableTokenRefreshOnExpiredKidHeader:** token refresh on expired kid is no longer experimental ([6800605](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/6800605360aae0d45680c8252ad432f453d1c4f5))
* **refresh-token:** handle 401: Unauthorized in getValidIdToken and getValidCustomToken ([d96d89f](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d96d89f3be6edbcd0d10174017e62aea886fbd33))

## [1.10.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.10.0...v1.10.1) (2025-08-18)


### Bug Fixes

* pass dynamicCustomClaimsKeys in refreshCookiesWithIdToken ([cbae23f](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/cbae23f461b84fc1642805f1602bb81f99b4dc63))

# [1.10.0](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.9.1...v1.10.0) (2025-08-11)


### Bug Fixes

* allow to use `/` as private path ([00eaeca](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/00eaeca9b2ea73a736fab5d2ba60f9f22a764f2b))
* encode redirect param ([2afeef3](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/2afeef38e0fab0214b0c06da2b258871c909414f))


### Features

* **middleware:** redirectToLogin supports privatePaths ([1a5450c](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/1a5450cade9266275c036b23752b66f0327d4669))
* exposing token-verifier for public use ([d4a3796](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d4a379692f41376608ecf4b865ed249f07daffd1))
* update firebase, firebase-admin and react dependencies ([41b94f7](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/41b94f7b16a9012b3707bf6942dee75eea1ea5bc))
* **metadata:** added metadata support ([9dda6dc](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/9dda6dc8ea88291b286cb6a6be47899f0e647d90))
* **metadata:** clear metadata cookies after logout ([d148629](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d148629daa226314fcd994ffafe094fc226b890a))
* **metadata:** improved getTokens warning readability ([6945e55](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/6945e55f4b6157d5d46799a07d0bb437954b594a))
* **metadata:** integrate metadata with starter example ([5ed8cf3](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/5ed8cf3880bf15fd153dcd3c00cbe44faeeb7145))
* **metadata:** update types with getMetadata method ([5d9dbaa](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/5d9dbaa4f692dc76b667197e3f20ed7a83d10310))

# [1.10.0-canary.7](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.10.0-canary.6...v1.10.0-canary.7) (2025-08-11)


### Bug Fixes

* allow to use `/` as private path ([00eaeca](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/00eaeca9b2ea73a736fab5d2ba60f9f22a764f2b))

# [1.10.0-canary.6](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.10.0-canary.5...v1.10.0-canary.6) (2025-08-11)


### Features

* **middleware:** redirectToLogin supports privatePaths ([1a5450c](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/1a5450cade9266275c036b23752b66f0327d4669))

# [1.10.0-canary.5](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.10.0-canary.4...v1.10.0-canary.5) (2025-08-11)


### Features

* update firebase, firebase-admin and react dependencies ([41b94f7](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/41b94f7b16a9012b3707bf6942dee75eea1ea5bc))

# [1.10.0-canary.4](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.10.0-canary.3...v1.10.0-canary.4) (2025-05-29)


### Bug Fixes

* encode redirect param ([2afeef3](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/2afeef38e0fab0214b0c06da2b258871c909414f))

# [1.10.0-canary.3](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.10.0-canary.2...v1.10.0-canary.3) (2025-04-08)


### Features

* exposing token-verifier for public use ([d4a3796](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d4a379692f41376608ecf4b865ed249f07daffd1))

# [1.10.0-canary.2](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.10.0-canary.1...v1.10.0-canary.2) (2025-03-11)


### Features

* **metadata:** clear metadata cookies after logout ([d148629](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d148629daa226314fcd994ffafe094fc226b890a))

# [1.10.0-canary.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.9.1...v1.10.0-canary.1) (2025-03-11)


### Features

* **metadata:** added metadata support ([9dda6dc](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/9dda6dc8ea88291b286cb6a6be47899f0e647d90))
* **metadata:** improved getTokens warning readability ([6945e55](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/6945e55f4b6157d5d46799a07d0bb437954b594a))
* **metadata:** integrate metadata with starter example ([5ed8cf3](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/5ed8cf3880bf15fd153dcd3c00cbe44faeeb7145))
* **metadata:** update types with getMetadata method ([5d9dbaa](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/5d9dbaa4f692dc76b667197e3f20ed7a83d10310))

## [1.9.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.9.0...v1.9.1) (2025-02-18)


### Bug Fixes

* **dynamic-custom-claims:** allow to update claims after token refresh ([475e767](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/475e76709ece48294746b334522c0c16dbc5ce6d))

# [1.9.0](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.2...v1.9.0) (2025-02-18)


### Bug Fixes

* **#297:** propagate custom claims when exchanging id token for custom, id and refresh tokens ([55254b8](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/55254b87196c9fb7f16c36785131b34edd3b219e)), closes [#297](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/297)
* **#303:** support npm 11 ([88328e5](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/88328e51abfebf2eef63895b37d91784a0e982ce)), closes [#303](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/303)
* **#306:** support Node.js 23 ([f27d210](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f27d21023b8f0120fd7ddfd17e9c9d42b2a28f31)), closes [#306](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/306)
* return cached token or server token ([c1a04a9](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/c1a04a96f12aea574aa5c44b2d41a053bf746f6c))
* return cached valid token ([a73f9ec](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/a73f9ecd04860c72613664c3ab857fe4efd46954))


### Features

* **#300:** added removeServerCookies method to logout from Server Actions ([cab2d23](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/cab2d238012ed7fb20cdbb09da7e69eab3867c14)), closes [#300](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/300)
* full firebase emulator support ([9dcf5e9](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/9dcf5e94be548b0f3bb0277bee6abce43592a7d2))

# [1.9.0-canary.6](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.9.0-canary.5...v1.9.0-canary.6) (2025-01-28)


### Bug Fixes

* **#306:** support Node.js 23 ([f27d210](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f27d21023b8f0120fd7ddfd17e9c9d42b2a28f31)), closes [#306](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/306)

# [1.9.0-canary.5](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.9.0-canary.4...v1.9.0-canary.5) (2025-01-23)


### Bug Fixes

* **#303:** support npm 11 ([88328e5](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/88328e51abfebf2eef63895b37d91784a0e982ce)), closes [#303](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/303)

# [1.9.0-canary.4](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.9.0-canary.3...v1.9.0-canary.4) (2025-01-22)


### Features

* **#300:** added removeServerCookies method to logout from Server Actions ([cab2d23](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/cab2d238012ed7fb20cdbb09da7e69eab3867c14)), closes [#300](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/300)

# [1.9.0-canary.3](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.9.0-canary.2...v1.9.0-canary.3) (2025-01-21)


### Bug Fixes

* **#297:** propagate custom claims when exchanging id token for custom, id and refresh tokens ([55254b8](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/55254b87196c9fb7f16c36785131b34edd3b219e)), closes [#297](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/297)

# [1.9.0-canary.2](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.9.0-canary.1...v1.9.0-canary.2) (2024-12-16)


### Bug Fixes

* return cached token or server token ([c1a04a9](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/c1a04a96f12aea574aa5c44b2d41a053bf746f6c))
* return cached valid token ([a73f9ec](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/a73f9ecd04860c72613664c3ab857fe4efd46954))

# [1.9.0-canary.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.2...v1.9.0-canary.1) (2024-11-15)


### Features

* full firebase emulator support ([9dcf5e9](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/9dcf5e94be548b0f3bb0277bee6abce43592a7d2))

## [1.8.2](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.1...v1.8.2) (2024-11-07)


### Bug Fixes

* **docs:** added `await` before calling `cookies` and `headers` due to change in Next.js 15 ([d14c9df](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d14c9df55aa3476ea30d56b884599f4e8af9e3ff))
* add logs to invalid token comparator func ([11eaede](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/11eaedee236b4cf93f5b2542ae10eebbe0c86884))
* added additional logs around cookie parser ([1550c80](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/1550c80e504e7e49ff44a89dd20c59c2878b6dbc))
* added additional logs to debug a failed verification in auth middleware ([30ddc5e](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/30ddc5e6f4cb7c7d713cc210d77648d8722d924c))
* await on parse cookie result to work around [#271](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/271) ([f6b5106](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f6b51062b4308e32d1ef1d123912d21dc93d3f85))
* debug Vercel logging by removing inheritance from Error ([46ca356](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/46ca35632f46d92dc4f0229552c09e4f455fee58))
* export error module explicitly ([575281c](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/575281c45e037eccdf48c833ae605cd373388896))
* remove console.log and improve debug logs around token fetching ([31dfbd2](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/31dfbd2226dcd775bd4a76cdb4a5c5f04f72954e))
* remove debug logs from cookie parser ([2ce3190](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/2ce3190cbffa476fd228f6cc1bf578cae6c8591f))
* remove unnecessary async in get tokens functions ([c0f530c](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/c0f530c3ecfe9c0e120f20d4a9e3bcab264a28db))
* work around [#271](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/271) in getCookiesTokens ([5fef799](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/5fef799648daa2a0fcf20829dd82b443b9f511e7))
* **#271:** use runtime flag to identify invalid token error ([d7220b0](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d7220b0e1dd642385d3320efd812b2e08117e51e)), closes [#271](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/271)

## [1.8.2-canary.11](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.2-canary.10...v1.8.2-canary.11) (2024-11-07)


### Bug Fixes

* **docs:** added `await` before calling `cookies` and `headers` due to change in Next.js 15 ([d14c9df](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d14c9df55aa3476ea30d56b884599f4e8af9e3ff))

## [1.8.2-canary.10](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.2-canary.9...v1.8.2-canary.10) (2024-11-06)


### Bug Fixes

* remove unnecessary async in get tokens functions ([c0f530c](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/c0f530c3ecfe9c0e120f20d4a9e3bcab264a28db))
* work around [#271](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/271) in getCookiesTokens ([5fef799](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/5fef799648daa2a0fcf20829dd82b443b9f511e7))

## [1.8.2-canary.9](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.2-canary.8...v1.8.2-canary.9) (2024-11-06)


### Bug Fixes

* await on parse cookie result to work around [#271](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/271) ([f6b5106](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f6b51062b4308e32d1ef1d123912d21dc93d3f85))

## [1.8.2-canary.8](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.2-canary.7...v1.8.2-canary.8) (2024-11-06)


### Bug Fixes

* remove debug logs from cookie parser ([2ce3190](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/2ce3190cbffa476fd228f6cc1bf578cae6c8591f))

## [1.8.2-canary.7](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.2-canary.6...v1.8.2-canary.7) (2024-11-06)


### Bug Fixes

* added additional logs around cookie parser ([1550c80](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/1550c80e504e7e49ff44a89dd20c59c2878b6dbc))

## [1.8.2-canary.6](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.2-canary.5...v1.8.2-canary.6) (2024-11-06)


### Bug Fixes

* debug Vercel logging by removing inheritance from Error ([46ca356](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/46ca35632f46d92dc4f0229552c09e4f455fee58))

## [1.8.2-canary.5](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.2-canary.4...v1.8.2-canary.5) (2024-11-06)


### Bug Fixes

* remove console.log and improve debug logs around token fetching ([31dfbd2](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/31dfbd2226dcd775bd4a76cdb4a5c5f04f72954e))

## [1.8.2-canary.4](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.2-canary.3...v1.8.2-canary.4) (2024-11-06)


### Bug Fixes

* add logs to invalid token comparator func ([11eaede](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/11eaedee236b4cf93f5b2542ae10eebbe0c86884))

## [1.8.2-canary.3](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.2-canary.2...v1.8.2-canary.3) (2024-11-06)


### Bug Fixes

* **#271:** use runtime flag to identify invalid token error ([d7220b0](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d7220b0e1dd642385d3320efd812b2e08117e51e)), closes [#271](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/271)

## [1.8.2-canary.2](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.2-canary.1...v1.8.2-canary.2) (2024-11-06)


### Bug Fixes

* export error module explicitly ([575281c](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/575281c45e037eccdf48c833ae605cd373388896))

## [1.8.2-canary.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.1...v1.8.2-canary.1) (2024-11-06)


### Bug Fixes

* added additional logs to debug a failed verification in auth middleware ([30ddc5e](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/30ddc5e6f4cb7c7d713cc210d77648d8722d924c))

## [1.8.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.0...v1.8.1) (2024-11-05)


### Bug Fixes

* update cookie library to avoid vulnerability in cookie < 0.7.0 ([0940e28](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/0940e2875a3f8d0b9769317914df074d70caa741))

# [1.8.0](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.1...v1.8.0) (2024-10-28)


### Bug Fixes

* added circular import validation ([deaa2e3](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/deaa2e393b4e7630090d0dce96ed9e7e6b7fa8e0))
* automated release build cache ([b6abf5a](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/b6abf5aea77efdfb3827b18864fe0d08c8a2f7e6))
* create request cookies provider from cloned headers ([d17c376](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d17c3762807ccba180116612c0463dec4357b0e9))
* include missing directories in package.json exports ([668ae8b](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/668ae8bc4dc55b05623de71e97a2faf1eb417928))
* remove declarations from esm build ([025e4c8](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/025e4c8a501201618df4fb77a6532d22aed9ddaf))


### Features

* make custom token optional ([4a18cb7](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/4a18cb7ed6aca3e8e72819437939fae1bc9eeffc))
* refactor cookies to separate multiple from single type ([9aba786](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/9aba786f04ab20c8e57e1daeacab670d59c770f0))
* support esm, commonjs and browser build targets ([93a17bd](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/93a17bde917817d7191cfaf5bce4f17a836c454b))
* validate tenantId when verifying id token ([798d0f1](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/798d0f1037b387a691284b22f6a092dfbfd0d156))

# [1.8.0-canary.9](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.0-canary.8...v1.8.0-canary.9) (2024-10-09)


### Features

* make custom token optional ([4a18cb7](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/4a18cb7ed6aca3e8e72819437939fae1bc9eeffc))

# [1.8.0-canary.8](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.0-canary.7...v1.8.0-canary.8) (2024-09-30)


### Bug Fixes

* create request cookies provider from cloned headers ([d17c376](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d17c3762807ccba180116612c0463dec4357b0e9))

# [1.8.0-canary.7](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.0-canary.6...v1.8.0-canary.7) (2024-09-30)


### Bug Fixes

* added circular import validation ([deaa2e3](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/deaa2e393b4e7630090d0dce96ed9e7e6b7fa8e0))

# [1.8.0-canary.6](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.0-canary.5...v1.8.0-canary.6) (2024-09-29)


### Features

* refactor cookies to separate multiple from single type ([9aba786](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/9aba786f04ab20c8e57e1daeacab670d59c770f0))

# [1.8.0-canary.5](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.0-canary.4...v1.8.0-canary.5) (2024-09-22)


### Bug Fixes

* include missing directories in package.json exports ([668ae8b](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/668ae8bc4dc55b05623de71e97a2faf1eb417928))

# [1.8.0-canary.4](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.0-canary.3...v1.8.0-canary.4) (2024-09-22)


### Bug Fixes

* automated release build cache ([b6abf5a](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/b6abf5aea77efdfb3827b18864fe0d08c8a2f7e6))

# [1.8.0-canary.3](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.0-canary.2...v1.8.0-canary.3) (2024-09-22)


### Bug Fixes

* remove declarations from esm build ([025e4c8](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/025e4c8a501201618df4fb77a6532d22aed9ddaf))

# [1.8.0-canary.2](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.8.0-canary.1...v1.8.0-canary.2) (2024-09-22)


### Features

* support esm, commonjs and browser build targets ([93a17bd](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/93a17bde917817d7191cfaf5bce4f17a836c454b))

# [1.8.0-canary.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.1...v1.8.0-canary.1) (2024-09-21)


### Features

* validate tenantId when verifying id token ([798d0f1](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/798d0f1037b387a691284b22f6a092dfbfd0d156))

## [1.7.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0...v1.7.1) (2024-09-13)


### Bug Fixes

* handle switch from multiple to single cookie ([9b18bd5](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/9b18bd58ed0b765c19727d8aaf8f1f45299623d0))

# [1.7.0](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.2...v1.7.0) (2024-09-09)


### Bug Fixes

* add debug logs for experimental feature ([41ef1df](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/41ef1dfcf6fe23a7dabfa4e8d3cc5e2c1172b31e))
* **#242:** use TextEncoder when mapping token to UInt8Array ([23b04dc](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/23b04dcd8867fd7c6b108c41496cb19930e5cc16)), closes [#242](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/242)
* **#246:** re-throw invalid PKCS8 error as AuthError with user-friendly message ([a7d7a22](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/a7d7a228733e67525b001cff70a523880d858e01)), closes [#246](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/246)
* **#249:** merge error stack trace in token verifier to improve visibility on fetch errors ([6bce756](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/6bce7564216dff60fe736ef85e8508d2df686eaf)), closes [#249](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/249)
* add missing name property to decoded id token type ([39b086d](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/39b086db222f619a8b4cf0365895f33c6832e3fc))
* pass cookie serialization options to cookie setter ([b28ce7a](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/b28ce7a866318f958e58b14e4adfcc85a47e5bef))
* recreate canary tags after force push ([c9b7c18](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/c9b7c18e5cb4f8a31e5388e0bfd23665e8b5674e))
* semantic-release rate exceeded error ([676b602](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/676b6021a013c0afdddd75a0cea71b2a8b4786e2))
* semantic-version git history issue ([d514f57](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d514f5713883e1713f265b07a4670518af646a6b))
* update next.js peer dependency to rc ([f2953fd](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f2953fd38bdd6df9b4b535a21abb47793249752b))


### Features

* **middleware:** introduced `redirectToPath` method and RegExp support in `redirectToLogin` method ([21024bb](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/21024bb02f6f0300301e7822751e047caef745c0))
* added `path` option to `redirectToHome` helper function ([54f07f4](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/54f07f4a09fad3e46fc089e5d762afa4df5eb1f5))
* allow setAuthCookies to accept custom auth headers or fall back ([b1d169b](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/b1d169b13d1c6132799aed23ef1c6da3698ba080))
* experimental option to refresh token on expired kid header ([2869531](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/28695315164fffee7b3a08879e95033c44b8a197))
* introduced `refreshCookiesWithIdToken` function to enable login using Server Actions ([#212](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/212)) ([6cd0b13](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/6cd0b138036ff0f4fcfa91d786fca5255cfa2654))
* next.js 15 rc support ([a994dd0](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/a994dd07bce5420049573b2651b08ecb1a82b63c))
* pass custom auth header from authMiddleware ([71286af](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/71286afe6c7faebf2cdcd568e507a5e0739720f0))
* **getTokens:** introduced optional `cookieSerializeOptions` option ([e041542](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/e041542c6b2f4380fcc7f803f7e1c8d5c14bc6e1))
* replaced no matching kid auth error with invalid token error ([9d2d0fc](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/9d2d0fcb49374d0bb6b260c43d8a2409377b0144))
* support Node.js 22 ([6c7f435](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/6c7f435485391a4d987f0bc3d0653536d4ef93ff))

# [1.7.0-canary.17](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.16...v1.7.0-canary.17) (2024-09-07)


### Features

* **middleware:** introduced `redirectToPath` method and RegExp support in `redirectToLogin` method ([21024bb](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/21024bb02f6f0300301e7822751e047caef745c0))

# [1.7.0-canary.16](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.15...v1.7.0-canary.16) (2024-09-06)


### Features

* allow setAuthCookies to accept custom auth headers or fall back ([b1d169b](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/b1d169b13d1c6132799aed23ef1c6da3698ba080))
* pass custom auth header from authMiddleware ([71286af](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/71286afe6c7faebf2cdcd568e507a5e0739720f0))

# [1.7.0-canary.15](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.14...v1.7.0-canary.15) (2024-09-06)


### Bug Fixes

* add debug logs for experimental feature ([41ef1df](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/41ef1dfcf6fe23a7dabfa4e8d3cc5e2c1172b31e))

# [1.7.0-canary.14](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.13...v1.7.0-canary.14) (2024-09-06)


### Features

* experimental option to refresh token on expired kid header ([2869531](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/28695315164fffee7b3a08879e95033c44b8a197))

# [1.7.0-canary.13](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.12...v1.7.0-canary.13) (2024-09-03)


### Bug Fixes

* **#249:** merge error stack trace in token verifier to improve visibility on fetch errors ([6bce756](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/6bce7564216dff60fe736ef85e8508d2df686eaf)), closes [#249](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/249)

# [1.7.0-canary.12](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.11...v1.7.0-canary.12) (2024-09-03)


### Bug Fixes

* **#242:** use TextEncoder when mapping token to UInt8Array ([23b04dc](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/23b04dcd8867fd7c6b108c41496cb19930e5cc16)), closes [#242](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/242)

# [1.7.0-canary.11](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.10...v1.7.0-canary.11) (2024-08-30)


### Bug Fixes

* **#246:** re-throw invalid PKCS8 error as AuthError with user-friendly message ([a7d7a22](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/a7d7a228733e67525b001cff70a523880d858e01)), closes [#246](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/246)

# [1.7.0-canary.10](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.9...v1.7.0-canary.10) (2024-08-22)


### Features

* **getTokens:** introduced optional `cookieSerializeOptions` option ([e041542](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/e041542c6b2f4380fcc7f803f7e1c8d5c14bc6e1))

# [1.7.0-canary.9](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.8...v1.7.0-canary.9) (2024-08-21)


### Bug Fixes

* pass cookie serialization options to cookie setter ([b28ce7a](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/b28ce7a866318f958e58b14e4adfcc85a47e5bef))

# [1.7.0-canary.8](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.7...v1.7.0-canary.8) (2024-08-21)


### Features

* replaced no matching kid auth error with invalid token error ([9d2d0fc](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/9d2d0fcb49374d0bb6b260c43d8a2409377b0144))

# [1.7.0-canary.7](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.6...v1.7.0-canary.7) (2024-08-21)


### Features

* support Node.js 22 ([6c7f435](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/6c7f435485391a4d987f0bc3d0653536d4ef93ff))

# [1.7.0-canary.6](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.5...v1.7.0-canary.6) (2024-08-10)


### Bug Fixes

* semantic-release rate exceeded error ([676b602](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/676b6021a013c0afdddd75a0cea71b2a8b4786e2))

# [1.7.0-canary.5](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.4...v1.7.0-canary.5) (2024-08-10)


### Bug Fixes

* update next.js peer dependency to rc ([f2953fd](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f2953fd38bdd6df9b4b535a21abb47793249752b))

# [1.7.0-canary.4](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.3...v1.7.0-canary.4) (2024-08-10)


### Bug Fixes

* add missing name property to decoded id token type ([39b086d](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/39b086db222f619a8b4cf0365895f33c6832e3fc))


### Features

* next.js 15 rc support ([a994dd0](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/a994dd07bce5420049573b2651b08ecb1a82b63c))

# [1.7.0-canary.3](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.7.0-canary.2...v1.7.0-canary.3) (2024-08-08)


### Bug Fixes

* recreate canary tags after force push ([c9b7c18](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/c9b7c18e5cb4f8a31e5388e0bfd23665e8b5674e))
* semantic-version git history issue ([d514f57](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d514f5713883e1713f265b07a4670518af646a6b))

# [1.7.0-canary.2](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.2...v1.7.0-canary.2) (2024-07-25)


### Features

* added `path` option to `redirectToHome` helper function ([54f07f4](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/54f07f4a09fad3e46fc089e5d762afa4df5eb1f5))


# [1.7.0-canary.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.1...v1.7.0-canary.1) (2024-07-16)


### Features

* introduced `refreshCookiesWithIdToken` function to enable login using Server Actions ([#212](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/212)) ([fd6b193](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/fd6b193d345af85e7cca502640b98e2c93aebadc))

## [1.6.2](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.1...v1.6.2) (2024-07-16)


### Bug Fixes

* fix `JWSInvalid: Invalid Compact JWS` error when migrating between token formats ([#214](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/214)) ([5b6b0c3](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/5b6b0c3c0eeb62e1f28c7e48c73ad93bee3c0bbc))

## [1.6.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.0...v1.6.1) (2024-07-15)


### Bug Fixes

* rename appendEmptyResponseHeaders to removeCookies ([498d044](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/498d0443b7981776cc7091049ac83a92a4d8d81b))

# [1.6.0](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.5.3...v1.6.0) (2024-07-15)


### Bug Fixes

* enable refresh token route ([d081c22](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d081c22f67bdde49211ac6053011901c616f99d6))
* fix "process is not defined" error in cloudflare worker [#192](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/192) ([6a94587](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/6a9458774da1ec8a026a223ffd9204eb5c11915f))
* return null from getValidIdToken if provided server token is empty ([613f230](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/613f230504e30e8329eb1c1be008fadbf4347c96))
* store latest valid id token on client ([5764a33](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/5764a33ae8cadff6e48f5e7cb6d31e977e4d8ab9))
* suppress unknown headers property error ([1459ba9](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/1459ba99703ba7a6b3e9f10f59304d0974ccc652))


### Features

* added `getValidCustomToken` method and documented client-side SDK usage ([2261ef9](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/2261ef9321a0e3974456af2db11915a128d69421))
* exposed customToken in handleValidToken, getTokens and getFirebaseAuth methods ([f95c34c](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f95c34cafb5f87b3afe60130a1631e3c337f2d34))
* introduced `enableMultipleCookies` auth middleware option to increase token capacity ([23ee02f](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/23ee02f2160faee133127dfb8808b1977dba4593))
* introduced refreshTokenPath middleware option and getValidIdToken client method ([56e07c5](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/56e07c59cc9b6da45fd818c0600638bb9258bafa))
* introduced removeCookie method ([f108984](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f108984a9c74ed8cf2cf26133a8f3f8f65c905f9))
* support for async response factory in refreshCredentials method ([25bf5c4](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/25bf5c46f68bc0f8cdd6cfd480802f3d23922a4d))

# [1.6.0-canary.9](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.0-canary.8...v1.6.0-canary.9) (2024-07-14)


### Features

* introduced `enableMultipleCookies` auth middleware option to increase token capacity ([23ee02f](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/23ee02f2160faee133127dfb8808b1977dba4593))

# [1.6.0-canary.8](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.0-canary.7...v1.6.0-canary.8) (2024-07-14)


### Features

* added `getValidCustomToken` method and documented client-side SDK usage ([2261ef9](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/2261ef9321a0e3974456af2db11915a128d69421))

# [1.6.0-canary.7](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.0-canary.6...v1.6.0-canary.7) (2024-07-07)


### Bug Fixes

* suppress unknown headers property error ([1459ba9](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/1459ba99703ba7a6b3e9f10f59304d0974ccc652))


### Features

* exposed customToken in handleValidToken, getTokens and getFirebaseAuth methods ([f95c34c](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f95c34cafb5f87b3afe60130a1631e3c337f2d34))

# [1.6.0-canary.6](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.0-canary.5...v1.6.0-canary.6) (2024-06-17)


### Bug Fixes

* return null from getValidIdToken if provided server token is empty ([613f230](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/613f230504e30e8329eb1c1be008fadbf4347c96))

# [1.6.0-canary.5](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.0-canary.4...v1.6.0-canary.5) (2024-06-15)


### Bug Fixes

* store latest valid id token on client ([5764a33](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/5764a33ae8cadff6e48f5e7cb6d31e977e4d8ab9))

# [1.6.0-canary.4](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.0-canary.3...v1.6.0-canary.4) (2024-06-15)


### Bug Fixes

* enable refresh token route ([d081c22](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/d081c22f67bdde49211ac6053011901c616f99d6))

# [1.6.0-canary.3](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.0-canary.2...v1.6.0-canary.3) (2024-06-15)


### Features

* introduced refreshTokenPath middleware option and getValidIdToken client method ([56e07c5](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/56e07c59cc9b6da45fd818c0600638bb9258bafa))

# [1.6.0-canary.2](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.6.0-canary.1...v1.6.0-canary.2) (2024-06-05)


### Features

* introduced removeCookie method ([f108984](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f108984a9c74ed8cf2cf26133a8f3f8f65c905f9))

# [1.6.0-canary.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.5.4-canary.1...v1.6.0-canary.1) (2024-06-05)


### Features

* support for async response factory in refreshCredentials method ([25bf5c4](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/25bf5c46f68bc0f8cdd6cfd480802f3d23922a4d))

## [1.5.4-canary.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.5.3...v1.5.4-canary.1) (2024-06-01)


### Bug Fixes

* fix "process is not defined" error in cloudflare worker [#192](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/192) ([6a94587](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/6a9458774da1ec8a026a223ffd9204eb5c11915f))

## [1.5.3](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.5.2...v1.5.3) (2024-05-31)


### Bug Fixes

* referer is now based on caller host ([2f75386](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/2f75386de3d91aea42345771c006221eff819104))

## [1.5.2](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.5.1...v1.5.2) (2024-05-30)


### Bug Fixes

* expose tokens in refreshCredentials response factory callback ([644b8a2](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/644b8a272cb48e830d21344f12bae9e3082ae1f4))

## [1.5.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.5.0...v1.5.1) (2024-05-30)


### Bug Fixes

* reintroduce refreshAuthCookies as refreshNextResponseCookiesWithToken ([620f986](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/620f98682b9002837bfca287d32ea0371f2b2017))

# [1.5.0](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.4.5...v1.5.0) (2024-05-30)


### Bug Fixes

* remove fetch `cache: no-store` due to https://github.com/awinogrodzki/next-firebase-auth-edge/issues/173 ([6fb8143](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/6fb81430b580b586f5a27c5b36624a441aa68e82))


### Features

* added refreshCredentials method that allows to pass modified request headers to NextResponse constructor ([2bf2877](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/2bf2877f5b12456c5e8125d5fa1babfc0074edaf))
* extract referer from Next.js request headers ([bc666fa](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/bc666fa887b81adbf91681faa7d1974417b20988))
* introduced Firebase API Key domain restriction support. Introduced changes to advanced methods and removed APIs deprecated in 1.0 ([67dbb9a](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/67dbb9a2908d62d90fb40a5a154cd2a7d8b14626))


### Performance Improvements

* **refreshCredentials:** slightly improve performance by generating signed tokens only once ([da2fc3e](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/da2fc3e164da0d5015e4d484813cafce2f033ea2))

# [1.5.0-canary.5](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.5.0-canary.4...v1.5.0-canary.5) (2024-05-30)


### Features

* extract referer from Next.js request headers ([bc666fa](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/bc666fa887b81adbf91681faa7d1974417b20988))

# [1.5.0-canary.4](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.5.0-canary.3...v1.5.0-canary.4) (2024-05-27)


### Performance Improvements

* **refreshCredentials:** slightly improve performance by generating signed tokens only once ([da2fc3e](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/da2fc3e164da0d5015e4d484813cafce2f033ea2))

# [1.5.0-canary.3](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.5.0-canary.2...v1.5.0-canary.3) (2024-05-27)


### Features

* added refreshCredentials method that allows to pass modified request headers to NextResponse constructor ([2bf2877](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/2bf2877f5b12456c5e8125d5fa1babfc0074edaf))

# [1.5.0-canary.2](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.5.0-canary.1...v1.5.0-canary.2) (2024-05-26)


### Bug Fixes

* remove fetch `cache: no-store` due to https://github.com/awinogrodzki/next-firebase-auth-edge/issues/173 ([6fb8143](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/6fb81430b580b586f5a27c5b36624a441aa68e82))

# [1.5.0-canary.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.4.5...v1.5.0-canary.1) (2024-05-26)


### Features

* introduced Firebase API Key domain restriction support. Introduced changes to advanced methods and removed APIs deprecated in 1.0 ([67dbb9a](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/67dbb9a2908d62d90fb40a5a154cd2a7d8b14626))

## [1.4.5](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.4.4...v1.4.5) (2024-05-26)


### Bug Fixes

* /api/login endpoint now fails with 400: Missing Token error when called without credentials ([2997fc5](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/2997fc51c503400fb9068750374797993f4a61d8))
* exclude lib folder from npmignore file ([f7ef2d5](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f7ef2d5249d7183f3f1204a34c540e03392943a4))
* fix build cache path in github workflows ([df4c98d](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/df4c98dfe7176029743a04513aa5b67c60a453a3))
* remove .env.dist from npm package ([5c136f9](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/5c136f9e2e7d2f3bc0427f21a91c7ff36a87d0d0))
* remove tests and lint steps from semantic release pipeline ([160662d](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/160662d53077e7cfdd69f194eb1d89e31a7e8d55))
* semantic release npm publish initialization ([3ed6ef5](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/3ed6ef591ced2613d3936aea7dd28140605ca167))
* semantic release package configuration ([ec93cc6](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/ec93cc67ed5a8a2a624cef526de88d7601829aec))
* set correct pkgRoot in semantic releases configuration ([9c36948](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/9c3694839088fee50e1362537cc7ad3e345d7763))

## [1.4.5-canary.7](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.4.5-canary.6...v1.4.5-canary.7) (2024-05-26)


### Bug Fixes

* fix build cache path in github workflows ([df4c98d](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/df4c98dfe7176029743a04513aa5b67c60a453a3))

## [1.4.5-canary.6](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.4.5-canary.5...v1.4.5-canary.6) (2024-05-26)


### Bug Fixes

* exclude lib folder from npmignore file ([f7ef2d5](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/f7ef2d5249d7183f3f1204a34c540e03392943a4))

## [1.4.5-canary.5](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.4.5-canary.4...v1.4.5-canary.5) (2024-05-26)


### Bug Fixes

* remove tests and lint steps from semantic release pipeline ([160662d](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/160662d53077e7cfdd69f194eb1d89e31a7e8d55))

## [1.4.5-canary.4](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.4.5-canary.3...v1.4.5-canary.4) (2024-05-26)


### Bug Fixes

* set correct pkgRoot in semantic releases configuration ([9c36948](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/9c3694839088fee50e1362537cc7ad3e345d7763))

## [1.4.5-canary.2](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.4.5-canary.1...v1.4.5-canary.2) (2024-05-26)


### Bug Fixes

* remove .env.dist from npm package ([5c136f9](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/5c136f9e2e7d2f3bc0427f21a91c7ff36a87d0d0))

## [1.4.5-canary.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.4.4...v1.4.5-canary.1) (2024-05-26)


### Bug Fixes

* /api/login endpoint now fails with 400: Missing Token error when called without credentials ([2997fc5](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/2997fc51c503400fb9068750374797993f4a61d8))
* semantic release npm publish initialization ([3ed6ef5](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/3ed6ef591ced2613d3936aea7dd28140605ca167))

## [1.4.4](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.4.3...v1.4.4) (2024-05-26)


### Bug Fixes

* disable default tag behavior in yarn publish ([1661468](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/1661468a501ad759ac55ce66d3eb0c8bab496b13))
* lint ([c703cfb](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/c703cfb9a4c5afc67165366fd1bcaa3651c67a73))
* semantic release publish step authorization ([232f624](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/232f6244e0126b0112cc4a0255780b070049910d))
* semantic release publish step git author ([c917de4](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/c917de4227f432e0aeefdcdc1fd6b38a0d79d7bf))

## [1.4.4-canary.1](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.4.3...v1.4.4-canary.1) (2024-05-26)


### Bug Fixes

* disable default tag behavior in yarn publish ([1661468](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/1661468a501ad759ac55ce66d3eb0c8bab496b13))
* lint ([c703cfb](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/c703cfb9a4c5afc67165366fd1bcaa3651c67a73))
* semantic release publish step authorization ([232f624](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/232f6244e0126b0112cc4a0255780b070049910d))
* semantic release publish step git author ([c917de4](https://github.com/awinogrodzki/next-firebase-auth-edge/commit/c917de4227f432e0aeefdcdc1fd6b38a0d79d7bf))

## 1.4.3

### Patch Changes

- Remove digest from debug logs

## 1.4.2

### Patch Changes

- Fetch Google public keys with cache: "no-store" to fix #159

## 1.4.1

### Patch Changes

- Improve cookieSignatureKeys input validation

## 1.4.0

### Minor Changes

- `handleInvalidToken` is now called with `InvalidTokenReason` as the first argument. It gives developers more inslight and control over authentication flow

## 1.3.0

### Minor Changes

- The library now stores tokens and signature in a single cookie, allowing to run in Firebase Hosting environment
- Use the library without service account in authenticated Google Cloud Run environment
- Added debug mode option

## 1.2.0

### Minor Changes

- Introduced refreshServerCookies method to refresh credentials from inside Server Actions

## 1.1.0

### Minor Changes

- Deprecated refreshAuthCookies methods in favor of refreshNextResponseCookies and refreshApiResponseCookies

## 1.0.1

### Patch Changes

- Update middleware token verification caching doc link

## 1.0.0

### Major Changes

- Reworked APIs

## 0.11.2

### Patch Changes

- Added getUserByEmail method

## 0.11.1

### Patch Changes

- Added Node.js 20 support

## 0.11.0

### Patch Changes

- Added App Check support

## 0.10.2

### Patch Changes

- Stop displaying middleware verification cache warning on prefetched routes

## 0.10.1

### Patch Changes

- Remove internal verification cookie on middleware request instead throwing an error
- Remove internal verification cookie on middleware request instead of throwing an error

## 0.10.0

### Minor Changes

- Next.js 14 support

## 0.9.5

### Patch Changes

- Skip response headers validation on redirect

## 0.9.4

### Patch Changes

- Add list users function support

## 0.9.3

### Patch Changes

- 964c04c: Check if the FIREBASE_AUTH_EMULATOR_HOST has already http:// added to it, otherwise you will get a cryptic fetch failed error.

## 0.9.2

### Patch Changes

- Support tenantId in refreshAuthCookies

## 0.9.1

### Patch Changes

- Return null if user was deleted from Firebase

## 0.9.0

### Minor Changes

- Added middleware token verification caching

## 0.8.8

### Patch Changes

- Add support for specifying tenantId in middleware

## 0.8.7

### Patch Changes

- Convert signature key to UInt8Array directly instead using base64url.decode due to #92

## 0.8.6

### Patch Changes

- Throw user friendly error on no matching kid in public keys response

## 0.8.5

### Patch Changes

- Revalidate token against all public keys if kid is missing

## 0.8.4

### Patch Changes

- Fix https://github.com/awinogrodzki/next-firebase-auth-edge/issues/90 by validating token against all returned public keys in case of not matching kid header

## 0.8.3

### Patch Changes

- Fix no "kid" claim in idToken error when using emulator

## 0.8.2

### Patch Changes

- Added createUser and updateUser methods

## 0.8.1

### Patch Changes

- Remove 'cache: no-store' header from refreshExpiredIdToken

## 0.8.0

### Minor Changes

- Refactor: remove custom JSON Web Token and Signature implementation in favor of jose

## 0.7.7

### Patch Changes

- Fix Node.js 18.17 native WebCrypto ArrayBuffer compatibility issue

## 0.7.6

### Patch Changes

- Import Next.js request cookie interfaces as type

## 0.7.5

### Patch Changes

- Make caches optional due to Vercel Edge middleware error https://github.com/vercel/next.js/issues/50102

## 0.7.4

### Patch Changes

- Set global cache before using ResponseCache

## 0.7.3

### Patch Changes

- Use polyfill only if runtime is defined

## 0.7.2

### Patch Changes

- Fix "body already used" error by cloning response upon rewriting

## 0.7.1

### Patch Changes

- Added @edge-runtime/primitives to dependencies

## 0.7.0

### Minor Changes

- Updated Next.js to 13.4 with stable app directory. Integrated edge-runtime and removed direct dependency to @peculiar/web-crypto. Integrated ServiceAccountCredential and PublicKeySignatureVerifier with Web APIs CacheStorage.

## 0.6.2

### Patch Changes

- Update engines to support Node 19

## 0.6.1

### Patch Changes

- Fix ReadonlyRequestCookies imports after update to Next.js 13.3.0

## 0.6.0

### Minor Changes

- Added setCustomUserClaims, getUser and refreshAuthCookies Edge-runtime compatible methods

## 0.5.1

### Patch Changes

- Handle refresh token error using handleError function
- Updated dependencies
  - next-firebase-auth-edge@0.5.1

## 0.5.0

### Minor Changes

- Rename methods from getAuthenticatedResponse, getUnauthenticatedResponse and getErrorResponse to more readable handleValidToken, handleInvalidToken and handleError functions

## 0.4.4

### Patch Changes

- Added refreshAuthCookies method to refresh cookie headers in api middleware

## 0.4.3

### Patch Changes

- Introduced getUnauthenticatedResponse middleware option to handle redirects for unauthenticated users

## 0.4.2

### Patch Changes

- getAuthenticatedResponse and getErrorResponse options are now async

## 0.4.1

### Patch Changes

- Optional redirectOptions for use-cases where authentication happens in more than one contexts

## 0.4.0

### Minor Changes

- Added authentication middleware to automatically handle redirection and authentication cookie refresh

## 0.3.1

### Patch Changes

- Re-throw INVALID_CREDENTIALS FirebaseAuthError with error details on token refresh error

## 0.3.0

### Minor Changes

- Updated peer next peer dependency to ^13.1.1 and removed allowMiddlewareResponseBody flag'

## 0.2.15

### Patch Changes

- Handle "USER_NOT_FOUND" error during token refresh

## 0.2.14

### Patch Changes

- Added Firebase Authentication Emulator support

## 0.2.13

### Patch Changes

- Fix incorrect HMAC algorithm key buffer size

## 0.2.12

### Patch Changes

- Update rotating credential HMAC key algorithm to SHA-512

## 0.2.11

### Patch Changes

- Update rotating credential HMAC key algorithm to SHA-256

## 0.2.10

### Patch Changes

- Support Next.js 18 LTS

## 0.2.9

### Patch Changes

- Update Next.js peerDependency version to ^13.0.5 to allow future minor/patch versions

## 0.2.8

### Patch Changes

- Integrated with changesets and eslint to improve transparency and legibility


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2023 Amadeusz Winogrodzki

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



================================================
FILE: README.md
================================================
<picture>
  <source media="(prefers-color-scheme: dark)" srcset="logo-white.svg">
  <source media="(prefers-color-scheme: light)" srcset="logo.svg">
  <img alt="next-firebase-auth-edge" src="logo.svg" width="320">
</picture>

---

Next.js Firebase Authentication for Edge and Node.js runtimes. Use Firebase Authentication with latest Next.js features.

[![npm version](https://badge.fury.io/js/next-firebase-auth-edge.svg)](https://badge.fury.io/js/next-firebase-auth-edge)

## Example

Check out a working demo here: [next-firebase-auth-edge-starter.vercel.app](https://next-firebase-auth-edge-starter.vercel.app/)

You can find the source code for this demo at [examples/next-typescript-starter](https://github.com/ensite-in/next-firebase-auth-edge/tree/main/examples/next-typescript-starter)

## Guide

New to Firebase or Next.js? No worries! Follow this easy, step-by-step guide to set up Firebase Authentication in Next.js app using the **next-firebase-auth-edge** library:

https://hackernoon.com/using-firebase-authentication-with-the-latest-nextjs-features

## Docs

The official documentation is available here: https://next-firebase-auth-edge-docs.vercel.app

## Why?

The official `firebase-admin` library depends heavily on Node.js’s internal `crypto` library, which isn’t available in [Next.js Edge Runtime](https://nextjs.org/docs/api-reference/edge-runtime).

This library solves that problem by handling the creation and verification of [Custom ID Tokens](https://firebase.google.com/docs/auth/admin/verify-id-tokens) using the Web Crypto API, which works in Edge runtimes.

## Features

`next-firebase-auth-edge` supports all the latest Next.js features, like the [App Router](https://nextjs.org/docs/app) and [Server Components](https://nextjs.org/docs/app/building-your-application/rendering/server-components).

To make adopting the newest Next.js features easier, this library works seamlessly with both [getServerSideProps](https://nextjs.org/docs/pages/building-your-application/data-fetching/get-server-side-props) and legacy [API Routes](https://nextjs.org/docs/pages/building-your-application/routing/api-routes).

### Key Features:
* **Supports Next.js's latest features**
* **Zero bundle size**
* **Minimal setup**: Unlike other libraries, you won’t need to create your own API routes or modify your `next.config.js`. Everything’s handled by [middleware](https://next-firebase-auth-edge-docs.vercel.app/docs/usage/middleware).
* **Secure**: Uses [jose](https://github.com/panva/jose) for JWT validation, and signs user cookies with rotating keys to prevent cryptanalysis attacks.

### What's New

Key updates in latest release include:

* New `enableTokenRefreshOnExpiredKidHeader` option in `authMiddleware`, which refreshes user tokens when Google’s public certificates expire (instead of throwing an error)
* Added `privatePaths` option to [redirectToLogin](https://next-firebase-auth-edge-docs.vercel.app/docs/usage/redirect-functions#redirecttologin) helper function 
* Added [Metadata](https://next-firebase-auth-edge-docs.vercel.app/docs/usage/middleware#metadata) feature that allows to store custom data inside session cookies
* Added `removeServerCookies` method to handle logout from inside Server Action 
* Added `experimental_createAnonymousUserIfUserNotFound` option to create anonymous user if no user was found 
* Full Firebase Emulator Support.
The library now fully supports the Firebase Emulator, enabling you to run your development app without needing to create a Firebase Project. Follow [starter example README](https://github.com/awinogrodzki/next-firebase-auth-edge/tree/main/examples/next-typescript-starter#emulator-support) for details
* Custom token is now optional. To enable custom token support use [enableCustomToken](https://next-firebase-auth-edge-docs.vercel.app/docs/usage/middleware#custom-token) option
* Support ESM, Browser and Node.js imports for better tree-shaking features
* Support for **Node.js 24+** and **NPM 11**
* Support for **Next.js 16**
* Support for **React 19**

## Installation

To install, run one of the following:

With **npm**

```shell
npm install next-firebase-auth-edge
```

With **yarn**

```shell
yarn add next-firebase-auth-edge
```

With **pnpm**

```shell
pnpm add next-firebase-auth-edge
```

## [→ Read the docs](https://next-firebase-auth-edge-docs.vercel.app/)


================================================
FILE: commitlint.config.js
================================================
module.exports = { extends: ['@commitlint/config-conventional'] };


================================================
FILE: docs/.eslintrc.js
================================================
module.exports = {
  extends: ['prettier'],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
  },
  plugins: ['@typescript-eslint', 'prettier'],
  root: true,
  rules: {
    'prettier/prettier': 'error',
  },
};


================================================
FILE: docs/.gitignore
================================================
/node_modules
/.next/
.DS_Store
.vercel
public/.nextra
tsconfig.tsbuildinfo
.env
public/robots.txt
public/sitemap.xml
public/sitemap-0.xml


================================================
FILE: docs/README.md
================================================
# docs

Website for `next-firebase-auth-edge`

You can run it locally like this:

```
yarn install
yarn dev
```


================================================
FILE: docs/components/Chip.tsx
================================================
import clsx from 'clsx';
import {ReactNode} from 'react';

type Props = {
  children: ReactNode;
  className?: string;
  color?: 'green' | 'yellow';
};

export default function Chip({children, className, color = 'green'}: Props) {
  return (
    <span
      className={clsx(
        className,
        'inline-block rounded-md px-[6px] py-[2px] text-xs font-semibold uppercase tracking-wider',
        {
          green:
            'bg-green-100 text-green-800 dark:bg-green-700/50 dark:text-green-100',
          yellow:
            'bg-yellow-100 text-orange-800 dark:bg-yellow-700/50 dark:text-yellow-100'
        }[color]
      )}
    >
      {children}
    </span>
  );
}


================================================
FILE: docs/components/CommunityLink.tsx
================================================
import Link from 'next/link';
import {ComponentProps} from 'react';
import Chip from './Chip';

type Props = Omit<ComponentProps<typeof Link>, 'children'> & {
  date: string;
  author: string;
  title: string;
  type?: 'article' | 'video';
};

export default function CommunityLink({
  author,
  date,
  title,
  type,
  ...rest
}: Props) {
  return (
    <div>
      <Link className="inline-block py-2" {...rest}>
        <p className="text-xl font-semibold">{title}</p>
        <div className="mt-2">
          {type && (
            <Chip
              className="mr-2 translate-y-[-1px]"
              color={({article: 'green', video: 'yellow'} as const)[type]}
            >
              {{article: 'Article', video: 'Video'}[type]}
            </Chip>
          )}
          <p className="inline-block text-base text-slate-500">{date}</p>
          <p className="inline-block text-base text-slate-500">{' ・ '}</p>
          <p className="inline-block text-base text-slate-500">{author}</p>
        </div>
      </Link>
    </div>
  );
}


================================================
FILE: docs/components/Example.tsx
================================================
import Chip from './Chip';

type Props = {
  demoLink?: string;
  sourceLink: string;
  hash: string;
  name: string;
  description: string;
  featured?: boolean;
};

export default function Example({
  demoLink,
  description,
  featured,
  hash,
  name,
  sourceLink
}: Props) {
  return (
    <div className="py-2">
      <h2
        className="flex scroll-mt-8 items-center text-xl font-semibold"
        id={hash}
      >
        {name}
        {featured && <Chip className="ml-3">Featured</Chip>}
      </h2>
      <div className="mt-2">
        <p className="mt-2 max-w-lg text-base text-slate-600 dark:text-slate-400">
          {description}
        </p>
        <div className="mt-2">
          <a
            className="nx-text-primary-600 inline-block text-base underline"
            href={sourceLink}
            rel="noreferrer"
            target="_blank"
          >
            Source
          </a>
          {demoLink && (
            <>
              <span className="inline-block text-base text-slate-500">
                {' ・ '}
              </span>
              <a
                className="nx-text-primary-600 inline-block text-base underline"
                href={demoLink}
                rel="noreferrer"
                target="_blank"
              >
                Demo
              </a>
            </>
          )}
        </div>
      </div>
    </div>
  );
}


================================================
FILE: docs/components/FeaturePanel.tsx
================================================
type Props = {
  code?: string;
  description: string;
  title: string;
};

export default function FeaturePanel({code, description, title}: Props) {
  return (
    <div className="-mx-4 flex flex-col overflow-hidden border-slate-200 lg:mx-0">
      {code && (
        <div className="grow rounded-sm bg-white dark:bg-slate-800">
          <pre className="-ml-4 overflow-x-auto !p-4 lg:!p-6">{code}</pre>
        </div>
      )}
      <div className="p-4 lg:p-6">
        <h3 className="font-semibold text-slate-900 dark:text-white">
          {title}
        </h3>
        <p className="mt-2 max-w-md text-slate-600 dark:text-slate-400">
          {description}
        </p>
      </div>
    </div>
  );
}


================================================
FILE: docs/components/Footer.tsx
================================================
import config from 'config';
import {useRouter} from 'next/router';
import FooterLink from './FooterLink';
import FooterSeparator from './FooterSeparator';

export default function Footer() {
  const router = useRouter();

  // Unfortunately, Nextra renders the footer incorrectly here
  const isHidden = router.pathname.startsWith('/examples');
  if (isHidden) return null;

  return (
    <div className="border-t border-slate-200 bg-slate-100 dark:border-t-slate-800 dark:bg-transparent">
      <div className="mx-auto max-w-[90rem] px-4 py-2 md:flex md:justify-between ">
        <div>
          <FooterLink href="/docs">Docs</FooterLink>
          <FooterSeparator />
          <FooterLink href="/examples">Examples</FooterLink>
        </div>
        <div>
          <FooterLink href={config.githubUrl} target="_blank">
            GitHub
          </FooterLink>
          <FooterSeparator />
          <FooterLink
            href="https://github.com/sponsors/awinogrodzki"
            target="_blank"
          >
            &#9829; Sponsor
          </FooterLink>
        </div>
      </div>
    </div>
  );
}


================================================
FILE: docs/components/FooterLink.tsx
================================================
import Link from 'next/link';
import {ComponentProps} from 'react';

type Props = ComponentProps<typeof Link>;

export default function FooterLink({children, ...rest}: Props) {
  return (
    <Link
      className="inline-block py-3 text-slate-500 transition-colors hover:text-slate-900 dark:text-slate-400 dark:hover:text-white"
      {...rest}
    >
      <p className="inline-flex items-center text-xs">{children}</p>
    </Link>
  );
}


================================================
FILE: docs/components/FooterSeparator.tsx
================================================
export default function FooterSeparator() {
  return (
    <span className="mx-1 text-slate-400 dark:text-slate-400">
      &nbsp;&middot;&nbsp;
    </span>
  );
}


================================================
FILE: docs/components/Hero.tsx
================================================
import HeroCode from './HeroCode';
import LinkButton from './LinkButton';
import Wrapper from './Wrapper';

type Props = {
  description: string;
  getStarted: string;
  titleRegular: string;
  titleStrong: string;
  viewExample: string;
};

export default function Hero({
  description,
  getStarted,
  titleRegular,
  titleStrong,
  viewExample
}: Props) {
  return (
    <div className="dark overflow-hidden">
      <div className="relative max-w-full overflow-hidden bg-slate-800 py-16 sm:px-2 lg:px-0">
        <div className="absolute left-0 top-0 h-[20500px] w-[20500px] translate-x-[-47.5%] rounded-full bg-gradient-to-b from-slate-900 via-cyan-500 md:top-1" />
        <Wrapper>
          <div className="flex flex-col gap-8 xl:flex-row xl:items-center xl:justify-between">
            <div className="max-w-3xl">
              <h1 className="inline bg-gradient-to-r from-white via-sky-100 to-primary bg-clip-text text-3xl leading-tight tracking-tight text-transparent lg:text-5xl">
                <strong className="font-semibold">{titleStrong}</strong>{' '}
                <span className="font-light">{titleRegular}</span>
              </h1>

              <p className="mt-3 max-w-xl text-lg leading-normal tracking-tight text-sky-100/70 lg:mt-4 lg:text-2xl lg:leading-normal">
                {description}
              </p>
              <div className="mt-8 flex gap-4 lg:mt-10">
                <LinkButton href="/docs">{getStarted}</LinkButton>
                <LinkButton
                  href="https://next-firebase-auth-edge-starter.vercel.app"
                  target="_blank"
                  variant="secondary"
                >
                  {viewExample}
                </LinkButton>
              </div>
            </div>
            <div className="max-w-[44rem] xl:-mr-8 2xl:-mr-16">
              <HeroCode />
            </div>
          </div>
        </Wrapper>
      </div>
    </div>
  );
}


================================================
FILE: docs/components/HeroCode.tsx
================================================
import clsx from 'clsx';
import {ReactNode, useState} from 'react';

function Tab({
  active,
  children,
  onClick
}: {
  active: boolean;
  children: ReactNode;
  onClick(): void;
}) {
  return (
    <button
      className={clsx(
        'flex items-center rounded-md px-4 py-2 text-sm font-medium transition-colors',
        active
          ? 'bg-slate-800 text-white'
          : 'bg-slate-800/40 text-slate-500 hover:bg-slate-800'
      )}
      onClick={onClick}
      type="button"
    >
      {children}
    </button>
  );
}

const files = [
  {
    name: 'proxy.ts',
    code: (
      <code
        className="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10"
        dir="ltr"
        data-language="tsx"
        data-theme="default"
      >
        <span className="line">
          <span style={{color: 'var(--shiki-token-keyword)'}}>import</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>type</span>
          <span style={{color: 'var(--shiki-color-text)'}}>
            {' '}
            {'{'} NextRequest {'}'}{' '}
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>from</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "next/server"
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>;</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-token-keyword)'}}>import</span>
          <span style={{color: 'var(--shiki-color-text)'}}>
            {' '}
            {'{'} authMiddleware {'}'}{' '}
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>from</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "next-firebase-auth-edge"
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>;</span>
        </span>
        {'\n'}
        <span className="line"> </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-token-keyword)'}}>export</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>async</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>function</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-function)'}}>proxy</span>
          <span style={{color: 'var(--shiki-color-text)'}}>(request</span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-function)'}}>
            NextRequest
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>) {'{'}</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'  '}</span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>return</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-function)'}}>
            authMiddleware
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>(request</span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
          <span style={{color: 'var(--shiki-color-text)'}}> {'{'}</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'    '}loginPath
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "/api/login"
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'    '}logoutPath
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "/api/logout"
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'    '}apiKey</span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX"
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'    '}cookieName
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "AuthToken"
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'    '}cookieSignatureKeys
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> [</span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "Key-Should-Be-at-least-32-bytes-in-length"
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>]</span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'    '}cookieSerializeOptions
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> {'{'}</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'      '}path</span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "/"
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'      '}httpOnly
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-constant)'}}>true</span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'      '}secure
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-constant)'}}>false</span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-comment)'}}>
            // Set this to true on HTTPS environments
          </span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'      '}sameSite
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "lax"
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>as</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>const</span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'      '}maxAge
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-constant)'}}>12</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>*</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-constant)'}}>60</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>*</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-constant)'}}>60</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>*</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-constant)'}}>24</span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-comment)'}}>
            // Twelve days
          </span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'    '}
            {'}'}
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'    '}serviceAccount
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> {'{'}</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'      '}projectId
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "your-firebase-project-id"
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'      '}clientEmail
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "firebase-adminsdk-nnw48@your-firebase-project-id.iam.gserviceaccount.com"
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'      '}privateKey
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'    '}
            {'}'}
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'  '}
            {'}'});
          </span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'}'}</span>
        </span>
        {'\n'}
        <span className="line"> </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-token-keyword)'}}>export</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>const</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-constant)'}}>config</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>=</span>
          <span style={{color: 'var(--shiki-color-text)'}}> {'{'}</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'  '}matcher</span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> [</span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "/api/login"
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "/api/logout"
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "/"
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "/((?!_next|favicon.ico|api|.*\\.).*)"
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>]</span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'}'};</span>
        </span>
      </code>
    )
  },
  {
    name: 'app/layout.tsx',
    code: (
      <code
        className="nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10"
        data-language="tsx"
        data-theme="default"
        dir="ltr"
      >
        <span className="line">
          <span style={{color: 'var(--shiki-token-keyword)'}}>import</span>
          <span style={{color: 'var(--shiki-color-text)'}}>
            {' '}
            {'{'} cookies {'}'}{' '}
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>from</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "next/headers"
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>;</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-token-keyword)'}}>import</span>
          <span style={{color: 'var(--shiki-color-text)'}}> {'{'}</span>
          <span style={{color: 'var(--shiki-color-text)'}}>
            {' '}
            getTokens {'}'}{' '}
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>from</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "next-firebase-auth-edge"
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>;</span>
        </span>
        {'\n'}
        <span className="line"> </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-token-keyword)'}}>export</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>default</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>async</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>function</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-function)'}}>RootLayout</span>
          <span style={{color: 'var(--shiki-color-text)'}}>({'{'}</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'  '}children</span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'}'}</span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> {'{'}</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'  '}children</span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-function)'}}>JSX</span>
          <span style={{color: 'var(--shiki-color-text)'}}>.</span>
          <span style={{color: 'var(--shiki-token-function)'}}>Element</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'}'}) {'{'}
          </span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'  '}</span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>const</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-constant)'}}>tokens</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>=</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>await</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-function)'}}>getTokens</span>
          <span style={{color: 'var(--shiki-color-text)'}}>(</span>
          <span style={{color: 'var(--shiki-token-function)'}}>cookies</span>
          <span style={{color: 'var(--shiki-color-text)'}}>()</span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
          <span style={{color: 'var(--shiki-color-text)'}}> {'{'}</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'    '}apiKey</span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            'XXxxXxXXXxXxxxxx_XxxxXxxxxxXxxxXXXxxXxX'
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'    '}cookieName
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            'AuthToken'
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'    '}cookieSignatureKeys
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> [</span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            'Key-Should-Be-at-least-32-bytes-in-length'
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>]</span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'    '}serviceAccount
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> {'{'}</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'      '}projectId
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            'your-firebase-project-id'
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'      '}clientEmail
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            'firebase-adminsdk-nnw48@your-firebase-project-id.iam.gserviceaccount.com'
          </span>
          <span style={{color: 'var(--shiki-token-punctuation)'}}>,</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'      '}privateKey
          </span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>:</span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n'
          </span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'    '}
            {'}'}
          </span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'  '}
            {'}'});
          </span>
        </span>
        {'\n'}
        <span className="line"> </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'  '}</span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>return</span>
          <span style={{color: 'var(--shiki-color-text)'}}> (</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'    '}&lt;</span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            html
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}> </span>
          <span style={{color: 'var(--shiki-token-function)'}}>lang</span>
          <span style={{color: 'var(--shiki-token-keyword)'}}>=</span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            "en"
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>&gt;</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'      '}&lt;</span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            head
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}> /&gt;</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'      '}&lt;</span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            body
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>&gt;</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'        '}
            {'{'}
          </span>
          <span style={{color: 'var(--shiki-token-comment)'}}>/* ... */</span>
          <span style={{color: 'var(--shiki-color-text)'}}>{'}'}</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>
            {'      '}&lt;/
          </span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            body
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>&gt;</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'    '}&lt;/</span>
          <span style={{color: 'var(--shiki-token-string-expression)'}}>
            html
          </span>
          <span style={{color: 'var(--shiki-color-text)'}}>&gt;</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'  '});</span>
        </span>
        {'\n'}
        <span className="line">
          <span style={{color: 'var(--shiki-color-text)'}}>{'}'}</span>
        </span>
      </code>
    )
  }
];

export default function HeroCode() {
  const [fileIndex, setFileIndex] = useState(0);

  return (
    <div className="relative">
      <div className="absolute inset-0 rounded-md bg-gradient-to-tr from-sky-300 via-sky-300/70 to-blue-300 opacity-10 blur-lg" />
      <div className="absolute inset-0 rounded-md bg-gradient-to-tr from-sky-300 via-sky-300/70 to-blue-300 opacity-10" />
      <div className="relative rounded-md bg-[#0A101F]/80 ring-1 ring-white/10 backdrop-blur">
        <div className="absolute -top-px right-10 h-px w-1/2 bg-gradient-to-r from-sky-300/0 via-sky-300/40 to-sky-300/0" />
        <div className="p-4">
          <svg
            aria-hidden="true"
            className="h-2.5 w-auto"
            fill="none"
            viewBox="0 0 42 10"
          >
            <circle className="fill-slate-800" cx={5} cy={5} r="4.5" />
            <circle className="fill-slate-800" cx={21} cy={5} r="4.5" />
            <circle className="fill-slate-800" cx={37} cy={5} r="4.5" />
          </svg>
          <div className="mt-4 flex space-x-2 overflow-x-auto">
            {files.map((file) => (
              <Tab
                key={file.name}
                active={fileIndex === files.indexOf(file)}
                onClick={() => setFileIndex(files.indexOf(file))}
              >
                {file.name}
              </Tab>
            ))}
          </div>
          <div className="mt-6 flex items-start lg:min-h-[260px] lg:w-[684px]">
            <pre className="ml-[-16px] flex overflow-x-auto px-0" data-theme>
              {files[fileIndex].code}
            </pre>
          </div>
        </div>
      </div>
    </div>
  );
}


================================================
FILE: docs/components/Link.tsx
================================================
import NextLink from 'next/link';
import {ComponentProps} from 'react';

type Props = Omit<ComponentProps<typeof NextLink>, 'className'>;

export default function Link(props: Props) {
  return (
    <NextLink
      className="text-sky-600 underline underline-offset-2 transition-colors hover:text-sky-700"
      {...props}
    />
  );
}


================================================
FILE: docs/components/LinkButton.tsx
================================================
import clsx from 'clsx';
import Link from 'next/link';
import {ComponentProps} from 'react';

type Props = {
  variant?: 'primary' | 'secondary';
} & Omit<ComponentProps<typeof Link>, 'className'>;

export default function LinkButton({
  children,
  variant = 'primary',
  ...rest
}: Props) {
  return (
    <Link
      className={clsx(
        'group inline-block rounded-full px-4 py-2 text-base font-semibold transition-colors lg:px-8 lg:py-4',
        variant === 'primary'
          ? 'bg-slate-800 text-white hover:bg-slate-700 dark:bg-primary dark:text-slate-900 dark:hover:bg-sky-200'
          : 'bg-slate-200 text-slate-700 dark:bg-slate-800 dark:text-white/90 dark:hover:bg-slate-700'
      )}
      {...rest}
    >
      {children}
      <span className="ml-2 inline-block transition-transform group-hover:translate-x-1">
        →
      </span>
    </Link>
  );
}


================================================
FILE: docs/components/Section.tsx
================================================
import {ReactNode} from 'react';
import Wrapper from './Wrapper';

type Props = {
  children: ReactNode;
  description: string;
  title: string;
};

export default function Section({children, description, title}: Props) {
  return (
    <section className="py-20 lg:py-40">
      <Wrapper>
        <div>
          <h2 className="text-2xl font-bold tracking-tight text-slate-900 lg:text-4xl dark:text-white">
            {title}
          </h2>
          <div className="mt-6 max-w-[42rem] text-base text-slate-600 lg:text-lg dark:text-slate-400">
            {description}
          </div>
        </div>
        <div className="mt-10 lg:mt-24">{children}</div>
      </Wrapper>
    </section>
  );
}


================================================
FILE: docs/components/Steps.module.css
================================================
.root {
  @apply ml-4 border-l border-slate-200 pl-8;
  counter-reset: step;
}

.root h3 {
  counter-increment: step;
  @apply text-lg;
}
.root h3:before {
  content: counter(step);
  @apply absolute mt-[-6px] ml-[-52px] inline-block h-10 w-10 rounded-full border-4 border-white bg-slate-100 pt-[4px] text-center text-base font-bold text-slate-500;
}

:global(.dark) .root {
  @apply border-slate-800;
}
:global(.dark) .root h3:before {
  @apply bg-slate-800 text-white/75;
  border-color: rgba(17, 17, 17, var(--tw-bg-opacity)); /* nx-bg-dark */
}


================================================
FILE: docs/components/Steps.tsx
================================================
import {ReactNode} from 'react';
import styles from './Steps.module.css';

type Props = {
  children: ReactNode;
};

export default function Steps({children}: Props) {
  return <div className={styles.root}>{children}</div>;
}


================================================
FILE: docs/components/Wrapper.tsx
================================================
import clsx from 'clsx';
import {ReactNode} from 'react';

type Props = {
  children: ReactNode;
  className?: string;
};

export default function Wrapper({children, className}: Props) {
  return (
    <div className={clsx(className, 'relative mx-auto max-w-[95rem] px-4')}>
      {children}
    </div>
  );
}


================================================
FILE: docs/config.js
================================================
module.exports = {
  baseUrl: 'https://next-firebase-auth-edge-docs.vercel.app',
  githubUrl: 'https://github.com/awinogrodzki/next-firebase-auth-edge'
};


================================================
FILE: docs/next-env.d.ts
================================================
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.


================================================
FILE: docs/next-sitemap.config.js
================================================
const config = require('./config');

/** @type {import('next-sitemap').IConfig} */
module.exports = {
  siteUrl: config.baseUrl,
  generateRobotsTxt: true
};


================================================
FILE: docs/next.config.js
================================================
const withNextra = require('nextra')({
  theme: 'nextra-theme-docs',
  themeConfig: './theme.config.tsx',
  staticImage: true,
  defaultShowCopyCode: true,
  flexsearch: {
    codeblocks: false
  }
});

module.exports = withNextra({
  redirects: () => [
    // Index pages
    {
      source: '/docs',
      destination: '/docs/getting-started',
      permanent: false
    },
    // Legacy pages
    {
      source: '/docs/usage/refresh-auth-cookies',
      destination: '/docs/usage/refresh-credentials',
      permanent: true
    },
  ],
});


================================================
FILE: docs/package.json
================================================
{
  "name": "docs",
  "version": "2.14.3",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "lint": "eslint ./pages ./components --ext .ts,.tsx",
    "test": "echo 'No tests yet'",
    "build": "next build",
    "sitemap": "next-sitemap",
    "start": "next start"
  },
  "dependencies": {
    "@heroicons/react": "^2.0.17",
    "@tailwindcss/typography": "^0.5.9",
    "@vercel/analytics": "1.1.0",
    "clsx": "^1.2.1",
    "http-status-codes": "^2.2.0",
    "next": "^14.0.4",
    "nextra": "^2.13.2",
    "nextra-theme-docs": "^2.13.2",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "tailwindcss": "^3.3.2"
  },
  "devDependencies": {
    "@types/node": "^20.1.2",
    "@types/react": "^18.2.29",
    "autoprefixer": "^10.4.0",
    "eslint": "^8.54.0",
    "eslint-config-molindo": "^7.0.0",
    "eslint-config-next": "^14.0.3",
    "eslint-config-prettier": "^9.1.0",
    "next-sitemap": "^4.0.7",
    "typescript": "^5.2.2"
  },
  "resolutions": {
    "strip-ansi": "6.0.1",
    "next-mdx-remote": "6.0.0"
  },
  "funding": "https://github.com/awinogrodzki/next-firebase-auth-edge?sponsor=1"
}


================================================
FILE: docs/pages/_app.tsx
================================================
import {AppProps} from 'next/app';
import {Inter} from 'next/font/google';
import {ReactNode} from 'react';
import 'nextra-theme-docs/style.css';
import '../styles.css';

const inter = Inter({subsets: ['latin']});

type Props = AppProps & {
  Component: {getLayout?(page: ReactNode): ReactNode};
};

export default function App({Component, pageProps}: Props) {
  const getLayout = Component.getLayout || ((page: ReactNode) => page);
  return (
    <div className={inter.className}>
      {getLayout(<Component {...pageProps} />)}
    </div>
  );
}


================================================
FILE: docs/pages/_document.tsx
================================================
import {Html, Head, Main, NextScript} from 'next/document';
import {SkipNavLink} from 'nextra-theme-docs';
import React from 'react';

export default function Document() {
  return (
    <Html lang="en">
      <Head />
      <body>
        <SkipNavLink styled />
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}


================================================
FILE: docs/pages/_meta.json
================================================
{
  "index": {
    "title": "Introduction",
    "type": "page",
    "display": "hidden",
    "theme": {"layout": "raw"}
  },
  "docs": {
    "title": "Docs",
    "type": "page"
  },
  "examples": {
    "title": "Examples",
    "type": "page",
    "theme": {
      "sidebar": false,
      "toc": false
    }
  }
}

================================================
FILE: docs/pages/docs/_meta.json
================================================
{
  "getting-started": "Getting started",
  "usage": "Usage guide",
  "emulator": "Emulator",
  "app-check": "App Check",
  "errors": "Handling errors",
  "faq": "FAQ"
}

================================================
FILE: docs/pages/docs/app-check.mdx
================================================
# App Check Support

This library provides support for [Firebase App Check](https://firebase.google.com/docs/app-check). To learn how to integrate App Check into your app, follow the instructions in the [starter example README](https://github.com/awinogrodzki/next-firebase-auth-edge/tree/main/examples/next-typescript-starter).

To use `next-firebase-auth-edge` with App Check, you need to include the `X-Firebase-AppCheck` header with the App Check token when making a call to the `/api/login` endpoint. You can see how this works in [this example](https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/examples/next-typescript-starter/api/index.ts#L10-L14).

```tsx
import { getToken } from "@firebase/app-check";
import { getAppCheck } from "../app-check";

const appCheckTokenResponse = await getToken(getAppCheck(), false);

await fetch("/api/login", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${token}`,
    "X-Firebase-AppCheck": appCheckTokenResponse.token,
  },
});
```

## Advanced Usage

If you need to explicitly create or verify an App Check token, you can use the `getAppCheck` function from `next-firebase-auth-edge/app-check`. You can see an example of how to do this below:

```tsx
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 });
```

```tsx
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);
```


================================================
FILE: docs/pages/docs/emulator.mdx
================================================
# Emulator Support

This library supports the Firebase Authentication Emulator. For more details on how to set it up, check out the [starter example README](https://github.com/awinogrodzki/next-firebase-auth-edge/tree/main/examples/next-typescript-starter).


================================================
FILE: docs/pages/docs/errors.mdx
================================================
# Handling Errors

## handleInvalidToken

The [Auth middleware](/docs/usage/middleware) provides a `handleInvalidToken` function, which is called with an `InvalidTokenReason` as the first argument.

The `InvalidTokenReason` is primarily for informational purposes. The `handleInvalidToken` function is typically called when something **expected** happens, allowing the user to be safely redirected to the login page. One common **expected** event is when a user visits your app for the first time.

### InvalidTokenReason

The table below describes the different types of `InvalidTokenReason`:

| Name                    | Description                                                                                                                                                                                                                      |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MISSING_CREDENTIALS`   | The request does not contain an authentication cookie                                                                                                                                                                            |
| `MISSING_REFRESH_TOKEN` | Credentials have expired, and no refresh token is available                                                                                                                                                                      |
| `MALFORMED_CREDENTIALS` | The cookies cannot be parsed or the structure has changed                                                                                                                                                                        |
| `INVALID_SIGNATURE`     | The cookie signature cannot be verified or the signature keys have changed                                                                                                                                                       |
| `INVALID_CREDENTIALS`   | The cookies have a valid structure, but the `idToken` cannot be verified                                                                                                                                                         |
| `INVALID_KID`           | This error usually means the certificate used to sign the token has expired, which is **expected**. Google periodically refreshes certificates as part of [key rotation](https://developer.okta.com/docs/concepts/key-rotation/) |

## handleError

Unlike `handleInvalidToken`, which handles **expected** issues, `handleError` is called when something **unexpected** occurs that a developer should investigate.

The `handleError` function receives an `AuthError` object as the first argument. This object includes `code` and `message` properties, which describe the type and meaning of the error.

### AuthError

The error codes are divided as follows:

| Code | Description |
| ---- | ----------- |
| `USER_NOT_FOUND` | The user cannot be found, possibly because they were removed after generating or refreshing the custom token |
| `INVALID_CREDENTIAL` | The token could not be refreshed due to an invalid refresh token or service account credentials |
| `TOKEN_EXPIRED` | Handled internally to refresh the token. Occurs when the custom `idToken` has expired |
| `USER_DISABLED` | Thrown when `authMiddleware` is called with `checkRevoked: true` and the user has been disabled |
| `TOKEN_REVOKED` | Thrown when `authMiddleware` is called with `checkRevoked: true` and the token has been revoked |
| `INVALID_ARGUMENT` | The token has an incorrect structure or the certificate used to sign it has expired |
| `INTERNAL_ERROR` | An internal error occurred. Check the error message for more details |
| `NO_KID_IN_HEADER` | Handled internally to verify the token against all public certificates. Re-throws `INVALID_SIGNATURE` if none of the public keys match the token's signature |
| `INVALID_SIGNATURE` | The token signature cannot be verified |
| `MISMATCHING_TENANT_ID` | Provided tenant ID does not match Firebase tenant ID from the token |


================================================
FILE: docs/pages/docs/faq.mdx
================================================
# FAQ

## Where are the login and logout API routes defined?

Unlike the [next-firebase-auth](https://github.com/gladly-team/next-firebase-auth?tab=readme-ov-file#get-started) library, `next-firebase-auth-edge` does not require you to manually define your own `/api/login` or `/api/logout` routes. These routes are automatically handled by the [authMiddleware](/docs/getting-started/middleware). For more details, check out this [explanation](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/34#issuecomment-1588032612).


================================================
FILE: docs/pages/docs/getting-started/_meta.json
================================================
{
  "index": "Welcome!",
  "middleware": "Middleware",
  "auth-context": "AuthContext",
  "auth-provider": "AuthProvider",
  "layout": "Layout",
  "login-page": "Usage with Firebase Auth",
  "login-with-server-action": "Sign in with Server Action",
  "logout-with-server-action": "Sign out with Server Action"
}


================================================
FILE: docs/pages/docs/getting-started/auth-context.mdx
================================================
# AuthContext

The library doesn't include any client-side code or built-in authentication state context. It's up to the developer to decide how to manage user data throughout the application.

Check out the example of an `AuthContext` below:

## Example AuthContext

The following is an example implementation of custom `AuthContext` using React's [createContext](https://react.dev/reference/react/createContext).

```tsx filename="AuthContext.ts"
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<AuthContextValue>({
  user: null
});

export const useAuth = () => useContext(AuthContext);
```


================================================
FILE: docs/pages/docs/getting-started/auth-provider.mdx
================================================
# AuthProvider

To share user data between the server and client components, we can use the custom `AuthContext` we created in the [previous step](/docs/getting-started/auth-context).

## Example AuthProvider

Below is an example of how to implement a custom `AuthProvider` component that uses `AuthContext` to pass user data between the server and client components.

```tsx filename="AuthProvider.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<AuthProviderProps> = ({
  user,
  children
}) => {
  return (
    <AuthContext.Provider
      value={{
        user
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};
```


================================================
FILE: docs/pages/docs/getting-started/index.mdx
================================================
import {Card} from 'nextra-theme-docs';
import {ChevronRightIcon} from '@heroicons/react/24/outline';

# Next.js Firebase Authentication

Welcome to the `next-firebase-auth-edge` docs!

In this guide you will learn how to set up Firebase Authentication in your Next.js app.

<div className="mt-8 flex flex-col gap-4 md:w-2/3">
  <Card
    icon={<ChevronRightIcon />}
    title="Setup Next.js Middleware"
    href="/docs/getting-started/middleware"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Setup custom AuthContext"
    href="/docs/getting-started/auth-context"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Setup custom AuthProvider"
    href="/docs/getting-started/auth-provider"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Setup App Router Layout"
    href="/docs/getting-started/layout"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Usage with Firebase Auth"
    href="/docs/getting-started/login-page"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Sign in with Server Action"
    href="/docs/getting-started/login-with-server-action"
  />
</div>


================================================
FILE: docs/pages/docs/getting-started/layout.mdx
================================================
# Layout

We can use the `getTokens` function from `next-firebase-auth-edge` to pull user information from request cookies.

Once we have the token details, we can map them to a `User` object and pass it to the `AuthProvider` we created in the [previous step](/docs/getting-started/auth-provider).

You can use `getTokens` in any React Server Component, whether it's `page.tsx` or `layout.tsx`.

Learn more about the Next.js App Router in the [official docs](https://nextjs.org/docs/app).

## Example RootLayout

Here’s an example of how to implement the `RootLayout` React Server Component. It uses the `getTokens` function to create a user object from cookies and passes it to the `AuthProvider` client component.

```tsx filename="app/layout.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 (
    <html lang="en">
      <head />
      <body>
        <main>
          <AuthProvider user={user}>{children}</AuthProvider>
        </main>
      </body>
    </html>
  );
}
```


================================================
FILE: docs/pages/docs/getting-started/login-page.mdx
================================================
# Using Firebase Auth

Follow the official `firebase/auth` [guide](https://firebase.google.com/docs/auth/web/password-auth) to handle different operations like `signInWithEmailAndPassword` or `signOut`.

Check out the [starter example](/examples#starter) for more complete examples, including login, registration, and password reset flows.

## Example LoginPage

Here’s a simple login page client component that lets users sign in with their `email` and `password`:

```tsx filename="page.tsx"
'use client';

import * as React from 'react';
import {getAuth, signInWithEmailAndPassword} from 'firebase/auth';
import {useRouter} from 'next/navigation';

export default function LoginPage() {
  const [email, setEmail] = React.useState('');
  const [password, setPassword] = React.useState('');
  const router = useRouter();

  async function handleSubmit(event: React.FormEvent) {
    event.preventDefault();
    event.stopPropagation();

    const credential = await signInWithEmailAndPassword(
      getAuth(),
      email,
      password
    );
    const idToken = await credential.user.getIdToken();

    // Sets authenticated browser cookies
    await fetch('/api/login', {
      headers: {
        Authorization: `Bearer ${idToken}`
      }
    });

    // Refresh page after updating browser cookies
    router.refresh();
  }

  return (
    <div>
      <h1>Login</h1>
      <form onSubmit={handleSubmit}>
        <input
          required
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          name="email"
          type="email"
          placeholder="Email address"
        />
        <br />
        <input
          required
          name="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          type="password"
          placeholder="Password"
          minLength={8}
        />
        <button type="submit">Submit</button>
      </form>
    </div>
  );
}
```

Let's focus on the form submission handler:
```tsx
async function handleSubmit(event: React.FormEvent) {
  event.preventDefault();
  event.stopPropagation();

  const credential = await signInWithEmailAndPassword(
    getAuth(),
    email,
    password
  );
  const idToken = await credential.user.getIdToken();

  // Sets authenticated browser cookies
  await fetch('/api/login', {
    headers: {
      Authorization: `Bearer ${idToken}`
    }
  });

  // Refresh page after updating browser cookies
  router.refresh();
}
```

It can be broken down to following actions:
1. We sign user in using email and password using `signInWithEmailAndPassword` from Firebase Client SDK
2. We extract `idToken` using `credential` returned by `signInWithEmailAndPassword`
3. We call `/api/login` endpoint exposed by the middleware to update browser cookies with authentication token
4. We call `router.refresh()` to re-render server components with updated credentials


================================================
FILE: docs/pages/docs/getting-started/login-with-server-action.mdx
================================================
# Sign in with Server Action

You can follow the official `firebase/auth` [guide](https://firebase.google.com/docs/auth/web/password-auth) to handle operations like `signInWithEmailAndPassword` or `signOut`.

## refreshCookiesWithIdToken

The `refreshCookiesWithIdToken` method updates browser cookies with the latest authenticated credentials based on the `idToken`. This method works with **Server Actions** and **Middleware**. After performing Firebase operations in a Server Action, you can use this method to refresh the browser cookies with updated credentials.

## Example loginAction and LoginPage

**Note for Vercel users:** The `firebase/auth` library isn't fully compatible with **Vercel** environments when used inside Server Actions.

If you get a `ReferenceError: document is not defined`, move the `firebase/auth` import to a client component.

Below is a simple example of a login page client component that lets users sign in using a Server Action and the `refreshCookiesWithIdToken` method.

First, let’s define our Server Action:

```tsx filename="login.tsx"
'use server';

import {refreshCookiesWithIdToken} from 'next-firebase-auth-edge/next/cookies';
import {signInWithEmailAndPassword} from 'firebase/auth';
import {cookies, headers} from 'next/headers';
import {redirect} from 'next/navigation';

// See starter example for implementation: https://github.com/awinogrodzki/next-firebase-auth-edge/tree/main/examples/next-typescript-starter
import {getFirebaseAuth} from '@/app/auth/firebase';
import {authConfig} from '@/config/server-config';

export async function loginAction(username: string, password: string) {
  const credential = await signInWithEmailAndPassword(
    getFirebaseAuth(),
    username,
    password
  );

  const idToken = await credential.user.getIdToken();

  // Since Next.js 15, `headers()` and `cookies()` return a Promise and must be preceded with `await`.
  // In Next.js 14, these functions are synchronous — call them without `await`.
  await refreshCookiesWithIdToken(
    idToken,
    await headers(),
    await cookies(),
    authConfig
  );
  redirect('/');
}
```

Next, create LoginPage client component that will call login action:

```tsx filename="LoginPage.tsx"
'use client';

import * as React from 'react';

interface LoginPageProps {
  loginAction: (email: string, password: string) => void;
}

export default function LoginPage({loginAction}: LoginPageProps) {
  const [email, setEmail] = React.useState('');
  const [password, setPassword] = React.useState('');
  let [isLoginActionPending, startTransition] = React.useTransition();

  async function handleSubmit(event: React.FormEvent) {
    event.preventDefault();
    event.stopPropagation();

    startTransition(() => loginAction(email, password));
  }

  return (
    <div>
      <h1>Login</h1>
      <form onSubmit={handleSubmit}>
        <input
          required
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          name="email"
          type="email"
          placeholder="Email address"
        />
        <br />
        <input
          required
          name="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          type="password"
          placeholder="Password"
          minLength={8}
        />
        <button disabled={isLoginActionPending} type="submit">
          Submit
        </button>
      </form>
    </div>
  );
}
```

Lastly, let's use LoginPage inside `page.tsx` Server Component:

```tsx filename="page.tsx"
import LoginPage from './LoginPage';
import {loginAction} from './login';

export default function Page() {
  return <LoginPage loginAction={loginAction} />;
}
```


================================================
FILE: docs/pages/docs/getting-started/logout-with-server-action.mdx
================================================
# Sign out with Server Action

## removeServerCookies [v1.9.0]

The `removeServerCookies` method removes server cookies from the browser. This method works with **Server Actions** and **Middleware**. 
After logging out with Firebase in a Server Action, you can use this method to remove the auth cookies from the browser.

Prior to version `1.9.0`, the `removeServerCookies` method was not available. Instead, you had to manually remove the cookies from the browser.

With multiple cookies enabled:

```tsx
cookies.delete(authConfig.cookieName + ".id");
cookies.delete(authConfig.cookieName + ".refresh");
cookies.delete(authConfig.cookieName + ".sig");

// Optionally, if you enabled custom token:
cookies.delete(authConfig.cookieName + ".custom");
```

Without multiple cookies enabled:

```tsx
cookies.delete(authConfig.cookieName);
```


## Example logoutAction and LogoutPage

Below is a simple example of a logout page component that lets users sign out using a Server Action and the `removeServerCookies` method.

First, let’s define our Server Action:

```tsx filename="logout.tsx"
'use server';

import {removeServerCookies} from "next-firebase-auth-edge/next/cookies";
import {signOut} from 'firebase/auth';
import {cookies} from 'next/headers';
import {redirect} from 'next/navigation';
import {getFirebaseAuth} from '@/app/auth/firebase';
import {authConfig} from '@/config/server-config';

export async function logoutAction() {
  await signOut(getFirebaseAuth());

  // Since Next.js 15, `cookies()` returns a Promise and must be preceded with `await`.
  // In Next.js 14, `cookies()` is synchronous — call it without `await`.
  removeServerCookies(await cookies(), { cookieName: authConfig.cookieName });
  redirect('/');
}
```

Next, create LogoutPage component that will call logout action:

```tsx filename="LogoutPage.tsx"
interface LogoutPageProps {
  logoutAction: () => void;
}

export default function LogoutPage({logoutAction}: LogoutPageProps) {
    return (
        <div>
            <h1>Logout</h1>
            <form action={logoutAction}>
                <button type="submit">Sign out</button>
            </form>
        </div>
    );
}
```

================================================
FILE: docs/pages/docs/getting-started/middleware.mdx
================================================
# Authentication Middleware

The library offers an `authMiddleware` function that's meant to be used with [Next.js Proxy](https://nextjs.org/docs/app/getting-started/proxy) (or [Middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware) in Next.js 14-15).

For more details, check out the [Authentication Middleware usage docs](/docs/usage/middleware).

Here's a basic example of how to use `authMiddleware` in `proxy.ts`:

> **Next.js 14-15:** Use `middleware.ts` with `export async function middleware(...)` instead. See the [Next.js 16 migration note](/docs/usage/middleware#nextjs-14-15-compatibility).

```tsx filename="proxy.ts"
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|.*\\.).*)"],
};
```


================================================
FILE: docs/pages/docs/usage/_meta.json
================================================
{
  "index": "Start",
  "middleware": "Middleware",
  "server-components": "Server Components",
  "redirect-functions": "Redirect Helper Functions",
  "app-router-api-routes": "App Router API Route Handlers",
  "pages-router-api-routes": "Pages Router API Routes",
  "get-server-side-props": "Usage in getServerSideProps",
  "refresh-credentials": "Refreshing credentials",
  "remove-credentials": "Removing credentials",
  "client-side-apis": "Using Client-Side APIs",
  "domain-restriction": "Firebase API Key domain restriction",
  "advanced-usage": "Advanced usage",
  "cloud-run": "Usage in Google Cloud Run",
  "firebase-hosting": "Usage in Firebase Hosting",
  "debug-mode": "Debug mode"
}


================================================
FILE: docs/pages/docs/usage/advanced-usage.mdx
================================================
# Advanced Usage

The authentication middleware may not cover every use case. To support more complex authentication flows, `next-firebase-auth-edge` offers a set of low-level tools:

## 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?                                                                                  | Description                                                                                                                                                    |
| ---------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| apiKey           | `string`                                                         | **Required**                                                                               | Firebase Web API Key from the Firebase Project settings page. This key becomes visible only after you enable Firebase Authentication in your Firebase project. |
| serviceAccount   | `{ projectId: string; clientEmail: string; privateKey: string }` | Optional (required unless in [Google Cloud Run](https://cloud.google.com/run) environment) | Firebase Service Account credentials.                                                                                                                          |
| tenantId         | `string`                                                         | Optional                                                                                   | Specify this if your project supports [multi-tenancy](https://cloud.google.com/identity-platform/docs/multi-tenancy-authentication).                           |
| serviceAccountId | `string`                                                         | Optional                                                                                   | Used to specify a service account ID in a [Google Cloud Run](https://cloud.google.com/run) environment.                                                        |

### Methods

| Name                           | Type                                                                                                                                                                           | Description                                                                                                                                                                                                                                                                                                                                                                      |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| getCustomIdAndRefreshTokens    | `(idToken: string, options?: {appCheckToken?: string, referer?: string}) => Promise<CustomTokens>`                                                                             | Generates new ID and refresh tokens for the user identified by the given `idToken`. Optionally accepts an `appCheckToken` if your app supports [App Check](https://firebase.google.com/docs/app-check). Can also accept a `referer` if your API key is domain-restricted.                                                                                                        |
| verifyIdToken                  | `(idToken: string, options?: {checkRevoked?: boolean, referer?: string, currentDate?: Date}) => Promise<DecodedIdToken>`                                                       | Verifies the given `idToken` and throws an `AuthError` if verification fails. You can check for revoked tokens by passing `checkRevoked`. The `referer` is used for domain-restricted API keys. Optionally set a `currentDate` to control when the token is validated against.                                                                                                   |
| verifyAndRefreshExpiredIdToken | `(tokens: {idToken: string, refreshToken: string, customToken?: string}, options?: {checkRevoked?: boolean, referer?: string, currentDate?: Date}) => Promise<VerifiedCookies>` | Verifies the `idToken`, and if it's expired, uses the `refreshToken` to revalidate it. Throws `InvalidTokenError` if the credentials are invalid. The options are the same as in `verifyIdToken`. Returns `VerifiedCookies` which includes the decoded token and the new tokens. Custom token can be enabled by setting `enableCustomToken` option to `true` in `authMiddleware`. |
| createCustomToken              | `(uid: string, developerClaims?: object) => Promise<string>`                                                                                                                   | Creates a custom token for the specified Firebase user. You can also pass optional `developerClaims` to include additional data.                                                                                                                                                                                                                                                 |
| handleTokenRefresh             | `(refreshToken: string, options?: {referer?: string, enableCustomToken?: boolean}) => Promise<VerifiedCookies>`                                                                                              | Returns a new ID token and its decoded form using the given `refreshToken`. The `referer` option is used if the API key is domain-restricted. `enableCustomToken` should match the value you pass to `authMiddleware`.                                                                                                                                                                                                                                 |
| getUser                        | `(uid: string) => Promise<UserRecord>`                                                                                                                                         | Retrieves a Firebase `UserRecord` by the user's `uid`.                                                                                                                                                                                                                                                                                                                           |
| getUserByEmail                 | `(email: string) => Promise<UserRecord>`                                                                                                                                       | Retrieves a Firebase `UserRecord` by the user's email address.                                                                                                                                                                                                                                                                                                                   |
| createUser                     | `(request: CreateRequest) => Promise<UserRecord>`                                                                                                                              | 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.                                                                                                                                                                 |
| updateUser                     | `(uid: string, request: UpdateRequest) => Promise<UserRecord>`                                                                                                                 | 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.                                                                                                                                                               |
| deleteUser                     | `(uid: string) => Promise<void>`                                                                                                                                               | Deletes the user associated with the provided `uid`.                                                                                                                                                                                                                                                                                                                             |
| setCustomUserClaims            | `(uid: string, customClaims: object ∣ null) => Promise<void>`                                                                                                                  | Sets custom claims for the specified user, overwriting existing values. Use `getUser` to retrieve the current claims.                                                                                                                                                                                                                                                            |


================================================
FILE: docs/pages/docs/usage/app-router-api-routes.mdx
================================================
# App Router API Route Handlers

Here’s an example of how to use the [getTokens](/docs/usage/server-components) function in [API Route Handlers](https://nextjs.org/docs/app/building-your-application/routing/route-handlers).

```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<string, string> = {
    "Content-Type": "application/json",
  };

  const response = new NextResponse(
    JSON.stringify({
      tokens,
    }),
    {
      status: 200,
      headers,
    }
  );

  return response;
}
```


================================================
FILE: docs/pages/docs/usage/client-side-apis.mdx
================================================
# Using Client-Side APIs

The starter example uses the [inMemoryPersistence](https://github.com/awinogrodzki/next-firebase-auth-edge/blob/main/examples/next-typescript-starter/app/auth/firebase.ts#L28-L30) strategy, relying entirely on server-side tokens. This avoids consistency issues on the client side.

While this approach is recommended, it can lead to a few challenges:

1. **Stale tokens:** In long-running client sessions, server-side tokens may expire, requiring the user to refresh the page to get a valid token. This typically happens if the user reopens a tab after about an hour.
2. **Unauthenticated Firebase Client SDK environment:** With `inMemoryPersistence`, `currentUser` will often be `null` when using [client-side APIs](https://firebase.google.com/docs/auth/web/manage-users), preventing the use of Firebase’s client-side SDKs.

However, `next-firebase-auth-edge` includes several features that address these issues:

### Enable Refresh Token API Endpoint in Auth Middleware

In long-running client sessions (e.g., when a user reopens a tab after an hour), the server-side token may expire. This can cause problems when validating external API calls or when using the `customToken` with Firebase's `signInWithCustomToken`.

To resolve this, you can expose an endpoint via `authMiddleware` to refresh client-side tokens when the server-side token has expired.

To enable this endpoint, define the `refreshTokenPath` option in proxy/middleware.

> **Next.js 14-15:** Use `middleware.ts` with `export async function middleware(...)` instead of `proxy.ts`. See the [compatibility note](/docs/usage/middleware#nextjs-14-15-compatibility).

```tsx filename="proxy.ts"
export async function proxy(request: NextRequest) {
  return authMiddleware(request, {
    loginPath: '/api/login',
    logoutPath: '/api/logout',
    refreshTokenPath: '/api/refresh-token'
    // other options...
  });
}

export const config = {
  // Make sure to include the path in `matcher`
  matcher: [
    '/api/login',
    '/api/logout',
    '/api/refresh-token',
    '/',
    '/((?!_next|favicon.ico|api|.*\\.).*)'
  ]
};
```

Calling `/api/refresh-token` will:

1. Check if the current token has expired. If it has, it regenerates the token and updates the cookies with a `Set-Cookie` header containing the fresh token.
2. Return JSON with a valid `idToken`. It can also return `customToken`, if `enableCustomToken` is set to `true` in `authMiddleware`.

### getValidIdToken

The `getValidIdToken` function works in conjunction with the [refresh token endpoint](/docs/usage/client-side-apis#enable-refresh-token-api-endpoint-in-auth-middleware) to ensure you have the latest valid ID token. This is helpful if you use tokens to authorize external API calls.

It requires `serverIdToken`, which is the `token` returned by the [getTokens](/docs/usage/server-components#gettokens) function in server components.

The function is optimized to be fast and safe for repeated calls. The `/api/refresh-token` endpoint will only be called if the token has expired.

Example usage:

```ts
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}`
    }
  });
}
```

### getValidCustomToken

Please note that since v1.8 custom token is disabled by default. In order to enable custom cookies, pass `enableCustomToken: true` option to `authMiddleware`.

Custom token introduces significant footprint on authentication cookie and is not required for most use-cases.

If you want to avoid cookie size issues, learn how to [split session into multiple cookies](/docs/usage/middleware#multiple-cookies)

Similar to `getValidIdToken`, the `getValidCustomToken` function works with the [refresh token endpoint](/docs/usage/client-side-apis#enable-refresh-token-api-endpoint-in-auth-middleware) to provide a valid custom token. This is useful when using the custom token with Firebase’s [signInWithCustomToken](https://firebase.google.com/docs/auth/web/custom-auth#authenticate-with-firebase) method.

It requires `serverCustomToken`, which is the `customToken` returned by the [getTokens](/docs/usage/server-components#gettokens) function in server components.

Like `getValidIdToken`, this function is designed to be efficient and only calls the `/api/refresh-token` endpoint if necessary.

Example usage:

```ts
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);
}
```

## Handling errors

`getValidIdToken` and `getValidCustomToken` can fail with [AuthError](/docs/errors#autherror).

Whenever the error happens, it usually means that the credentials have expired due to various reasons, and **user should be redirected to the sign in page**.

## Using Firebase Client SDKs

The Firebase Client SDK exposes the [signInWithCustomToken](https://firebase.google.com/docs/auth/web/custom-auth#authenticate-with-firebase) method, which allows you to access the current user using a custom token.

You can obtain a custom token by calling the [getTokens](/docs/usage/server-components#gettokens) function in server components.

```tsx
import {signInWithCustomToken} from 'firebase/auth';
import {getValidCustomToken} from 'next-firebase-auth-edge/next/client';

import {doc, getDoc, getFirestore, updateDoc, setDoc} from 'firebase/firestore';

export async function doSomethingWithFirestoreClient(
  serverCustomToken: string
) {
  const auth = getAuth(getFirebaseApp());

  // See https://next-firebase-auth-edge-docs.vercel.app/docs/usage/client-side-apis#getvalidcustomtoken
  const customToken = await getValidCustomToken({
    serverCustomToken,
    refreshTokenUrl: '/api/refresh-token'
  });

  if (!customToken) {
    throw new Error('Invalid custom token');
  }

  const {user: firebaseUser} = await signInWithCustomToken(auth, customToken);

  // Use client-side firestore instance
  const db = getFirestore(getApp());
}
```


================================================
FILE: docs/pages/docs/usage/cloud-run.mdx
================================================
# Usage in Google Cloud Run Environment

Before running `next-firebase-auth-edge` in a Google Cloud Run environment, make sure to:

1. [Enable the IAM Service Account Credentials API](https://console.cloud.google.com/apis/api/iamcredentials.googleapis.com).
2. Assign the `iam.serviceAccounts.signBlob` permission to the IAM role attached to the [default compute service account](https://console.cloud.google.com/iam-admin/iam).

Once this is done, you can omit the `serviceAccount` option in `authMiddleware`, `getTokens`, and other functions. If `serviceAccount` is `undefined`, `next-firebase-auth-edge` will automatically extract credentials from the authenticated [Google Cloud Run](https://cloud.google.com/run) environment.

Keep in mind that you still need to provide the Firebase `apiKey`.

Example [authMiddleware](/docs/usage/middleware) usage:

> **Next.js 14-15:** Use `middleware.ts` with `export async function middleware(...)` instead of `proxy.ts`. See the [compatibility note](/docs/usage/middleware#nextjs-14-15-compatibility).

```tsx filename="proxy.ts"
import { NextRequest, NextResponse } 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,
      sameSite: "lax" as const,
      maxAge: 12 * 60 * 60 * 24,
    },
  });
}
```

Example [getTokens](/docs/usage/server-components) usage:

```tsx
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'],
});
```


================================================
FILE: docs/pages/docs/usage/debug-mode.mdx
================================================
# Debug Mode

You can enable `debug mode` by setting `debug: true` in the options for `authMiddleware` and `getTokens`.

When debug mode is active, the middleware will log additional details about the authentication process to the console.

> **Next.js 14-15:** Use `middleware.ts` with `export async function middleware(...)` instead of `proxy.ts`. See the [compatibility note](/docs/usage/middleware#nextjs-14-15-compatibility).

```tsx filename="proxy.ts"
import { NextRequest, NextResponse } from "next/server";
import { authMiddleware } from "next-firebase-auth-edge";

export async function proxy(request: NextRequest) {
  return authMiddleware(request, {
    debug: true, // Enable debug mode

    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,
      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|.*\\.).*)"],
};
```



```tsx
import { getTokens } from "next-firebase-auth-edge";
import { cookies } from "next/headers";
```

```tsx
// 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(), {
  debug: true,
  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'
  }
});
```

================================================
FILE: docs/pages/docs/usage/domain-restriction.mdx
================================================
# Firebase API Key Domain Restriction

In a production-ready application, it's important to restrict your Firebase API key by domain for security purposes.

You can update your API key restrictions in the [Google Cloud Console](https://console.cloud.google.com/apis/credentials).

## Enable Referer Validation

To support API key domain restrictions, you need to inform Google APIs about the referer of your requests.

If you are using any of the advanced methods like `getCustomIdAndRefreshTokens`, `verifyIdToken`, `handleTokenRefresh`, or `verifyAndRefreshExpiredIdToken` from the [advanced usage](/docs/usage/advanced-usage) section, make sure to pass the `referer` option. The `referer` should be the authorized domain, derived from the request headers. You can use the `getReferer` function (imported from `next-firebase-auth-edge/next/utils`) to extract the referer from the headers of `NextRequest`.

```ts
import {getFirebaseAuth} from 'next-firebase-auth-edge/auth';
import {getReferer} from 'next-firebase-auth-edge/next/utils';
import type {NextRequest} from 'next/server';

const {verifyIdToken} = getFirebaseAuth(/*{...}*/);

export async function POST(request: NextRequest) {
  const token = request.headers.get('Authorization')?.split(' ')[1] ?? '';

  if (!token) {
    throw new Error('Unauthenticated');
  }

  await verifyIdToken(token, {
    referer: getReferer(request.headers)
  });

  //...
}
```


================================================
FILE: docs/pages/docs/usage/firebase-hosting.mdx
================================================
# Usage in Firebase Hosting Environment

By default, the Firebase Hosting environment strips all cookies except for `__session`. (See [this StackOverflow thread](https://stackoverflow.com/questions/44929653/firebase-cloud-function-wont-store-cookie-named-other-than-session) for more details.)

To use `next-firebase-auth-edge` in Firebase Hosting, you need to set a custom `cookieName` with the value `__session`, as shown in the examples below:

> **Next.js 14-15:** Use `middleware.ts` with `export async function middleware(...)` instead of `proxy.ts`. See the [compatibility note](/docs/usage/middleware#nextjs-14-15-compatibility).

```tsx filename="proxy.ts"
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|.*\\.).*)"],
};
```

Example [getTokens](/docs/usage/server-components) usage:

```tsx
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",
  },
});
```


================================================
FILE: docs/pages/docs/usage/get-server-side-props.mdx
================================================
# Usage in getServerSideProps

Example usage of [getApiRequestTokens](/docs/usage/pages-router-api-routes) function in [getServerSideProps](https://nextjs.org/docs/pages/building-your-application/data-fetching/get-server-side-props)

```tsx
import { GetServerSidePropsContext } from "next";
import { getApiRequestTokens } from "next-firebase-auth-edge";

export async function getServerSideProps(context: GetServerSidePropsContext) {
  const tokens = await getApiRequestTokens(context.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'
    },
    // Optional
    tenantId: 'your-tenant-id',
  });

  return { props: { tokens } };
}
```


================================================
FILE: docs/pages/docs/usage/index.mdx
================================================
import {Card, Cards} from 'nextra-theme-docs';
import {ChevronRightIcon} from '@heroicons/react/24/outline';

# Usage Guide

This page provides comprehensive documentation for the `next-firebase-auth-edge` functions and their use cases.

If you prefer a more hands-on learning experience, you can explore these example applications instead:

- [Starter Example](/examples#starter)
- [Minimal Example](/examples#minimal)

## Sections

<Cards num={2}>
  <Card
    icon={<ChevronRightIcon />}
    title="Authentication Middleware"
    href="/docs/usage/middleware"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Server Components"
    href="/docs/usage/server-components"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Redirect Helper Functions"
    href="/docs/usage/redirect-functions"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="App Router API Route Handlers"
    href="/docs/usage/app-router-api-routes"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Pages Router API Routes"
    href="/docs/usage/pages-router-api-routes"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Usage in getServerSideProps"
    href="/docs/usage/get-server-side-props"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Refreshing credentials"
    href="/docs/usage/refresh-credentials"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Removing credentials"
    href="/docs/usage/remove-credentials"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Using Client-Side APIs"
    href="/docs/usage/client-side-apis"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Advanced usage"
    href="/docs/usage/advanced-usage"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Usage in Google Cloud Run"
    href="/docs/usage/cloud-run"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Usage in Firebase Hosting"
    href="/docs/usage/firebase-hosting"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Debug mode"
    href="/docs/usage/debug-mode"
  />
  <Card
    icon={<ChevronRightIcon />}
    title="Firebase API Key domain restriction"
    href="/docs/usage/domain-restriction"
  />
</Cards>


================================================
FILE: docs/pages/docs/usage/middleware.mdx
================================================
# Authentication Middleware

The `authMiddleware` works with the [getTokens](/docs/usage/server-components) function to share valid user credentials between [Next.js Proxy](https://nextjs.org/docs/app/getting-started/proxy) (or [Middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware) in Next.js 14-15) and [Server Components](https://nextjs.org/docs/app/building-your-application/rendering/server-components).

## Key Features

1. Sets up `/api/login` and `/api/logout` endpoints for managing browser authentication cookies. You don't need to create these API routes yourself—the middleware handles it for you. You can rename these endpoints by adjusting the `loginPath` and `logoutPath` options in the middleware settings.
2. Automatically refreshes browser authentication cookies when the token expires, allowing developers to handle it accordingly.
3. Signs user cookies with rotating keys to reduce the risk of cryptanalysis attacks.
4. Validates user cookies on every request.
5. Provides flexibility by allowing you to define custom behavior using the `handleValidToken`, `handleInvalidToken`, and `handleError` callbacks.

## Next.js 14-15 Compatibility

Starting from Next.js 16, there are two key API changes:

1. **`middleware.ts` has been renamed to `proxy.ts`** and the exported function should be named `proxy` instead of `middleware`. The proxy runs on the Node.js runtime instead of the Edge runtime.
2. **Async `cookies()` and `headers()` are now mandatory.** Next.js 15 introduced async versions of `cookies()` and `headers()` with temporary synchronous backward compatibility. In Next.js 16, the synchronous fallback is removed — you must use `await cookies()` and `await headers()`.

All code examples in the documentation use the **Next.js 15-16** convention with `await cookies()` and `await headers()`.

If you are using **Next.js 14 or 15**, replace `proxy.ts` with `middleware.ts` and `export async function proxy(...)` with `export async function middleware(...)`. If you are using **Next.js 14**, you should also remove the `await` before `cookies()` and `headers()` calls, as these functions are synchronous in Next.js 14.

The `authMiddleware` function and its options remain the same across all versions.

## Advanced usage

Advanced usage of `authMiddleware` in `proxy.ts`, based on [starter example](/examples#starter):

```tsx filename="proxy.ts"
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|.*\\.)*)'
  ]
};
```

## Metadata

Starting from v1.10.0, Authentication Middleware allows **you** to store custom data within cookies. The data is signed and verified together with the token, so it's safe to use it to, for example, load user permissions from the database.

Example usage:

```tsx filename="proxy.ts"
export async function proxy(request: NextRequest) {
  return authMiddleware(request, {
    // Store additional data in the cookies
    getMetadata: async (tokens: TokenSet) => {
      const roles = await loadRolesFromDb();
      return {roles};
    }
    // ...other options
  });
}
```

Access the data using [getTokens](/docs/usage/server-components):

```tsx
const {
  metadata: {roles}
} = await getTokens(await cookies(), authConfig);
```

## Custom Token

Starting from v1.8.0, **custom token is no longer enabled by default**. If you wish to enable custom token, set `enableCustomToken` option to `true` in `authMiddleware`.

Custom token introduces a significant footprint on the size of authentication cookie and is not required for most use-cases.

It's recommended to use `enableCustomToken` together with `enableMultipleCookies`. `enableMultipleCookies` would split session into multiple cookies, eliminating issues that can come from cookie size, as explained below.

## Multiple Cookies

Starting from v1.6.0, the `authMiddleware` supports the `enableMultipleCookies` option.

By default, the session data is stored in a single cookie. This works for most cases, but it limits the size of custom claims you can add to a token. Most browsers won't store a cookie larger than [4096 bytes](https://support.convert.com/hc/en-us/articles/4511582623117-Cookie-size-limits-and-the-impact-on-the-use-of-Convert-goals).

To prevent cookie size issues, it's recommended to set `enableMultipleCookies` to `true`.

When enabled, the session will be split into four cookies:

- `${cookieName}.id` – stores the `idToken`
- `${cookieName}.refresh` – stores the `refreshToken`
- `${cookieName}.custom` – stores the `customToken`
- `${cookieName}.sig` – stores the `signature` used to validate the tokens

### Firebase Hosting and Multiple Cookies

If you're using [Firebase Hosting](/docs/usage/firebase-hosting), set `enableMultipleCookies` to `false`.

Due to an issue with Firebase Hosting ([details here](https://stackoverflow.com/questions/44929653/firebase-cloud-function-wont-store-cookie-named-other-than-session)), multiple cookies are not supported.

If you run into cookie size problems on Firebase Hosting, you may want to either reduce the size of custom claims in your tokens or consider switching to a different hosting provider.

## Middleware Token Verification Caching

Since v0.9.0, the `handleValidToken` function is called with modified request `headers` as a second parameter.

You can pass this headers object to `NextResponse.next({ request: { headers } })` to enable token verification caching.

For more details on modifying request headers in middleware, check out [Modifying Request Headers in Middleware](https://vercel.com/templates/next.js/edge-functions-modify-request-header).

The example below shows a simplified version of how you can combine other middleware with `next-firebase-auth-edge`.

```tsx
handleValidToken: async ({token, decodedToken, customToken}, headers) => {
  return NextResponse.next({
    request: {
      headers // Pass modified request headers to skip token verification in subsequent getTokens and getApiRequestTokens calls
    }
  });
};
```

## Usage with `next-intl` and other middlewares

```tsx filename="proxy.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);
    }
  });
}
```

**Note:** When using `next-intl` middleware, you don't need to pass `headers` like you would in [middleware token verification caching](https://next-firebase-auth-edge-docs.vercel.app/docs/usage/middleware#middleware-token-verification-caching). By the time we call `intlMiddleware`, the `request` already has the updated headers. `next-intl` will handle passing the modified headers for you.

If you're experiencing issues with redirects while using `next-intl` middleware, check out [this comment on GitHub](https://github.com/awinogrodzki/next-firebase-auth-edge/issues/169#issuecomment-2076683598) for code examples.

## Options

| Name                                 | Required?                                                                                                       | Type/Default                                                                                                                                                    | Description                                                                                                                                                                                                                                                                                                                                                                                                       |
| ------------------------------------ | --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| loginPath                            | **Required**                                                                                                    |                                                                                                                                                                 | Defines the API login endpoint. When called with a Firebase auth token from the client, it responds with `Set-Cookie` headers containing signed ID and refresh tokens.                                                                                                                                                                                                                                            |
| logoutPath                           | **Required**                                                                                                    |                                                                                                                                                                 | Defines the API logout endpoint. When called from the client, it returns empty `Set-Cookie` headers that clear any previously set credentials.                                                                                                                                                                                                                                                                    |
| apiKey                               | **Required**                                                                                                    |                                                                                                                                                                 | The Firebase project API key, used to fetch Firebase ID and refresh tokens.                                                                                                                                                                                                                                                                                                                                       |
| cookieName                           | **Required**                                                                                                    |                                                                                                                                                                 | The name of the cookie set by the `loginPath` API route.                                                                                                                                                                                                                                                                                                                                                          |
| cookieSignatureKeys                  | **Required**                                                                                                    |                                                                                                                                                                 | [Rotating keys](https://developer.okta.com/docs/concepts/key-rotation/#:~:text=Key%20rotation%20is%20when%20a,and%20follows%20cryptographic%20best%20practices.) used to validate the cookie.                                                                                                                                                                                                                     |
| cookieSerializeOptions               | **Required**                                                                                                    |                                                                                                                                                                 | Defines additional options for the `Set-Cookie` headers.                                                                                                                                                                                                                                                                                                                                                          |
| serviceAccount                       | Optional in authenticated [Google Cloud Run](https://cloud.google.com/run) environments. Otherwise **required** |                                                                                                                                                                 | The Firebase project service account.                                                                                                                                                                                                                                                                                                                                                                             |
| enableMultipleCookies                | Optional                                                                                                        | `boolean`, defaults to `false`                                                                                                                                  | Splits session tokens into multiple cookies to increase token claims capacity. Recommended, but defaults to `false` for backwards compatibility. Set to `false` on Firebase Hosting due to limitations like [this](https://stackoverflow.com/questions/44929653/firebase-cloud-function-wont-store-cookie-named-other-than-session).                                                                              |
| enableCustomToken                    | Optional                                                                                                        | `boolean`, defaults to `false`                                                                                                                                  | If enabled, authentication cookie would contain custom token. This is helpful if you want to use [signInWithCustomToken](https://firebase.google.com/docs/auth/web/custom-auth) Firebase Client SDK method                                                                                                                                                                                                        |
| tenantId                             | Optional                                                                                                        | `string`, defaults to `undefined`                                                                                                                               | The Google Cloud Platform tenant identifier. Specify if your project supports [multi-tenancy](https://cloud.google.com/identity-platform/docs/multi-tenancy-authentication).                                                                                                                                                                                                                                      |
| authorizationHeaderName              | Optional                                                                                                        | `string`, defaults to `Authorization`                                                                                                                           | The name of the authorization header expected by the login endpoint.                                                                                                                                                                                                                                                                                                                                              |
| checkRevoked                         | Optional                                                                                                        | `boolean`, defaults to `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>`, defaults to `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>`, defaults to `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>`, defaults to `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<object>`                                                                                                                         | 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)                                                                                                                                                         |
| debug                                | Optional                                                                                                        | `boolean`, defaults to `false`                                                                                                                                  | Enables helpful logs for better understanding and debugging of the authentication flow.                                                                                                                                                                                                                                                                                                                           |
| dynamicCustomClaimsKeys              | Optional                                                                                                        | `string[]`, defaults to `undefined`                                                                                                                             | By default, when you update custom user claims using `setCustomUserClaims`, the changes will only take effect after the user logs in again. If you want the updated claim to be available immediately after refreshing the token (e.g., after handling `refreshNextResponseCookies`), you need to include the claim key in `dynamicCustomClaimsKeys`.                                                             |
| enableTokenRefreshOnExpiredKidHeader | Optional                                                                                                        | `boolean`, defaults to `true`                                                                                                                                   | By default, [when Google public keys expire](https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library) the token is refreshed automatically. Set `false` to opt-out from automatic refresh. When opted-out, `authMiddleware` will call [handleInvalidToken](/docs/errors#handleinvalidtoken) with `INVALID_KID` reason, allowing user to be safely redirected to sign in page.                |


================================================
FILE: docs/pages/docs/usage/pages-router-api-routes.mdx
================================================
# Pages Router API Routes

To support gradual adoption of the latest Next.js features, `next-firebase-auth-edge` offers the `getApiRequestTokens` function. This function is designed to work with [getServerSideProps](/docs/usage/get-server-side-props) and [API Routes](https://nextjs.org/docs/pages/building-your-application/routing/api-routes).

The `getApiRequestTokens` function works similarly to `getTokens`, but it's specifically for extracting cookie information from the `req` object.

```tsx
import { NextApiRequest, NextApiResponse } from "next";
import { getApiRequestTokens } from "next-firebase-auth-edge";

export default async function handle
Download .txt
gitextract_erfprbrg/

├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       ├── main.yml
│       └── release.yml
├── .gitignore
├── .husky/
│   ├── commit-msg
│   └── pre-commit
├── .npmignore
├── .releaserc.yaml
├── .swcrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── commitlint.config.js
├── docs/
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── README.md
│   ├── components/
│   │   ├── Chip.tsx
│   │   ├── CommunityLink.tsx
│   │   ├── Example.tsx
│   │   ├── FeaturePanel.tsx
│   │   ├── Footer.tsx
│   │   ├── FooterLink.tsx
│   │   ├── FooterSeparator.tsx
│   │   ├── Hero.tsx
│   │   ├── HeroCode.tsx
│   │   ├── Link.tsx
│   │   ├── LinkButton.tsx
│   │   ├── Section.tsx
│   │   ├── Steps.module.css
│   │   ├── Steps.tsx
│   │   └── Wrapper.tsx
│   ├── config.js
│   ├── next-env.d.ts
│   ├── next-sitemap.config.js
│   ├── next.config.js
│   ├── package.json
│   ├── pages/
│   │   ├── _app.tsx
│   │   ├── _document.tsx
│   │   ├── _meta.json
│   │   ├── docs/
│   │   │   ├── _meta.json
│   │   │   ├── app-check.mdx
│   │   │   ├── emulator.mdx
│   │   │   ├── errors.mdx
│   │   │   ├── faq.mdx
│   │   │   ├── getting-started/
│   │   │   │   ├── _meta.json
│   │   │   │   ├── auth-context.mdx
│   │   │   │   ├── auth-provider.mdx
│   │   │   │   ├── index.mdx
│   │   │   │   ├── layout.mdx
│   │   │   │   ├── login-page.mdx
│   │   │   │   ├── login-with-server-action.mdx
│   │   │   │   ├── logout-with-server-action.mdx
│   │   │   │   └── middleware.mdx
│   │   │   └── usage/
│   │   │       ├── _meta.json
│   │   │       ├── advanced-usage.mdx
│   │   │       ├── app-router-api-routes.mdx
│   │   │       ├── client-side-apis.mdx
│   │   │       ├── cloud-run.mdx
│   │   │       ├── debug-mode.mdx
│   │   │       ├── domain-restriction.mdx
│   │   │       ├── firebase-hosting.mdx
│   │   │       ├── get-server-side-props.mdx
│   │   │       ├── index.mdx
│   │   │       ├── middleware.mdx
│   │   │       ├── pages-router-api-routes.mdx
│   │   │       ├── redirect-functions.mdx
│   │   │       ├── refresh-credentials.mdx
│   │   │       ├── remove-credentials.mdx
│   │   │       └── server-components.mdx
│   │   ├── examples/
│   │   │   └── index.mdx
│   │   └── index.mdx
│   ├── postcss.config.js
│   ├── prettier.config.js
│   ├── public/
│   │   └── favicon/
│   │       └── site.webmanifest
│   ├── services/
│   │   ├── BrowserTracker.tsx
│   │   └── ServerTracker.tsx
│   ├── styles.css
│   ├── tailwind.config.js
│   ├── theme.config.tsx
│   └── tsconfig.json
├── eslint.config.mjs
├── examples/
│   ├── next-typescript-minimal/
│   │   ├── .eslintrc.json
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── app/
│   │   │   ├── HomePage.tsx
│   │   │   ├── globals.css
│   │   │   ├── layout.tsx
│   │   │   ├── login/
│   │   │   │   └── page.tsx
│   │   │   ├── page.tsx
│   │   │   └── register/
│   │   │       └── page.tsx
│   │   ├── config.ts
│   │   ├── firebase.ts
│   │   ├── middleware.ts
│   │   ├── next.config.mjs
│   │   ├── package.json
│   │   ├── postcss.config.js
│   │   ├── tailwind.config.ts
│   │   └── tsconfig.json
│   └── next-typescript-starter/
│       ├── .dockerignore
│       ├── .firebaserc
│       ├── .gitignore
│       ├── Dockerfile
│       ├── README.md
│       ├── api/
│       │   └── index.ts
│       ├── app/
│       │   ├── actions/
│       │   │   ├── login.ts
│       │   │   ├── refresh-cookies.ts
│       │   │   └── user-counters.ts
│       │   ├── api/
│       │   │   ├── check-email-verification/
│       │   │   │   └── route.ts
│       │   │   ├── custom-claims/
│       │   │   │   └── route.ts
│       │   │   ├── test-app-check/
│       │   │   │   └── route.ts
│       │   │   ├── token-test/
│       │   │   │   └── route.ts
│       │   │   └── user-counters/
│       │   │       └── route.ts
│       │   ├── auth/
│       │   │   ├── AuthContext.ts
│       │   │   ├── AuthProvider.tsx
│       │   │   └── firebase.ts
│       │   ├── firebase.ts
│       │   ├── globals.css
│       │   ├── layout.module.css
│       │   ├── layout.tsx
│       │   ├── login/
│       │   │   ├── LoginPage.tsx
│       │   │   ├── firebase.ts
│       │   │   ├── login.module.css
│       │   │   └── page.tsx
│       │   ├── page.module.css
│       │   ├── page.tsx
│       │   ├── profile/
│       │   │   ├── UserProfile/
│       │   │   │   ├── UserProfile.module.css
│       │   │   │   ├── UserProfile.tsx
│       │   │   │   ├── index.ts
│       │   │   │   ├── user-counters-server.ts
│       │   │   │   └── user-counters.ts
│       │   │   ├── page.module.css
│       │   │   └── page.tsx
│       │   ├── register/
│       │   │   ├── RegisterPage.tsx
│       │   │   ├── firebase.ts
│       │   │   ├── page.tsx
│       │   │   └── register.module.css
│       │   ├── reset-password/
│       │   │   ├── ResetPasswordPage.module.css
│       │   │   ├── ResetPasswordPage.tsx
│       │   │   ├── firebase.ts
│       │   │   └── page.tsx
│       │   └── shared/
│       │       ├── redirect.ts
│       │       ├── useRedirectAfterLogin.ts
│       │       ├── useRedirectParam.ts
│       │       └── user.ts
│       ├── app-check/
│       │   └── index.ts
│       ├── config/
│       │   ├── client-config.ts
│       │   └── server-config.ts
│       ├── eslint.config.mjs
│       ├── firebase.json
│       ├── next-env.d.ts
│       ├── next.config.js
│       ├── package.json
│       ├── pages/
│       │   └── api/
│       │       └── tokens.ts
│       ├── proxy.ts
│       ├── tsconfig.json
│       └── ui/
│           ├── Badge/
│           │   ├── Badge.module.css
│           │   ├── Badge.tsx
│           │   └── index.ts
│           ├── Button/
│           │   ├── Button.module.css
│           │   ├── Button.tsx
│           │   └── index.ts
│           ├── ButtonGroup/
│           │   ├── ButtonGroup.module.css
│           │   ├── ButtonGroup.tsx
│           │   └── index.ts
│           ├── Card/
│           │   ├── Card.module.css
│           │   ├── Card.tsx
│           │   └── index.ts
│           ├── FormError/
│           │   ├── FormError.module.css
│           │   ├── FormError.tsx
│           │   └── index.ts
│           ├── HomeLink/
│           │   ├── HomeLink.module.css
│           │   ├── HomeLink.tsx
│           │   └── index.ts
│           ├── IconButton/
│           │   ├── IconButton.module.css
│           │   ├── IconButton.tsx
│           │   └── index.ts
│           ├── Input/
│           │   ├── Input.module.css
│           │   ├── Input.tsx
│           │   └── index.ts
│           ├── MainTitle/
│           │   ├── MainTitle.module.css
│           │   ├── MainTitle.tsx
│           │   └── index.ts
│           ├── PasswordForm/
│           │   ├── PasswordForm.module.css
│           │   ├── PasswordForm.tsx
│           │   └── index.ts
│           ├── Switch/
│           │   ├── Switch.module.css
│           │   ├── Switch.tsx
│           │   ├── index.ts
│           │   └── vars.css
│           ├── classNames.ts
│           └── icons/
│               ├── HiddenIcon.tsx
│               ├── HomeIcon.tsx
│               ├── LoadingIcon.tsx
│               ├── VisibleIcon.tsx
│               ├── icons.module.css
│               └── index.ts
├── jest.config.js
├── jest.setup.ts
├── package.json
├── prettier.config.js
├── src/
│   ├── app-check/
│   │   ├── api-client.ts
│   │   ├── index.ts
│   │   ├── test/
│   │   │   └── app-check.integration.test.ts
│   │   ├── token-generator.ts
│   │   ├── token-verifier.ts
│   │   └── types.ts
│   ├── auth/
│   │   ├── auth-request-handler.ts
│   │   ├── claims.ts
│   │   ├── credential.ts
│   │   ├── custom-token/
│   │   │   ├── index.test.ts
│   │   │   └── index.ts
│   │   ├── default-credential.ts
│   │   ├── error.ts
│   │   ├── firebase.ts
│   │   ├── index.ts
│   │   ├── jwt/
│   │   │   ├── consts.ts
│   │   │   ├── crypto-signer.ts
│   │   │   ├── sign.test.ts
│   │   │   ├── sign.ts
│   │   │   ├── verify.test.ts
│   │   │   └── verify.ts
│   │   ├── rotating-credential.test.ts
│   │   ├── rotating-credential.ts
│   │   ├── signature-verifier.test.ts
│   │   ├── signature-verifier.ts
│   │   ├── test/
│   │   │   ├── create-custom-token.integration.test.ts
│   │   │   ├── no-matching-kid.integration.test.ts
│   │   │   ├── session-cookie.test.ts
│   │   │   ├── set-custom-user-claims.integration.test.ts
│   │   │   ├── user.integration.test.ts
│   │   │   └── verify-token.integration.test.ts
│   │   ├── token-generator.ts
│   │   ├── token-verifier.ts
│   │   ├── types.ts
│   │   ├── user-record.ts
│   │   ├── utils.ts
│   │   └── validator.ts
│   ├── debug/
│   │   └── index.ts
│   ├── index.ts
│   └── next/
│       ├── api.ts
│       ├── client.ts
│       ├── cookies/
│       │   ├── AuthCookies.test.ts
│       │   ├── AuthCookies.ts
│       │   ├── builder/
│       │   │   ├── CookieBuilder.ts
│       │   │   ├── CookieBuilderFactory.ts
│       │   │   ├── MultipleCookieBuilder.test.ts
│       │   │   ├── MultipleCookieBuilder.ts
│       │   │   ├── SingleCookieBuilder.test.ts
│       │   │   └── SingleCookieBuilder.ts
│       │   ├── expiration/
│       │   │   ├── CombinedCookieExpiration.ts
│       │   │   ├── CookieExpiration.ts
│       │   │   ├── CookieExpirationFactory.test.ts
│       │   │   ├── CookieExpirationFactory.ts
│       │   │   ├── MultipleCookieExpiration.test.ts
│       │   │   ├── MultipleCookieExpiration.ts
│       │   │   ├── SingleCookieExpiration.test.ts
│       │   │   └── SingleCookieExpiration.ts
│       │   ├── index.test.ts
│       │   ├── index.ts
│       │   ├── parser/
│       │   │   ├── CookieParser.ts
│       │   │   ├── CookieParserFactory.test.ts
│       │   │   ├── CookieParserFactory.ts
│       │   │   ├── CookiesProvider.ts
│       │   │   ├── MultipleCookiesParser.test.ts
│       │   │   ├── MultipleCookiesParser.ts
│       │   │   ├── ObjectCookiesProvider.ts
│       │   │   ├── RequestCookiesProvider.test.ts
│       │   │   ├── RequestCookiesProvider.ts
│       │   │   ├── SingleCookieParser.test.ts
│       │   │   └── SingleCookieParser.ts
│       │   ├── remover/
│       │   │   ├── CombinedCookieRemover.ts
│       │   │   ├── CookieRemover.ts
│       │   │   ├── CookieRemoverFactory.test.ts
│       │   │   ├── CookieRemoverFactory.ts
│       │   │   ├── MultipleCookieRemover.test.ts
│       │   │   ├── MultipleCookieRemover.ts
│       │   │   └── SingleCookieRemover.ts
│       │   ├── setter/
│       │   │   ├── CookieSetter.ts
│       │   │   ├── CookieSetterFactory.ts
│       │   │   ├── HeadersCookieSetter.test.ts
│       │   │   ├── HeadersCookieSetter.ts
│       │   │   ├── NextApiResponseHeadersCookieSetter.ts
│       │   │   ├── RequestCookieSetter.test.ts
│       │   │   └── RequestCookieSetter.ts
│       │   └── types.ts
│       ├── metadata.ts
│       ├── middleware.ts
│       ├── refresh-token.ts
│       ├── tokens.ts
│       └── utils.ts
├── tsconfig.base.json
├── tsconfig.browser.json
├── tsconfig.esm.json
├── tsconfig.json
└── tsconfig.test.json
Download .txt
SYMBOL INDEX (588 symbols across 149 files)

FILE: docs/components/Chip.tsx
  type Props (line 4) | type Props = {
  function Chip (line 10) | function Chip({children, className, color = 'green'}: Props) {

FILE: docs/components/CommunityLink.tsx
  type Props (line 5) | type Props = Omit<ComponentProps<typeof Link>, 'children'> & {
  function CommunityLink (line 12) | function CommunityLink({

FILE: docs/components/Example.tsx
  type Props (line 3) | type Props = {
  function Example (line 12) | function Example({

FILE: docs/components/FeaturePanel.tsx
  type Props (line 1) | type Props = {
  function FeaturePanel (line 7) | function FeaturePanel({code, description, title}: Props) {

FILE: docs/components/Footer.tsx
  function Footer (line 6) | function Footer() {

FILE: docs/components/FooterLink.tsx
  type Props (line 4) | type Props = ComponentProps<typeof Link>;
  function FooterLink (line 6) | function FooterLink({children, ...rest}: Props) {

FILE: docs/components/FooterSeparator.tsx
  function FooterSeparator (line 1) | function FooterSeparator() {

FILE: docs/components/Hero.tsx
  type Props (line 5) | type Props = {
  function Hero (line 13) | function Hero({

FILE: docs/components/HeroCode.tsx
  function Tab (line 4) | function Tab({
  function HeroCode (line 625) | function HeroCode() {

FILE: docs/components/Link.tsx
  type Props (line 4) | type Props = Omit<ComponentProps<typeof NextLink>, 'className'>;
  function Link (line 6) | function Link(props: Props) {

FILE: docs/components/LinkButton.tsx
  type Props (line 5) | type Props = {
  function LinkButton (line 9) | function LinkButton({

FILE: docs/components/Section.tsx
  type Props (line 4) | type Props = {
  function Section (line 10) | function Section({children, description, title}: Props) {

FILE: docs/components/Steps.tsx
  type Props (line 4) | type Props = {
  function Steps (line 8) | function Steps({children}: Props) {

FILE: docs/components/Wrapper.tsx
  type Props (line 4) | type Props = {
  function Wrapper (line 9) | function Wrapper({children, className}: Props) {

FILE: docs/pages/_app.tsx
  type Props (line 9) | type Props = AppProps & {
  function App (line 13) | function App({Component, pageProps}: Props) {

FILE: docs/pages/_document.tsx
  function Document (line 5) | function Document() {

FILE: docs/services/BrowserTracker.tsx
  type Event (line 3) | type Event = {
  class BrowserTracker (line 8) | class BrowserTracker {
    method trackEvent (line 9) | public static trackEvent({data, name}: Event) {

FILE: docs/services/ServerTracker.tsx
  class ServerTracker (line 3) | class ServerTracker {
    method postToCollect (line 4) | private static postToCollect({
    method createAuth (line 59) | private static createAuth(request: Request) {
    method trackEvent (line 69) | public static async trackEvent({

FILE: docs/theme.config.tsx
  method useNextSeoProps (line 196) | useNextSeoProps() {
  method component (line 219) | component(props: ComponentProps<typeof ThemeSwitch>) {

FILE: examples/next-typescript-minimal/app/HomePage.tsx
  type HomePageProps (line 7) | interface HomePageProps {
  function HomePage (line 11) | function HomePage({ email }: HomePageProps) {

FILE: examples/next-typescript-minimal/app/layout.tsx
  function RootLayout (line 12) | function RootLayout({

FILE: examples/next-typescript-minimal/app/login/page.tsx
  function Login (line 9) | function Login() {

FILE: examples/next-typescript-minimal/app/page.tsx
  function Home (line 7) | async function Home() {

FILE: examples/next-typescript-minimal/app/register/page.tsx
  function Register (line 9) | function Register() {

FILE: examples/next-typescript-minimal/middleware.ts
  constant PUBLIC_PATHS (line 5) | const PUBLIC_PATHS = ['/register', '/login'];
  function middleware (line 7) | async function middleware(request: NextRequest) {

FILE: examples/next-typescript-starter/api/index.ts
  function login (line 5) | async function login(token: string) {
  function loginWithCredential (line 23) | async function loginWithCredential(credential: UserCredential) {
  function logout (line 29) | async function logout() {
  function checkEmailVerification (line 45) | async function checkEmailVerification() {

FILE: examples/next-typescript-starter/app-check/index.ts
  function getOrInitializeAppCheck (line 11) | function getOrInitializeAppCheck(app: FirebaseApp): AppCheck {
  function getAppCheck (line 32) | function getAppCheck() {

FILE: examples/next-typescript-starter/app/actions/login.ts
  function loginAction (line 10) | async function loginAction(username: string, password: string) {

FILE: examples/next-typescript-starter/app/actions/refresh-cookies.ts
  function refreshCookies (line 8) | async function refreshCookies() {

FILE: examples/next-typescript-starter/app/actions/user-counters.ts
  function incrementCounter (line 10) | async function incrementCounter() {

FILE: examples/next-typescript-starter/app/api/check-email-verification/route.ts
  function GET (line 7) | async function GET(request: NextRequest) {

FILE: examples/next-typescript-starter/app/api/custom-claims/route.ts
  function POST (line 15) | async function POST(request: NextRequest) {

FILE: examples/next-typescript-starter/app/api/test-app-check/route.ts
  function POST (line 7) | async function POST(request: NextRequest) {

FILE: examples/next-typescript-starter/app/api/token-test/route.ts
  function GET (line 7) | async function GET(_request: NextRequest) {

FILE: examples/next-typescript-starter/app/api/user-counters/route.ts
  function POST (line 8) | async function POST(request: NextRequest) {

FILE: examples/next-typescript-starter/app/auth/AuthContext.ts
  type Metadata (line 5) | interface Metadata {
  type User (line 10) | interface User extends UserInfo {
  type AuthContextValue (line 18) | interface AuthContextValue {

FILE: examples/next-typescript-starter/app/auth/AuthProvider.tsx
  type AuthProviderProps (line 6) | interface AuthProviderProps {

FILE: examples/next-typescript-starter/app/auth/firebase.ts
  function getFirebaseAuth (line 18) | function getFirebaseAuth() {

FILE: examples/next-typescript-starter/app/layout.tsx
  function RootLayout (line 10) | async function RootLayout({

FILE: examples/next-typescript-starter/app/login/LoginPage.tsx
  function LoginPage (line 35) | function LoginPage({

FILE: examples/next-typescript-starter/app/login/firebase.ts
  constant CREDENTIAL_ALREADY_IN_USE_ERROR (line 17) | const CREDENTIAL_ALREADY_IN_USE_ERROR = 'auth/credential-already-in-use';

FILE: examples/next-typescript-starter/app/login/page.tsx
  function Login (line 4) | function Login() {

FILE: examples/next-typescript-starter/app/page.tsx
  function generateStaticParams (line 8) | async function generateStaticParams() {
  function Home (line 12) | function Home() {

FILE: examples/next-typescript-starter/app/profile/UserProfile/UserProfile.tsx
  type UserProfileProps (line 21) | interface UserProfileProps {
  function UserProfile (line 26) | function UserProfile({count, incrementCounter}: UserProfileProps) {

FILE: examples/next-typescript-starter/app/profile/UserProfile/user-counters-server.ts
  function getServerFirebase (line 6) | async function getServerFirebase(authIdToken?: string) {
  type UserCounter (line 17) | interface UserCounter {
  function getUserCounter (line 22) | async function getUserCounter(

FILE: examples/next-typescript-starter/app/profile/UserProfile/user-counters.ts
  function incrementCounterUsingClientFirestore (line 25) | async function incrementCounterUsingClientFirestore(

FILE: examples/next-typescript-starter/app/profile/page.tsx
  function Profile (line 13) | async function Profile() {
  function generateMetadata (line 39) | async function generateMetadata(): Promise<Metadata> {

FILE: examples/next-typescript-starter/app/register/RegisterPage.tsx
  function RegisterPage (line 22) | function RegisterPage() {

FILE: examples/next-typescript-starter/app/register/firebase.ts
  constant CREDENTIAL_ALREADY_IN_USE_ERROR (line 10) | const CREDENTIAL_ALREADY_IN_USE_ERROR = 'auth/credential-already-in-use';

FILE: examples/next-typescript-starter/app/register/page.tsx
  function Register (line 3) | function Register() {

FILE: examples/next-typescript-starter/app/reset-password/ResetPasswordPage.tsx
  function ResetPasswordPage (line 17) | function ResetPasswordPage() {

FILE: examples/next-typescript-starter/app/reset-password/firebase.ts
  constant CREDENTIAL_ALREADY_IN_USE_ERROR (line 10) | const CREDENTIAL_ALREADY_IN_USE_ERROR = 'auth/credential-already-in-use';

FILE: examples/next-typescript-starter/app/reset-password/page.tsx
  function ResetPassword (line 3) | function ResetPassword() {

FILE: examples/next-typescript-starter/app/shared/redirect.ts
  function appendRedirectParam (line 1) | function appendRedirectParam(url: string, redirectUrl: string | null) {

FILE: examples/next-typescript-starter/app/shared/useRedirectAfterLogin.ts
  function useRedirectAfterLogin (line 4) | function useRedirectAfterLogin() {

FILE: examples/next-typescript-starter/app/shared/useRedirectParam.ts
  function useRedirectParam (line 3) | function useRedirectParam(): string | null {

FILE: examples/next-typescript-starter/next.config.js
  method rewrites (line 10) | async rewrites() {

FILE: examples/next-typescript-starter/pages/api/tokens.ts
  function handler (line 5) | async function handler(

FILE: examples/next-typescript-starter/proxy.ts
  constant PRIVATE_PATHS (line 10) | const PRIVATE_PATHS = ['/', '/profile'];
  constant PUBLIC_PATHS (line 11) | const PUBLIC_PATHS = ['/register', '/login', '/reset-password'];
  function proxy (line 13) | async function proxy(request: NextRequest) {

FILE: examples/next-typescript-starter/ui/Badge/Badge.tsx
  function Badge (line 4) | function Badge(props: JSX.IntrinsicElements['span']) {

FILE: examples/next-typescript-starter/ui/Button/Button.tsx
  function Button (line 12) | function Button({

FILE: examples/next-typescript-starter/ui/ButtonGroup/ButtonGroup.tsx
  function ButtonGroup (line 4) | function ButtonGroup(props: JSX.IntrinsicElements['div']) {

FILE: examples/next-typescript-starter/ui/Card/Card.tsx
  function Card (line 4) | function Card(props: JSX.IntrinsicElements['div']) {

FILE: examples/next-typescript-starter/ui/FormError/FormError.tsx
  function FormError (line 4) | function FormError(props: JSX.IntrinsicElements['span']) {

FILE: examples/next-typescript-starter/ui/HomeLink/HomeLink.tsx
  function HomeLink (line 5) | function HomeLink() {

FILE: examples/next-typescript-starter/ui/IconButton/IconButton.tsx
  function IconButton (line 5) | function IconButton(props: JSX.IntrinsicElements['button']) {

FILE: examples/next-typescript-starter/ui/Input/Input.tsx
  function Input (line 6) | function Input({children, ...props}: JSX.IntrinsicElements['input']) {

FILE: examples/next-typescript-starter/ui/MainTitle/MainTitle.tsx
  function MainTitle (line 4) | function MainTitle(props: JSX.IntrinsicElements['h1']) {

FILE: examples/next-typescript-starter/ui/PasswordForm/PasswordForm.tsx
  type PasswordFormValue (line 13) | interface PasswordFormValue {
  type PasswordFormProps (line 18) | interface PasswordFormProps
  function PasswordForm (line 26) | function PasswordForm({

FILE: examples/next-typescript-starter/ui/Switch/Switch.tsx
  type SwitchProps (line 3) | interface SwitchProps {
  function Switch (line 8) | function Switch({value, onChange}: SwitchProps) {

FILE: examples/next-typescript-starter/ui/classNames.ts
  function cx (line 1) | function cx(...className: (string | undefined)[]): string {

FILE: examples/next-typescript-starter/ui/icons/HiddenIcon.tsx
  function HiddenIcon (line 5) | function HiddenIcon(props: JSX.IntrinsicElements['span']) {

FILE: examples/next-typescript-starter/ui/icons/HomeIcon.tsx
  function HomeIcon (line 5) | function HomeIcon(props: JSX.IntrinsicElements['span']) {

FILE: examples/next-typescript-starter/ui/icons/LoadingIcon.tsx
  function LoadingIcon (line 5) | function LoadingIcon(props: JSX.IntrinsicElements['span']) {

FILE: examples/next-typescript-starter/ui/icons/VisibleIcon.tsx
  function VisibleIcon (line 5) | function VisibleIcon(props: JSX.IntrinsicElements['span']) {

FILE: src/app-check/api-client.ts
  constant FIREBASE_APP_CHECK_V1_API_URL_FORMAT (line 6) | const FIREBASE_APP_CHECK_V1_API_URL_FORMAT =
  constant FIREBASE_APP_CHECK_CONFIG_HEADERS (line 9) | const FIREBASE_APP_CHECK_CONFIG_HEADERS = {
  class AppCheckApiClient (line 13) | class AppCheckApiClient {
    method constructor (line 14) | constructor(private credential: Credential) {}
    method exchangeToken (line 16) | public async exchangeToken(
    method getUrl (line 39) | private async getUrl(appId: string): Promise<string> {
    method toFirebaseError (line 53) | private async toFirebaseError(
    method toAppCheckToken (line 66) | private async toAppCheckToken(response: Response): Promise<AppCheckTok...
    method stringToMilliseconds (line 77) | private stringToMilliseconds(duration: string): number {
  type ErrorResponse (line 89) | interface ErrorResponse {
  type Error (line 93) | interface Error {
  constant APP_CHECK_ERROR_CODE_MAPPING (line 99) | const APP_CHECK_ERROR_CODE_MAPPING: {
  type AppCheckErrorCode (line 112) | type AppCheckErrorCode =
  class FirebaseAppCheckError (line 123) | class FirebaseAppCheckError extends Error {
    method constructor (line 124) | constructor(

FILE: src/app-check/index.ts
  class AppCheck (line 18) | class AppCheck {
    method constructor (line 23) | constructor(credential: Credential, tenantId?: string) {
  type AppCheckOptions (line 57) | interface AppCheckOptions {
  function isAppCheckOptions (line 62) | function isAppCheckOptions(
  function getAppCheck (line 80) | function getAppCheck(

FILE: src/app-check/test/app-check.integration.test.ts
  constant TEST_SERVICE_ACCOUNT (line 12) | const TEST_SERVICE_ACCOUNT = {

FILE: src/app-check/token-generator.ts
  constant ONE_MINUTE_IN_SECONDS (line 5) | const ONE_MINUTE_IN_SECONDS = 60;
  constant ONE_MINUTE_IN_MILLIS (line 6) | const ONE_MINUTE_IN_MILLIS = ONE_MINUTE_IN_SECONDS * 1000;
  constant ONE_DAY_IN_MILLIS (line 7) | const ONE_DAY_IN_MILLIS = 24 * 60 * 60 * 1000;
  constant FIREBASE_APP_CHECK_AUDIENCE (line 9) | const FIREBASE_APP_CHECK_AUDIENCE =
  function transformMillisecondsToSecondsString (line 12) | function transformMillisecondsToSecondsString(milliseconds: number): str...
  class AppCheckTokenGenerator (line 28) | class AppCheckTokenGenerator {
    method constructor (line 31) | constructor(signer: CryptoSigner) {
    method createCustomToken (line 35) | public async createCustomToken(
    method validateTokenOptions (line 66) | private validateTokenOptions(options: AppCheckTokenOptions): {

FILE: src/app-check/token-verifier.ts
  constant APP_CHECK_ISSUER (line 14) | const APP_CHECK_ISSUER = 'https://firebaseappcheck.googleapis.com/';
  constant JWKS_URL (line 15) | const JWKS_URL = 'https://firebaseappcheck.googleapis.com/v1/jwks';
  class AppCheckTokenVerifier (line 17) | class AppCheckTokenVerifier {
    method constructor (line 20) | constructor(private readonly credential: Credential) {
    method verifyToken (line 24) | public async verifyToken(
    method decodeAndVerify (line 36) | private async decodeAndVerify(
    method verifyContent (line 50) | private verifyContent(
    method verifySignature (line 97) | private verifySignature(
    method mapJwtErrorToAppCheckError (line 108) | private mapJwtErrorToAppCheckError(error: JOSEError): FirebaseAppCheck...

FILE: src/app-check/types.ts
  type AppCheckToken (line 1) | interface AppCheckToken {
  type AppCheckTokenOptions (line 6) | interface AppCheckTokenOptions {
  type DecodedAppCheckToken (line 10) | interface DecodedAppCheckToken {
  type VerifyAppCheckTokenResponse (line 20) | interface VerifyAppCheckTokenResponse {

FILE: src/auth/auth-request-handler.ts
  type HttpMethod (line 12) | type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD';
  class ApiSettings (line 14) | class ApiSettings {
    method constructor (line 15) | constructor(
    method getEndpoint (line 20) | public getEndpoint(): string {
    method getHttpMethod (line 24) | public getHttpMethod(): HttpMethod {
  function getSdkVersion (line 29) | function getSdkVersion(): string {
  constant FIREBASE_AUTH_HEADER (line 33) | const FIREBASE_AUTH_HEADER = {
  constant FIREBASE_AUTH_BASE_URL_FORMAT (line 39) | const FIREBASE_AUTH_BASE_URL_FORMAT =
  constant FIREBASE_AUTH_EMULATOR_BASE_URL_FORMAT (line 42) | const FIREBASE_AUTH_EMULATOR_BASE_URL_FORMAT =
  class AuthResourceUrlBuilder (line 45) | class AuthResourceUrlBuilder {
    method constructor (line 48) | constructor(
    method getUrl (line 61) | public async getUrl(api?: string, params?: object): Promise<string> {
  constant FIREBASE_AUTH_CREATE_SESSION_COOKIE (line 72) | const FIREBASE_AUTH_CREATE_SESSION_COOKIE = new ApiSettings(
  constant FIREBASE_AUTH_GET_ACCOUNT_INFO (line 77) | const FIREBASE_AUTH_GET_ACCOUNT_INFO = new ApiSettings(
  constant FIREBASE_AUTH_DELETE_ACCOUNT (line 82) | const FIREBASE_AUTH_DELETE_ACCOUNT = new ApiSettings(
  constant FIREBASE_AUTH_SET_ACCOUNT_INFO (line 87) | const FIREBASE_AUTH_SET_ACCOUNT_INFO = new ApiSettings(
  constant FIREBASE_AUTH_SIGN_UP_NEW_USER (line 92) | const FIREBASE_AUTH_SIGN_UP_NEW_USER = new ApiSettings(
  constant FIREBASE_AUTH_LIST_USERS_INFO (line 97) | const FIREBASE_AUTH_LIST_USERS_INFO = new ApiSettings(
  type ListUsersResponse (line 102) | type ListUsersResponse = {
  type GetAccountInfoByEmailResponse (line 108) | type GetAccountInfoByEmailResponse = {
  type ResponseObject (line 112) | type ResponseObject = {
  type AuthRequestHandlerOptions (line 116) | interface AuthRequestHandlerOptions {
  type ErrorResponse (line 120) | interface ErrorResponse {
  method getErrorCode (line 128) | private static getErrorCode(response: unknown): string | null {
  method constructor (line 137) | constructor(
  method prepareRequest (line 150) | private prepareRequest(request: object) {
  method getAccountInfoByUid (line 161) | public getAccountInfoByUid(
  method deleteAccount (line 175) | public deleteAccount(uid: string): Promise<ResponseObject> {
  method getAccountInfoByEmail (line 185) | public getAccountInfoByEmail(
  method createNewAccount (line 205) | public createNewAccount(properties: CreateRequest): Promise<string> {
  method createSessionCookie (line 263) | public createSessionCookie(
  method updateExistingAccount (line 280) | public updateExistingAccount(
  method setCustomUserClaims (line 388) | public setCustomUserClaims(
  method listUsers (line 410) | public listUsers(nextPageToken?: string, maxResults?: number) {
  method getSearchParams (line 423) | private getSearchParams(requestData: object) {
  method decorateUrlWithParams (line 437) | private decorateUrlWithParams(url: string, requestData: object) {
  method invokeRequestHandler (line 448) | protected async invokeRequestHandler<T = ResponseObject>(
  method getAuthUrlBuilder (line 499) | private getAuthUrlBuilder(): AuthResourceUrlBuilder {
  class AuthRequestHandler (line 507) | class AuthRequestHandler extends AbstractAuthRequestHandler {
    method constructor (line 510) | constructor(
    method newAuthUrlBuilder (line 518) | protected newAuthUrlBuilder(): AuthResourceUrlBuilder {
  function isPhoneFactor (line 523) | function isPhoneFactor(
  function isUTCDateString (line 529) | function isUTCDateString(dateString: string): boolean {
  function convertMultiFactorInfoToServerFormat (line 539) | function convertMultiFactorInfoToServerFormat(
  type AuthFactorInfo (line 575) | interface AuthFactorInfo {
  type BaseUpdateMultiFactorInfoRequest (line 583) | interface BaseUpdateMultiFactorInfoRequest {
  type UpdatePhoneMultiFactorInfoRequest (line 590) | interface UpdatePhoneMultiFactorInfoRequest
  type UpdateMultiFactorInfoRequest (line 595) | type UpdateMultiFactorInfoRequest = UpdatePhoneMultiFactorInfoRequest;
  type MultiFactorUpdateSettings (line 597) | interface MultiFactorUpdateSettings {
  type UpdateRequest (line 601) | interface UpdateRequest {
  type UserProvider (line 615) | interface UserProvider {
  type BaseCreateMultiFactorInfoRequest (line 624) | interface BaseCreateMultiFactorInfoRequest {
  type CreatePhoneMultiFactorInfoRequest (line 629) | interface CreatePhoneMultiFactorInfoRequest
  type CreateMultiFactorInfoRequest (line 634) | type CreateMultiFactorInfoRequest = CreatePhoneMultiFactorInfoRequest;
  type MultiFactorCreateSettings (line 636) | interface MultiFactorCreateSettings {
  type CreateRequest (line 640) | interface CreateRequest extends UpdateRequest {

FILE: src/auth/claims.ts
  type Claims (line 1) | type Claims = {[key: string]: unknown};
  constant STANDARD_CLAIMS (line 3) | const STANDARD_CLAIMS = [

FILE: src/auth/credential.ts
  type GoogleOAuthAccessToken (line 5) | interface GoogleOAuthAccessToken {
  type Credential (line 10) | interface Credential {
  constant TOKEN_EXPIRY_THRESHOLD_MILLIS (line 16) | const TOKEN_EXPIRY_THRESHOLD_MILLIS = 5 * 60 * 1000;
  constant GOOGLE_TOKEN_AUDIENCE (line 17) | const GOOGLE_TOKEN_AUDIENCE = 'https://accounts.google.com/o/oauth2/token';
  constant GOOGLE_AUTH_TOKEN_HOST (line 18) | const GOOGLE_AUTH_TOKEN_HOST = 'accounts.google.com';
  constant GOOGLE_AUTH_TOKEN_PATH (line 19) | const GOOGLE_AUTH_TOKEN_PATH = '/o/oauth2/token';
  constant ONE_HOUR_IN_SECONDS (line 20) | const ONE_HOUR_IN_SECONDS = 60 * 60;
  type ServiceAccount (line 22) | interface ServiceAccount {
  class ServiceAccountCredential (line 30) | class ServiceAccountCredential implements Credential {
    method constructor (line 35) | constructor(serviceAccount: ServiceAccount) {
    method fetchAccessToken (line 41) | private async fetchAccessToken(url: string): Promise<FirebaseAccessTok...
    method getProjectId (line 59) | public getProjectId(): Promise<string> {
    method getServiceAccountEmail (line 63) | public getServiceAccountEmail(): Promise<string> {
    method fetchAndCacheAccessToken (line 67) | private async fetchAndCacheAccessToken(url: string) {
    method getAccessToken (line 72) | public async getAccessToken(
    method createJwt (line 94) | private async createJwt(): Promise<string> {
  function requestAccessToken (line 119) | async function requestAccessToken(
  function getExplicitProjectId (line 137) | function getExplicitProjectId(): string | null {
  constant GOOGLE_METADATA_SERVICE_HOST (line 146) | const GOOGLE_METADATA_SERVICE_HOST = 'metadata.google.internal';
  constant GOOGLE_METADATA_SERVICE_TOKEN_PATH (line 147) | const GOOGLE_METADATA_SERVICE_TOKEN_PATH =
  constant GOOGLE_METADATA_SERVICE_IDENTITY_PATH (line 149) | const GOOGLE_METADATA_SERVICE_IDENTITY_PATH =
  constant GOOGLE_METADATA_SERVICE_PROJECT_ID_PATH (line 151) | const GOOGLE_METADATA_SERVICE_PROJECT_ID_PATH =
  constant GOOGLE_METADATA_SERVICE_ACCOUNT_ID_PATH (line 153) | const GOOGLE_METADATA_SERVICE_ACCOUNT_ID_PATH =
  function requestIDToken (line 156) | async function requestIDToken(
  class ComputeEngineCredential (line 171) | class ComputeEngineCredential implements Credential {
    method constructor (line 176) | constructor() {}
    method getAccessToken (line 178) | public async getAccessToken(
    method getIDToken (line 196) | public getIDToken(audience: string): Promise<string> {
    method getProjectId (line 203) | public async getProjectId(): Promise<string> {
    method getServiceAccountEmail (line 220) | public async getServiceAccountEmail(): Promise<string> {
    method buildRequest (line 237) | private buildRequest(): RequestInit {
  type FirebaseAccessToken (line 247) | interface FirebaseAccessToken {
  function getToken (line 253) | async function getToken(forceRefresh = false): Promise<FirebaseAccessTok...

FILE: src/auth/custom-token/index.ts
  type CustomTokens (line 12) | interface CustomTokens {
  type ParsedCookies (line 18) | interface ParsedCookies<Metadata extends object> {
  type VerifiedCookies (line 25) | interface VerifiedCookies<Metadata extends object> {
  type CustomJWTHeader (line 33) | interface CustomJWTHeader {
  type CustomJWTPayload (line 38) | interface CustomJWTPayload<Metadata extends object | undefined>
  function createCustomSignature (line 46) | async function createCustomSignature<Metadata extends object>(
  function verifyCustomSignature (line 67) | async function verifyCustomSignature<Metadata extends object>(
  function createCustomJWT (line 77) | async function createCustomJWT<Metadata extends object>(
  function verifyCustomJWT (line 88) | async function verifyCustomJWT<Metadata extends object>(

FILE: src/auth/error.ts
  type AuthErrorCode (line 1) | enum AuthErrorCode {
  type HttpError (line 15) | interface HttpError {
  function getErrorMessage (line 35) | function getErrorMessage(code: AuthErrorCode, customMessage?: string) {
  function mergeStackTraceAndCause (line 43) | function mergeStackTraceAndCause(target: Error, original: unknown) {
  class AuthError (line 54) | class AuthError extends Error {
    method fromError (line 55) | public static fromError(
    method constructor (line 66) | constructor(
    method toJSON (line 74) | public toJSON(): object {
  type InvalidTokenReason (line 82) | enum InvalidTokenReason {
  class InvalidTokenError (line 102) | class InvalidTokenError extends Error {
    method fromError (line 103) | public static fromError(error: unknown, reason: InvalidTokenReason) {
    method constructor (line 113) | constructor(public readonly reason: InvalidTokenReason) {
  function isInvalidTokenError (line 119) | function isInvalidTokenError(

FILE: src/auth/firebase.ts
  constant FIREBASE_AUDIENCE (line 1) | const FIREBASE_AUDIENCE =
  constant CLIENT_CERT_URL (line 3) | const CLIENT_CERT_URL =
  function emulatorHost (line 6) | function emulatorHost(): string | undefined {
  function useEmulator (line 11) | function useEmulator(): boolean {

FILE: src/auth/index.ts
  type CustomTokenToIdAndRefreshTokensOptions (line 65) | interface CustomTokenToIdAndRefreshTokensOptions {
  function customTokenToIdAndRefreshTokens (line 71) | async function customTokenToIdAndRefreshTokens(
  function createAnonymousAccount (line 118) | async function createAnonymousAccount(
  type ErrorResponse (line 148) | interface ErrorResponse {
  type UserNotFoundResponse (line 157) | interface UserNotFoundResponse extends ErrorResponse {
  type TokenRefreshOptions (line 174) | interface TokenRefreshOptions {
  function isUserNotFoundError (line 214) | function isUserNotFoundError(error: unknown): error is AuthError {
  function isInvalidCredentialError (line 218) | function isInvalidCredentialError(error: unknown): error is AuthError {
  function handleVerifyTokenError (line 222) | async function handleVerifyTokenError<T>(
  function handleExpiredToken (line 234) | async function handleExpiredToken<T>(
  type IdAndRefreshTokens (line 277) | interface IdAndRefreshTokens {
  type CreateAnonymousRequest (line 282) | interface CreateAnonymousRequest {
  type AnonymousTokens (line 288) | interface AnonymousTokens {
  type UsersList (line 294) | interface UsersList {
  type GetCustomIdAndRefreshTokensOptions (line 299) | interface GetCustomIdAndRefreshTokensOptions {
  type AuthOptions (line 305) | interface AuthOptions {
  type Auth (line 313) | type Auth = ReturnType<typeof getAuth>;
  constant DEFAULT_VERIFY_OPTIONS (line 315) | const DEFAULT_VERIFY_OPTIONS = {referer: ''};
  function getAuth (line 317) | function getAuth(options: AuthOptions) {
  function isFirebaseAuthOptions (line 613) | function isFirebaseAuthOptions(
  type FirebaseAuthOptions (line 625) | interface FirebaseAuthOptions {
  function getFirebaseAuth (line 639) | function getFirebaseAuth(

FILE: src/auth/jwt/consts.ts
  constant ALGORITHMS (line 1) | const ALGORITHMS = {

FILE: src/auth/jwt/crypto-signer.ts
  type CryptoSigner (line 7) | interface CryptoSigner {
  function createEmulatorToken (line 12) | function createEmulatorToken(payload: JWTPayload) {
  class EmulatorSigner (line 21) | class EmulatorSigner implements CryptoSigner {
    method constructor (line 22) | constructor(private readonly tenantId?: string) {}
    method sign (line 24) | public async sign(payload: JWTPayload): Promise<string> {
    method getAccountId (line 32) | public getAccountId(): Promise<string> {
  class ServiceAccountSigner (line 37) | class ServiceAccountSigner implements CryptoSigner {
    method constructor (line 38) | constructor(
    method sign (line 43) | public async sign(payload: JWTPayload): Promise<string> {
    method getAccountId (line 51) | public getAccountId(): Promise<string> {
  class IAMSigner (line 56) | class IAMSigner implements CryptoSigner {
    method constructor (line 63) | constructor(
    method sign (line 73) | public async sign(payload: JWTPayload): Promise<string> {
    method getAccountId (line 88) | public async getAccountId(): Promise<string> {

FILE: src/auth/jwt/sign.test.ts
  type GlobalAny (line 3) | type GlobalAny = {
  constant PRIVATE_KEY (line 13) | const PRIVATE_KEY =

FILE: src/auth/jwt/sign.ts
  type SignOptions (line 6) | type SignOptions = {
  function sign (line 12) | async function sign({
  type SignBlobOptions (line 34) | type SignBlobOptions = {
  function formatBase64 (line 40) | function formatBase64(value: string) {
  function encodeSegment (line 44) | function encodeSegment(segment: Record<string, string> | JWTPayload): st...
  function signBlob (line 50) | async function signBlob({

FILE: src/auth/jwt/verify.ts
  constant ALGORITHM_RS256 (line 12) | const ALGORITHM_RS256 = 'RS256' as const;
  function importPublicCryptoKey (line 16) | async function importPublicCryptoKey(publicKey: string) {
  function getPublicCryptoKey (line 24) | async function getPublicCryptoKey(publicKey: string): Promise<KeyLike> {
  function verify (line 36) | async function verify(

FILE: src/auth/rotating-credential.test.ts
  type MockMetadata (line 5) | type MockMetadata = {foo: 'bar'};

FILE: src/auth/rotating-credential.ts
  class RotatingCredential (line 11) | class RotatingCredential<Metadata extends object> {
    method constructor (line 12) | constructor(private keys: string[]) {}
    method sign (line 14) | public async sign(payload: CustomJWTPayload<Metadata>) {
    method createSignature (line 18) | public async createSignature(
    method verify (line 24) | public async verify(customJWT: string): Promise<CustomJWTPayload<Metad...
    method verifySignature (line 46) | public async verifySignature(

FILE: src/auth/signature-verifier.ts
  type PublicKeys (line 18) | type PublicKeys = {[key: string]: string};
  type PublicKeysResponse (line 20) | interface PublicKeysResponse {
  type DecodedToken (line 25) | type DecodedToken = {
  type SignatureVerifier (line 30) | interface SignatureVerifier {
  type KeyFetcher (line 34) | interface KeyFetcher {
  function getExpiresAt (line 38) | function getExpiresAt(res: Response) {
  class UrlKeyFetcher (line 59) | class UrlKeyFetcher implements KeyFetcher {
    method constructor (line 60) | constructor(private clientCertUrl: string) {
    method fetchPublicKeysResponse (line 68) | private async fetchPublicKeysResponse(url: URL): Promise<PublicKeysRes...
    method fetchAndCachePublicKeys (line 111) | private async fetchAndCachePublicKeys(url: URL): Promise<PublicKeys> {
    method fetchPublicKeys (line 132) | public async fetchPublicKeys(): Promise<PublicKeys> {
  class JWKSSignatureVerifier (line 157) | class JWKSSignatureVerifier implements SignatureVerifier {
    method constructor (line 160) | constructor(
    method getPublicKey (line 171) | private async getPublicKey(
    method verify (line 179) | public async verify(token: string, options: VerifyOptions): Promise<vo...
  class PublicKeySignatureVerifier (line 205) | class PublicKeySignatureVerifier implements SignatureVerifier {
    method constructor (line 206) | constructor(private keyFetcher: KeyFetcher) {
    method withCertificateUrl (line 212) | public static withCertificateUrl(
    method getPublicKey (line 218) | private async getPublicKey(
    method verify (line 228) | public async verify(token: string, options: VerifyOptions): Promise<vo...
    method verifyWithoutKid (line 243) | private async verifyWithoutKid(
    method verifyWithAllKeys (line 252) | private async verifyWithAllKeys(
  function fetchPublicKey (line 284) | async function fetchPublicKey(

FILE: src/auth/test/create-custom-token.integration.test.ts
  constant TEST_SERVICE_ACCOUNT (line 14) | const TEST_SERVICE_ACCOUNT = {
  constant REFERER (line 20) | const REFERER = 'http://localhost:3000';

FILE: src/auth/test/no-matching-kid.integration.test.ts
  constant TEST_SERVICE_ACCOUNT (line 13) | const TEST_SERVICE_ACCOUNT = {
  constant REFERER (line 19) | const REFERER = 'http://localhost:3000';

FILE: src/auth/test/session-cookie.test.ts
  constant TEST_SERVICE_ACCOUNT (line 12) | const TEST_SERVICE_ACCOUNT = {
  constant REFERER (line 18) | const REFERER = 'http://localhost:3000';

FILE: src/auth/test/set-custom-user-claims.integration.test.ts
  constant TEST_SERVICE_ACCOUNT (line 14) | const TEST_SERVICE_ACCOUNT = {
  constant REFERER (line 20) | const REFERER = 'http://localhost:3000';

FILE: src/auth/test/user.integration.test.ts
  constant TEST_USER_ID (line 11) | const TEST_USER_ID = '39d14e52-6e22-4afd-a844-c8aa2e685224';

FILE: src/auth/test/verify-token.integration.test.ts
  constant TEST_SERVICE_ACCOUNT (line 20) | const TEST_SERVICE_ACCOUNT = {
  constant REFERER (line 26) | const REFERER = 'http://localhost:3000';
  function customGetToken (line 209) | async function customGetToken() {

FILE: src/auth/token-generator.ts
  constant ONE_HOUR_IN_SECONDS (line 13) | const ONE_HOUR_IN_SECONDS = 60 * 60;
  constant BLACKLISTED_CLAIMS (line 15) | const BLACKLISTED_CLAIMS = [
  constant FIREBASE_AUDIENCE (line 32) | const FIREBASE_AUDIENCE =
  class FirebaseTokenGenerator (line 35) | class FirebaseTokenGenerator {
    method constructor (line 38) | constructor(signer: CryptoSigner) {
    method createCustomToken (line 42) | public createCustomToken(
    method isDeveloperClaimsValid_ (line 94) | private static isDeveloperClaimsValid_(developerClaims?: object): bool...
  function cryptoSignerFromCredential (line 102) | function cryptoSignerFromCredential(
  function createFirebaseTokenGenerator (line 114) | function createFirebaseTokenGenerator(

FILE: src/auth/token-verifier.ts
  class FirebaseTokenVerifier (line 15) | class FirebaseTokenVerifier {
    method constructor (line 18) | constructor(
    method verifyJWT (line 35) | public async verifyJWT(
    method decodeAndVerify (line 54) | private async decodeAndVerify(
    method verifyContent (line 68) | private verifyContent(
    method verifySignature (line 98) | private verifySignature(
    method mapJoseErrorToAuthError (line 107) | private mapJoseErrorToAuthError(error: JOSEError): Error {
  function createIdTokenVerifier (line 132) | function createIdTokenVerifier(

FILE: src/auth/types.ts
  type FirebaseClaims (line 1) | interface FirebaseClaims {
  type DecodedIdToken (line 12) | interface DecodedIdToken {
  type VerifyOptions (line 30) | interface VerifyOptions {
  type Tokens (line 37) | interface Tokens<Metadata extends object = object> {
  type TokenSet (line 46) | interface TokenSet {

FILE: src/auth/user-record.ts
  constant B64_REDACTED (line 6) | const B64_REDACTED = base64url.encode('REDACTED');
  function parseDate (line 8) | function parseDate(time: unknown): string | null {
  type MultiFactorInfoResponse (line 21) | interface MultiFactorInfoResponse {
  type ProviderUserInfoResponse (line 29) | interface ProviderUserInfoResponse {
  type GetAccountInfoUserResponse (line 39) | interface GetAccountInfoUserResponse {
  type MultiFactorId (line 60) | enum MultiFactorId {
  type MultiFactorInfoType (line 64) | interface MultiFactorInfoType {
  method initMultiFactorInfo (line 76) | public static initMultiFactorInfo(
  method constructor (line 89) | constructor(response: MultiFactorInfoResponse) {
  method toJSON (line 93) | public toJSON(): MultiFactorInfoType {
  method initFromServerResponse (line 106) | private initFromServerResponse(response: MultiFactorInfoResponse): void {
  class PhoneMultiFactorInfo (line 129) | class PhoneMultiFactorInfo extends MultiFactorInfo {
    method constructor (line 132) | constructor(response: MultiFactorInfoResponse) {
    method toJSON (line 137) | public toJSON(): object {
    method getFactorId (line 143) | protected getFactorId(response: MultiFactorInfoResponse): string | null {
  class MultiFactorSettings (line 148) | class MultiFactorSettings {
    method constructor (line 151) | constructor(response: GetAccountInfoUserResponse) {
    method toJSON (line 175) | public toJSON(): object {
  type UserMetadataType (line 182) | interface UserMetadataType {
  class UserMetadata (line 188) | class UserMetadata {
    method constructor (line 193) | constructor(response: GetAccountInfoUserResponse) {
    method toJSON (line 202) | public toJSON(): UserMetadataType {
  type UserInfoType (line 211) | type UserInfoType = {
  class UserInfo (line 220) | class UserInfo {
    method constructor (line 228) | constructor(response: ProviderUserInfoResponse) {
    method toJSON (line 244) | public toJSON(): UserInfoType {
  class UserRecord (line 256) | class UserRecord {
    method constructor (line 273) | constructor(response: GetAccountInfoUserResponse) {
    method toJSON (line 326) | public toJSON(): UserRecordType {
  type UserRecordType (line 353) | interface UserRecordType {

FILE: src/auth/utils.ts
  function formatString (line 4) | function formatString(str: string, params?: object): string {
  function getDetailFromResponse (line 15) | async function getDetailFromResponse(response: Response): Promise<string> {
  function fetchJson (line 34) | async function fetchJson(url: string, init: RequestInit) {
  function fetchText (line 38) | async function fetchText(url: string, init: RequestInit) {
  function fetchAny (line 42) | async function fetchAny(url: string, init: RequestInit) {
  function mapJwtPayloadToDecodedIdToken (line 52) | function mapJwtPayloadToDecodedIdToken(payload: JWTPayload) {
  function addReadonlyGetter (line 58) | function addReadonlyGetter(
  function deepCopy (line 70) | function deepCopy<T>(value: T): T {
  function deepExtend (line 74) | function deepExtend<T>(target: T, source: T): T {
  function toUint8Array (line 113) | function toUint8Array(key: string) {

FILE: src/auth/validator.ts
  function isObject (line 1) | function isObject(value: unknown): boolean {
  function isArray (line 5) | function isArray<T>(value: unknown): value is T[] {
  function isNonNullObject (line 9) | function isNonNullObject<T>(value: T | null | undefined): value is T {
  function isEmail (line 13) | function isEmail(email: unknown): boolean {
  function isURL (line 22) | function isURL(urlStr: unknown): boolean {

FILE: src/debug/index.ts
  function enableDebugMode (line 3) | function enableDebugMode() {
  function debug (line 7) | function debug(

FILE: src/next/api.ts
  function refreshApiResponseCookies (line 11) | async function refreshApiResponseCookies<Metadata extends object>(
  function appendAuthCookiesApi (line 26) | async function appendAuthCookiesApi<Metadata extends object>(
  function refreshApiCookies (line 40) | async function refreshApiCookies<Metadata extends object>(

FILE: src/next/client.ts
  class ClientTokenCache (line 4) | class ClientTokenCache {
    method constructor (line 7) | constructor() {}
    method get (line 9) | public get(value: string) {
    method set (line 17) | public set(originalValue: string, value: string) {
  type GetValidIdTokenOptions (line 25) | interface GetValidIdTokenOptions {
  function getValidIdToken (line 31) | async function getValidIdToken({
  type GetValidCustomTokenOptions (line 63) | interface GetValidCustomTokenOptions {
  function getValidCustomToken (line 69) | async function getValidCustomToken({
  function mapResponseToAuthError (line 108) | async function mapResponseToAuthError(
  function safeResponse (line 129) | function safeResponse<T>(response: Response): Promise<T> {
  function fetchApi (line 138) | async function fetchApi<T>(

FILE: src/next/cookies/AuthCookies.ts
  class AuthCookies (line 16) | class AuthCookies<Metadata extends object> {
    method constructor (line 20) | constructor(
    method shouldClearMultipleCookies (line 27) | private shouldClearMultipleCookies() {
    method shouldClearCustomTokenCookie (line 41) | private shouldClearCustomTokenCookie() {
    method shouldClearSingleCookie (line 51) | private shouldClearSingleCookie() {
    method clearUnusedCookies (line 57) | private clearUnusedCookies(setter: CookieSetter) {
    method getCookies (line 84) | private async getCookies(value: ParsedCookies<Metadata>): Promise<Cook...
    method setAuthCookies (line 100) | public async setAuthCookies(
    method setAuthHeaders (line 111) | public async setAuthHeaders(
    method setAuthNextApiResponseHeaders (line 122) | public async setAuthNextApiResponseHeaders(

FILE: src/next/cookies/builder/CookieBuilder.ts
  type Cookie (line 3) | interface Cookie {
  type CookieBuilder (line 8) | interface CookieBuilder<Metadata extends object> {

FILE: src/next/cookies/builder/CookieBuilderFactory.ts
  class CookieBuilderFactory (line 5) | class CookieBuilderFactory {
    method fromOptions (line 6) | static fromOptions<Metadata extends object>(

FILE: src/next/cookies/builder/MultipleCookieBuilder.ts
  class MultipleCookieBuilder (line 6) | class MultipleCookieBuilder<Metadata extends object>
    method constructor (line 11) | constructor(
    method buildCookies (line 18) | public async buildCookies(value: ParsedCookies<Metadata>): Promise<Coo...

FILE: src/next/cookies/builder/SingleCookieBuilder.ts
  class SingleCookieBuilder (line 8) | class SingleCookieBuilder<Metadata extends object>
    method constructor (line 13) | constructor(
    method buildCookies (line 20) | public async buildCookies(value: ParsedCookies<Metadata>): Promise<Coo...

FILE: src/next/cookies/expiration/CombinedCookieExpiration.ts
  class CombinedCookieExpiration (line 6) | class CombinedCookieExpiration implements CookieExpiration {
    method constructor (line 7) | constructor(
    method expireCookies (line 12) | expireCookies(options: CookieSerializeOptions): void {

FILE: src/next/cookies/expiration/CookieExpiration.ts
  type CookieExpiration (line 3) | interface CookieExpiration {
  function getExpiredSerializeOptions (line 7) | function getExpiredSerializeOptions(options: CookieSerializeOptions) {

FILE: src/next/cookies/expiration/CookieExpirationFactory.test.ts
  function getTestCookie (line 50) | function getTestCookie(name: string) {
  function getLegacyTestCookie (line 54) | function getLegacyTestCookie(name: string) {
  function getSingleCookie (line 58) | function getSingleCookie(name: string) {

FILE: src/next/cookies/expiration/CookieExpirationFactory.ts
  class CookieExpirationFactory (line 9) | class CookieExpirationFactory {
    method fromSetter (line 10) | private static fromSetter(
    method fromHeaders (line 40) | static fromHeaders(

FILE: src/next/cookies/expiration/MultipleCookieExpiration.ts
  class MultipleCookieExpiration (line 9) | class MultipleCookieExpiration implements CookieExpiration {
    method constructor (line 10) | public constructor(
    method expireCustomCookie (line 15) | expireCustomCookie(options: CookieSerializeOptions) {
    method expireCookies (line 26) | expireCookies(options: CookieSerializeOptions): void {

FILE: src/next/cookies/expiration/SingleCookieExpiration.ts
  class SingleCookieExpiration (line 9) | class SingleCookieExpiration implements CookieExpiration {
    method constructor (line 10) | public constructor(
    method expireCookies (line 15) | expireCookies(options: CookieSerializeOptions): void {

FILE: src/next/cookies/index.test.ts
  type NextRequest (line 12) | interface NextRequest {
  type NextResponse (line 16) | interface NextResponse {
  constant MOCK_OPTIONS (line 37) | const MOCK_OPTIONS: SetAuthCookiesOptions<never> = {

FILE: src/next/cookies/index.ts
  function appendAuthCookies (line 21) | async function appendAuthCookies<Metadata extends object>(
  function setAuthCookies (line 37) | async function setAuthCookies<Metadata extends object>(
  type RemoveServerCookiesOptions (line 95) | interface RemoveServerCookiesOptions {
  function removeServerCookies (line 98) | function removeServerCookies(
  type RemoveAuthCookiesOptions (line 111) | interface RemoveAuthCookiesOptions {
  function removeCookies (line 116) | function removeCookies(
  function removeAuthCookies (line 130) | function removeAuthCookies(
  function verifyApiCookies (line 148) | async function verifyApiCookies<Metadata extends object>(
  function verifyNextCookies (line 172) | async function verifyNextCookies<Metadata extends object>(
  function refreshNextCookies (line 199) | async function refreshNextCookies<Metadata extends object>(
  function refreshCredentials (line 230) | async function refreshCredentials<Metadata extends object>(
  function refreshNextResponseCookiesWithToken (line 273) | async function refreshNextResponseCookiesWithToken<
  function refreshCookiesWithIdToken (line 314) | async function refreshCookiesWithIdToken<Metadata extends object>(
  function refreshNextResponseCookies (line 352) | async function refreshNextResponseCookies<Metadata extends object>(
  function refreshServerCookies (line 368) | async function refreshServerCookies<Metadata extends object>(

FILE: src/next/cookies/parser/CookieParser.ts
  type CookieParser (line 3) | interface CookieParser<Metadata extends object> {

FILE: src/next/cookies/parser/CookieParserFactory.test.ts
  function toHeader (line 16) | function toHeader(cookie: Cookie): string {

FILE: src/next/cookies/parser/CookieParserFactory.ts
  class CookieParserFactory (line 12) | class CookieParserFactory {
    method hasMultipleCookies (line 13) | public static hasMultipleCookies(
    method hasCustomTokenCookie (line 22) | public static hasCustomTokenCookie(
    method hasLegacyMultipleCookies (line 29) | public static hasLegacyMultipleCookies(
    method getCompatibleProvider (line 41) | private static getCompatibleProvider(
    method fromProvider (line 62) | private static fromProvider<Metadata extends object>(
    method fromRequestCookies (line 106) | static fromRequestCookies<Metadata extends object>(
    method fromHeaders (line 115) | static fromHeaders<Metadata extends object>(
    method fromObject (line 124) | static fromObject<Metadata extends object>(

FILE: src/next/cookies/parser/CookiesProvider.ts
  type CookiesProvider (line 1) | interface CookiesProvider {

FILE: src/next/cookies/parser/MultipleCookiesParser.ts
  class MultipleCookiesParser (line 10) | class MultipleCookiesParser<Metadata extends object>
    method constructor (line 13) | constructor(
    method parseCookies (line 19) | async parseCookies(): Promise<ParsedCookies<Metadata>> {

FILE: src/next/cookies/parser/ObjectCookiesProvider.ts
  class ObjectCookiesProvider (line 3) | class ObjectCookiesProvider {
    method constructor (line 4) | constructor(private cookies: CookiesObject) {}
    method get (line 6) | get(key: string) {

FILE: src/next/cookies/parser/RequestCookiesProvider.ts
  class RequestCookiesProvider (line 4) | class RequestCookiesProvider {
    method fromHeaders (line 5) | static fromHeaders(headers: Headers) {
    method fromRequestCookies (line 11) | static fromRequestCookies(cookies: RequestCookies | ReadonlyRequestCoo...
    method constructor (line 15) | constructor(private cookies: RequestCookies | ReadonlyRequestCookies) {}
    method get (line 17) | get(key: string) {

FILE: src/next/cookies/parser/SingleCookieParser.ts
  class SingleCookieParser (line 8) | class SingleCookieParser<Metadata extends object>
    method constructor (line 11) | constructor(
    method parseCookies (line 17) | async parseCookies(): Promise<ParsedCookies<Metadata>> {

FILE: src/next/cookies/remover/CombinedCookieRemover.ts
  class CombinedCookieRemover (line 5) | class CombinedCookieRemover implements CookieRemover {
    method constructor (line 6) | constructor(
    method removeCookies (line 11) | removeCookies(): void {

FILE: src/next/cookies/remover/CookieRemover.ts
  type CookieRemover (line 1) | interface CookieRemover {

FILE: src/next/cookies/remover/CookieRemoverFactory.test.ts
  function getTestCookie (line 42) | function getTestCookie(name: string) {
  function getLegacyTestCookie (line 46) | function getLegacyTestCookie(name: string) {
  function getSingleCookie (line 50) | function getSingleCookie(name: string) {

FILE: src/next/cookies/remover/CookieRemoverFactory.ts
  class CookieRemoverFactory (line 9) | class CookieRemoverFactory {
    method fromRequestCookies (line 10) | static fromRequestCookies(

FILE: src/next/cookies/remover/MultipleCookieRemover.ts
  class MultipleCookieRemover (line 5) | class MultipleCookieRemover implements CookieRemover {
    method constructor (line 6) | public constructor(
    method removeCookies (line 11) | removeCookies(): void {

FILE: src/next/cookies/remover/SingleCookieRemover.ts
  class SingleCookieRemover (line 5) | class SingleCookieRemover implements CookieRemover {
    method constructor (line 6) | public constructor(
    method removeCookies (line 11) | removeCookies(): void {

FILE: src/next/cookies/setter/CookieSetter.ts
  type CookieSetter (line 4) | interface CookieSetter {

FILE: src/next/cookies/setter/CookieSetterFactory.ts
  class CookieSetterFactory (line 6) | class CookieSetterFactory {
    method fromRequestCookies (line 7) | static fromRequestCookies(cookies: RequestCookies | ReadonlyRequestCoo...
    method fromHeaders (line 11) | static fromHeaders(headers: Headers) {

FILE: src/next/cookies/setter/HeadersCookieSetter.ts
  class HeadersCookieSetter (line 5) | class HeadersCookieSetter implements CookieSetter {
    method constructor (line 6) | constructor(private headers: Headers) {}
    method setCookies (line 8) | setCookies(cookies: Cookie[], options: CookieSerializeOptions): void {

FILE: src/next/cookies/setter/NextApiResponseHeadersCookieSetter.ts
  class NextApiResponseCookieSetter (line 6) | class NextApiResponseCookieSetter implements CookieSetter {
    method constructor (line 7) | constructor(private response: NextApiResponse) {}
    method setCookies (line 9) | setCookies(cookies: Cookie[], options: CookieSerializeOptions): void {

FILE: src/next/cookies/setter/RequestCookieSetter.ts
  class RequestCookieSetter (line 7) | class RequestCookieSetter implements CookieSetter {
    method constructor (line 8) | constructor(private cookies: RequestCookies | ReadonlyRequestCookies) {}
    method setCookies (line 10) | setCookies(cookies: Cookie[], options: CookieSerializeOptions): void {

FILE: src/next/cookies/types.ts
  type SetAuthCookiesOptions (line 5) | interface SetAuthCookiesOptions<Metadata extends object> {
  type CookiesObject (line 20) | type CookiesObject = Partial<{[K in string]: string}>;
  type GetCookiesTokensOptions (line 22) | interface GetCookiesTokensOptions {

FILE: src/next/metadata.ts
  function getMetadataInternal (line 4) | async function getMetadataInternal<Metadata extends object>(

FILE: src/next/middleware.ts
  type CreateAuthMiddlewareOptions (line 27) | interface CreateAuthMiddlewareOptions<Metadata extends object>
  type RedirectToPathOptions (line 35) | interface RedirectToPathOptions {
  function redirectToPath (line 39) | function redirectToPath(
  type RedirectToHomeOptions (line 54) | interface RedirectToHomeOptions {
  function redirectToHome (line 58) | function redirectToHome(
  type Path (line 67) | type Path = string | RegExp;
  type PublicPath (line 70) | type PublicPath = Path;
  type RedirectToLoginOptions (line 72) | interface RedirectToLoginOptions {
  function doesRequestPathnameMatchPath (line 79) | function doesRequestPathnameMatchPath(request: NextRequest, path: Path) {
  function doesRequestPathnameMatchOneOfPaths (line 87) | function doesRequestPathnameMatchOneOfPaths(
  function getUrlWithoutTrailingSlash (line 94) | function getUrlWithoutTrailingSlash(url: string) {
  function createLoginRedirectResponse (line 102) | function createLoginRedirectResponse(
  function redirectToLogin (line 117) | function redirectToLogin(
  function createAuthMiddlewareResponse (line 141) | async function createAuthMiddlewareResponse<Metadata extends object>(
  type HandleInvalidToken (line 167) | type HandleInvalidToken = (
  type HandleValidToken (line 170) | type HandleValidToken<Metadata extends object> = (
  type HandleError (line 174) | type HandleError = (e: unknown) => Promise<NextResponse>;
  type AuthMiddlewareOptions (line 176) | interface AuthMiddlewareOptions<Metadata extends object>
  function authMiddleware (line 201) | async function authMiddleware<Metadata extends object>(

FILE: src/next/refresh-token.ts
  function refreshToken (line 10) | async function refreshToken<Metadata extends object>(

FILE: src/next/tokens.ts
  type GetTokensOptions (line 15) | interface GetTokensOptions extends GetCookiesTokensOptions {
  function validateOptions (line 24) | function validateOptions(options: GetTokensOptions) {
  function getRequestCookiesTokens (line 34) | function getRequestCookiesTokens<Metadata extends object>(
  function getTokens (line 46) | async function getTokens<Metadata extends object>(
  function getCookiesTokens (line 86) | function getCookiesTokens<Metadata extends object>(
  function getApiRequestTokens (line 95) | async function getApiRequestTokens<Metadata extends object>(
  function getTokensFromObject (line 122) | async function getTokensFromObject<Metadata extends object>(

FILE: src/next/utils.ts
  function getReferer (line 1) | function getReferer(headers: Headers) {
Condensed preview — 295 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (665K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 20,
    "preview": "github: awinogrodzki"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 3292,
    "preview": "name: Main\n\non:\n  pull_request:\n    paths:\n      - \"**\"\n      - \"!*.md\"\n      - \"!**/*.md\"\n      - \"!.gitignore\"\n\nconcur"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 3223,
    "preview": "name: Release\n\nenv:\n  FIREBASE_API_KEY: AIzaSyAXYgJha6lO_L4qfWpnhf3KijeKYDhuFzQ\n  FIREBASE_PROJECT_ID: next-firebase-aut"
  },
  {
    "path": ".gitignore",
    "chars": 182,
    "preview": "node_modules\n.vscode\nyarn-error.log\n.yarn\n.next\n.env\n\n\ntmp\npackage-lock.json\ncoverage\nwebpack-stats.json\n.turbo\n.DS_Stor"
  },
  {
    "path": ".husky/commit-msg",
    "chars": 37,
    "preview": "npx --no -- commitlint --edit \"${1}\"\n"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 68,
    "preview": "yarn test\nyarn lint --fix\nyarn check-circular-imports\ngit add --all\n"
  },
  {
    "path": ".npmignore",
    "chars": 46,
    "preview": ".env\n.env.dist\nexamples\nsrc\n!lib\n!browser\n!esm"
  },
  {
    "path": ".releaserc.yaml",
    "chars": 329,
    "preview": "plugins:\n  - \"@semantic-release/commit-analyzer\"\n  - \"@semantic-release/release-notes-generator\"\n  - \"@semantic-release/"
  },
  {
    "path": ".swcrc",
    "chars": 196,
    "preview": "{\n  \"jsc\": {\n     \"parser\": {\n        \"syntax\": \"typescript\",\n        \"decorators\": true\n     },\n     \"transform\": {\n   "
  },
  {
    "path": "CHANGELOG.md",
    "chars": 55661,
    "preview": "# [1.12.0](https://github.com/awinogrodzki/next-firebase-auth-edge/compare/v1.11.5...v1.12.0) (2026-02-26)\n\n\n### Bug Fix"
  },
  {
    "path": "LICENSE",
    "chars": 1078,
    "preview": "MIT License\n\nCopyright (c) 2023 Amadeusz Winogrodzki\n\nPermission is hereby granted, free of charge, to any person obtain"
  },
  {
    "path": "README.md",
    "chars": 4363,
    "preview": "<picture>\n  <source media=\"(prefers-color-scheme: dark)\" srcset=\"logo-white.svg\">\n  <source media=\"(prefers-color-scheme"
  },
  {
    "path": "commitlint.config.js",
    "chars": 67,
    "preview": "module.exports = { extends: ['@commitlint/config-conventional'] };\n"
  },
  {
    "path": "docs/.eslintrc.js",
    "chars": 270,
    "preview": "module.exports = {\n  extends: ['prettier'],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 2"
  },
  {
    "path": "docs/.gitignore",
    "chars": 139,
    "preview": "/node_modules\n/.next/\n.DS_Store\n.vercel\npublic/.nextra\ntsconfig.tsbuildinfo\n.env\npublic/robots.txt\npublic/sitemap.xml\npu"
  },
  {
    "path": "docs/README.md",
    "chars": 112,
    "preview": "# docs\n\nWebsite for `next-firebase-auth-edge`\n\nYou can run it locally like this:\n\n```\nyarn install\nyarn dev\n```\n"
  },
  {
    "path": "docs/components/Chip.tsx",
    "chars": 678,
    "preview": "import clsx from 'clsx';\nimport {ReactNode} from 'react';\n\ntype Props = {\n  children: ReactNode;\n  className?: string;\n "
  },
  {
    "path": "docs/components/CommunityLink.tsx",
    "chars": 1045,
    "preview": "import Link from 'next/link';\nimport {ComponentProps} from 'react';\nimport Chip from './Chip';\n\ntype Props = Omit<Compon"
  },
  {
    "path": "docs/components/Example.tsx",
    "chars": 1401,
    "preview": "import Chip from './Chip';\n\ntype Props = {\n  demoLink?: string;\n  sourceLink: string;\n  hash: string;\n  name: string;\n  "
  },
  {
    "path": "docs/components/FeaturePanel.tsx",
    "chars": 707,
    "preview": "type Props = {\n  code?: string;\n  description: string;\n  title: string;\n};\n\nexport default function FeaturePanel({code, "
  },
  {
    "path": "docs/components/Footer.tsx",
    "chars": 1119,
    "preview": "import config from 'config';\nimport {useRouter} from 'next/router';\nimport FooterLink from './FooterLink';\nimport Footer"
  },
  {
    "path": "docs/components/FooterLink.tsx",
    "chars": 440,
    "preview": "import Link from 'next/link';\nimport {ComponentProps} from 'react';\n\ntype Props = ComponentProps<typeof Link>;\n\nexport d"
  },
  {
    "path": "docs/components/FooterSeparator.tsx",
    "chars": 164,
    "preview": "export default function FooterSeparator() {\n  return (\n    <span className=\"mx-1 text-slate-400 dark:text-slate-400\">\n  "
  },
  {
    "path": "docs/components/Hero.tsx",
    "chars": 1940,
    "preview": "import HeroCode from './HeroCode';\nimport LinkButton from './LinkButton';\nimport Wrapper from './Wrapper';\n\ntype Props ="
  },
  {
    "path": "docs/components/HeroCode.tsx",
    "chars": 28893,
    "preview": "import clsx from 'clsx';\nimport {ReactNode, useState} from 'react';\n\nfunction Tab({\n  active,\n  children,\n  onClick\n}: {"
  },
  {
    "path": "docs/components/Link.tsx",
    "chars": 337,
    "preview": "import NextLink from 'next/link';\nimport {ComponentProps} from 'react';\n\ntype Props = Omit<ComponentProps<typeof NextLin"
  },
  {
    "path": "docs/components/LinkButton.tsx",
    "chars": 877,
    "preview": "import clsx from 'clsx';\nimport Link from 'next/link';\nimport {ComponentProps} from 'react';\n\ntype Props = {\n  variant?:"
  },
  {
    "path": "docs/components/Section.tsx",
    "chars": 701,
    "preview": "import {ReactNode} from 'react';\nimport Wrapper from './Wrapper';\n\ntype Props = {\n  children: ReactNode;\n  description: "
  },
  {
    "path": "docs/components/Steps.module.css",
    "chars": 549,
    "preview": ".root {\n  @apply ml-4 border-l border-slate-200 pl-8;\n  counter-reset: step;\n}\n\n.root h3 {\n  counter-increment: step;\n  "
  },
  {
    "path": "docs/components/Steps.tsx",
    "chars": 226,
    "preview": "import {ReactNode} from 'react';\nimport styles from './Steps.module.css';\n\ntype Props = {\n  children: ReactNode;\n};\n\nexp"
  },
  {
    "path": "docs/components/Wrapper.tsx",
    "chars": 310,
    "preview": "import clsx from 'clsx';\nimport {ReactNode} from 'react';\n\ntype Props = {\n  children: ReactNode;\n  className?: string;\n}"
  },
  {
    "path": "docs/config.js",
    "chars": 155,
    "preview": "module.exports = {\n  baseUrl: 'https://next-firebase-auth-edge-docs.vercel.app',\n  githubUrl: 'https://github.com/awinog"
  },
  {
    "path": "docs/next-env.d.ts",
    "chars": 201,
    "preview": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// NOTE: This file should not be edite"
  },
  {
    "path": "docs/next-sitemap.config.js",
    "chars": 158,
    "preview": "const config = require('./config');\n\n/** @type {import('next-sitemap').IConfig} */\nmodule.exports = {\n  siteUrl: config."
  },
  {
    "path": "docs/next.config.js",
    "chars": 544,
    "preview": "const withNextra = require('nextra')({\n  theme: 'nextra-theme-docs',\n  themeConfig: './theme.config.tsx',\n  staticImage:"
  },
  {
    "path": "docs/package.json",
    "chars": 1122,
    "preview": "{\n  \"name\": \"docs\",\n  \"version\": \"2.14.3\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"lint\": \"eslint "
  },
  {
    "path": "docs/pages/_app.tsx",
    "chars": 548,
    "preview": "import {AppProps} from 'next/app';\nimport {Inter} from 'next/font/google';\nimport {ReactNode} from 'react';\nimport 'next"
  },
  {
    "path": "docs/pages/_document.tsx",
    "chars": 336,
    "preview": "import {Html, Head, Main, NextScript} from 'next/document';\nimport {SkipNavLink} from 'nextra-theme-docs';\nimport React "
  },
  {
    "path": "docs/pages/_meta.json",
    "chars": 312,
    "preview": "{\n  \"index\": {\n    \"title\": \"Introduction\",\n    \"type\": \"page\",\n    \"display\": \"hidden\",\n    \"theme\": {\"layout\": \"raw\"}\n"
  },
  {
    "path": "docs/pages/docs/_meta.json",
    "chars": 169,
    "preview": "{\n  \"getting-started\": \"Getting started\",\n  \"usage\": \"Usage guide\",\n  \"emulator\": \"Emulator\",\n  \"app-check\": \"App Check\""
  },
  {
    "path": "docs/pages/docs/app-check.mdx",
    "chars": 2116,
    "preview": "# App Check Support\n\nThis library provides support for [Firebase App Check](https://firebase.google.com/docs/app-check)."
  },
  {
    "path": "docs/pages/docs/emulator.mdx",
    "chars": 258,
    "preview": "# Emulator Support\n\nThis library supports the Firebase Authentication Emulator. For more details on how to set it up, ch"
  },
  {
    "path": "docs/pages/docs/errors.mdx",
    "chars": 4248,
    "preview": "# Handling Errors\n\n## handleInvalidToken\n\nThe [Auth middleware](/docs/usage/middleware) provides a `handleInvalidToken` "
  },
  {
    "path": "docs/pages/docs/faq.mdx",
    "chars": 535,
    "preview": "# FAQ\n\n## Where are the login and logout API routes defined?\n\nUnlike the [next-firebase-auth](https://github.com/gladly-"
  },
  {
    "path": "docs/pages/docs/getting-started/_meta.json",
    "chars": 312,
    "preview": "{\n  \"index\": \"Welcome!\",\n  \"middleware\": \"Middleware\",\n  \"auth-context\": \"AuthContext\",\n  \"auth-provider\": \"AuthProvider"
  },
  {
    "path": "docs/pages/docs/getting-started/auth-context.mdx",
    "chars": 890,
    "preview": "# AuthContext\n\nThe library doesn't include any client-side code or built-in authentication state context. It's up to the"
  },
  {
    "path": "docs/pages/docs/getting-started/auth-provider.mdx",
    "chars": 830,
    "preview": "# AuthProvider\n\nTo share user data between the server and client components, we can use the custom `AuthContext` we crea"
  },
  {
    "path": "docs/pages/docs/getting-started/index.mdx",
    "chars": 1107,
    "preview": "import {Card} from 'nextra-theme-docs';\nimport {ChevronRightIcon} from '@heroicons/react/24/outline';\n\n# Next.js Firebas"
  },
  {
    "path": "docs/pages/docs/getting-started/layout.mdx",
    "chars": 2594,
    "preview": "# Layout\n\nWe can use the `getTokens` function from `next-firebase-auth-edge` to pull user information from request cooki"
  },
  {
    "path": "docs/pages/docs/getting-started/login-page.mdx",
    "chars": 2909,
    "preview": "# Using Firebase Auth\n\nFollow the official `firebase/auth` [guide](https://firebase.google.com/docs/auth/web/password-au"
  },
  {
    "path": "docs/pages/docs/getting-started/login-with-server-action.mdx",
    "chars": 3707,
    "preview": "# Sign in with Server Action\n\nYou can follow the official `firebase/auth` [guide](https://firebase.google.com/docs/auth/"
  },
  {
    "path": "docs/pages/docs/getting-started/logout-with-server-action.mdx",
    "chars": 2170,
    "preview": "# Sign out with Server Action\n\n## removeServerCookies [v1.9.0]\n\nThe `removeServerCookies` method removes server cookies "
  },
  {
    "path": "docs/pages/docs/getting-started/middleware.mdx",
    "chars": 1670,
    "preview": "# Authentication Middleware\n\nThe library offers an `authMiddleware` function that's meant to be used with [Next.js Proxy"
  },
  {
    "path": "docs/pages/docs/usage/_meta.json",
    "chars": 697,
    "preview": "{\n  \"index\": \"Start\",\n  \"middleware\": \"Middleware\",\n  \"server-components\": \"Server Components\",\n  \"redirect-functions\": "
  },
  {
    "path": "docs/pages/docs/usage/advanced-usage.mdx",
    "chars": 10686,
    "preview": "# Advanced Usage\n\nThe authentication middleware may not cover every use case. To support more complex authentication flo"
  },
  {
    "path": "docs/pages/docs/usage/app-router-api-routes.mdx",
    "chars": 1167,
    "preview": "# App Router API Route Handlers\n\nHere’s an example of how to use the [getTokens](/docs/usage/server-components) function"
  },
  {
    "path": "docs/pages/docs/usage/client-side-apis.mdx",
    "chars": 6459,
    "preview": "# Using Client-Side APIs\n\nThe starter example uses the [inMemoryPersistence](https://github.com/awinogrodzki/next-fireba"
  },
  {
    "path": "docs/pages/docs/usage/cloud-run.mdx",
    "chars": 2007,
    "preview": "# Usage in Google Cloud Run Environment\n\nBefore running `next-firebase-auth-edge` in a Google Cloud Run environment, mak"
  },
  {
    "path": "docs/pages/docs/usage/debug-mode.mdx",
    "chars": 2244,
    "preview": "# Debug Mode\n\nYou can enable `debug mode` by setting `debug: true` in the options for `authMiddleware` and `getTokens`.\n"
  },
  {
    "path": "docs/pages/docs/usage/domain-restriction.mdx",
    "chars": 1421,
    "preview": "# Firebase API Key Domain Restriction\n\nIn a production-ready application, it's important to restrict your Firebase API k"
  },
  {
    "path": "docs/pages/docs/usage/firebase-hosting.mdx",
    "chars": 2266,
    "preview": "# Usage in Firebase Hosting Environment\n\nBy default, the Firebase Hosting environment strips all cookies except for `__s"
  },
  {
    "path": "docs/pages/docs/usage/get-server-side-props.mdx",
    "chars": 992,
    "preview": "# Usage in getServerSideProps\n\nExample usage of [getApiRequestTokens](/docs/usage/pages-router-api-routes) function in ["
  },
  {
    "path": "docs/pages/docs/usage/index.mdx",
    "chars": 2156,
    "preview": "import {Card, Cards} from 'nextra-theme-docs';\nimport {ChevronRightIcon} from '@heroicons/react/24/outline';\n\n# Usage Gu"
  },
  {
    "path": "docs/pages/docs/usage/middleware.mdx",
    "chars": 25061,
    "preview": "# Authentication Middleware\n\nThe `authMiddleware` works with the [getTokens](/docs/usage/server-components) function to "
  },
  {
    "path": "docs/pages/docs/usage/pages-router-api-routes.mdx",
    "chars": 1283,
    "preview": "# Pages Router API Routes\n\nTo support gradual adoption of the latest Next.js features, `next-firebase-auth-edge` offers "
  },
  {
    "path": "docs/pages/docs/usage/redirect-functions.mdx",
    "chars": 2105,
    "preview": "# Redirect Helper Functions\n\nThis library provides a set of helper functions to simplify handling common redirect scenar"
  },
  {
    "path": "docs/pages/docs/usage/refresh-credentials.mdx",
    "chars": 11153,
    "preview": "# Refreshing Credentials\n\n`next-firebase-auth-edge` provides three different functions for updating user credentials aft"
  },
  {
    "path": "docs/pages/docs/usage/remove-credentials.mdx",
    "chars": 1755,
    "preview": "# Removing Credentials\n\nThe `next-firebase-auth-edge` library provides a `removeCookies` method to remove authenticated "
  },
  {
    "path": "docs/pages/docs/usage/server-components.mdx",
    "chars": 4928,
    "preview": "# Usage in Server Components\n\nThe library provides a `getTokens` function to extract and validate user credentials. This"
  },
  {
    "path": "docs/pages/examples/index.mdx",
    "chars": 760,
    "preview": "import Example from 'components/Example';\n\n# Examples\n\n<div className=\"mt-8 flex flex-col gap-4\">\n\n<Example\n  featured\n "
  },
  {
    "path": "docs/pages/index.mdx",
    "chars": 359,
    "preview": "---\ntitle: next-firebase-auth-edge\n---\n\nimport Hero from 'components/Hero';\n\n<div className=\"bg-slate-50 dark:bg-gray-90"
  },
  {
    "path": "docs/postcss.config.js",
    "chars": 81,
    "preview": "module.exports = {\n  plugins: {\n    tailwindcss: {},\n    autoprefixer: {}\n  }\n};\n"
  },
  {
    "path": "docs/prettier.config.js",
    "chars": 92,
    "preview": "module.exports = {\n  singleQuote: true,\n  trailingComma: 'none',\n  bracketSpacing: false\n};\n"
  },
  {
    "path": "docs/public/favicon/site.webmanifest",
    "chars": 426,
    "preview": "{\n    \"name\": \"\",\n    \"short_name\": \"\",\n    \"icons\": [\n        {\n            \"src\": \"/android-chrome-192x192.png\",\n     "
  },
  {
    "path": "docs/services/BrowserTracker.tsx",
    "chars": 560,
    "preview": "import * as vercel from '@vercel/analytics/react';\n\ntype Event = {\n  name: 'partner-referral';\n  data: {href: string; na"
  },
  {
    "path": "docs/services/ServerTracker.tsx",
    "chars": 2312,
    "preview": "import * as vercel from '@vercel/analytics/server';\n\nexport default class ServerTracker {\n  private static postToCollect"
  },
  {
    "path": "docs/styles.css",
    "chars": 1309,
    "preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n:root {\n  --shiki-token-punctuation: rgba(0, 0, 0, 0.5);\n  -"
  },
  {
    "path": "docs/tailwind.config.js",
    "chars": 1289,
    "preview": "/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n  darkMode: 'class',\n  content: [\n    './components/**/*."
  },
  {
    "path": "docs/theme.config.tsx",
    "chars": 17963,
    "preview": "import Footer from 'components/Footer';\nimport { useRouter } from 'next/router';\nimport { ThemeConfig } from 'nextra';\ni"
  },
  {
    "path": "docs/tsconfig.json",
    "chars": 698,
    "preview": "{\n  \"extends\": \"eslint-config-molindo/tsconfig.json\",\n  \"compilerOptions\": {\n    \"baseUrl\": \".\",\n    \"lib\": [\n      \"dom"
  },
  {
    "path": "eslint.config.mjs",
    "chars": 467,
    "preview": "import eslint from '@eslint/js';\nimport eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';\nimpor"
  },
  {
    "path": "examples/next-typescript-minimal/.eslintrc.json",
    "chars": 40,
    "preview": "{\n  \"extends\": \"next/core-web-vitals\"\n}\n"
  },
  {
    "path": "examples/next-typescript-minimal/.gitignore",
    "chars": 391,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
  },
  {
    "path": "examples/next-typescript-minimal/README.md",
    "chars": 1383,
    "preview": "This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js"
  },
  {
    "path": "examples/next-typescript-minimal/app/HomePage.tsx",
    "chars": 1030,
    "preview": "\"use client\";\n\nimport { useRouter } from \"next/navigation\";\nimport { getAuth, signOut } from \"firebase/auth\";\nimport { a"
  },
  {
    "path": "examples/next-typescript-minimal/app/globals.css",
    "chars": 606,
    "preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n:root {\n  --foreground-rgb: 0, 0, 0;\n  --background-start-rg"
  },
  {
    "path": "examples/next-typescript-minimal/app/layout.tsx",
    "chars": 473,
    "preview": "import type { Metadata } from \"next\";\nimport { Inter } from \"next/font/google\";\nimport \"./globals.css\";\n\nconst inter = I"
  },
  {
    "path": "examples/next-typescript-minimal/app/login/page.tsx",
    "chars": 4254,
    "preview": "\"use client\";\n\nimport { FormEvent, useState } from \"react\";\nimport Link from \"next/link\";\nimport { useRouter } from \"nex"
  },
  {
    "path": "examples/next-typescript-minimal/app/page.tsx",
    "chars": 601,
    "preview": "import { getTokens } from \"next-firebase-auth-edge\";\nimport { cookies } from \"next/headers\";\nimport { notFound } from \"n"
  },
  {
    "path": "examples/next-typescript-minimal/app/register/page.tsx",
    "chars": 5133,
    "preview": "\"use client\";\n\nimport { FormEvent, useState } from \"react\";\nimport Link from \"next/link\";\nimport { getAuth, createUserWi"
  },
  {
    "path": "examples/next-typescript-minimal/config.ts",
    "chars": 949,
    "preview": "export const serverConfig = {\n  cookieName: process.env.AUTH_COOKIE_NAME!,\n  cookieSignatureKeys: [process.env.AUTH_COOK"
  },
  {
    "path": "examples/next-typescript-minimal/firebase.ts",
    "chars": 136,
    "preview": "import { initializeApp } from 'firebase/app';\nimport { clientConfig } from './config';\n\nexport const app = initializeApp"
  },
  {
    "path": "examples/next-typescript-minimal/middleware.ts",
    "chars": 1617,
    "preview": "import { NextRequest, NextResponse } from \"next/server\";\nimport { authMiddleware, redirectToHome, redirectToLogin } from"
  },
  {
    "path": "examples/next-typescript-minimal/next.config.mjs",
    "chars": 92,
    "preview": "/** @type {import('next').NextConfig} */\nconst nextConfig = {};\n\nexport default nextConfig;\n"
  },
  {
    "path": "examples/next-typescript-minimal/package.json",
    "chars": 615,
    "preview": "{\n  \"name\": \"my-app\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"next "
  },
  {
    "path": "examples/next-typescript-minimal/postcss.config.js",
    "chars": 83,
    "preview": "module.exports = {\n  plugins: {\n    tailwindcss: {},\n    autoprefixer: {},\n  },\n};\n"
  },
  {
    "path": "examples/next-typescript-minimal/tailwind.config.ts",
    "chars": 498,
    "preview": "import type { Config } from \"tailwindcss\";\n\nconst config: Config = {\n  content: [\n    \"./pages/**/*.{js,ts,jsx,tsx,mdx}\""
  },
  {
    "path": "examples/next-typescript-minimal/tsconfig.json",
    "chars": 574,
    "preview": "{\n  \"compilerOptions\": {\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n  "
  },
  {
    "path": "examples/next-typescript-starter/.dockerignore",
    "chars": 52,
    "preview": "Dockerfile\n.dockerignore\nnode_modules\nnpm-debug.log\n"
  },
  {
    "path": "examples/next-typescript-starter/.firebaserc",
    "chars": 54,
    "preview": "{\n  \"projects\": {\n    \"default\": \"fake-project\"\n  }\n}\n"
  },
  {
    "path": "examples/next-typescript-starter/.gitignore",
    "chars": 176,
    "preview": "node_modules\n.vscode\nyarn-error.log\n.yarn\n.next\n.env\n.env.local\n.env.temp\nlib\ncjs\ntmp\npackage-lock.json\ncoverage\nwebpack"
  },
  {
    "path": "examples/next-typescript-starter/Dockerfile",
    "chars": 138,
    "preview": "FROM node:18.19.0-alpine\n\nWORKDIR /usr/app\n\nCOPY . .\n\nRUN yarn install --production\n\nRUN printenv\n\nRUN yarn build\n\nCMD ["
  },
  {
    "path": "examples/next-typescript-starter/README.md",
    "chars": 4294,
    "preview": "# next-firebase-auth-edge starter\n\nThis is a [Next.js](https://nextjs.org/) project showcasing `next-firebase-auth-edge`"
  },
  {
    "path": "examples/next-typescript-starter/api/index.ts",
    "chars": 1744,
    "preview": "import {getToken} from '@firebase/app-check';\nimport {getAppCheck} from '../app-check';\nimport {UserCredential} from 'fi"
  },
  {
    "path": "examples/next-typescript-starter/app/actions/login.ts",
    "chars": 714,
    "preview": "'use server';\n\nimport {signInWithEmailAndPassword} from 'firebase/auth';\nimport {refreshCookiesWithIdToken} from 'next-f"
  },
  {
    "path": "examples/next-typescript-starter/app/actions/refresh-cookies.ts",
    "chars": 518,
    "preview": "'use server';\n\nimport {cookies, headers} from 'next/headers';\nimport {getTokens} from 'next-firebase-auth-edge';\nimport "
  },
  {
    "path": "examples/next-typescript-starter/app/actions/user-counters.ts",
    "chars": 1064,
    "preview": "'use server';\n\nimport {getFirestore} from 'firebase-admin/firestore';\nimport {getTokens} from 'next-firebase-auth-edge';"
  },
  {
    "path": "examples/next-typescript-starter/app/api/check-email-verification/route.ts",
    "chars": 795,
    "preview": "import {refreshNextResponseCookies} from 'next-firebase-auth-edge/next/cookies';\nimport {getTokens} from 'next-firebase-"
  },
  {
    "path": "examples/next-typescript-starter/app/api/custom-claims/route.ts",
    "chars": 1274,
    "preview": "import {getFirebaseAuth} from 'next-firebase-auth-edge/auth';\nimport {refreshNextResponseCookies} from 'next-firebase-au"
  },
  {
    "path": "examples/next-typescript-starter/app/api/test-app-check/route.ts",
    "chars": 1219,
    "preview": "import {NextResponse} from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport {serverConfig} from '.."
  },
  {
    "path": "examples/next-typescript-starter/app/api/token-test/route.ts",
    "chars": 655,
    "preview": "import {NextResponse} from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport {getTokens} from 'next-"
  },
  {
    "path": "examples/next-typescript-starter/app/api/user-counters/route.ts",
    "chars": 1153,
    "preview": "import {NextResponse} from 'next/server';\nimport type { NextRequest } from 'next/server';\nimport {authConfig} from '../."
  },
  {
    "path": "examples/next-typescript-starter/app/auth/AuthContext.ts",
    "chars": 569,
    "preview": "import {createContext, useContext} from 'react';\nimport {UserInfo} from 'firebase/auth';\nimport {Claims} from 'next-fire"
  },
  {
    "path": "examples/next-typescript-starter/app/auth/AuthProvider.tsx",
    "chars": 422,
    "preview": "'use client';\n\nimport * as React from 'react';\nimport {AuthContext, User} from './AuthContext';\n\nexport interface AuthPr"
  },
  {
    "path": "examples/next-typescript-starter/app/auth/firebase.ts",
    "chars": 1127,
    "preview": "import { getApp, getApps, initializeApp } from 'firebase/app';\nimport {\n  connectAuthEmulator,\n  getAuth,\n  inMemoryPers"
  },
  {
    "path": "examples/next-typescript-starter/app/firebase.ts",
    "chars": 777,
    "preview": "import admin from 'firebase-admin';\nimport {authConfig} from '../config/server-config';\n\nconst initializeApp = () => {\n "
  },
  {
    "path": "examples/next-typescript-starter/app/globals.css",
    "chars": 706,
    "preview": "html,\nbody {\n  height: 100%;\n  padding: 0;\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Robo"
  },
  {
    "path": "examples/next-typescript-starter/app/layout.module.css",
    "chars": 532,
    "preview": ".container {\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n}\n\n.main {\n  padding: 1.5rem 0;\n  flex: 1;\n  dis"
  },
  {
    "path": "examples/next-typescript-starter/app/layout.tsx",
    "chars": 1299,
    "preview": "import { getTokens } from 'next-firebase-auth-edge';\nimport { cookies } from 'next/headers';\nimport { authConfig } from "
  },
  {
    "path": "examples/next-typescript-starter/app/login/LoginPage.tsx",
    "chars": 6358,
    "preview": "'use client';\n\nimport {\n  UserCredential,\n  getRedirectResult,\n  isSignInWithEmailLink,\n  sendSignInLinkToEmail,\n  signI"
  },
  {
    "path": "examples/next-typescript-starter/app/login/firebase.ts",
    "chars": 1222,
    "preview": "import type {\n  Auth,\n  AuthError,\n  AuthProvider,\n  User,\n  UserCredential\n} from 'firebase/auth';\nimport {\n  browserPo"
  },
  {
    "path": "examples/next-typescript-starter/app/login/login.module.css",
    "chars": 560,
    "preview": ".page {\n  width: 640px;\n  max-width: 100%;\n  height: 100%;\n  flex-direction: column;\n  display: flex;\n  align-items: cen"
  },
  {
    "path": "examples/next-typescript-starter/app/login/page.tsx",
    "chars": 197,
    "preview": "import {loginAction} from '../actions/login';\nimport {LoginPage as ClientLoginPage} from './LoginPage';\n\nexport default "
  },
  {
    "path": "examples/next-typescript-starter/app/page.module.css",
    "chars": 34,
    "preview": ".container {\n  padding: 0 2rem;\n}\n"
  },
  {
    "path": "examples/next-typescript-starter/app/page.tsx",
    "chars": 661,
    "preview": "import styles from './page.module.css';\nimport Link from 'next/link';\nimport {Button} from '../ui/Button';\nimport {MainT"
  },
  {
    "path": "examples/next-typescript-starter/app/profile/UserProfile/UserProfile.module.css",
    "chars": 802,
    "preview": ".container {\n  display: flex;\n  gap: 1rem;\n  width: 100%;\n}\n\n.title {\n  display: flex;\n  align-items: center;\n  justify-"
  },
  {
    "path": "examples/next-typescript-starter/app/profile/UserProfile/UserProfile.tsx",
    "chars": 6788,
    "preview": "'use client';\n\nimport {getToken} from '@firebase/app-check';\nimport * as React from 'react';\nimport {useLoadingCallback}"
  },
  {
    "path": "examples/next-typescript-starter/app/profile/UserProfile/index.ts",
    "chars": 43,
    "preview": "export {UserProfile} from './UserProfile';\n"
  },
  {
    "path": "examples/next-typescript-starter/app/profile/UserProfile/user-counters-server.ts",
    "chars": 1063,
    "preview": "import {initializeServerApp} from 'firebase/app';\nimport {doc, getDoc, getFirestore} from 'firebase/firestore';\nimport {"
  },
  {
    "path": "examples/next-typescript-starter/app/profile/UserProfile/user-counters.ts",
    "chars": 1568,
    "preview": "import {signInWithCustomToken} from 'firebase/auth';\nimport {getValidCustomToken} from 'next-firebase-auth-edge/next/cli"
  },
  {
    "path": "examples/next-typescript-starter/app/profile/page.module.css",
    "chars": 180,
    "preview": ".container {\n  padding: 0 1.5rem;\n  width: 800px;\n  max-width: 100%;\n  height: 100%;\n  flex-direction: column;\n  display"
  },
  {
    "path": "examples/next-typescript-starter/app/profile/page.tsx",
    "chars": 1507,
    "preview": "import styles from './page.module.css';\nimport {UserProfile} from './UserProfile';\nimport {Metadata} from 'next';\nimport"
  },
  {
    "path": "examples/next-typescript-starter/app/register/RegisterPage.tsx",
    "chars": 2138,
    "preview": "'use client';\n\nimport * as React from 'react';\nimport {useLoadingCallback} from 'react-loading-hook';\nimport {\n  createU"
  },
  {
    "path": "examples/next-typescript-starter/app/register/firebase.ts",
    "chars": 1004,
    "preview": "import type {Auth, AuthError, AuthProvider, User} from 'firebase/auth';\nimport {\n  browserPopupRedirectResolver,\n  Googl"
  },
  {
    "path": "examples/next-typescript-starter/app/register/page.tsx",
    "chars": 112,
    "preview": "import {RegisterPage} from './RegisterPage';\n\nexport default function Register() {\n  return <RegisterPage />;\n}\n"
  },
  {
    "path": "examples/next-typescript-starter/app/register/register.module.css",
    "chars": 262,
    "preview": ".page {\n  width: 640px;\n  max-width: 100%;\n  height: 100%;\n  flex-direction: column;\n  display: flex;\n  align-items: cen"
  },
  {
    "path": "examples/next-typescript-starter/app/reset-password/ResetPasswordPage.module.css",
    "chars": 304,
    "preview": ".page {\n  width: 640px;\n  max-width: 100%;\n  height: 100%;\n  flex-direction: column;\n  display: flex;\n  align-items: cen"
  },
  {
    "path": "examples/next-typescript-starter/app/reset-password/ResetPasswordPage.tsx",
    "chars": 2075,
    "preview": "'use client';\n\nimport * as React from 'react';\nimport {sendPasswordResetEmail} from 'firebase/auth';\nimport Link from 'n"
  },
  {
    "path": "examples/next-typescript-starter/app/reset-password/firebase.ts",
    "chars": 1006,
    "preview": "import type {Auth, AuthError, AuthProvider, User} from 'firebase/auth';\nimport {\n  browserPopupRedirectResolver,\n  Googl"
  },
  {
    "path": "examples/next-typescript-starter/app/reset-password/page.tsx",
    "chars": 132,
    "preview": "import {ResetPasswordPage} from './ResetPasswordPage';\n\nexport default function ResetPassword() {\n  return <ResetPasswor"
  },
  {
    "path": "examples/next-typescript-starter/app/shared/redirect.ts",
    "chars": 166,
    "preview": "export function appendRedirectParam(url: string, redirectUrl: string | null) {\n  if (redirectUrl) {\n    return `${url}?r"
  },
  {
    "path": "examples/next-typescript-starter/app/shared/useRedirectAfterLogin.ts",
    "chars": 295,
    "preview": "import {useRouter} from 'next/navigation';\nimport {useRedirectParam} from './useRedirectParam';\n\nexport function useRedi"
  },
  {
    "path": "examples/next-typescript-starter/app/shared/useRedirectParam.ts",
    "chars": 183,
    "preview": "import {useSearchParams} from 'next/navigation';\n\nexport function useRedirectParam(): string | null {\n  const params = u"
  },
  {
    "path": "examples/next-typescript-starter/app/shared/user.ts",
    "chars": 845,
    "preview": "import {Tokens} from 'next-firebase-auth-edge';\nimport {Metadata, User} from '../auth/AuthContext';\nimport {filterStanda"
  },
  {
    "path": "examples/next-typescript-starter/app-check/index.ts",
    "chars": 975,
    "preview": "import {\n  AppCheck,\n  initializeAppCheck,\n  ReCaptchaEnterpriseProvider,\n} from \"@firebase/app-check\";\nimport { getFire"
  },
  {
    "path": "examples/next-typescript-starter/config/client-config.ts",
    "chars": 687,
    "preview": "export const clientConfig = {\n  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY!,\n  authDomain: process.env.NEXT_PUBLIC"
  },
  {
    "path": "examples/next-typescript-starter/config/server-config.ts",
    "chars": 1645,
    "preview": "import {TokenSet} from 'next-firebase-auth-edge/auth';\nimport {clientConfig} from './client-config';\n\nexport const serve"
  },
  {
    "path": "examples/next-typescript-starter/eslint.config.mjs",
    "chars": 369,
    "preview": "import { dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { FlatCompat } from '@eslint/eslintrc';\n\ncon"
  },
  {
    "path": "examples/next-typescript-starter/firebase.json",
    "chars": 181,
    "preview": "{\n  \"emulators\": {\n    \"singleProjectMode\": true,\n    \"auth\": {\n      \"port\": 9099\n    },\n    \"firestore\": {\n      \"port"
  },
  {
    "path": "examples/next-typescript-starter/next-env.d.ts",
    "chars": 313,
    "preview": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n/// <reference types=\"next/navigation-t"
  },
  {
    "path": "examples/next-typescript-starter/next.config.js",
    "chars": 1271,
    "preview": "const path = require('path');\n\n/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  turbopack: {\n    root: pa"
  },
  {
    "path": "examples/next-typescript-starter/package.json",
    "chars": 665,
    "preview": "{\n  \"name\": \"next-typescript-starter\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n  "
  },
  {
    "path": "examples/next-typescript-starter/pages/api/tokens.ts",
    "chars": 545,
    "preview": "import {NextApiRequest, NextApiResponse} from 'next';\nimport {getApiRequestTokens} from 'next-firebase-auth-edge/next/to"
  },
  {
    "path": "examples/next-typescript-starter/proxy.ts",
    "chars": 2217,
    "preview": "import {NextResponse} from 'next/server';\nimport type {NextRequest} from 'next/server';\nimport {\n  authMiddleware,\n  red"
  },
  {
    "path": "examples/next-typescript-starter/tsconfig.json",
    "chars": 636,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    "
  },
  {
    "path": "examples/next-typescript-starter/ui/Badge/Badge.module.css",
    "chars": 166,
    "preview": ".badge {\n  font-size: 0.675rem;\n  line-height: 1rem;\n  color: #0070f3;\n  border: 1px solid #0070f3;\n  padding: 0.5rem;\n "
  },
  {
    "path": "examples/next-typescript-starter/ui/Badge/Badge.tsx",
    "chars": 242,
    "preview": "import styles from './Badge.module.css';\nimport {cx} from '../classNames';\nimport {JSX} from 'react';\nexport function Ba"
  },
  {
    "path": "examples/next-typescript-starter/ui/Badge/index.ts",
    "chars": 33,
    "preview": "export { Badge } from \"./Badge\";\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/Button/Button.module.css",
    "chars": 1008,
    "preview": ".button {\n  font-size: 1rem;\n  padding: 0.75rem 1rem;\n  color: inherit;\n  text-decoration: none;\n  background: transpare"
  },
  {
    "path": "examples/next-typescript-starter/ui/Button/Button.tsx",
    "chars": 688,
    "preview": "import * as React from 'react';\nimport styles from './Button.module.css';\nimport {LoadingIcon} from '../icons';\nimport {"
  },
  {
    "path": "examples/next-typescript-starter/ui/Button/index.ts",
    "chars": 35,
    "preview": "export { Button } from \"./Button\";\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/ButtonGroup/ButtonGroup.module.css",
    "chars": 180,
    "preview": ".group {\n  display: flex;\n  flex-direction: column;\n  padding: 0;\n  gap: 1rem;\n  max-width: 100%;\n}\n\n.group a {\n  width:"
  },
  {
    "path": "examples/next-typescript-starter/ui/ButtonGroup/ButtonGroup.tsx",
    "chars": 252,
    "preview": "import styles from './ButtonGroup.module.css';\nimport {cx} from '../classNames';\nimport {JSX} from 'react';\nexport funct"
  },
  {
    "path": "examples/next-typescript-starter/ui/ButtonGroup/index.ts",
    "chars": 45,
    "preview": "export { ButtonGroup } from \"./ButtonGroup\";\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/Card/Card.module.css",
    "chars": 485,
    "preview": ".card {\n  display: block;\n  margin: 1rem auto;\n  padding: 1.5rem;\n  color: inherit;\n  text-decoration: none;\n  border: 1"
  },
  {
    "path": "examples/next-typescript-starter/ui/Card/Card.tsx",
    "chars": 237,
    "preview": "import styles from './Card.module.css';\nimport {cx} from '../classNames';\nimport {JSX} from 'react';\nexport function Car"
  },
  {
    "path": "examples/next-typescript-starter/ui/Card/index.ts",
    "chars": 31,
    "preview": "export { Card } from \"./Card\";\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/FormError/FormError.module.css",
    "chars": 168,
    "preview": ".error {\n  font-size: 0.675rem;\n  line-height: 1rem;\n  color: #da4e42;\n  border: 1px solid #da4e42;\n  padding: 0.5rem;\n "
  },
  {
    "path": "examples/next-typescript-starter/ui/FormError/FormError.tsx",
    "chars": 250,
    "preview": "import styles from './FormError.module.css';\nimport {cx} from '../classNames';\nimport {JSX} from 'react';\nexport functio"
  },
  {
    "path": "examples/next-typescript-starter/ui/FormError/index.ts",
    "chars": 41,
    "preview": "export { FormError } from \"./FormError\";\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/HomeLink/HomeLink.module.css",
    "chars": 376,
    "preview": ".home {\n  display: inline-flex;\n  width: 3rem;\n  height: 3rem;\n  align-items: center;\n  justify-content: center;\n  borde"
  },
  {
    "path": "examples/next-typescript-starter/ui/HomeLink/HomeLink.tsx",
    "chars": 243,
    "preview": "import styles from \"./HomeLink.module.css\";\nimport { HomeIcon } from \"../icons/HomeIcon\";\nimport Link from \"next/link\";\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/HomeLink/index.ts",
    "chars": 39,
    "preview": "export { HomeLink } from \"./HomeLink\";\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/IconButton/IconButton.module.css",
    "chars": 429,
    "preview": ".button {\n  display: inline-flex;\n  width: 2rem;\n  height: 2rem;\n  align-items: center;\n  justify-content: center;\n  bor"
  },
  {
    "path": "examples/next-typescript-starter/ui/IconButton/IconButton.tsx",
    "chars": 320,
    "preview": "import styles from './IconButton.module.css';\nimport {cx} from '../classNames';\nimport {JSX} from 'react';\n\nexport funct"
  },
  {
    "path": "examples/next-typescript-starter/ui/IconButton/index.ts",
    "chars": 43,
    "preview": "export { IconButton } from \"./IconButton\";\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/Input/Input.module.css",
    "chars": 322,
    "preview": ".input {\n  display: flex;\n  font-size: 1rem;\n  padding: 0.75rem 1rem;\n  color: inherit;\n  text-decoration: none;\n  backg"
  },
  {
    "path": "examples/next-typescript-starter/ui/Input/Input.tsx",
    "chars": 292,
    "preview": "import * as React from 'react';\nimport styles from './Input.module.css';\nimport {cx} from '../classNames';\nimport {JSX} "
  },
  {
    "path": "examples/next-typescript-starter/ui/Input/index.ts",
    "chars": 33,
    "preview": "export { Input } from \"./Input\";\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/MainTitle/MainTitle.module.css",
    "chars": 898,
    "preview": ".title {\n  position: relative;\n  margin: 0 0 0.63em;\n  line-height: 1.15;\n  font-size: 4rem;\n  font-style: normal;\n  fon"
  },
  {
    "path": "examples/next-typescript-starter/ui/MainTitle/MainTitle.tsx",
    "chars": 246,
    "preview": "import styles from './MainTitle.module.css';\nimport {cx} from '../classNames';\nimport {JSX} from 'react';\nexport functio"
  },
  {
    "path": "examples/next-typescript-starter/ui/MainTitle/index.ts",
    "chars": 41,
    "preview": "export { MainTitle } from \"./MainTitle\";\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/PasswordForm/PasswordForm.module.css",
    "chars": 315,
    "preview": ".form {\n  display: flex;\n  flex-direction: column;\n  gap: 1rem;\n}\n\n.container {\n  display: flex;\n  flex-direction: colum"
  },
  {
    "path": "examples/next-typescript-starter/ui/PasswordForm/PasswordForm.tsx",
    "chars": 2675,
    "preview": "import * as React from 'react';\nimport styles from './PasswordForm.module.css';\nimport {cx} from '../classNames';\nimport"
  },
  {
    "path": "examples/next-typescript-starter/ui/PasswordForm/index.ts",
    "chars": 47,
    "preview": "export { PasswordForm } from \"./PasswordForm\";\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/Switch/Switch.module.css",
    "chars": 770,
    "preview": ".switch {\n  position: relative;\n  display: inline-block;\n  width: 40px;\n  height: 22px;\n}\n\n.switch input {\n  opacity: 0;"
  },
  {
    "path": "examples/next-typescript-starter/ui/Switch/Switch.tsx",
    "chars": 416,
    "preview": "import styles from './Switch.module.css';\n\ninterface SwitchProps {\n  value: boolean;\n  onChange: (value: boolean) => voi"
  },
  {
    "path": "examples/next-typescript-starter/ui/Switch/index.ts",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/next-typescript-starter/ui/Switch/vars.css",
    "chars": 262,
    "preview": ":root {\n  --toggle-color: 204, 204, 204;\n  --background-color: 214, 219, 220;\n  --slider-color: 255, 255, 255;\n}\n\n@media"
  },
  {
    "path": "examples/next-typescript-starter/ui/classNames.ts",
    "chars": 115,
    "preview": "export function cx(...className: (string | undefined)[]): string {\n  return className.filter(Boolean).join(\" \");\n}\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/icons/HiddenIcon.tsx",
    "chars": 974,
    "preview": "import * as React from 'react';\nimport styles from './icons.module.css';\nimport {JSX} from 'react';\n\nexport function Hid"
  },
  {
    "path": "examples/next-typescript-starter/ui/icons/HomeIcon.tsx",
    "chars": 507,
    "preview": "import * as React from 'react';\nimport styles from './icons.module.css';\nimport {JSX} from 'react';\n\nexport function Hom"
  },
  {
    "path": "examples/next-typescript-starter/ui/icons/LoadingIcon.tsx",
    "chars": 1500,
    "preview": "import * as React from 'react';\nimport styles from './icons.module.css';\nimport {JSX} from 'react';\n\nexport function Loa"
  },
  {
    "path": "examples/next-typescript-starter/ui/icons/VisibleIcon.tsx",
    "chars": 684,
    "preview": "import * as React from 'react';\nimport styles from './icons.module.css';\nimport {JSX} from 'react';\n\nexport function Vis"
  },
  {
    "path": "examples/next-typescript-starter/ui/icons/icons.module.css",
    "chars": 83,
    "preview": ".icon {\n  width: 24px;\n  height: 24px;\n  display: inline-flex;\n  color: inherit;\n}\n"
  },
  {
    "path": "examples/next-typescript-starter/ui/icons/index.ts",
    "chars": 45,
    "preview": "export { LoadingIcon } from './LoadingIcon';\n"
  },
  {
    "path": "jest.config.js",
    "chars": 420,
    "preview": "module.exports = {\n  setupFiles: ['dotenv/config'],\n  testEnvironment: 'node',\n  setupFilesAfterEnv: ['<rootDir>/jest.se"
  },
  {
    "path": "jest.setup.ts",
    "chars": 51,
    "preview": "import \"isomorphic-fetch\";\nimport \"dotenv/config\";\n"
  },
  {
    "path": "package.json",
    "chars": 12535,
    "preview": "{\n  \"name\": \"next-firebase-auth-edge\",\n  \"version\": \"1.12.0\",\n  \"description\": \"Next.js Firebase Authentication for Edge"
  },
  {
    "path": "prettier.config.js",
    "chars": 93,
    "preview": "module.exports = {\n  bracketSpacing: false,\n  singleQuote: true,\n  trailingComma: 'none',\n};\n"
  }
]

// ... and 95 more files (download for full content)

About this extraction

This page contains the full source code of the ensite-in/next-firebase-auth-edge GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 295 files (606.8 KB), approximately 177.4k tokens, and a symbol index with 588 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!