Node.js yönetim SDK'sı

@keenauth/node, KeenAuth yönetim API'si için TypeScript SDK'sıdır. Node.js 22 veya üzeri bir sürüm gerektirir ve çalışma zamanı bağımlılığı yoktur. Henüz npm'de yayımlanmamıştır.

Paketin şu giriş noktaları vardır:

İçe aktarma Kullanım amacı
@keenauth/node Yönetim API istemcisi, yönetim token'ları, sayfalama ve hatalar
@keenauth/node/webhooks API istemcisini yüklemeden webhook imzalarını doğrulama
@keenauth/node/bff Sunucu uygulamaları için oturum açma: Express ve Fastify
@keenauth/node/middleware Bearer token'larla API'nizi koruma
@keenauth/node/testing Çevrimdışı test kiti

İstemci oluşturma

Gizli veya kısıtlı bir API anahtarıyla:

import { KeenAuth } from "@keenauth/node";

const keenauth = new KeenAuth({
  baseUrl: "https://api.eu.keenauth.com/v1",
  apiKey: process.env.KEENAUTH_API_KEY!,
});

const user = await keenauth.users.getUser({ userId: "usr_01j9zzzzzzzzzzzzzzzzzzzz" });

baseUrl, bölgenizin API adresidir ve sonuna /v1 eklenir. https kullanmalıdır; düz http yalnızca localhost için kabul edilir. Anahtar yalnızca Authorization başlığında ve yalnızca bu adrese gönderilir. Yönlendirmeler takip edilmez.

API anahtarı olmadan kimlik doğrulama

management tipindeki bir uygulama, statik bir anahtar yerine kısa ömürlü bir token ile API'yi çağırabilir. Uygulama, özel anahtarıyla bir istemci onayı (assertion) imzalar (private_key_jwt, RFC 7523) ve SDK bunu ortamınızın token uç noktasında değiştirir.

  1. Panelde management tipinde bir uygulama ve ihtiyaç duyduğu izinlere sahip bir yönetim istemci kaydı oluşturun (bkz. Yönetim istemcisi oluşturma).
  2. Bir anahtar çifti üretin ve genel anahtarı uygulamanın bir public_key kimlik bilgisi olarak kaydedin. Örneğin ES256 için: openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out management-key.pem.
  3. Özel anahtarı gizli bilgi deponuzda saklayın. SDK'ya iletin:
import { readFileSync } from "node:fs";
import { KeenAuth } from "@keenauth/node";

const keenauth = new KeenAuth({
  baseUrl: "https://api.eu.keenauth.com/v1",
  credentials: {
    issuer: "https://acme.eu.keenauth.app", // ortamınızın issuer değeri, birebir
    clientId: "app_01j9zzzzzzzzzzzzzzzzzzzz",
    privateKey: readFileSync("management-key.pem", "utf8"), // PEM, özel JWK veya KeyObject
    scope: ["users:read", "users:write"], // isteğe bağlı; varsayılan: uygulamanın varsayılan kapsamları
  },
});

SDK şunları yapar:

Başarısız bir token isteği, OAuth code (örneğin invalid_client veya invalid_scope), description ve status ile birlikte TokenError fırlatır. Özel anahtar yerine genel anahtar verilmesi gibi bir yapılandırma hatası ise istemci oluşturulduğunda fırlatılır.

apiKey ve credentials birlikte kullanılamaz.

Yeniden deneme

API 429, 502, 503 veya 504 yanıtı verdiğinde ya da bağlantı kurulamadığında SDK bir isteği en fazla toplam 3 kez yeniden dener. Yalnızca GET, PUT ve DELETE istekleri ile bir Idempotency-Key taşıyan POST istekleri yeniden denenir. If-Match taşıyan bir PATCH yalnızca 429 yanıtında yeniden denenir: hız sınırlayıcı isteği çalışmadan reddeder ve If-Match, bir değişikliğin iki kez uygulanmasını önler. Diğer tüm PATCH istekleri hiçbir zaman yeniden denenmez.

SDK, desteklediği her POST işlemine rastgele bir Idempotency-Key ekler; böylece yeniden denenen bir oluşturma işlemi ikinci bir nesne oluşturmaz. Kendi yeniden denemelerinizi de güvenli kılmak için aynı anahtarı kendiniz iletebilirsiniz:

await keenauth.users.createUser({
  userCreateRequest: { email: "ada@example.com" },
  idempotencyKey: "signup-7d1f0c2a-0d7e-4c55",
});

Sayfalama

Listeleme uç noktaları tek bir sayfa döndürür: data ve before ile after imleçlerini içeren listMetadata. paginate, imleçleri sizin yerinize takip eder:

import { paginate } from "@keenauth/node";

for await (const user of paginate((p) => keenauth.users.listUsers(p), { limit: 100 })) {
  console.log(user.id);
  if (user.email === "ada@example.com") break; // bir sonraki sayfayı yüklemeden durur
}

