開発者向け
SSO·SCIM連携仕様
OIDC・SAML 2.0・SCIM 2.0連携に必要な値と動作の仕様です。
画面での設定手順はSSOとSCIMを参照してください。
以下の表の{API}は、お使いの環境のKeural APIアドレスです(例: https://api.keural.ai)。正確な値は組織管理 → SSO画面に表示されているアドレスをそのまま使います。
登録値の要約
| 項目 | 値 |
|---|---|
| OIDC リダイレクトURI | {API}/api/sso/callback |
| OIDC・SAML サインイン開始 | {API}/api/sso/{orgId}/login |
| SAML SP EntityID | {API}/api/sso/saml/metadata |
| SAML ACS URL | {API}/api/sso/saml/callback |
| SCIM Base URL | {API}/scim/v2 |
サインインは常にKeural側から開始します(SP-initiated)。サインイン画面で登録済みドメインのメールアドレスを入力すると、サインイン開始アドレスに移動します。成功するとKeuralのホーム画面に、失敗すると/login?error=ssoに移動します。
OIDC
| 項目 | 動作 |
|---|---|
| フロー | Authorization Code |
| authorize リクエスト | response_type=code、client_id、redirect_uri、scope=openid email profile、state、nonce |
| state · nonce | 1回限りで、10分間有効です。サインインのウィンドウを10分以上開いたままにすると、最初からやり直しになります。 |
| トークン交換 | token endpointへPOST、application/x-www-form-urlencoded。クライアント認証はclient_secret_postです(本文にclient_idとclient_secret)。 |
| ID トークンの署名 | RS256のみ受け付けます。鍵はjwks_uriからkidで探します。 |
| ID トークンの検証 | 署名、exp、audにclient_idが含まれること、nonceの一致、issがIssuer URLと一致すること(末尾の/は無視)。 |
| メールアドレス | ID トークンのemailクレーム。ない場合は、Authorization: Bearer <access_token>でuserinfo endpointを呼び出し、emailを読み取ります。 |
| 名前 | ID トークンのnameクレーム |
| エンドポイント | Issuer URLの/.well-known/openid-configurationから探します。見つからないIdPは、詳細設定を開くで authorization・token・JWKS・userinfo のアドレスを直接入力します。 |
| 時間制限 | IdPへの呼び出しごとに15秒 |
IdPのアプリケーションでclient_secret_postを許可しておく必要があります。client_secret_basicやprivate_key_jwtだけを許可する設定では、トークン交換に失敗します。
SAML 2.0
| 項目 | 動作 |
|---|---|
| リクエスト | AuthnRequestをHTTP-Redirectバインディングで送信します。リクエストには署名しません。 |
| リクエストの内容 | Destination=IdP SSO URL、AssertionConsumerServiceURL=ACS URL、ProtocolBinding=HTTP-POST、Issuer=SP EntityID、NameIDPolicy Format=…:nameid-format:unspecified、AllowCreate=true |
| レスポンス | HTTP-POSTバインディング。SAMLResponseとRelayStateを含みます。RelayStateは、Keuralが送った値をそのまま返す必要があります。 |
| 署名 | ResponseまたはAssertionのどちらかに有効な署名が必要です。検証には画面に登録した証明書だけを使います。 |
| アサーション | レスポンスの中にアサーションがちょうど1つ必要です。暗号化されたアサーション(EncryptedAssertion)は受け付けません。 |
| ステータス | StatusCodeがurn:oasis:names:tc:SAML:2.0:status:Success |
| Issuer | IdP EntityIDを入力した場合は、アサーションのIssuerと一致する必要があります。 |
| 条件 | NotBefore・NotOnOrAfter(許容誤差300秒)、Audience=SP EntityID |
| SubjectConfirmationData | Recipient=ACS URL、NotOnOrAfter(許容誤差300秒)、InResponseTo=Keuralが送ったリクエストID |
| メールアドレス | 属性のNameまたはFriendlyNameが次のいずれか(大文字と小文字を区別しない): email、mail、emailAddress、E-Mail-Addresses、http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress。見つからない場合は、@を含むNameIDを使います。 |
| 名前 | displayName、name、cn、http://schemas.microsoft.com/identity/claims/displayname |
| 証明書 | X.509の証明書を1つ。PEMまたはBase64(DER)。交換するときは、新しい証明書を入力して保存します。 |
| メタデータ | IdPのメタデータXMLをアップロードする代わりに、IdP EntityID・IdP SSO URL・証明書の3つの値を入力します。 |
ユーザーの判定
| 項目 | 動作 |
|---|---|
| SSOに送る基準 | メールアドレスの@の後ろがメールドメイン一覧の項目と完全に一致すること(大文字と小文字を区別しない)。サブドメインは個別に登録します。 |
| アカウントの検索 | IdPから受け取ったメールアドレス(小文字)でKeuralアカウントを探します。 |
| アカウントがない場合 | 未登録ユーザーの自動作成(JIT)がオンなら作成し、オフならサインインを拒否します。 |
| 組織への参加 | 組織のメンバーでない場合は、メンバーとして参加します。座席が埋まっているアカウントや別の組織に属するアカウントは参加せず、サインインだけができます。 |
| メールドメインを保存する条件 | DNS TXTで認証したドメイン。公開メールドメインは除きます。 |
ドメインの認証
| 項目 | 値 |
|---|---|
| レコードの種類 | TXT |
| ホスト | 登録したドメインそのもの(例: acme.com)。接頭辞のサブドメインは使いません。 |
| 値 | keural-verify=<UUID>。画面に表示された値をそのまま使います。 |
| 確認のタイミング | 認証を確認を押したときに一度だけ照会します。 |
SCIM 2.0
| 項目 | 値 |
|---|---|
| Base URL | {API}/scim/v2 |
| 認証 | Authorization: Bearer <SCIMトークン>。トークンはscim_で始まり、発行時に一度だけ表示されます。 |
| Content-Type | リクエストはapplication/scim+jsonまたはapplication/json、レスポンスはapplication/scim+json |
| ステータスコード | 実際のHTTPステータスコードで返します。エラー本文はSCIM Error形式(schemas、status、detail、scimType)です。 |
エンドポイント
| メソッド | パス | 動作 |
|---|---|---|
GET | /Users | 一覧。filter=userName eq "…"、startIndex(既定1)、count(既定100、最大200) |
GET | /Users/{id} | 1人を照会 |
POST | /Users | 作成(201)。同じメールアドレスがあれば409 |
PATCH | /Users/{id} | active、displayName、name.formatted、name.givenNameを変更 |
PUT | /Users/{id} | displayName・name・activeを反映。activeを省略すると有効とみなします。 |
DELETE | /Users/{id} | アカウントを停止(204)。データは削除しません。 |
GET | /Groups、/Groups/{id} | 固定グループ2つを照会。filter=displayName eq "…" |
PATCH | /Groups/{id} | メンバーの追加・削除・置き換え |
GET | /ServiceProviderConfig、/ResourceTypes、/Schemas | 対応機能を照会 |
ユーザーの属性
| 属性 | 用途 |
|---|---|
userName | メールアドレス。ない場合はemails[0].valueを使います。 |
displayName · name.formatted · name.givenName+name.familyName | 表示名 |
active | falseで停止(サインインをブロック)、trueで復旧 |
id | Keuralのユーザー ID。レスポンスに含まれます。 |
externalIdは保存しません。IdPでユーザーを探すときは、userNameフィルターを使います。
グループ
| id | displayName | メンバーを入れると | メンバーを外すと |
|---|---|---|---|
keural-admins | Keural Admins | 管理者 | メンバー |
keural-members | Keural Members | メンバー | 変化なし |
組織オーナーの役割はSCIMでは変わりません。グループの作成・削除(POST・DELETE /Groups)は501を返します。グループメンバーのvalueは、Keuralのユーザー ID(/Usersのid)です。
対応範囲
| 機能 | 対応 |
|---|---|
| PATCH | はい |
| フィルター | userName eq、displayName eq |
| Bulk・並べ替え・ETag・パスワード変更 | いいえ |
エラー
| ステータス | scimType | 原因 |
|---|---|---|
400 | invalidValue | userNameとemailsがどちらもない |
401 | — | トークンがない、または誤っている。SCIMプロビジョニングがオフになっている。 |
404 | — | この組織のユーザーまたはグループではない |
409 | uniqueness | 同じメールアドレスのアカウントがすでにある、座席を超過している |
501 | — | グループの作成・削除 |