Hosted Login#
Hosted Login は Environment の Interaction Domain 上で動作する Zeroword の認証画面である。OIDC/OAuth 2.0 の認可フローを利用する場合に使い、独自のログイン画面を構築する場合は Public Authentication API を使う。
認可フロー#
- アプリは Environment の Canonical Issuer にある
GET /e/{environmentId}/oauth2/authorizeへ OIDC 認可リクエストを送る。Canonical Issuer と Interaction Domain は別の host である。エンドポイント、PKCE、callback の条件は OIDC / OAuth 2.0 を参照する。 - 認可リクエストが有効なら、Authorization Server は短命の認証 transaction を作成し、Interaction Domain の
/へtx、exp、macを付けて302redirect する。この handoff は transaction を Hosted Login へ渡すためのもので、認証処理は Interaction Domain 上で行う。 - Hosted Login は
GET /v1/auth/transactions/{transactionId}で状態とavailable_methodsを読み、theme のmethodsの順を維持しつつ利用可能な方式だけを表示する。方式に応じて Public Authentication API の Email OTP、Passkey、Social login の transaction endpoint を呼び出す。 - 認証後、Hosted Login は
POST /v1/auth/transactions/{transactionId}/completeを呼び、返されたredirect_uriにcodeと元のstateを付けてアプリへ戻る。アプリは通常の OIDC code exchange を行う。
Hosted Login の画面と認証方式#
ログイン画面に表示される方式は、Environment で利用可能な方式と theme の methods の積集合である。methods は表示順も指定する。
| 方式 | Hosted Login の動作 | 有効になる条件 |
|---|---|---|
email_otp |
メールアドレスを入力し、メールで受け取った OTP を入力する。 | 常に利用可能な基本方式で、theme の methods に含める。 |
passkey |
Passkey の sign-in prompt からブラウザーの WebAuthn UI を開始する。Email OTP 認証の直後には Passkey 登録 prompt も表示され、登録を後回しにできる。 | 常に利用可能な基本方式で、theme の methods に含める。既定 RP ID が retired になった後は既定 host の available_methods から除外される。 |
| Social login | 有効な provider ごとのボタンを表示し、provider の認証画面へ遷移する。google、apple、github、microsoft、generic_oidc を扱う。 |
Management API で Social connection が active であること。generic_oidc はさらに owner_confirmed が必要である。方式を theme の methods に含める。 |
| 既存アカウントとの連携 | Social callback が既存アカウントとの連携を必要とする場合、対象 provider と既存方式で再認証する説明画面を表示する。利用者がログインを続け、既存の方式で認証した後に pending identity が連携される。メールアドレス一致だけで自動連携はしない。 | Social provider と既存アカウントの状態によって transaction が link_required になった場合。 |
方式の有効化は /environments/{environmentId}/settings では行わない。この endpoint が現在提供する設定は impersonation_enabled のみであり、ログイン方式を切り替える項目はない。passkey と email_otp は基本方式として利用可能で、Social login は active な Social connection から導出される。画面に出すかどうかと順序は theme の methods で制御する。Social connection の設定は Management API を参照する。
Locale#
Hosted Login は ja と en に対応する。Interaction Domain の / に有効な locale=ja または locale=en があればそれを使い、それ以外または未指定なら theme の defaultLocale を使う。通常の /authorize redirect は transaction handoff の tx、exp、mac を設定するが、認可リクエストの locale は引き継がないため、標準フローの locale は defaultLocale で決まる。
Theme の設定#
Theme は Environment ごとの Hosted Login 外観と表示方式を指定する。正規の JSON Schema は specs/theme.schema.json である。許可されるプロパティは次のとおり。
| プロパティ | 許可値 |
|---|---|
logoUrl |
任意。HTTPS URL。 |
appearance.primaryColor, backgroundColor, textColor |
#rgb、#rrggbb、#rrggbbaa 形式の hex color。 |
appearance.borderRadius |
0–24 の整数ピクセル。 |
appearance.fontFamily |
system、sans、serif、mono のいずれか。任意の外部 font は指定できない。 |
appearance.density |
comfortable または compact。 |
methods |
passkey、email_otp、google、apple、github、microsoft、generic_oidc の重複しない非空配列。配列順が画面の表示順になる。 |
defaultLocale |
ja または en。 |
termsUrl, privacyUrl, supportUrl |
任意。HTTPS URL。画面の legal/support link に使う。 |
Theme は strict schema であり、上記以外のキー、任意 HTML、任意 JavaScript、inline event handler、script URL、data URL の SVG、任意 CSS は受け付けない。Theme に任意の文言を挿入する項目もない。色、数値、URL、enum は schema で制限され、値は CSS custom properties へ変換される。
Management API の theme endpoint は environments:read / environments:write scope を使う。GET は { environment_id, version, theme } と ETag を返す。PUT は theme オブジェクト全体を body に送る。If-Match は任意だが、指定する場合は直前の GET で返った ETag を使う。ETag が stale、または保存中に競合が起きた場合は 412 precondition_failed、schema 不正は 400 invalid_theme になる。If-Match を省略すると ETag による事前条件チェックは行われない。Preview endpoint は CSS custom properties を返す。
export MANAGEMENT_API=https://api.zeroword.smartcrab.ai/v1
export AUTH_PLATFORM_API_KEY='<api-key>'
export ENVIRONMENT_ID='<environmentId>'
curl -sS -D theme.headers \
-H "Authorization: Bearer ${AUTH_PLATFORM_API_KEY}" \
"${MANAGEMENT_API}/environments/${ENVIRONMENT_ID}/theme"
curl -sS \
-H "Authorization: Bearer ${AUTH_PLATFORM_API_KEY}" \
"${MANAGEMENT_API}/environments/${ENVIRONMENT_ID}/theme/preview-css"
Theme の変更には、If-Match に直前の GET で取得した ETag を指定する条件付き更新を推奨する。body には上記 schema に適合する完全な theme オブジェクトを PUT /environments/{environmentId}/theme へ送る。GET /environments/{environmentId}/settings と PATCH /environments/{environmentId}/settings は impersonation_enabled を読み書きする別設定 API である。
Custom Domain と Passkey の RP ID#
Custom Domain は Management API の /domains で Environment に登録する。登録直後の status は pending であり、DNS と証明書の検証が完了して active になるまで、その host は有効な Interaction Domain として受理されない。
curl -sS -X POST \
-H "Authorization: Bearer ${AUTH_PLATFORM_API_KEY}" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: <unique-key>' \
--data '{"environment_id":"<environmentId>","hostname":"auth.customer.example","rp_enabled":true}' \
"${MANAGEMENT_API}/domains"
POST /domains は 201 と Domain object を返す。response には id、environment_id、hostname、status、rp_enabled、validation_errors、created_at、updated_at、activated_at が含まれる。status の値は pending、active、moved、failed、deleting であり、validation_errors は検証エラー文字列の配列、activated_at は有効化時刻(未有効なら null)である。
DNS 設定は response に含まれない。登録した hostname に次の CNAME を作成する。証明書は CNAME 経由の HTTP 検証で自動発行されるため、TXT record は不要である。
| Type | Name | Target |
|---|---|---|
CNAME |
auth.customer.example (登録した hostname) |
saas-fallback.zeroword.smartcrab.ai |
DNS 事業者が proxy 機能を持つ場合は無効 (DNS only) にする。CNAME の反映後に POST /domains/{domainId}/retry-validation を呼ぶと最新の検証状態を再確認し、結果に応じて Domain の status と validation_errors を更新する。GET /domains/{domainId} で状態を確認する。
rp_enabled: true の active な Custom Domain は、その Environment の Interaction Domain と WebAuthn RP ID の両方になる。1 Environment につき rp_enabled の Custom Domain は 1 つまでである。Production で Passkey を登録する前に Custom Domain を設定する。既定構成では Interaction Domain と RP ID はともに Default Interaction Domain であり、Custom Domain の有効化後はともにその hostname になる。
RP ID は Passkey credential に束縛されるため、Custom Domain の有効化後は旧 RP ID と新 RP ID の Passkey が併存する移行期間を設ける。利用者は旧 RP ID の Passkey(ブラウザーが WebAuthn Related Origin Requests に対応する場合)、または Email OTP / Social login で再認証し、新 RP ID 上で Passkey を登録する。旧 RP ID の Passkey を Custom Domain から直接使うには、旧 RP ID の /.well-known/webauthn が新しい origin を許可する必要がある。対応しない browser では Email OTP / Social login を使う。
移行状態は次で取得する。migrated_share は移行対象者のうち新 RP ID の Passkey を持つ利用者の割合であり、集計対象は失効していない Passkey である。
curl -sS \
-H "Authorization: Bearer ${AUTH_PLATFORM_API_KEY}" \
"${MANAGEMENT_API}/environments/${ENVIRONMENT_ID}/rp-migration"
POST /environments/{environmentId}/rp-migration/disable-legacy に {"confirm_rp_id":"<legacyRpId>"} を送ると旧 RP を無効化する。入力値は旧 RP ID と完全一致する必要がある。この操作は取り消せない。旧 RP を無効化した後は既定 host での passkey 操作が拒否され、rp_enabled domain の解除や削除も拒否される。移行を完了する前に無効化してはならない。
Native app association files#
Native app の Passkey 関連付けは Canonical Issuer ではなく Environment の Interaction Domain 上で取得する。
| Platform | Endpoint | 生成元 |
|---|---|---|
| iOS | /.well-known/apple-app-site-association |
登録済み mobile app の Apple Team ID と bundle ID。 |
| Android | /.well-known/assetlinks.json |
登録済み mobile app の package name と SHA-256 certificate fingerprint。 |
未登録アプリは含まれない。両 endpoint は Cache-Control: public, max-age=300 と弱い ETag を返す。If-None-Match が現在の config_version に一致すれば body なしの 304 を返す。iOS は Associated Domains、Android は App Links / Credential Manager の設定で該当する Interaction Domain を使う。React Native SDK のセットアップは React Native SDK (@auth-platform/react-native) を参照する。
CSP#
HTML response には次の Content Security Policy が設定される。
default-src 'none';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' https: data:;
connect-src 'self';
font-src 'self';
frame-ancestors 'none';
base-uri 'none';
form-action 'self';
object-src 'none';
Hosted Login HTML は次の security headers も返す。
| Header | Value |
|---|---|
Cross-Origin-Opener-Policy |
same-origin |
Cross-Origin-Resource-Policy |
same-origin |
Referrer-Policy |
no-referrer |
X-Content-Type-Options |
nosniff |
X-Frame-Options |
DENY |
style-src の inline style allowance は、安全に検証された Theme の値を CSS custom properties として設定するためのものであり、任意 CSS や HTML/JavaScript の拡張を許可するものではない。