
# FastAPI oturumları

`keenauth.bff.fastapi`, bir FastAPI uygulamasına giriş yapma özelliği ekler. Sunucunuz OAuth istemcisidir ve tüm belirteçleri sunucuda tutar. Tarayıcı yalnızca şifrelenmiş, HttpOnly bir oturum çerezi alır ve hiçbir zaman erişim, yenileme veya ID belirteci görmez. Bu, backend-for-frontend (BFF) desenidir. `keenauth-python` paketinin bir parçasıdır ve henüz PyPI'de yayımlanmamıştır.

Bunun yerine taşıyıcı belirteç alan bir API'yi korumak için bkz. [API'nizi koruma](/docs/sdk/protect-api).

## Kurulum

```sh
pip install "keenauth-python[fastapi]"
```

## Başlamadan önce

1. Kontrol panelinde, ortamınızda bir web uygulaması oluşturun.
2. İstemci kimlik doğrulamasını seçin: `private_key_jwt` (önerilen, `PrivateKeyJwt`) veya bir istemci sırrı (`ClientSecretBasic`).
3. `https://app.acme.example/auth/callback` yönlendirme URI'sini ve `https://app.acme.example/` çıkış sonrası yönlendirme URI'sini ekleyin.
4. En az 32 karakterlik bir çerez sırrı oluşturun, örneğin `openssl rand -base64 32` ile. Bunu depoda değil, gizli bilgi deponuzda saklayın.

## Örneği oluşturun

```python
import os
from keenauth.bff import BffOptions, ClientSecretBasic, KeenAuthBff

bff = KeenAuthBff(BffOptions(
    issuer="https://acme.eu.keenauth.app",  # your environment's issuer, exactly
    client_id="app_01j9zzzzzzzzzzzzzzzzzzzz",
    client_auth=ClientSecretBasic(os.environ["KEENAUTH_CLIENT_SECRET"]),
    app_base_url="https://app.acme.example",
    secret=os.environ["KEENAUTH_COOKIE_SECRET"],
))
```

`app_base_url`, uygulamanızın herkese açık adresidir. SDK, yönlendirme URI'sini ve tüm yönlendirmeleri bundan oluşturur; istekteki `Host` veya `X-Forwarded-*` üstbilgilerinden asla oluşturmaz. Düz `http` yalnızca `localhost` için kabul edilir. Seçenekler `KeenAuthBff` oluşturulurken denetlenir, dolayısıyla bir yapılandırma hatası uygulamayı başlangıçta durdurur.

## private_key_jwt kullanın

`private_key_jwt` ile uygulamanın paylaşılan bir sırrı yoktur. `PrivateKeyJwt`'ye özel anahtarınızı verin; SDK, belirteç uç noktasına yapılan her istek için yeni bir istemci onayı (RFC 7523) imzalar:

```python
from keenauth.bff import PrivateKeyJwt

client_auth = PrivateKeyJwt(key=os.environ["KEENAUTH_PRIVATE_KEY"])  # unencrypted PEM
```

- Desteklenen anahtarlar: EC P-256 (`ES256`), EC P-384 (`ES384`), Ed25519 (`EdDSA`) ve en az 2048 bitlik RSA (varsayılan olarak `PS256`; `RS256` için `algorithm="RS256"` geçin).
- Her onayda `iss` ve `sub` istemci kimliğinize, `aud` ise sağlayıcıya ayarlanır; ayrıca rastgele bir `jti` ve 60 saniyelik bir geçerlilik süresi bulunur. `kid` değeri, genel anahtarın RFC 7638 parmak izidir.
- Genel anahtarı uygulamaya kaydedin. `keenauth.m2m.load_private_key(pem).public_jwk()` bunu bir JWK olarak döndürür.

Kendi anahtar servisinizle (bir KMS veya HSM) imzalamak için bunun yerine bir işlev geçin: `PrivateKeyJwt(assertion=sign)`. `sign()` her çağrıda yeni bir imzalı onay döndürmelidir.

## Ara katmanı kurun

```python
from fastapi import Depends, FastAPI
from keenauth.bff import SessionContext
from keenauth.bff.fastapi import RequireSession, install

app = FastAPI()
install(app, bff)

@app.get("/orders")
def orders(ctx: SessionContext = Depends(RequireSession(bff))):
    return {"email": ctx.session.user.email}
```

`install`, aşağıdaki rotaları sunar ve diğer her istekte oturumu okuyup `request.state.keenauth` içine koyar. SDK'nın ağ çağrıları eşzamanlıdır; `install`, olay döngüsünü engellememek için bunları Starlette'in iş parçacığı havuzunda çalıştırır.

## Rotalar

| Rota | Ne yapar |
|---|---|
| `GET /auth/login` | Giriş yapmayı başlatır. İsteğe bağlı sorgu parametreleri: `returnTo` (kullanıcının ineceği yer) ve `organization` (bir kuruluşa giriş yapmak için). |
| `GET /auth/callback` | Girişi tamamlar ve oturum çerezini ayarlar. |
| `GET` veya `POST /auth/logout` | KeenAuth'tan çıkış yapar ve uygulamanıza döner. |

