Public Authentication API#
この API は、Hosted Login を使わずにログイン画面を構築するための Public Authentication API である。OIDC 認可コードフローの transaction、Email OTP、Passkey、Social login、認証後の自ユーザー管理を提供する。
Base URL#
同じ Public Authentication API を、Environment の Interaction Domain または Canonical Issuer で呼び出せる。
| 形式 | Base URL | 用途 |
|---|---|---|
| Interaction Domain | https://<interaction-domain>/v1 |
Hosted Login と同じ Interaction Domain 上で認証する。Passkey の RP ID と Origin は Interaction Domain に結び付く。通常の Headless UI ではこちらを使う。 |
| Canonical Issuer alias | https://id.zeroword.smartcrab.ai/e/<environmentId>/v1 |
Canonical Issuer だけを知る Client や Native Client から使う。Environment は path の <environmentId> で指定し、host は Canonical Issuer でなければならない。 |
Default Interaction Domain は env-<environmentId の env_ 以降>.login.zeroword.smartcrab.ai である。Environment で有効な Custom Domain が設定されている場合は、その Interaction Domain を使う。Canonical Issuer、Interaction Domain、RP ID の関係は概念とテナントモデルを参照する。
例では次の値を使う。
AUTH_ENVIRONMENT_ID="<environmentId>"
AUTH_API="https://<interaction-domain>/v1"
AUTH_ISSUER_ENV="https://id.zeroword.smartcrab.ai/e/$AUTH_ENVIRONMENT_ID"
AUTH_CLIENT_ID="<clientId>"
AUTH_REDIRECT_URI="https://app.example.com/auth/callback"
Canonical Issuer alias を使う場合は、AUTH_API="$AUTH_ISSUER_ENV/v1" とする。各 Endpoint の path は、上記どちらかの Base URL に続けて指定する。
統合方法の選択#
通常の OIDC ログインで Hosted Login へ遷移する場合は、アプリから GET /oauth2/authorize を呼び出す。Authorization Server が認可 request から内部 transaction を作成し、Interaction Domain へ handoff する。この経路に対して POST /v1/auth/transactions を重ねて呼ばない。
独自ログイン UI では、OIDC authorize redirect を開始せず、アプリが保持する client_id、redirect_uri、PKCE、state、scope を POST /v1/auth/transactions へ渡す。これは独立した認証 transaction を作るが、Client 登録、許可済み redirect URI、PKCE を省略できる standalone login ではない。
/v1/config は公開 Environment 設定を返し、/v1/me 以下の Endpoint は OIDC access token で認証する。Token Endpoint、scope、TTL、Client 認証の詳細はOIDC / OAuth 2.0を参照する。
公開設定#
GET /v1/config?client_id=<clientId> は現在の Host から Environment を解決し、Client の公開設定を返す。client_id は必須である。レスポンスには issuer、rp_id、available_methods、theme、sdk_compatibility_version、legal が含まれる。available_methods には passkey、email_otp および有効な Social provider が入る。Provider secret や内部構成は返さない。
curl "$AUTH_API/config?client_id=$AUTH_CLIENT_ID"
Transaction lifecycle#
作成#
POST /v1/auth/transactions は 201 Created を返す。client_id、redirect_uri、code_challenge、code_challenge_method: "S256"、state、scope は必須。nonce、resource、response_mode は任意である。PKCE の plain は使えない。redirect_uri は Client に登録された値と完全一致させる。
curl -i -X POST "$AUTH_API/auth/transactions" \
-H 'content-type: application/json' \
-d '{
"client_id": "<clientId>",
"redirect_uri": "https://app.example.com/auth/callback",
"code_challenge": "<base64url-sha256-of-code-verifier>",
"code_challenge_method": "S256",
"state": "<random-state>",
"nonce": "<random-nonce>",
"scope": "openid profile email offline_access",
"resource": ["https://api.example.com"],
"response_mode": "redirect"
}'
response_mode は redirect または native_return である。resource は最大 20 個の URI を指定できる。作成レスポンスは transaction_id、expires_at、available_methods を返す。transaction の TTL は 10 分である。
状態取得、cancel、complete#
| Method | Path | 動作 |
|---|---|---|
GET |
/auth/transactions/{transactionId} |
現在の状態、期限、利用可能な認証方式、必要な場合は method と pending_link を返す。 |
POST |
/auth/transactions/{transactionId}/cancel |
body なし。failed にして再開不可にする。 |
POST |
/auth/transactions/{transactionId}/complete |
body なし。authenticated の transaction を完了し、1 回限りの authorization code を返す。 |
状態は created → interaction_started → challenge_issued → authenticated → code_issued → consumed と進む。Social account linking が必要な場合は link_required になる。キャンセル後は failed、TTL 超過後は expired である。各 verify Endpoint は成功時に authenticated へ進めるが、access token / refresh token は返さない。complete のレスポンスに含まれる state は作成時の値と照合し、redirect_uri は Client 登録値と再照合する。authorization code の TTL は 60 秒である。
curl -i "$AUTH_API/auth/transactions/<transactionId>"
curl -i -X POST "$AUTH_API/auth/transactions/<transactionId>/complete"
complete で得た authorization_code を、元の PKCE verifier と redirect URI で Token Endpoint へ交換する。
curl -X POST "$AUTH_ISSUER_ENV/oauth2/token" \
-H 'content-type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code=<authorization_code>' \
--data-urlencode "redirect_uri=$AUTH_REDIRECT_URI" \
--data-urlencode 'code_verifier=<original-code-verifier>' \
--data-urlencode "client_id=$AUTH_CLIENT_ID"
SPA / React Native Client では Client secret を送らず、PKCE を使う。Token Endpoint は OIDC access token と、grant に応じて refresh token・ID token を返す。/v1/me には ID token ではなく access token を使う。
Email OTP#
OTP は 6 桁、TTL は 5 分である。Environment・email・purpose ごとに同時に有効な code は 1 つであり、保存時は server pepper 付き HMAC を用いる。誤った code の verify は最大 5 回で、5 回目に challenge を失効する。Resend は最短 30 秒間隔であり、再送時には generation が増えて以前の code が無効になる。
| Method | Path | Request | 成功時 |
|---|---|---|---|
POST |
/auth/transactions/{transactionId}/email/start |
{"email":"user@example.com"} |
202、challenge_id と expires_at |
POST |
/auth/transactions/{transactionId}/email/resend |
{"challenge_id":"<challengeId>"} |
202、新しい challenge 情報 |
POST |
/auth/transactions/{transactionId}/email/verify |
{"challenge_id":"<challengeId>","code":"123456"} |
200、transaction_id と status: "authenticated" |
メールアドレスが既存かどうかをレスポンスから判別できない。既存・未登録アドレスの start は同じ HTTP status と response shape を返し、UI には「コードを送信できる場合は送信した」と表示する。suppression 対象への送信も外部レスポンスを変えない。resend_too_soon などの 429 では Retry-After を確認し、challenge 状態を取り直してから再試行する。Verify 後は別途 transaction を complete する。
Passkey / WebAuthn#
WebAuthn の binary 値は Base64URL で JSON に直列化する。ブラウザでは options の Base64URL field を ArrayBuffer へ戻し、navigator.credentials.create() または navigator.credentials.get() へ渡す。返された PublicKeyCredential は Base64URL へ変換して verify Endpoint へ送る。Browser の credential origin は、Environment の Interaction Domain(active な Custom Domain が RP として有効ならその Domain)または ceremony で選択した RP ID の HTTPS origin のいずれかに一致させる。
登録#
認証済みで fresh な transaction(直前の OTP / Social 再認証を含む)または fresh session が必要である。
| Method | Path | Request | Response |
|---|---|---|---|
POST |
/auth/transactions/{transactionId}/passkeys/registration/options |
body なし。Native で RP を明示する場合は optional な rp_id を指定できる。 |
WebAuthn creation options |
POST |
/auth/transactions/{transactionId}/passkeys/registration/verify |
{"credential":{"id":"<base64url>","rawId":"<base64url>","type":"public-key","response":{"clientDataJSON":"<base64url>","attestationObject":"<base64url>"}},"name":"<optional-label>"} |
登録した passkey summary と transaction status |
Creation options の JSON は rp: {id, name}、user: {id, name, displayName}、challenge、pubKeyCredParams、timeout、excludeCredentials、authenticatorSelection、attestation を含む。user.id は opaque な user handle であり、email を入れない。residentKey: "required"、userVerification: "required"、attestation: "none" は固定値である。Platform authenticator と security key の双方を許可する。
Verify payload の credential.response には clientDataJSON と attestationObject が必須で、transports、publicKey、publicKeyAlgorithm などは Authenticator が返した場合に含められる。Server は challenge、origin、RP ID、UP、UV、signature を検証し、challenge は成功・失敗を問わず再利用できない。
/v1/me/passkeys/registration/verify でも、clientDataJSON.origin は上記の WebAuthn origin と一致しなければならない。Client の allowed_origins は CORS 用であり、別の app origin を WebAuthn verifier の許可 origin には追加しない。Android Native の origin は登録済み mobile app の署名 fingerprint から導出する。
認証#
| Method | Path | Request | Response |
|---|---|---|---|
POST |
/auth/transactions/{transactionId}/passkeys/authentication/options |
application/json body。email は optional で credential を絞れる。rp(active / legacy)または rp_id も指定可能で、両方は同時に指定できない。指定なしなら {} を送る。 |
WebAuthn request options |
POST |
/auth/transactions/{transactionId}/passkeys/authentication/verify |
{"credential":{"id":"<base64url>","rawId":"<base64url>","type":"public-key","response":{"clientDataJSON":"<base64url>","authenticatorData":"<base64url>","signature":"<base64url>"}}} |
transaction_id と status: "authenticated" |
Discoverable credential によるユーザー名なしの認証が標準である。Options response は challenge、rpId、timeout、allowCredentials、userVerification: "required" を含む。任意の email で絞った場合も、該当 credential の有無をレスポンスから判別できないようにする。Verify 後は complete を呼び、code を Token Endpoint へ交換する。sign counter の変化だけで同期 passkey を直ちに block しない。
/v1/me/passkeys 以下の追加登録は Bearer access token で認証する。List は credential ID、公開鍵、sign count を返さない。最後の認証手段を削除しようとすると last_factor_deletion_requires_confirmation で拒否される。
Social login#
利用可能な provider segment は google、apple、github、microsoft、generic_oidc である。Environment で active な connection だけを開始できる。POST /auth/transactions/{transactionId}/social/{provider}/start は body なしで、{"authorization_url":"https://..."} を返す。System browser へ遷移し、embedded WebView は使わない。
Provider callback は /v1/auth/social/{provider}/callback である。Managed connection は Canonical Issuer の /e/{environmentId}/v1/auth/social/{provider}/callback へ、BYO connection は Environment の Interaction Domain へ戻る。Callback に transaction ID path parameter はなく、state に含まれる署名済み transaction ID から transaction を復元する。Provider は GET query、または POST の form / JSON body で state と code(拒否時は error / error_description)を返す。認証成功後、通常の redirect mode では Interaction Domain へ戻るため、Client は transaction 状態を取得して complete する。Native return mode では登録 redirect URI に tx、元の state、social=completed が付いて戻る。
/v1/me/identities/{provider}/link は既存ユーザーの identity linking を開始する。fresh な Bearer session と {"redirect_uri":"<redirect-uri>"} が必要で、レスポンスは同じ authorization_url shape である。redirect_uri は呼び出し元 Client に登録済みの redirect URI と byte-for-byte 完全一致し、fragment を含めない。不一致は 400 (invalid_redirect_uri) を返す。OAuth callback 後の app return 先として link state に保存され、callback はこの URI へ結果 query を付けて redirect する。Provider callback は transaction ID ではなく署名済み link state を使う。Email 一致だけで自動 link / account merge はしない。GET /v1/me/identities で一覧を取得し、DELETE /v1/me/identities/{identityId} で unlink する。
/v1/me self-service#
すべての Endpoint で OIDC access token を Authorization: Bearer <access_token> に設定する。Hosted Login の session cookie や ID token は認証に使わない。Bearer token を明示的な HTTP header で送るため、CSRF token は要求されない。Email 変更、全 session 失効など security version を更新する操作後は、再認証して access token を取得し直す。
| Method | Path | Request / response |
|---|---|---|
GET |
/me |
プロフィール。email、verification 状態、name、avatar_url、locale、timezone、status、作成・最終 login 時刻などを返す。 |
PATCH |
/me |
更新可能 field は name、avatar_url、locale、timezone。email は更新不可。成功時は更新後プロフィールを返す。 |
POST |
/me/email/change/start |
{"new_email":"new@example.com"}。現在の email へ OTP を送り、202 で challenge を返す。 |
POST |
/me/email/change/verify-old |
{"challenge_id":"<old-challenge>","code":"123456"}。旧 email を確認し、新 email 宛の challenge を 202 で返す。 |
POST |
/me/email/change/verify-new |
{"challenge_id":"<new-challenge>","code":"123456"}。成功時は {"email":"new@example.com","email_verified":true} を返し、email を切り替える。 |
GET |
/me/identities |
linked Social identities の identity_id、provider、link 時刻、最終利用時刻を返す。 |
POST |
/me/identities/{provider}/link |
fresh session が必要。{"redirect_uri":"<redirect-uri>"} は provider callback 後の app return URL である。authorization_url を得て system browser を開く。 |
DELETE |
/me/identities/{identityId} |
自ユーザーの identity を unlink し、{"identity_id":"<identityId>","unlinked":true} を返す。 |
GET |
/me/passkeys |
自ユーザーの passkey summary を返す。credential ID と公開鍵は含まない。 |
POST |
/me/passkeys/registration/options |
Bearer access token で追加登録 options を取得する。body なし。Native で RP を明示する場合は optional な {"rp_id":"<hostname>"} を送る。 |
POST |
/me/passkeys/registration/verify |
{"credential":{...WebAuthn registration credential...},"name":"<optional-label>"}。成功時は登録 passkey summary を返す。 |
DELETE |
/me/passkeys/{passkeyId} |
自ユーザーの passkey を削除し、{"passkey_id":"<passkeyId>","deleted":true} を返す。最後の認証手段は削除できない。 |
GET |
/me/sessions |
session_id、client_id、device_name、作成時刻、最終活動時刻、現在の session かを返す。 |
DELETE |
/me/sessions/{sessionId} |
指定 session を失効し、{"session_id":"<sessionId>","revoked":true} を返す。現在の session を失効すると、その後の API call には新しい認証が必要になる。 |
DELETE |
/me/sessions |
すべての session を失効し、{"revoked":true} を返す。 |
DELETE |
/me |
body なし。fresh session が必要。論理削除状態 pending_deletion へ移し、user_id と status を返す。 |
fresh session は auth_time が直近 5 分以内であることを指す。Email 変更は旧・新 email 両方の所有確認が必須で、旧 email へ変更通知を送る。変更成功後は security version が更新され、以前の access token が無効になるため再認証する。Email 変更用 challenge の期限は 5 分である。Login OTP の resend route は Email 変更にはない。
CORS と Allowed Origins#
Browser UI から cross-origin で呼ぶ場合、Client の Allowed Origins へ UI の Origin を正確に登録する。Wildcard origin は使わない。JSON request や Authorization header は preflight を発生させるため、OPTIONS を通せる Origin であることも確認する。未登録 Origin は 403 origin_not_allowed となる。Native Client や same-origin server-to-server request ではブラウザ CORS preflight は発生しない。
Errors#
Public Authentication API の error body は RFC 9457 Problem Details(application/problem+json)で、すべての response に X-Request-Id が付く。概形は次のとおりである。
{
"type": "https://docs.example-auth.com/errors/resend-too-soon",
"title": "Too Many Requests",
"status": 429,
"code": "resend_too_soon",
"request_id": "req_<request-id>"
}
Problem Details の code は拡張される可能性のある文字列であり、固定の enum ではない。未知の code を許容し、必要な分岐だけを行う。完全な schema は specs/public-api.openapi.yaml を参照する。よく使う code の例を示す。
| HTTP | code |
例 |
|---|---|---|
| 400 | invalid_request, invalid_request_body |
JSON / input shape が不正 |
| 400 | invalid_code, webauthn_verification_failed, state_mismatch |
OTP、WebAuthn、Social state の検証失敗 |
| 400 | passkey_not_found, identity_not_found |
/v1/me の対象 credential / identity が見つからない |
| 400 | last_factor_deletion_requires_confirmation |
最後の認証手段を削除しようとした |
| 401 | unauthorized, invalid_token |
Bearer token がない、期限切れ、失効済み、または security version が古い |
| 403 | origin_not_allowed, new_user_creation_blocked |
Allowed Origin 拒否、または Environment の新規ユーザー作成 gate |
| 404 | auth_transaction_not_found, session_not_found, connection_not_found |
transaction、session、provider connection が見つからない |
| 409 | transaction_not_authenticated, email_already_registered |
認証前の complete、または既存 email との競合 |
| 410 | auth_transaction_expired |
transaction 期限切れ |
| 429 | rate_limited, resend_too_soon |
Rate limit。OTP resend のときは Retry-After を確認する |
| 503 | user_unavailable |
user / session state または security status の参照に失敗した一時障害。再認証せず retry する。 |
| OAuth Token Endpoint のエラーは OAuth error response であり、この Problem Details 表とは別である。再試行、Rate limit、Problem Details の共通方針はErrors、rate limit、retry、冪等性を参照する。 |