
# 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](/docs/sdk/nextjs) 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

- Bir KeenAuth ortamı. Veren adresi `https://your-environment.eu.keenauth.app` gibi görünür.
- Ortamda bir web uygulaması ([Uygulama oluşturma](/docs/api/management/applications/create)). İstemci kimlik doğrulaması olarak `private_key_jwt` ya da bir istemci gizli anahtarı kullanır. `development` ortamında `http://localhost/auth/callback` yönlendirme URI'sini ve `http://localhost/` çıkış sonrası yönlendirme URI'sini kaydedin; loopback URI'si bağlantı noktası olmadan kaydedilir ve `3000` gibi herhangi bir bağlantı noktasıyla eşleşir.
- Ortamda kayıtlı, `messages:read` kapsamına sahip bir API ([API oluşturma](/docs/api/management/apis/create)). Örneğin `https://api.example.com` olan `identifier` değeri, erişim belirteçlerinin hedef kitlesidir. [Express hızlı başlangıcı](/docs/quickstarts/express), bu belirteçleri kabul eden bir API oluşturur.
- Node.js 22.18 veya daha yeni bir sürüm.

## 1. Kurulum

```sh
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.

```ts
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.

```ts
/** 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:

```ts
// 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.

```ts
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:

```ts
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.

```tsx
  // 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 `fetch`tir:

```ts
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:

```ts
  // 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.

```tsx
      <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:

```sh
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.

```ts
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);
```

```sh
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](/docs/sdk/nextjs#bugünkü-sınırlar).

## Sonraki adımlar

- [Next.js SDK](/docs/sdk/nextjs): her seçenek, oturum çerezi ve mevcut sınırlar.
- [Express API'sini koruma](/docs/quickstarts/express): bu uygulamanın çağırdığı API.
- [Belirteçleri doğrulama](/docs/sdk/token-verification): API'nizin ara katmanının altındaki doğrulayıcı.
