Next.js uygulamasına giriş ekleme

Bu hızlı başlangıç, @keenauth/nextjs SDK'sı ile bir Next.js App Router uygulamasına KeenAuth girişi ekler. Uygulamanız OAuth istemcisidir ve tüm belirteçleri sunucuda tutar; tarayıcı yalnızca şifreli, HttpOnly bir oturum çerezi alır. Giriş yollarını eklersiniz, bir sayfayı korursunuz, kullanıcının erişim belirteciyle korumalı bir API'yi çağırırsınız ve uygulamayı çevrimdışı test edersiniz. SDK'nın desteklediği tek yönlendirici App Router'dır. SDK, Next.js SDK sayfasında açıklanmıştır.

Uygulamanın şu sayfaları ve yolları vardır:

Yol Ne yapar
/ Herkese açık ana sayfa: bir giriş bağlantısı ya da kullanıcının adı ve bir çıkış düğmesi
/dashboard Oturum gerektirir. Kullanıcıyı ve API'nizin döndürdüğü iletileri gösterir
/api/messages Oturum gerektirir. API'nizi kullanıcının erişim belirteciyle çağırır
/auth/login, /auth/callback, /auth/logout SDK tarafından sunulur

Başlamadan önce

1. Kurulum

npm install @keenauth/nextjs next@16.4.2 react@19.3.1 react-dom@19.3.1

SDK henüz yayımlanmadı. Yayımlanana kadar örnek, package.json dosyasındaki SDK kaynağına bağlanır.

2. Yapılandırma

Uygulama yapılandırmasını yalnızca ortam değişkenlerinden okur. Bunları Next.js'in yüklediği .env.local dosyasına koyun ve bu dosyayı asla commit etmeyin.

Değişken Gerekli Anlamı
KEENAUTH_ISSUER evet Ortamınızın veren adresi
KEENAUTH_CLIENT_ID ikisinden biri Web uygulamasının client_id değeri
KEENAUTH_CLIENT_KEY ikisinden biri private_key_jwt için özel anahtar (JSON özel JWK), önerilir
KEENAUTH_CLIENT_SECRET ikisinden biri Bir istemci gizli anahtarı
APP_BASE_URL evet Uygulamanın herkese açık URL'si. SDK, yönlendirme URI'sini ve tüm yönlendirmeleri bundan oluşturur. Yalnızca localhost, 127.0.0.1 veya [::1] için http kullanılabilir
KEENAUTH_COOKIE_SECRET evet En az 32 karakter; oturum çerezini mühürler. openssl rand -base64 32 ile bir tane üretin
API_URL evet Uygulamanın çağırdığı API, örneğin http://localhost:8080
KEENAUTH_API_AUDIENCE evet KeenAuth'taki bu API'nin tanımlayıcısı

loadConfig bu değerleri okur ve denetler. Değerlerden biri eksikse ya da iki istemci kimlik bilgisinden ikisi birden ya da hiçbiri ayarlanmamışsa çalışmayı durdurur ve hata iletilerinde hiçbir zaman gizli anahtar bulunmaz.