Giriş, PKCE (S256) ile yetkilendirme kodu akışını kullanır. Ortamınız sunduğunda istek sunucuya itilir (PAR). Geri çağrıda SDK, `state`, `iss` ve ID belirtecini, `nonce` dahil olmak üzere denetler. Her başarılı giriş yeni bir oturum oluşturur; eski oturum atılır.

`returnTo`, `/orders?tab=open` gibi uygulamanıza ait bir yol olmalıdır. `//evil.example` veya tam bir URL gibi başka bir değer yok sayılır ve kullanıcı `/` adresine iner.

## Korumalı görünümler

Bir yol işlemine `Depends(RequireSession(bff))` ekleyin. Bu, oturum bağlamını döndürür.


Oturum yoksa:

- sayfa isteği (`GET` veya `HEAD`), `returnTo` ile birlikte `/auth/login` adresine yönlendirilir;
- `/api/…` yoluna yapılan bir istek veya başka bir yöntem, bir problem belgesiyle `401` alır. Herhangi bir yolda `401` yanıtı vermek için `api=True` geçin.

`POST`, `PUT`, `PATCH`, `DELETE` ve diğer güvenli olmayan yöntemler için tarayıcı isteğin uygulamanızdan geldiğini belirtmelidir: `Sec-Fetch-Site: same-origin` veya uygulamanızın kaynağına eşit bir `Origin` üstbilgisi. Diğer istekler `403` alır. Bu, `SameSite=Lax` ile birlikte siteler arası istek sahteciliğine karşı koruma sağlar.

## Oturumu kullanın ve API'nizi çağırın

Oturum bağlamında şunlar bulunur:

- `session`: `None` ya da giriş yapmış kullanıcı. `session.user`, `subject`, `email`, `name`, `org_id` ve `org_roles` gibi türlendirilmiş ID belirteci iddialarına sahiptir; tüm iddialar `session.user.claims` içindedir. Oturum nesnesi hiçbir zaman bir belirteç içermez.
- `access_token`: sunucu tarafı çağrılar için geçerli bir erişim belirteci ya da `None`. Bunu tarayıcıya göndermeyin.

Erişim belirtecinin süresi 60 saniye içinde dolacaksa SDK, görünümünüz çalışmadan önce onu yeniler. Her yenileme, yenileme belirtecini döndürür ve yanıta yeni oturum çerezini ayarlar. Sunucu yenileme belirtecini reddederse oturum sona erer. Geçici bir sunucu hatası oturumu değiştirmeden bırakır. Bir süreçteki eşzamanlı istekler tek bir yenilemeyi paylaşır.

## Kuruluş değiştirin

`bff.switch_organization_path("org_01j9…", "/dashboard")`, kullanıcıyı o kuruluşta yeniden giriş yaptıran bir `/auth/login` bağlantısı döndürür. KeenAuth üyeliği denetler. Girişten sonra `session.user.org_id` kuruluşu tutar.

## Çıkış yapın

Bir formdan `/auth/logout` adresine `POST` gönderin. SDK, oturum çerezini (ve bir depo kullanıyorsanız saklanan oturumu) siler, yenileme belirtecini iptal eder ve tarayıcıyı ortamınızın çıkış uç noktasına gönderir; bu uç nokta da tarayıcıyı uygulamanıza döndürür. Tarayıcının başka bir siteden geldiğini işaretlediği istek reddedilir. `Sec-Fetch-Site` göndermeyen tarayıcılar yalnızca kendi sayfalarınızdan gelen bir `POST` ile çıkış yapabilir.

## Oturum depolama

Varsayılan olarak tüm oturum çerezdedir; `secret` değerinden türetilen bir anahtarla AES-256-GCM kullanılarak şifrelenir ve kimliği doğrulanır. Değiştirilmiş ya da kopyalanmış bir çerez reddedilir. Çerezin adı `__Host-keenauth_session.0` olur ve `Secure`, `HttpOnly`, `SameSite=Lax` ve `Path=/` ile ayarlanır. `http://localhost` üzerinde `__Host-` öneki ve `Secure` kullanılmaz. Büyük oturumlar en fazla üç çereze bölünür.

Belirteçleri sunucuda tutmak için, `get(id)`, `set(id, session, ttl_seconds)` ve `delete(id)` yöntemlerine sahip bir nesneyi `store=` ile geçin; örneğin Redis destekli bir depo. Bu durumda çerez yalnızca şifrelenmiş rastgele bir oturum kimliği tutar. Her giriş yeni bir kimlik oluşturur ve önceki kaydı siler. Depo belirteçleri tuttuğundan erişimini kısıtlayın. `MemorySessionStore` yalnızca geliştirme ve testler içindir.

Bir oturum en fazla 7 gün sürer (`session_max_age`); yenileme bu süreyi uzatmaz. Sırrı değiştirmek için bir liste geçin: `secret=[new_secret, old_secret]`. Eski sırrı `session_max_age` süresinden sonra kaldırın.

## Bugünkü sınırlar

- DPoP'a bağlı belirteçler ve arka kanal çıkışı henüz işlenmiyor.
- Yenilemeler yalnızca tek bir sunucu süreci içinde paylaşılır. Birden çok süreç varsa, `refresh_reuse_interval_s` uygulama ayarı (varsayılan 5 saniye), paralel bir yenilemenin başarılı olmasına izin verir; değeri `0` olarak ayarlarsanız ikinci yenileme oturumu sonlandırır.
