Test kiti ile çevrimdışı test etme

Her sunucu SDK'sının (Go, TypeScript ve Python) birim testleri ve CI için bir testing modülü vardır. Bu modül, sabit bir test anahtarıyla imzalanmış erişim belirteçleri ve kimlik belirteçleri üretir, yalnızca bu belirteçleri kabul eden bir belirteç doğrulayıcı oluşturur, ağ erişimi gerektirmeden çalışır, örnek olay yükleri sunar ve webhook teslimlerini herkese açık bir test sırrıyla imzalar. Testleriniz KeenAuth ortamı olmadan, kimlik bilgisi olmadan ve internet bağlantısı olmadan çalışır.

Nasıl çalışır

Test modu diğer kontrolleri zayıflatmaz: süresi dolmuş belirteçler, yanlış hedef kitle, değiştirilmiş yük, eksik jti ve DPoP'ye bağlı ama kanıtı olmayan bir belirteç, üretimdekiyle aynı şekilde reddedilir. Tam liste için API'nizde belirteçleri doğrulama sayfasına bakın.

Test modunu yalnızca test kodunda kullanın. Test belirteçlerini herkes imzalayabilir, dolayısıyla bu modu etkinleştiren bir servis sahte belirteçleri kabul ederdi.

Go

Paket keenauthtest adındadır ve net/http/httptest tarzını izler.

import (
	"github.com/keenauth/keenauth-go/keenauthtest"
	"github.com/keenauth/keenauth-go/verify"
)

func TestOrdersAPI(t *testing.T) {
	v, err := keenauthtest.NewVerifier(verify.Config{Audience: "https://api.acme.example"})
	if err != nil {
		t.Fatal(err)
	}
	token, err := keenauthtest.AccessToken("https://api.acme.example",
		keenauthtest.WithClaims(map[string]any{"scope": "orders:read", "org_id": "org_01m3vnbwg0fvav6zw6w7v3st0r"}))
	if err != nil {
		t.Fatal(err)
	}
	// Pass v to the handler under test and send "Authorization: Bearer " + token.
	claims, err := v.VerifyAccessToken(context.Background(), token, nil)
	if err != nil || claims.Scope != "orders:read" {
		t.Fatal(err)
	}
}

keenauthtest.IDToken(clientID, ...) bir kimlik belirteci üretir. WithLifetime geçerlilik süresini değiştirir (negatif bir değer süresi dolmuş bir belirteç üretir) ve WithIssuedAt düzenlenme zamanını ayarlar. WithClaims içinde nil değeri bir talep alanını kaldırır. Paketi kullanmadan verify.Config{TestingMode: true} değerini kendiniz ayarlayabilirsiniz.

TypeScript

Modül @keenauth/node/testing alt yoludur.

import { createTestVerifier, mintAccessToken } from "@keenauth/node/testing";

const verifier = createTestVerifier({ audience: "https://api.acme.example" });
const token = mintAccessToken("https://api.acme.example", {
  claims: { scope: "orders:read", org_id: "org_01m3vnbwg0fvav6zw6w7v3st0r" },
});

const claims = await verifier.verifyAccessToken(token);
// claims.subject, claims.scope, claims.claims.org_id

mintIdToken(clientId, ...) bir kimlik belirteci üretir. Seçenekler claims (null değeri bir talep alanını kaldırır), lifetimeSeconds ve issuedAt'tir. Modülü kullanmadan createVerifier fonksiyonuna testing: true geçebilirsiniz.

Python

Modül keenauth.testing olup doğrulayıcı gibi verify ek paketini gerektirir.

from keenauth import testing

verifier = testing.verifier(audience="https://api.acme.example")
token = testing.mint_access_token(
    "https://api.acme.example",
    claims={"scope": "orders:read", "org_id": "org_01m3vnbwg0fvav6zw6w7v3st0r"},
)

claims = verifier.verify_access_token(token)
# claims.subject, claims.scope, claims.claims["org_id"]

testing.mint_id_token(client_id, ...) bir kimlik belirteci üretir. Anahtar kelime argümanları claims (None değeri bir talep alanını kaldırır), lifetime_seconds ve issued_at'tir. Modülü kullanmadan VerifierConfig içine testing=True geçebilirsiniz.

Varsayılan talep alanları

Talep Erişim belirteci Kimlik belirteci
iss https://test.keenauth.invalid https://test.keenauth.invalid
sub usr_01m3vnbwg0e8mbe7h7xxp6rmkc usr_01m3vnbwg0e8mbe7h7xxp6rmkc
aud geçtiğiniz hedef kitle geçtiğiniz istemci kimliği
client_id app_01m3vnbwg0fqba5ntanfd63s8n —
iat, exp şu an, şu an + 3600 saniye şu an, şu an + 3600 saniye
jti rastgele —
auth_time — iat ile aynı

