Supabase TOTP 2FA for Next.js App Router

By (author)fizzah abdullah

Tech stack:
JS
TS
CSS

Drop-in 2FA for Next.js and Supabase: authenticator setup with a QR code, a code check at sign-in, and a guard that blocks pages, API routes and data...
read more
AI Contributions:0
Published At:October 19, 2026
Files Included:5 file(s)

Read Me

# Supabase TOTP 2FA for Next.js App Router

## Description

Drop-in two-factor authentication for a Next.js App Router app using Supabase Auth MFA. It includes TOTP enrolment with a QR code and manual secret, a verification screen for every password sign-in, middleware redirects, server component guards, API route guards, and database policies that require an `aal2` session.

## Skills

Next.js, React, TypeScript, Supabase, PostgreSQL

## Custom tags

2FA, TOTP, MFA, authentication, Row Level Security, App Router

## What it does

- Redirects signed-in users with no verified TOTP factor to `/2fa/enrol`.
- Redirects enrolled users whose current session is still `aal1` to `/2fa/verify`.
- Uses `supabase.auth.mfa.enroll`, `challenge`, and `verify` / `challengeAndVerify` flow to promote the session to `aal2`.
- Provides `requireAal2User()` for Server Components and `requireApiAal2Session()` for route handlers.
- Complements Supabase Row Level Security policies that check `(select auth.jwt()->>'aal') = 'aal2'`.

## Files included in this app

- `middleware.ts`
- `lib/supabase/middleware.ts`
- `lib/auth/session.ts`
- `lib/auth/redirect.ts`
- `app/(auth)/2fa/enrol/page.tsx`
- `app/(auth)/2fa/verify/page.tsx`
- `components/auth/two-factor-form.tsx`
- `supabase/migrations/20250101000000_core_tables.sql`
- `supabase/migrations/20250101000100_profile_trigger.sql`

## Install

```bash
npm install next react react-dom @supabase/ssr @supabase/supabase-js
```

## Setup

1. Create a Supabase project and enable Email auth.
2. In Supabase Auth, enable MFA with TOTP factors.
3. Add these variables to your environment:

```bash
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
```

4. Use `@supabase/ssr` clients so the browser, route handlers and middleware share the same cookie-backed session.
5. Add RLS policies that require both the signed-in user and an AAL2 session:

```sql
using (
  user_id = (select auth.uid())
  and (select auth.jwt()->>'aal') = 'aal2'
)
```

## Usage example

Protect pages in middleware before they render:

```ts
if (user && isProtectedPath(pathname)) {
  if (aal.nextLevel === "aal1") {
    const enrol = new URL("/2fa/enrol", origin);
    enrol.searchParams.set("next", `${pathname}${search}`);
    return redirectWithCookies(enrol, response);
  }

  if (aal.nextLevel === "aal2" && aal.currentLevel !== "aal2") {
    const verify = new URL("/2fa/verify", origin);
    verify.searchParams.set("next", `${pathname}${search}`);
    return redirectWithCookies(verify, response);
  }
}
```

Protect Server Components too:

```ts
import { requireAal2User } from "@/lib/auth/session";

export default async function DashboardPage() {
  const user = await requireAal2User("/dashboard");
  return <p>Signed in as {user.email}</p>;
}
```

Protect route handlers:

```ts
const session = await requireApiAal2Session();
if (!session.ok) {
  return Response.json({ ok: false, error: session.reason }, { status: session.status });
}
```

## Options and limits

- The sample protects `/dashboard`; add more protected prefixes in `lib/auth/redirect.ts`.
- `next` redirects are sanitized to in-app paths only.
- TOTP codes are generated by the user's authenticator app and usually rotate every 30 seconds.
- Supabase determines `currentLevel` and `nextLevel`; the app should not infer 2FA state from local storage or user metadata.
- API guards return JSON errors instead of redirects so clients can show a friendly message.

## Dependencies and licences

- Next.js — MIT: https://github.com/vercel/next.js
- React — MIT: https://github.com/facebook/react
- Supabase JS — MIT: https://github.com/supabase/supabase-js
- Supabase SSR — MIT: https://github.com/supabase/ssr
- PostgreSQL / Supabase Row Level Security — PostgreSQL licence / Supabase platform docs

## Contributors

Roshaan Tahir, M Hammad Khan, Fizzah Abdullah, Hammad Khan

---

## GIG READY block

GIG READY: Supabase TOTP 2FA
Publish at Devmarketplace → Add your Gigs

1. Thumbnail
   Upload docs/gigs/thumbnails/supabase-totp-2fa.png

2. Basic Info
   Title (40/50): Supabase TOTP 2FA for Next.js App Router
   Description (177/200): Drop-in 2FA for Next.js and Supabase: authenticator setup with a QR code, a code check at sign-in, and a guard that blocks pages, API routes and database rows until 2FA is done.

3. Tech Stack
   Skills (pick the closest ones in the list): Next.js, React, TypeScript, Supabase, PostgreSQL
   Custom tags (6/10, press Enter after each): 2FA, TOTP, MFA, authentication, Row Level Security, App Router

4. Code Snippet
   Language: TypeScript
   From: middleware.ts, 27 to 43

```ts
if (user && isProtectedPath(pathname)) {
  if (aal.nextLevel === "aal1") {
    const enrol = new URL(TWO_FACTOR_ENROL_PATH, origin);
    enrol.searchParams.set("next", `${pathname}${search}`);
    return redirectWithCookies(enrol, response);
  }

  if (aal.nextLevel === "aal2" && aal.currentLevel !== "aal2") {
    const verify = new URL(TWO_FACTOR_VERIFY_PATH, origin);
    verify.searchParams.set("next", `${pathname}${search}`);
    return redirectWithCookies(verify, response);
  }
}
```

5. Read ME
   Open docs/gigs/supabase-totp-2fa.md on GitHub, copy the rendered page and paste it into the editor.

6. After you click Create
   Add the gig link to the tracker in docs/GIGS.md and to the Devpost draft.

Loading

Loading

Loading

More like this View all

Unclaimed librarychat

A unified TypeScript SDK for building chat bots across Slack, Microsoft Teams, Google Chat, Discord, and more.

  • 0

    Ratings

  • 0

    Files

    • TS
    • CSS
    • +2

    Tech stack

Unclaimed librarysaasternity

Open source SaaS boilerplate, built with Next.js and Aceternity UI, deployed on Vercel.

  • 0

    Ratings

  • 0

    Files

    • TS
    • CSS
    • +2

    Tech stack

Unclaimed librarynext-enterprise

💼 An enterprise-grade Next.js boilerplate for high-performance, maintainable apps. Packed with features like Tailwind CSS, TypeScript, ESLint, Prettier, testing tools, and more to accelerate your development.

  • 0

    Ratings

  • 0

    Files

    • TS
    • JS
    • +2

    Tech stack