Hatalar

Bir hata yanıtı, status, code, title, detail, requestId ve alan bazlı errors içeren bir ProblemError (RFC 9457) olur. İleti metnini değil, code değerini kontrol edin. SDK'nın tanımadığı kodlar dize olarak kullanılabilir kalır.

import { ProblemError } from "@keenauth/node";

try {
  await keenauth.users.getUser({ userId });
} catch (e) {
  if (e instanceof ProblemError && e.code === "not_found") {
    // …
  }
}

Bir proxy'den gelen HTML sayfası gibi, problem belgesi içermeyen bir yanıt ise ham response ile birlikte oluşturulmuş ResponseError olur.

Webhook'ları doğrulama

KeenAuth, webhook'ları Standard Webhooks v1 şemasıyla imzalar. İmzayı, isteği ayrıştırmadan önce ham istek gövdesiyle doğrulayın:

import express from "express";
import { Webhook, WebhookVerificationError } from "@keenauth/node/webhooks";

const webhook = new Webhook(process.env.KEENAUTH_WEBHOOK_SECRET!); // idp_whsec_…

const app = express();
app.post("/webhooks/keenauth", express.raw({ type: "application/json" }), (req, res) => {
  let event;
  try {
    event = webhook.verify(req.body, req.headers);
  } catch (e) {
    if (e instanceof WebhookVerificationError) return res.status(400).send(e.kind);
    throw e;
  }
  // event.type değerini işleyin, ardından hızlıca yanıt verin
  res.sendStatus(204);
});

Webhook'lar birden fazla kez gelebilir. Yinelenenleri yok saymak için webhook-id değerini kullanın.

Tipli olaylar ve talepler

@keenauth/node/events, herkese açık olay şemalarından üretilen her müşteri olayı için bir tip içerir. parseEvent, doğrulanmış bir gövdeyi kontrol eder ve KeenAuthEvent | UnknownEvent döndürür. isKnownEvent sonrasında switch (event.type), olayı tek bir tipe daraltır. @keenauth/node/webhooks içindeki verifyEvent her iki adımı birden yapar:

import { verifyEvent } from "@keenauth/node/webhooks";
import { isKnownEvent } from "@keenauth/node/events";

const event = verifyEvent(webhook, req.body, req.headers); // WebhookVerificationError veya EventParseError
if (!isKnownEvent(event)) {
  // Bu SDK sürümünün henüz bilmediği bir tip. event.type ve event.data.object.id yine de tiplidir.
  return res.sendStatus(204);
}
switch (event.type) {
  case "user.created":
    console.log(event.data.object.id);
    break;
  case "email_sending.suspended":
    console.log(event.data.object.reason); // "bounce_rate" | "complaint_rate" | (string & {})
    break;
}

@keenauth/node/claims, doğrulanmış bir token'ın taleplerini tiplendirir: parseIdTokenClaims (OpenID Connect Core) ve parseAccessTokenClaims (RFC 9068). Talep tiplerini kontrol ederler ancak hiçbir şeyi doğrulamazlar; bu yüzden doğrulayıcının döndürdüğü claims üzerinde çağırın:

import { parseAccessTokenClaims } from "@keenauth/node/claims";

const at = await verifier.verifyAccessToken(token);
const claims = parseAccessTokenClaims(at.claims);
claims.client_id; // string
claims.org_roles; // string[] | undefined
claims["tenant_tier"]; // unknown: kendi talepleriniz

Uygun olmayan bir talep, adını içeren bir ClaimsParseError fırlatır.

Kullanımdan kaldırma uyarıları

Bir yanıt Deprecation (RFC 9745) veya Sunset (RFC 8594) başlığı taşıdığında SDK, süreç yaşadığı sürece her uç nokta ve başlık değeri için bir uyarı yazar. Uyarı, yöntemi, kimlikler yerine {id} konmuş yolu ve başlık değerlerini içerir; token, sorgu dizesi veya kullanıcı verisi asla içermez. Hiçbir zaman hata fırlatmaz.

Varsayılan olarak uyarı, KeenAuthDeprecationWarning tipiyle process.emitWarning fonksiyonuna gönderilir. Uyarıyı bunun yerine kendi günlükçünüze göndermek için:

const keenauth = new KeenAuth({
  baseUrl: "https://api.eu.keenauth.com/v1",
  apiKey: process.env.KEENAUTH_API_KEY!,
  onWarning: (message) => logger.warn(message),
});

Telemetri başlığı

Her istek Idp-Client: keenauth-ts/<version> (node/<version>) başlığını taşır. Kişisel veri içermez ve kapatılamaz; KeenAuth bunu destek amacıyla ve kullanımdan kaldırılmış SDK sürümleri hakkında sizi bilgilendirmek için kullanır.