Erişim belirteci başlığında typ: at+jwt bulunur (RFC 9068). scope, org_id, permissions, acr, amr veya auth_time gibi API'nizin okuduğu talepleri ekleyin. Kimlik belirteçleri için kodunuz bir nonce kontrol ediyorsa bu talebi ekleyin.

Örnek olaylar

Kit, yaygın olayların örnek yüklerini içerir: user.created, user.updated, user.deleted, session.created, session.revoked, organization.created ve organization_membership.created. Bunlar KeenAuth'un gönderdiği olaylarla aynı zarfı ve şemaları kullanır; varsayılan ince modda çalışırlar: tanımlayıcılar, durum ve değişen alan adları içerir, kişisel veri içermezler. Olay işleyicilerinizi test etmek için bunları kullanın.

Webhook'ları test etme

Kit, bir payload'ı tıpkı bir KeenAuth webhook teslimi gibi imzalar (Standard Webhooks v1): ham gövdeyi ve webhook-id, webhook-timestamp ve webhook-signature başlıklarını döndürür. İşleyiciniz bunu, üretimde çalışan aynı kod olan SDK'nın webhook doğrulayıcısıyla doğrular. Yalnızca sır farklıdır.

Node

import { Webhook, WebhookVerificationError } from "@keenauth/node/webhooks";
import { sampleEvent, signWebhook, testWebhookSecret } from "@keenauth/node/testing";

const webhook = new Webhook(testWebhookSecret()); // in production: process.env.KEENAUTH_WEBHOOK_SECRET

const delivery = signWebhook(sampleEvent("user.created"));
const event = webhook.verify(delivery.body, delivery.headers); // the parsed event

// A delivery from an hour ago is refused.
const old = signWebhook(sampleEvent("user.created"), { timestamp: Math.floor(Date.now() / 1000) - 3600 });
try {
  webhook.verify(old.body, old.headers);
} catch (e) {
  // e instanceof WebhookVerificationError, e.kind === "timestamp"
}

signWebhook(payload, options) bir dize, bir Uint8Array veya bir nesne alır (JSON.stringify ile serileştirilir). Seçenekler secret, id ve timestamp'tir (Unix saniyesi veya bir Date). Bir HTTP işleyicisini test etmek için delivery.body değerini ham istek gövdesi olarak, delivery.headers değerini ve Content-Type: application/json başlığını göndərin.

Python

import time

from keenauth import testing
from keenauth.webhooks import WebhookTimestampError, WebhookVerifier

verifier = WebhookVerifier(testing.webhook_secret())  # in production: os.environ["KEENAUTH_WEBHOOK_SECRET"]

delivery = testing.sign_webhook(testing.sample_event("user.created"))
verifier.verify(delivery.body, delivery.headers)

# A delivery from an hour ago is refused.
old = testing.sign_webhook(testing.sample_event("user.created"), timestamp=int(time.time()) - 3600)
try:
    verifier.verify(old.body, old.headers)
except WebhookTimestampError:
    pass

testing.sign_webhook(payload, secret=None, msg_id=None, timestamp=None) bayt dizisi, dize veya sözlük alır (sıkıştırılmış JSON olarak serileştirilir) ve delivery.body (bayt) ile delivery.headers (sözlük) değerlerini döndürür. Flask veya FastAPI test istemcisiyle delivery.body değerini ham gövde, delivery.headers değerini başlık olarak gönderin.

Go

import (
	"net/http"
	"net/http/httptest"

	"github.com/keenauth/keenauth-go/keenauthtest"
	"github.com/keenauth/keenauth-go/webhook"
)

func TestWebhookHandler(t *testing.T) {
	v, err := webhook.NewVerifier([]string{keenauthtest.WebhookSecret()}) // in production: os.Getenv("KEENAUTH_WEBHOOK_SECRET")
	if err != nil {
		t.Fatal(err)
	}
	body, err := keenauthtest.Event("user.created")
	if err != nil {
		t.Fatal(err)
	}
	delivery, err := keenauthtest.SignWebhook(body)
	if err != nil {
		t.Fatal(err)
	}
	req, err := delivery.Request("http://localhost/webhooks/keenauth")
	if err != nil {
		t.Fatal(err)
	}
	rec := httptest.NewRecorder()
	newWebhookHandler(v).ServeHTTP(rec, req) // your handler, which calls v.Verify(r.Header, body)
	if rec.Code != http.StatusOK {
		t.Fatalf("status %d", rec.Code)
	}
}

keenauthtest.SignWebhook(payload, ...) delivery.Body ve delivery.Header değerlerini döndürür; delivery.Request(url) Content-Type: application/json başlığıyla POST isteği oluşturur. Seçenekler WithWebhookSecret, WithWebhookID ve WithWebhookTimestamp'tir.

Kitin yapmadıkları