export function loadConfig(env: Record<string, string | undefined>): AppConfig {
  const need = (name: string): string => {
    const value = env[name];
    if (!value) throw new Error(`${name} is required`);
    return value;
  };

3. SDK örneğini oluşturma

createAuth, SDK örneğini oluşturur ve SDK her seçeneği oluşturulduğu anda denetler. getApp, ilk kullanımda süreç başına bir örnek oluşturur; böylece next build hiçbir gizli bilgiye ihtiyaç duymaz.

/** Builds the SDK instance. The options are checked here, so a configuration error stops the app at start-up. */
export function createAuth(config: AppConfig, overrides: Partial<KeenAuthOptions> = {}): KeenAuth {
  return createKeenAuth({ ...config.auth, ...overrides });
}

let instance: { auth: KeenAuth; config: AppConfig } | undefined;

/** One instance per process, created on first use so that `next build` needs no secrets. */
export function getApp(): { auth: KeenAuth; config: AppConfig } {
  if (!instance) {
    const config = loadConfig(process.env);
    instance = { auth: createAuth(config), config };
  }
  return instance;
}

Yapılandırma, resource değerini API'nizin tanımlayıcısına ayarlar (RFC 8707). Bu olmadan erişim belirteci API'niz için tasarlanmamış olur ve API bu belirteci reddeder.

4. Giriş yollarını ekleme

Tek bir catch-all yol işleyicisi /auth/login, /auth/callback ve /auth/logout yollarına hizmet eder:

// Serves /auth/login, /auth/callback and /auth/logout.
export const GET = (request: Request) => getAuth().handlers.GET(request);
export const POST = (request: Request) => getAuth().handlers.POST(request);

Giriş, PKCE ile yetkilendirme kodu akışını kullanır ve ortamınız destekliyorsa itilen bir yetkilendirme isteği kullanır. Geri çağırma state, iss ve kimlik belirtecini denetler. Uygulamanızın yolu olmayan bir returnTo değeri yok sayılır.

5. Sayfaları proxy ile koruma

proxy.ts (Next.js 16 öncesinde middleware.ts), sayfa oluşturulmadan önce oturumu yeniler ve seçtiğiniz yolları korur. Oturumu olmayan bir sayfa isteği returnTo ile /auth/login adresine yönlendirilir; /api/… isteğine ise 401 yanıtı verilir.

export async function proxy(request: NextRequest) {
  const result = await getAuth().proxy(request, { protect: isProtected });
  if (result.response) return result.response;
  const response = NextResponse.next({ request: { headers: result.requestHeaders } });
  result.apply(response);
  return response;
}

Oturum gerektiren yollar tek bir fonksiyonda tanımlanır:

export function isProtected(pathname: string): boolean {
  return pathname === "/dashboard" || pathname.startsWith("/dashboard/") || pathname.startsWith("/api/");
}

Bir proxy eşleştiricisi bir yolu kaçırabilir; bu nedenle kullanıcı gerektiren her sayfa ve yol işleyicisi oturumu kendisi de denetler.

6. API'nizi çağırma

Bir Server Component içinde oturumu okuyun ve erişim belirtecini çerez deposundan alın. Belirteç sunucuda kalır; tarayıcı yalnızca HTML alır.

  // The proxy has already sent users without a session to the sign-in; check again here, because a matcher can miss a path.
  const session = await auth.getSession(cookieStore);
  if (!session) return <a href="/auth/login?returnTo=/dashboard">Sign in</a>;

  // The access token stays on the server. The browser receives only the HTML below.
  const response = await fetchMessages(config.apiUrl, await auth.getAccessToken(cookieStore));

session.user, subject, email ve name gibi kimlik belirtecinin talep değerlerini tutar. Oturum hiçbir zaman bir belirteç içermez.

Çağrının kendisi, taşıyıcı belirteçli düz bir fetchtir:

export async function fetchMessages(apiUrl: string, accessToken: string, fetchImpl: typeof fetch = fetch): Promise<Response> {
  return fetchImpl(new URL("/api/messages", apiUrl), {
    headers: { Authorization: `Bearer ${accessToken}` },
    cache: "no-store",
  });
}

Bir yol işleyicisi de çerez ayarlayabilir; bu nedenle süresi dolmak üzere olan bir erişim belirtecini yenileyen updateSession kullanılır:

  // A route handler can set cookies, so updateSession also refreshes an access token that is about to expire.
  const { accessToken, apply } = await auth.updateSession(request);
  if (!accessToken) return new Response(null, { status: 401 });

Erişim belirtecini bir Client Component'e geçirmeyin.

7. Çıkış yapma

Çıkış, /auth/logout adresine veri gönderen bir formdur. SDK oturum çerezini siler, yenileme belirtecini iptal eder ve tarayıcıyı ortamınızın çıkış uç noktasına gönderir; bu uç nokta tarayıcıyı uygulamanıza geri döndürür. Tarayıcının başka bir siteden geldiğini belirttiği istek reddedilir.

      <form action="/auth/logout" method="post">
        <button type="submit">Sign out</button>
      </form>

8. Uygulamayı çalıştırma

Express hızlı başlangıcındaki API'yi (ya da bu belirteçleri kabul eden herhangi bir API'yi) başlatın ve uygulamayı çalıştırın:

npm run dev

http://localhost:3000 adresini açın, Sign in seçeneğini seçin, KeenAuth'ta giriş yapın ve kontrol panelini açın.

9. Ağ olmadan test etme

Testler ağ bağlantısı ya da bir KeenAuth hesabı gerektirmez. Sahte bir fetch, yetkilendirme sunucusunu (keşif ve itilen yetkilendirme isteği) taklit eder ve Node, TypeScript testlerini doğrudan çalıştırır.

test("proxy: a page request without a session is redirected to sign-in with returnTo", async () => {
  const { auth } = app();
  const result = await auth.proxy(new Request(`${APP}/dashboard?tab=1`), { protect: isProtected });
  assert.equal(result.response?.status, 307);
npm test
npm run deps    # pinned versions, lockfile sources and licences

Testler, yapılandırmanın başlangıçta denetlendiğini, oturumu olmayan bir sayfanın giriş sayfasına yönlendirildiğini ve bir API yolunun 401 yanıtı verdiğini, girişin PKCE S256 itilen istek gönderdiğini ve mühürlenmiş bir HttpOnly çerez ayarladığını, bilinmeyen bir state değeriyle gelen geri çağırmanın reddedildiğini, başka bir siteden gelen çıkışın reddedildiğini ve erişim belirtecinin Authorization başlığında API'ye gönderildiğini denetler.

Gerçek bir tarayıcıyla tam giriş, bir KeenAuth ortamı gerektirir. Bu, çevrimdışı testlerin bir parçası değildir.

Proxy veya yük dengeleyici arkasında

APP_BASE_URL değerini uygulamanın herkese açık URL'sine ayarlayın. SDK, yönlendirmeleri oluşturmak için hiçbir zaman Host ya da X-Forwarded-* başlıklarını okumaz. Birden çok sunucu örneği kullanıldığında iki örnek aynı yenileme belirtecini aynı anda yenileyebilir; bkz. Mevcut sınırlar.

Sonraki adımlar