Fastify oturumları
@keenauth/node/bff paketi, bir Fastify 5 uygulamasına giriş ekler. Sunucunuz OAuth istemcisidir ve tüm belirteçleri sunucuda tutar. Tarayıcıya yalnızca şifrelenmiş, HttpOnly bir oturum çerezi gönderilir; tarayıcı hiçbir erişim, yenileme veya ID belirtecini görmez. Bu, arka uç-ön uç (BFF) desenidir. Paket Fastify'ı içe aktarmaz, bu nedenle ek bir bağımlılık eklemez. Henüz npm'de yayımlanmamıştır.
Taşıyıcı (bearer) belirteçleri alan bir API'yi korumak için bunun yerine API'nizi koruma sayfasına bakın.
Başlamadan önce
- Panelde, ortamınızda bir web uygulaması oluşturun.
- İstemci kimlik doğrulamasını seçin: bir istemci sırrı (
client_secret_basic) ya da genel anahtarını uygulamaya kaydettiğiniz bir anahtar çifti ileprivate_key_jwt. Paylaşılan bir sır sunucunuzdan çıkmadığı içinprivate_key_jwtönerilir. - Yönlendirme URI'sini
https://app.acme.example/auth/callbackve çıkış sonrası yönlendirme URI'sinihttps://app.acme.example/olarak ekleyin. - En az 32 karakterlik bir çerez sırrı oluşturun; örneğin
openssl rand -base64 32ile. Bunu depoya değil, gizli bilgi deponuzda saklayın.
Kurulum
import Fastify from "fastify";
import { createBff, fastifyRequireAuth, fastifySession } from "@keenauth/node/bff";
const bff = createBff({
issuer: "https://acme.eu.keenauth.app", // your environment's issuer, exactly
clientId: "app_01j9zzzzzzzzzzzzzzzzzzzz",
clientAuth: { method: "client_secret_basic", clientSecret: process.env.KEENAUTH_CLIENT_SECRET! },
appBaseUrl: "https://app.acme.example",
secret: process.env.KEENAUTH_COOKIE_SECRET!,
});
const app = Fastify();
fastifySession(app, bff); // on the root instance, so it applies to every route
app.get("/orders", { preHandler: fastifyRequireAuth(bff) }, async (request) => {
return `Signed in as ${request.keenauth!.session!.user.email}`;
});
private_key_jwt kullanırken sır yerine özel anahtarı geçirin: clientAuth: { method: "private_key_jwt", privateKey: readFileSync("bff-key.pem", "utf8") }. SDK, belirteç ve PAR uç noktalarına yapılan her istek için yeni bir istemci onayı imzalar. Anahtar bir KMS veya HSM'de tutuluyorsa, assertion() her çağrıldığında yeni bir imzalı istemci onayı döndüren clientAuth: { method: "private_key_jwt", assertion } değerini geçirin. Onayı ve desteklenen algoritmaları Express sayfası açıklar.
fastifySession işlevini kök örnekte çağırın. Kapsüllenmiş bir eklentinin içinde çağrılırsa yalnızca o eklentinin yollarında geçerli olur.
appBaseUrl, 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-* başlıklarından asla oluşturmaz. Bu nedenle trustProxy seçeneği buna etki etmez. Düz http yalnızca localhost için kabul edilir.
Seçenekler createBff çalıştığında denetlenir; dolayısıyla bir yapılandırma hatası uygulamayı başlangıçta durdurur.
Yollar
fastifySession üç yol ekler ve diğer her istekte bir onRequest kancasında oturumu okur:
| Yol | Ne yapar |
|---|---|
GET /auth/login |
Girişi başlatır. İsteğe bağlı sorgu parametreleri: returnTo (kullanıcının varacağı yer) ve organization (bir kuruluşta giriş yapın). |
GET /auth/callback |
Girişi tamamlar ve oturum çerezini ayarlar. |
GET veya POST /auth/logout |
KeenAuth'tan çıkış yapar ve uygulamanıza geri döner. |
Giriş, PKCE (S256) ile yetkilendirme kodu akışını kullanır. Ortamınız destekliyorsa istek sunucuya gönderilir (PAR). Geri çağırmada SDK state, iss ve ID belirtecini, nonce dahil, denetler. Her başarılı girişte yeni bir oturum oluşturulur; eski oturum atılır.
returnTo, uygulamanıza ait bir yol olmalıdır, örneğin /orders?tab=open. //evil.example ya da tam bir URL gibi başka her değer yok sayılır ve kullanıcı / sayfasına yönlendirilir.
Yolları koruma
fastifyRequireAuth(bff), yalnızca oturumu olan isteklerin geçmesine izin veren bir preHandler'dır:
- oturumu olmayan bir sayfa isteği (
GETveyaHEAD),returnToile birlikte/auth/loginadresine yönlendirilir; /api/…yoluna yapılan bir istek veya başka bir yöntemle yapılan istek, sorun belgesiyle birlikte401alır. Her yolda401yanıtı için{ api: true }geçin.
POST, PUT, PATCH, DELETE ve diğer güvensiz yöntemler için tarayıcı isteğin uygulamanızdan geldiğini belirtmelidir: Sec-Fetch-Site: same-origin ya da uygulamanızın kaynağına eşit bir Origin başlığı. Diğer istekler 403 alır. Bu, SameSite=Lax korumasına ek olarak siteler arası istek sahteciliğine karşı korur.
Oturumu kullanın ve API'nizi çağırın
request.keenauth şunları içerir:
session:nullveya oturum açmış kullanıcı.session.user,subject,email,name,orgIdveorgRolesgibi türlendirilmiş ID belirteci iddialarını içerir; tüm iddialarsession.user.claimsiçindedir. Oturum nesnesi hiçbir zaman belirteç içermez.accessToken: sunucu tarafı çağrılar için geçerli bir erişim belirteci ya danull.
app.get("/api/orders", { preHandler: fastifyRequireAuth(bff) }, async (request, reply) => {
const upstream = await fetch("https://api.acme.example/v1/orders", {
headers: { Authorization: `Bearer ${request.keenauth!.accessToken}` },
});
return reply.code(upstream.status).send(await upstream.json());
});
TypeScript'te özelliği bir kez bildirin:
import type { SessionContext } from "@keenauth/node/bff";
declare module "fastify" {
interface FastifyRequest {
keenauth?: SessionContext | null;
}
}
Erişim belirtecinin süresi 60 saniye içinde dolacaksa SDK, işleyiciniz çalışmadan önce belirteci 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.
Erişim belirtecini tarayıcıya göndermeyin.
Kuruluş değiştirme
bff.switchOrganizationPath("org_01j9…", "/dashboard"), kullanıcıyı o kuruluşta yeniden giriş yaptıran /auth/login bağlantısını döndürür. KeenAuth üyeliği denetler. Girişten sonra session.user.orgId kuruluşu içerir.
Çıkış yapma
Bir formdan /auth/logout adresine POST gönderin. SDK şunları yapar:
- oturum çerezini siler (bir depo kullanıyorsanız saklanan oturumu da);
- yenileme belirtecini iptal eder;
- tarayıcıyı, sizi uygulamanıza geri döndüren ortamınızın çıkış uç noktasına gönderir.
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 gönderilen 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 doğrulanır. Değiştirilmiş ya da kopyalanmış çerez reddedilir. Çerez adı __Host-keenauth_session.0 olup 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 bir depo geçirin:
import { createBff, type SessionStore } from "@keenauth/node/bff";
const store: SessionStore = {
get: async (id) => JSON.parse((await redis.get(`sess:${id}`)) ?? "null"),
set: async (id, session, ttl) => void (await redis.set(`sess:${id}`, JSON.stringify(session), { EX: ttl })),
delete: async (id) => void (await redis.del(`sess:${id}`)),
};
const bff = createBff({ /* … */ store });
Bu durumda çerez yalnızca şifrelenmiş rastgele bir oturum kimliği içerir. Her giriş yeni bir kimlik oluşturur ve önceki kaydı siler. Depo belirteç içerdiği için erişimi kısıtlayın. MemorySessionStore yalnızca geliştirme ve testler içindir.
Oturum en fazla 7 gün sürer (sessionMaxAge); yenileme bu süreyi uzatmaz. Sırrı değiştirmek için bir liste geçin: secret: [newSecret, oldSecret]. Eski sırrı sessionMaxAge süresinden sonra kaldırın.
Bugünkü sınırlar
- DPoP'a bağlı belirteçler ve arka kanal çıkışı henüz desteklenmiyor.
- Yenilemeler yalnızca tek bir sunucu sürecinde paylaşılır. Birden çok örnek varsa,
refresh_reuse_interval_suygulama ayarı (varsayılan 5 saniye) paralel yenilemenin başarılı olmasına izin verir; değeri0yaparsanız ikinci yenileme oturumu sonlandırır.