بدء سريع: Next.js
أضف تسجيل الدخول إلى تطبيق Next.js يستخدم App Router. حزمة @usher/nextjs قادمة، وإلى أن تصدر، يستخدم هذا الدليل تدفق OpenID Connect القياسي، وهو بالضبط ما ستفعله الحزمة نيابةً عنك.
قبل أن تبدأ
- تطبيق Next.js 15 أو 16 يستخدم App Router.
- بيئة في Usher. في Usher Console، افتح مشروعك، واختر بيئة، ودوّن جهة الإصدار الخاصة بها.
سجّل تطبيقك
في Console، انتقل إلى التطبيقات وأنشئ تطبيق ويب. أضف عنوان URI لإعادة التوجيه هذا كما هو تمامًا:
http://localhost:3000/auth/callbackانسخ معرّف العميل وسر العميل. يُعرض السر مرة واحدة فقط.
أضف متغيرات البيئة
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اكتشف جهة الإصدار
يقرأ الاكتشاف نقاط النهاية والمفاتيح الخاصة بجهة الإصدار مرة واحدة، فلا يُكتب شيء منها بشكل ثابت في الشيفرة.
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`أرسل الأشخاص إلى Lobby
يُنشئ معالج المسار (route handler) مُحقِّق PKCE وقيمة state، ويحفظهما في ملف تعريف ارتباط قصير العمر، ثم يعيد التوجيه إلى Lobby.
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 وتوقيع رمز الهوية نيابةً عنك.
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 لكي ينساه Lobby أيضًا.
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
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 />
}