> For the complete documentation index, see [llms.txt](https://docs.oidc-spa.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.oidc-spa.dev/docs/v11/integration-guides/next.js.md).

# Next.js

Use oidc-spa in a Next.js App Router app.

## Before you start

{% hint style="warning" %}
Using `oidc-spa` in Next.js is easy and infra-light.

But it also changes the architecture.

Authentication happens in the browser. The server rendering your pages cannot know who the user is. That removes most SSR auth-at-render-time benefits and effectively pushes your app toward SPA behavior.

Use this setup only if you accept that trade-off.
{% endhint %}

## The example

{% embed url="<https://youtu.be/zkOWKeTZcYk>" %}

This example shows the minimum wiring needed for a Next.js App Router app.

```bash
npx gitpick keycloakify/oidc-spa/tree/main/examples/next oidc-spa-next
cd oidc-spa-next
cp .env.local.sample .env.local
npm install
npm run dev

# Start exploring with: lib/oidc.tsx
```

{% embed url="<https://github.com/keycloakify/oidc-spa/tree/main/examples/next>" %}

## Installation

{% tabs %}
{% tab title="npm" %}

```bash
npm install oidc-spa zod
```

{% endtab %}

{% tab title="yarn" %}

```bash
yarn add oidc-spa zod
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm add oidc-spa zod
```

{% endtab %}

{% tab title="bun" %}

```bash
bun add oidc-spa zod
```

{% endtab %}
{% endtabs %}

> **Note:**\
> [Zod](https://zod.dev/) is optional but highly recommended.\
> Writing validators manually is error-prone, and skipping validation means losing early guarantees about what your auth server provides. You can use another validator though, it doesn't have to be Zod.

## Required wiring

### Initialize early on the client

Use `instrumentation-client.ts` to run `oidcEarlyInit()` as early as possible.

{% code title="instrumentation-client.ts" %}

```ts
import { oidcEarlyInit } from "oidc-spa/entrypoint";

oidcEarlyInit({
    BASE_URL: process.env.__NEXT_ROUTER_BASEPATH || "/"
});
```

{% endcode %}

### Wrap the app

Wrap the whole app in `OidcInitializationGate`.

In the example, this happens in [`app/layout.tsx`](https://github.com/keycloakify/oidc-spa/blob/main/examples/next/app/layout.tsx).

### Configure oidc-spa

Configure `oidc-spa` and export its utilities as shown in [`lib/oidc.tsx`](https://github.com/keycloakify/oidc-spa/blob/main/examples/next/lib/oidc.tsx).

### Keep oidc-spa on the client

Anything that touches `oidc-spa` must run on the client.

Add `"use client";` to those modules.

## Important limitation

Next.js cannot know who the user is at render time when auth is handled by `oidc-spa` in the browser.

In practice, that means you give up most SSR auth-at-render-time benefits.

You should treat this setup as a SPA architecture running inside Next.js.

## Routes in the example

* `/` public landing page with login and logout controls
* `/protected` guarded page using `withLoginEnforced` from `oidc-spa/react-nextjs`
* `/admin-only` guarded page with a simple role check

Now that authentication is handled, there’s one last piece of the puzzle: your resource server, the backend your app will communicate with.

This can be any type of service: a REST API, tRPC server, or WebSocket endpoint, as long as it can validate access tokens issued by your IdP.

If you’re building it in JavaScript or TypeScript (for example, using Express), oidc-spa provides ready-to-use utilities to decode and validate access tokens on the server side.

You’ll find the full documentation here:

{% content-ref url="/pages/yolKsccF0yDQcZTXQnPo" %}
[Backend Token Validation](/docs/v11/integration-guides/backend-token-validation.md)
{% endcontent-ref %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.oidc-spa.dev/docs/v11/integration-guides/next.js.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
