Langsung ke konten
Dokumentasi · Next.js

Panduan cepat: Next.js

Tambahkan proses masuk ke aplikasi Next.js dengan App Router. SDK @usher/nextjs segera hadir; sampai saat itu, panduan ini menggunakan alur OpenID Connect standar, persis seperti yang nanti dikerjakan SDK untuk Anda.

Sebelum memulai

  • Aplikasi Next.js 15 atau 16 yang menggunakan App Router.
  • Lingkungan Usher. Di Usher Console, buka proyek Anda, pilih lingkungan, lalu catat penerbit lingkungan tersebut.

Daftarkan aplikasi Anda

Di Console, buka Aplikasi lalu buat aplikasi web. Tambahkan URI pengalihan ini persis seperti tertulis:

http://localhost:3000/auth/callback

Salin ID klien dan rahasia klien. Rahasia hanya ditampilkan sekali.

Tambahkan variabel lingkungan

.env.local
USHER_ISSUER=https://acme.usherid.com
USHER_CLIENT_ID=your_client_id
USHER_CLIENT_SECRET=your_client_secret
APP_URL=http://localhost:3000

Pasang klien OpenID Connect

Klien bersertifikasi apa pun bisa dipakai. Panduan ini menggunakan openid-client, yang menangani discovery, PKCE, dan validasi token.

Terminal
pnpm add openid-client

Temukan penerbit Anda

Discovery membaca endpoint dan kunci penerbit satu kali, sehingga tidak ada yang perlu ditulis langsung di kode.

lib/usher.ts
import * as client from 'openid-client'

let config: Promise<client.Configuration> | undefined

export function usher() {
  config ??= client.discovery(
    new URL(process.env.USHER_ISSUER!),
    process.env.USHER_CLIENT_ID!,
    process.env.USHER_CLIENT_SECRET!,
  )
  return config
}

export const redirectUri = `${process.env.APP_URL}/auth/callback`

Arahkan orang ke Lobby

Sebuah route handler membuat verifier PKCE dan nilai state, menyimpannya di cookie berumur pendek, lalu mengalihkan ke Lobby.

app/auth/sign-in/route.ts
import * as client from 'openid-client'
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'
import { redirectUri, usher } from '@/lib/usher'

export async function GET() {
  const config = await usher()
  const codeVerifier = client.randomPKCECodeVerifier()
  const state = client.randomState()

  const jar = await cookies()
  jar.set('usher_flow', JSON.stringify({ codeVerifier, state }), {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    path: '/auth',
    maxAge: 600,
  })

  const url = client.buildAuthorizationUrl(config, {
    redirect_uri: redirectUri,
    scope: 'openid profile email offline_access',
    code_challenge: await client.calculatePKCECodeChallenge(codeVerifier),
    code_challenge_method: 'S256',
    state,
  })
  redirect(url.href)
}

Tangani callback

Usher mengembalikan orang tersebut dengan sebuah kode. Tukarkan kode itu dengan token; openid-client memeriksa state, verifier PKCE, dan tanda tangan token ID untuk Anda.

app/auth/callback/route.ts
import * as client from 'openid-client'
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'
import { usher } from '@/lib/usher'

export async function GET(request: Request) {
  const config = await usher()
  const jar = await cookies()
  const flow = JSON.parse(jar.get('usher_flow')?.value ?? '{}')
  jar.delete('usher_flow')

  const tokens = await client.authorizationCodeGrant(config, new URL(request.url), {
    pkceCodeVerifier: flow.codeVerifier,
    expectedState: flow.state,
  })
  const claims = tokens.claims()! // sub, email, name, …

  // start your own session here: store claims.sub, and keep the refresh token server-side
  redirect('/')
}

Keluar

Akhiri sesi orang tersebut di aplikasi Anda, lalu arahkan mereka ke endpoint end-session Usher agar Lobby juga melupakan mereka.

app/auth/sign-out/route.ts
import * as client from 'openid-client'
import { redirect } from 'next/navigation'
import { usher } from '@/lib/usher'

export async function GET() {
  const config = await usher()
  // clear your own session first
  const url = client.buildEndSessionUrl(config, {
    post_logout_redirect_uri: process.env.APP_URL!,
  })
  redirect(url.href)
}

Dengan SDK

Saat @usher/nextjs dipublikasikan, aplikasi yang sama akan terlihat seperti ini. Pratinjau di bawah dapat berubah sebelum rilis.

app/layout.tsx · app/page.tsx (pratinjau)
// app/layout.tsx
import { UsherProvider } from '@usher/nextjs'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <UsherProvider>{children}</UsherProvider>
      </body>
    </html>
  )
}

// app/page.tsx
import { SignIn, UserButton, currentUser } from '@usher/nextjs'

export default async function Page() {
  const user = await currentUser()
  return user ? <UserButton /> : <SignIn />
}

Langkah berikutnya