Python 서버 SDK

keenauth-python은 Python 3.10 이상을 위한 서버 SDK입니다. 타입이 지정된 메서드로 관리 API를 호출하며, 모든 KeenAuth 서버 SDK가 공통으로 제공하는 기능을 추가로 제공합니다. 여기에는 API 키 또는 private_key_jwt 머신 간 토큰을 사용한 인증, 재시도, 커서 페이지네이션, 타입이 지정된 오류, 웹훅 서명 검사, 지원 중단 경고가 포함됩니다. 이 패키지는 아직 PyPI에 게시되지 않았습니다.

웹 앱에서 로그인을 구현하려면 Django, Flask, FastAPI를 참조하십시오. 베어러 토큰을 받는 API를 보호하려면 API 보호를 참조하십시오.

설치

pip install keenauth-python

private_key_jwt 서명자는 cryptography 패키지가 필요합니다. m2m 추가 기능과 함께 설치하십시오.

pip install "keenauth-python[m2m]"

API 키로 관리 API 호출

import os
from keenauth import KeenAuth

client = KeenAuth("https://api.eu.keenauth.com/v1", os.environ["KEENAUTH_API_KEY"])

page = client.users.list_users(limit=20)
for user in page.data:
    print(user.id)

생성된 모든 API 클래스는 속성으로 사용할 수 있습니다. 예를 들어 client.users, client.organizations, client.api_keys 등을 사용할 수 있습니다. 기본 URL은 https를 사용해야 하며, http는 localhost에서만 허용됩니다. SDK는 리디렉션을 따르지 않으므로 자격 증명이 다른 호스트로 전송되지 않습니다.

private_key_jwt 관리 토큰 사용

관리 애플리케이션은 API 키 대신 개인 키로 인증합니다. SDK는 클라이언트 어서션(RFC 7523)에 서명하고, 환경의 토큰 엔드포인트에서 관리 API 토큰을 가져오며, 만료되기 60초 전에 토큰을 갱신합니다.

import os
from keenauth import KeenAuth
from keenauth.m2m import ManagementTokenSource

source = ManagementTokenSource(
    issuer="https://acme.eu.keenauth.app",          # your environment's default host
    client_id="app_01j9zzzzzzzzzzzzzzzzzzzz",       # a management application
    private_key=os.environ["KEENAUTH_PRIVATE_KEY"],  # unencrypted PEM
    resource="https://api.eu.keenauth.com",          # the management API of your region
    scopes=["users:read", "users:write"],            # optional; default: the grant's default scopes
)
client = KeenAuth("https://api.eu.keenauth.com/v1", token_source=source)

재시도

SDK는 429, 502, 503, 504 응답으로 실패했거나 연결 오류 또는 시간 초과가 발생한 요청을 재시도합니다. 재시도 대상은 GET, PUT, DELETE 요청과 Idempotency-Key가 포함된 POST 요청뿐입니다. If-Match가 포함된 PATCH 요청은 429에서만 재시도됩니다. 속도 제한기는 요청을 실행하기 전에 거부하며, If-Match는 변경 사항이 두 번 적용되지 않도록 합니다. 그 밖의 PATCH 요청은 재시도되지 않습니다. 총 시도 횟수는 최대 3회입니다.

페이지네이션

목록 메서드는 하나의 페이지를 반환합니다. 이 페이지에는 data와 after, before 커서가 포함된 list_metadata가 있습니다. paginate는 모든 페이지를 순회하며, 다음 페이지는 해당 지점에 도달했을 때만 가져옵니다.

from keenauth import paginate

for user in paginate(client.users.list_users, limit=100, status="active"):
    if user.email == "ada@example.com":
        break  # no further page is requested

오류

application/problem+json(RFC 9457) 형식의 오류 응답은 keenauth.ProblemError를 발생시킵니다. 이때 code, status, detail, request_id, errors 필드를 사용하십시오. 이 SDK 버전이 알지 못하는 code도 문자열로 반환되므로, 서버에 새로운 오류 코드가 추가되어도 코드가 중단되지 않습니다.

from keenauth import ProblemError

try:
    client.users.get_user("usr_01j9zzzzzzzzzzzzzzzzzzzz")
except ProblemError as e:
    if e.code == "not_found":
        ...
    print(e.request_id)

웹훅 검증

KeenAuth는 Standard Webhooks 방식으로 웹훅에 서명합니다. WebhookVerifier는 webhook-id, webhook-timestamp, webhook-signature 헤더를 엔드포인트의 idp_whsec_ 시크릿과 대조하여 확인합니다.

import os
from flask import Flask, request
from keenauth.webhooks import WebhookVerificationError, WebhookVerifier

app = Flask(__name__)
verifier = WebhookVerifier(os.environ["KEENAUTH_WEBHOOK_SECRET"])

@app.post("/webhooks/keenauth")
def keenauth_webhook():
    try:
        verifier.verify(request.get_data(), request.headers)
    except WebhookVerificationError as e:
        return {"error": e.reason}, 400
    event = request.get_json()
    ...
    return "", 204

타입이 지정된 이벤트와 클레임

keenauth.events에는 공개 이벤트 스키마에서 생성된 모든 고객 이벤트 유형에 대한 frozen dataclass가 있습니다. parse_event는 검증된 본문을 확인하고 해당 유형의 클래스를 반환합니다. keenauth.webhooks.verify_event는 한 번의 호출로 검증과 파싱을 함께 수행합니다. match 또는 isinstance로 범위를 좁히십시오.

from keenauth.events import EmailSendingSuspendedEvent, UnknownEvent, UserCreatedEvent
from keenauth.webhooks import verify_event

event = verify_event(verifier, request.get_data(), request.headers)
match event:
    case UserCreatedEvent():
        print(event.data.object.id)
    case EmailSendingSuspendedEvent():
        print(event.data.object.reason)
    case UnknownEvent():
        pass  # a type this SDK version does not know yet; event.type and event.raw are still available

keenauth.claims는 검증된 토큰의 클레임에 타입을 지정합니다. 제공되는 함수는 parse_id_token_claims(OpenID Connect Core)와 parse_access_token_claims(RFC 9068)입니다. 이 함수들은 클레임 타입만 확인하고 아무것도 검증하지 않으므로, 검증기가 반환한 claims에 대해 호출하십시오.

from keenauth.claims import parse_access_token_claims

at = verifier.verify_access_token(token)
claims = parse_access_token_claims(at.claims)
claims.client_id     # str
claims.org_roles     # tuple[str, ...] | None
claims.custom        # your own claims

aud는 항상 튜플입니다. 형식이 맞지 않는 클레임이 있으면 이름과 함께 ClaimsParseError가 발생합니다.

지원 중단 경고

응답에 Deprecation(RFC 9745) 또는 Sunset(RFC 8594) 헤더가 있으면, SDK는 프로세스당 한 번씩 표준 logging 모듈을 통해 keenauth 로거에 경고를 기록합니다. 경고에는 메서드, 리소스, 헤더 값이 표시되며, ID, 쿼리 문자열, 자격 증명은 포함되지 않습니다. 요청 자체는 영향을 받지 않습니다.

import logging

logging.getLogger("keenauth").setLevel(logging.WARNING)

텔레메트리 헤더

모든 요청에는 Idp-Client: keenauth-python/<version> (python/<version>) 헤더가 포함됩니다. 이 헤더에는 개인 정보가 포함되지 않으며 끌 수 없습니다. KeenAuth는 이 헤더를 지원 및 지원 중단 안내에 사용합니다.