मजकुराकडे जा
दस्तऐवज · Next.js

झटपट सुरुवात: Next.js

App Router असलेल्या Next.js ॲपमध्ये साइन-इन जोडा. @usher/nextjs SDK येत आहे; ते येईपर्यंत, हे मार्गदर्शक मानक OpenID Connect फ्लो वापरते, जे SDK तुमच्यासाठी नेमके हेच करेल.

सुरू करण्यापूर्वी

  • App Router वापरणारे Next.js 15 किंवा 16 ॲप.
  • एक Usher एन्व्हायर्नमेंट. Usher Console मध्ये, तुमचा प्रोजेक्ट उघडा, एक एन्व्हायर्नमेंट निवडा, आणि त्याचा इश्युअर लिहून ठेवा.

तुमचे ॲप नोंदवा

Console मध्ये, ॲप्लिकेशन वर जा आणि एक वेब ॲप्लिकेशन तयार करा. हा रीडायरेक्ट URI अगदी जसाच्या तसा जोडा:

http://localhost:3000/auth/callback

क्लायंट ID आणि क्लायंट सिक्रेट कॉपी करा. सिक्रेट एकदाच दाखवले जाते.

तुमचे एन्व्हायर्नमेंट व्हेरिएबल जोडा

.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

OpenID Connect क्लायंट इन्स्टॉल करा

कोणताही प्रमाणित क्लायंट चालतो. हे मार्गदर्शक openid-client वापरते, जे डिस्कव्हरी, PKCE आणि टोकन व्हॅलिडेशन हाताळते.

टर्मिनल
pnpm add openid-client

तुमचा इश्युअर शोधा

डिस्कव्हरी इश्युअरचे एंडपॉइंट आणि की एकदाच वाचते, त्यामुळे काहीही हार्ड-कोड केलेले नसते.

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`

लोकांना लॉबीकडे पाठवा

एक रूट हँडलर PKCE व्हेरिफायर आणि state मूल्य बनवतो, ते अल्पकालीन कुकीमध्ये ठेवतो, आणि लॉबीकडे रीडायरेक्ट करतो.

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)
}

कॉलबॅक हाताळा

Usher व्यक्तीला एका कोडसह परत पाठवतो. त्याच्या बदल्यात टोकन घ्या; openid-client तुमच्यासाठी state, PKCE व्हेरिफायर आणि ID टोकनची सही तपासते.

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('/')
}

साइन आउट

तुमच्या ॲपमधील व्यक्तीचे सेशन संपवा, मग त्यांना Usher च्या end-session एंडपॉइंटकडे पाठवा, म्हणजे लॉबीही त्यांना विसरते.

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)
}

SDK सह

@usher/nextjs प्रकाशित झाल्यावर, तेच ॲप असे दिसते. खालील पूर्वावलोकन रिलीझपूर्वी बदलू शकते.

app/layout.tsx · app/page.tsx (पूर्वावलोकन)
// 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 />
}

पुढील पायऱ्या