Express oturumları
@keenauth/node/bff bir Express 4 veya 5 uygulamasına kimlik doğrulama ekler. Sunucunuz OAuth istemcisidir ve tüm belirteçleri sunucuda tutar. Tarayıcı yalnızca şifrelenmiş, HttpOnly bir oturum çerezi alır; hiçbir erişim, yenileme veya ID belirtecini görmez. Bu, arka uç-ön uç (BFF) desenidir. Paket Express'i içe aktarmaz, dolayısıyla ek bir bağımlılık eklemez. Henüz npm'de yayımlanmamıştır.
Bearer belirteçleri alan bir API'yi korumak için bunun yerine API'nizi koruma bölümüne bakın. Yönetim API'sini çağırmak için Node.js yönetim SDK'sı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) veya genel anahtarını uygulamaya kaydettiğiniz bir anahtar çifti ileprivate_key_jwt. Paylaşılan bir sır sunucunuzdan çıkmadığı içinprivate_key_jwtönerilir. https://app.acme.example/auth/callbackyönlendirme URI'sini vehttps://app.acme.example/çıkış sonrası yönlendirme URI'sini ekleyin.- En az 32 karakterlik bir çerez sırrı üretin, örneğin
openssl rand -base64 32ile. Bunu depoda değil, gizli bilgi deponuzda saklayın.
Kurulum
import express from "express";
import { createBff, expressRequireAuth, expressSession } 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 = express();
app.use(expressSession(bff));
app.get("/orders", expressRequireAuth(bff), (req, res) => {
const { session } = req.keenauth!;
res.send(`Signed in as ${session!.user.email}`);
});
private_key_jwt kullanırken sır yerine özel anahtarı geçirin. SDK, belirteç ve PAR uç noktasına yapılan her istek için yeni bir istemci onay belirteci imzalar (aud issuer'dır, jti rastgeledir, 120 saniye geçerlidir, kid anahtarın RFC 7638 parmak izidir). Algoritma anahtarı izler: RSA için RS256 (veya alg: "PS256"), P-256 için ES256 ve Ed25519 için EdDSA.
import { readFileSync } from "node:fs";
const bff = createBff({
issuer: "https://acme.eu.keenauth.app",
clientId: "app_01j9zzzzzzzzzzzzzzzzzzzz",
clientAuth: { method: "private_key_jwt", privateKey: readFileSync("bff-key.pem", "utf8") },
appBaseUrl: "https://app.acme.example",
secret: process.env.KEENAUTH_COOKIE_SECRET!,
});
Anahtar bir KMS veya HSM içinde tutuluyorsa, bunun yerine clientAuth: { method: "private_key_jwt", assertion } geçirin; burada assertion() her seferinde yeni bir imzalı istemci onay belirteci döndürür. privateKey veya assertion değerlerinden yalnızca birini geçirin, ikisini birden değil.
appBaseUrl, uygulamanızın herkese açık adresidir. SDK yönlendirme URI'sini ve tüm yönlendirmeleri bundan oluşturur; isteğin Host veya X-Forwarded-* başlıklarından asla oluşturmaz, bu yüzden trust proxy ayarı 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.
Rotalar
expressSession üç rota sunar ve diğer her istekte oturumu okur:
| Rota | Ne yapar |
|---|---|
GET /auth/login |
Oturum açmayı başlatır. İsteğe bağlı sorgu parametreleri: returnTo (kullanıcının geleceği yer) ve organization (bir kuruluşta oturum açmak için). |
GET /auth/callback |
Oturum açmayı tamamlar ve oturum çerezini ayarlar. |
GET veya POST /auth/logout |
KeenAuth'ta oturumu kapatır ve uygulamanıza geri döner. |
Oturum açma, PKCE (S256) ile yetkilendirme kodu akışını kullanır. Ortamınız sunduğunda istek sunucuya gönderilir (PAR). Geri çağırmada SDK state, iss ve ID belirtecini, nonce dahil, denetler. Her başarılı oturum açma 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 değerler yok sayılır ve kullanıcı / adresine gelir.
Rotaları koruma
expressRequireAuth(bff), bir isteğin yalnızca oturumla geçmesine izin verir:
- Oturumu olmayan bir sayfa isteği (
GETveyaHEAD),returnToile birlikte/auth/loginadresine yönlendirilir; /api/…yoluna yapılan bir istek veya başka bir yöntemdeki istek, bir sorun belgesiyle birlikte401alır. Her yolda401yanıtı vermek için{ api: true }geçirin.
POST, PUT, PATCH, DELETE ve diğer güvensiz yöntemlerde tarayıcı isteğin uygulamanızdan geldiğini belirtmelidir: Sec-Fetch-Site: same-origin veya uygulamanızın kaynağına eşit bir Origin başlığı. 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
req.keenauth şunları içerir:
session:nullveya oturum açmış kullanıcı.session.user,subject,email,name,orgIdveorgRolesgibi tip tanımlı ID belirteci taleplerine sahiptir; tüm taleplersession.user.claimsiçindedir. Oturum nesnesi asla bir belirteç içermez.accessToken: sunucu tarafı çağrılar için geçerli bir erişim belirteci veyanull.
app.get("/api/orders", expressRequireAuth(bff), async (req, res) => {
const upstream = await fetch("https://api.acme.example/v1/orders", {
headers: { Authorization: `Bearer ${req.keenauth!.accessToken}` },
});
res.status(upstream.status).json(await upstream.json());
});
TypeScript'te özelliği bir kez tanımlayın:
import type { SessionContext } from "@keenauth/node/bff";
declare module "express-serve-static-core" {
interface Request {
keenauth?: SessionContext | null;
}
}
Erişim belirtecinin süresi 60 saniye içinde dolacaksa SDK, işleyiciniz çalışmadan önce onu yeniler. Her yenileme, yenileme belirtecini döndürür ve yanıtta 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ştirin
bff.switchOrganizationPath("org_01j9…", "/dashboard"), kullanıcıyı o kuruluşta yeniden oturum açtıran bir /auth/login bağlantısı döndürür. KeenAuth üyeliği denetler. Oturum açtıktan sonra session.user.orgId kuruluşu tutar.
Oturumu kapatın
Bir formdan /auth/logout adresine POST gönderin. SDK şunları yapar:
- oturum çerezini siler (ve 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 bir istek reddedilir. Sec-Fetch-Site göndermeyen tarayıcılar, oturumu yalnızca kendi sayfalarınızdan gelen bir POST ile kapatabilir.
Oturum depolama
Varsayılan olarak tüm oturum çerezde bulunur; secret değerinden türetilmiş bir anahtarla AES-256-GCM kullanılarak şifrelenir ve kimlik doğrulaması yapılır. Değiştirilmiş veya kopyalanmış bir çerez reddedilir. Çerez __Host-keenauth_session.0 adını taşır ve Secure, HttpOnly, SameSite=Lax ve Path=/ ile ayarlanır. http://localhost üzerinde __Host- öneki ve Secure kaldırılır. 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 oturum açma yeni bir kimlik oluşturur ve önceki kaydı siler. Depo belirteçleri tuttuğu için erişimi kısıtlayın. MemorySessionStore yalnızca geliştirme ve testler içindir.
Bir oturum en fazla 7 gün sürer (sessionMaxAge); yenileme bu süreyi uzatmaz. Sırrı değiştirmek için bir liste geçirin: secret: [newSecret, oldSecret]. Eskisini sessionMaxAge süresinden sonra kaldırın.
Bugünkü sınırlar
- DPoP ile bağlanmış belirteçler ve arka kanal çıkışı henüz işlenmiyor.
- Yenilemeler yalnızca tek bir sunucu süreci içinde paylaşılır. Birden fazla örnekte,
refresh_reuse_interval_suygulama ayarı (varsayılan 5 saniye) paralel bir yenilemenin başarılı olmasına izin verir; bunu0olarak ayarlarsanız ikinci yenileme oturumu sonlandırır.