> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zappway.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Auth API

> Internal reference for the Auth API — NextAuth.js handlers, organization context switching, magic-link/invite flows, and session management.

> **Internal documentation for developers.** This page covers the authentication layer, session structure, organization switching, and invite flows. Not intended for end users.

***

## Route Map

| Method     | Endpoint                  | Handler File                          |
| ---------- | ------------------------- | ------------------------------------- |
| `GET/POST` | `/api/auth/[...nextauth]` | `app/api/auth/[...nextauth]/route.ts` |
| `GET/POST` | `/api/auth/update-org`    | `app/api/auth/update-org/route.ts`    |
| `GET/POST` | `/api/auth/invite`        | `app/api/auth/invite/route.ts`        |
| `GET/POST` | `/api/auth/admin-sync`    | `app/api/auth/admin-sync/route.ts`    |

***

## NextAuth Handler

The `[...nextauth]` route is a thin wrapper around `@zappway/lib/auth`:

```ts theme={null}
// app/api/auth/[...nextauth]/route.ts
import { handlers } from "@zappway/lib/auth";

export const GET = async (req: NextRequest) => originalGet(req);
export const POST = async (req: NextRequest) => originalPost(req);
export const runtime = "nodejs";
```

The auth config (providers, callbacks, session strategy) lives in `@zappway/lib/auth`. This route only delegates to it.

***

## Session Object (`AppRouteRequest.session`)

All authenticated routes receive an `AppRouteRequest` with a populated `session`:

```ts theme={null}
interface AppRouteRequest extends NextRequest {
  session: {
    user: {
      id: string;
      email: string;
      name: string;
    };
    organization: {
      id: string;
      slug: string;
      name: string;
    };
    locale: string;
    permissions: string[];
    membership: {
      id: string;
      role: string;
      accessGroupIds: string[];
    };
  };
  locale: string;
}
```

***

## Organization Switching (`update-org`)

Users can belong to multiple organizations. The `update-org` endpoint updates the active organization in the session.

**Flow:**

1. User selects a different organization in the UI
2. `POST /api/auth/update-org` is called with the target `organizationId`
3. Server validates the user has a membership in that org
4. Session cookie is refreshed with the new org context

***

## Invite Flow (`invite`)

```
1. Admin invites a new user:
   POST /api/auth/invite { email, role, accessGroupId }
   → Creates a pending membership + sends email

2. Invitee clicks link in email
   GET /api/auth/invite?token=...
   → Validates token
   → Creates user (if new) or adds membership (if existing)
   → Redirects to dashboard
```

***

## Admin Sync (`admin-sync`)

Internal endpoint used to synchronize admin-tier organization memberships (e.g., after a plan upgrade). Called by billing webhooks via server-side HTTP (not from the client).

***

## `withPermissionRoute` Auth Modes

| `authMode`            | Description                                 | Performance                                           |
| --------------------- | ------------------------------------------- | ----------------------------------------------------- |
| `'lightweight'`       | Uses cached session from token only         | Fast — no extra DB round-trip                         |
| `undefined` (default) | Full session validation including DB lookup | Slightly slower — verifies membership is still active |

Use `authMode: 'lightweight'` for all read endpoints to reduce latency.

***

## Permission Check Pattern

```ts theme={null}
// Single permission
withPermissionRoute(req, { permission: 'agents.write' }, handler)

// Any of multiple permissions (OR logic)
withPermissionRoute(req, { anyPermission: ['agents.read', 'team.invite'] }, handler)
```

***

## Known Issues / Gotchas

* **`runtime = "nodejs"`** is required on the `[...nextauth]` route — the auth library uses Node.js-only APIs not available in Edge Runtime.
* **Session cookies** are HTTPOnly and scoped to the domain. Never try to read them from client-side JS.
* The `update-org` endpoint must invalidate any active WebSocket/SSE connections for the user so that real-time updates reflect the new org context.
* **Magic link auth** (if enabled via the lib) is handled by NextAuth's email provider internally — there is no separate `verify-magic-link` route in this app.
