Authagonal
ドキュメント
Authagonal を使い始めるために必要なことはすべてここにあります。最初のテナントの作成から、SSO、SCIM、カスタムブランディングの設定まで扱います。
はじめに
Authagonal は、テナントごとに標準に完全準拠した OIDC サーバーを提供します。各テナントは独自の発行者 URL、ディスカバリードキュメント、トークンエンドポイントを持ち、テナント間で共有されるインフラストラクチャはありません。ゼロから動作するログインフローまで、5 分以内でたどり着けます。
アカウントの作成
authagonal.io でサインアップし、アカウントのスラッグを選択します。スラッグは発行者ドメイン {slug}.authagonal.io になります。アカウントを作成したら、メールアドレスを確認して利用を開始してください。


サインアップ時に、アカウント固有のスラッグを選択します
クライアントの登録
ポータルのサイドバーで クライアント を開き、新しいクライアント をクリックします。アプリケーションの clientId と clientName を入力します。次に、クライアントの URI タブで、リダイレクト URI を少なくとも 1 つ追加します。これは認証後にユーザーが送られる先です。例:https://app.example.com/callback。新しいクライアントではデフォルトでクライアントシークレットが必須のため、バックエンドを持たないブラウザアプリの場合は シークレットを必須にする を 全般 タブでオフにしてください。


ポータルで新しい OAuth クライアントを登録します
ローカル開発
http://localhost:3000/callback を使用してください。Authagonal は、localhost オリジンに対しては HTTPS 以外のリダイレクト URI を許可します。最初のログイン
最も手早く統合する方法は、JavaScript および TypeScript アプリケーション向けの軽量な OIDC クライアントライブラリ oidc-client-ts を使うことです。
import { UserManager } from 'oidc-client-ts';
const mgr = new UserManager({
authority: 'https://acme.authagonal.io',
client_id: 'my-app',
redirect_uri: 'https://app.example.com/callback',
response_type: 'code',
scope: 'openid profile email',
});
// Redirect to login
mgr.signinRedirect();
// On callback page
const user = await mgr.signinRedirectCallback();
console.log(user.profile); // { sub, email, name, ... }ライブラリを使わない最小構成がよければ、標準の OAuth 2.0 認可コードフローを素の fetch で実装できます:
// 1. Redirect the user to the authorization endpoint
const authorizeUrl = new URL('https://acme.authagonal.io/connect/authorize');
authorizeUrl.searchParams.set('client_id', 'my-app');
authorizeUrl.searchParams.set('redirect_uri', 'https://app.example.com/callback');
authorizeUrl.searchParams.set('response_type', 'code');
authorizeUrl.searchParams.set('scope', 'openid profile email');
authorizeUrl.searchParams.set('code_challenge', codeChallenge);
authorizeUrl.searchParams.set('code_challenge_method', 'S256');
window.location.href = authorizeUrl.toString();
// 2. On the callback page, exchange the code for tokens
const res = await fetch('https://acme.authagonal.io/connect/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: new URLSearchParams(window.location.search).get('code')!,
redirect_uri: 'https://app.example.com/callback',
client_id: 'my-app',
code_verifier: codeVerifier,
}),
});
const tokens = await res.json();
// tokens.id_token, tokens.access_token (refresh_token only when offline_access is requested and allowed)

テナントのデフォルトのログインページ
サンドボックスモード
{env}-{slug}.authagonal.io、例:test1-acme.authagonal.io)があり、ライブユーザーに影響を与えることなく、いつでも空の状態にリセットできます。ダッシュボード
ポータルのダッシュボードでは、テナントの状況をリアルタイムで把握できます。ユーザー数の推移や認証アクティビティなど最も重要な指標を表示し、ポータルのすべての機能へすばやく移動できます。
概要
ダッシュボードの上部には、ウェルカムメッセージと、テナントのホスト型ログインへの ログインページを開く リンクが表示されます。統計カードの下にある 月間アクティブユーザー メーターはプランの上限に対する使用量を示し、80% を超えるとプランの選択肢へのリンクが表示されます。ページの下部には、サインインのアクティビティ チャートと、最新の監査エントリを表示する 最近のアクティビティ フィードがあります。


統計カードとサインインのアクティビティを表示したダッシュボードのホーム画面
アクティビティ指標
6 つの統計カードで、テナントの状況をひと目で把握できます:
- アクティブユーザー:テナント内のユーザーの総数
- サインイン(24時間):過去 24 時間に成功したサインイン
- MFA 登録済み:MFA に登録済みのユーザーの割合と、登録済みユーザー数および総数
- 失敗した試行(24時間):過去 24 時間に失敗したサインイン(誤った認証情報、ロックされたアカウント、ポリシーによる拒否など)
- SCIM 同期:接続された IdP からのプロビジョニングのアクティビティ。「アイドル」または操作件数として表示されます
- 月額費用:今月これまでの費用と、月末時点の予測額
24 時間のカードは、過去 24 時間をその前の 24 時間と比較します。サインインのアクティビティ チャートは、成功したサインインと失敗したサインインを 1 日ごとに、14、30、90 日 のいずれかの期間でプロットします。ダッシュボードは 1 分ごとに更新されます。


過去 24 時間をまとめた統計カード
クイックナビゲーション
指標の下には、クライアント、SSO、ユーザー、SCIM、ブランディング、設定、請求、ドメイン、監査ログへ直接移動できるナビゲーションカードがあります。各カードには簡単な説明が表示されるため、新しいチームメンバーもすぐに全体を把握できます。
クライアント
OAuth クライアントは、テナントを通じてユーザーを認証するアプリケーションを表します。各クライアントは、リダイレクト URI、スコープ、グラントタイプ、トークンの有効期間、MFA ポリシーについて独自の設定を持ちます。
クライアント一覧
クライアントページには、登録済みのすべてのクライアントが表で表示されます。各行には clientId、表示名、許可されたグラントタイプ(色付きバッジ)、PKCE が有効かどうかが表示されます。行をクリックすると、完全な設定エディターが開きます。


グラントタイプのバッジと PKCE インジケーターを表示したクライアント一覧
クライアントの作成
新しいクライアント をクリックして、新しいアプリケーションを登録します。必要な項目は次の 2 つです:
clientId:クライアントの一意の識別子(例:my-spa)clientName:人が読める表示名


新しい OAuth クライアントを登録します
クライアントの削除
クライアントを削除するには、クライアント一覧の該当する行にあるゴミ箱アイコンをクリックし、確認のためにクライアント ID を入力します。クライアントは完全に削除され、ユーザーのサインインやトークンのリフレッシュに使用できなくなります。発行済みのアクセストークンは取り消されず、有効期限が切れるまで有効なままです。
クライアント設定リファレンス
各クライアントには、全般、URI、スコープとグラント、トークン、セキュリティの 5 つのタブに整理された包括的な設定オプションがあります。
全般設定
| 設定 | 説明 | デフォルト |
|---|---|---|
clientName | 同意画面とポータルに表示される表示名 | - |
requirePkce | 認可コードフローで Proof Key for Code Exchange を必須にします | オン |
requireClientSecret | トークンリクエストにクライアントシークレットを必須にします(SPA などのパブリッククライアントでは無効にします) | オン |
allowOfflineAccess | offline_access スコープによるリフレッシュトークンの要求をクライアントに許可します | オフ |
alwaysIncludeUserClaimsInIdToken | 対応するスコープが要求されていない場合でも、プロフィール、メール、ロール、グループのクレームを ID トークンに含めます | オフ |
includeGroupsInTokens | groups スコープが要求されたときに発行されるトークンに、ユーザーの SCIM グループの名前を groups クレームとして含めます | オフ |
PKCE のセキュリティ
URI
URI フィールドはタグ入力形式です。値を入力して Enter または カンマ を押すと追加されます。タグの X をクリックすると削除されます。
| 設定 | 説明 |
|---|---|
redirectUris | 認証後に許可されるコールバック URL。認可リクエストの redirect_uri パラメーターと完全に一致する必要があります。 |
postLogoutRedirectUris | ログアウト後のリダイレクト先として許可される URL。 |
allowedCorsOrigins | トークンエンドポイントと UserInfo エンドポイントへのクロスオリジンリクエストが許可されるオリジン。 |


URI を設定するタグ入力フィールド
スコープとグラントタイプ
| 設定 | オプション |
|---|---|
allowedScopes | openid profile email offline_access phone roles groups |
allowedGrantTypes | authorization_code client_credentials refresh_token urn:ietf:params:oauth:grant-type:device_code urn:ietf:params:oauth:grant-type:token-exchange |
トークンの有効期間
| 設定 | 説明 | デフォルト |
|---|---|---|
accessTokenLifetimeSeconds | アクセストークンの有効期間 | 1800(30 分) |
identityTokenLifetimeSeconds | ID トークンの有効期間 | 300(5 分) |
authorizationCodeLifetimeSeconds | 認可コードを交換に使用できる期間 | 300(5 分) |
absoluteRefreshTokenLifetimeSeconds | アクティビティに関係なく適用される、リフレッシュトークンの最大有効期間 | 2592000(30 日) |
slidingRefreshTokenLifetimeSeconds | リフレッシュトークンの有効期限は使用するたびにリセットされます(絶対有効期間が上限) | 1296000(15 日) |


クライアントごとにトークンの有効期間を設定します
ログアウト URI
クライアントは、バックチャネルとフロントチャネルの両方のログアウト URI を登録できます。どちらも任意で、片方だけでも両方でも構いません。アプリケーションのセッションの消去方法に合うものを設定してください。
| 設定 | 説明 |
|---|---|
backChannelLogoutUri | 署名付きログアウトトークンを使ったサーバー間の POST。ユーザーのブラウザーがオフラインでも確実に届きます。 |
frontChannelLogoutUri | ログアウト時に非表示の iframe 内で表示され、ブラウザーが Cookie とローカルストレージを消去できるようにします。 |
frontChannelLogoutSessionRequired | オンにすると、ログアウト URL が iss と sid のクエリパラメーターを受け取るため、アプリはログアウトを特定のセッションと関連付けられます。 |
両方を併用する
MFA ポリシー
各クライアントには独自の MFA ポリシーがあり、クライアントの <strong>セキュリティ</strong> タブで設定します。MFA ポリシーのドロップダウンには、次の 3 つのオプションがあります:
| ポリシー | 動作 |
|---|---|
| 無効 | このクライアントでは MFA を一切求めません |
| 有効 | ユーザーは任意で MFA に登録できます。登録済みの場合は MFA を求められます |
| 必須 | このクライアントで認証するには、すべてのユーザーが MFA を完了する必要があります |


クライアントごとの MFA ポリシー
エンタープライズ SSO
エンタープライズ SSO を使うと、顧客は自社の ID プロバイダーを持ち込めます。Authagonal は SAML 2.0 と OIDC フェデレーションの両方に対応し、ドメインベースのルーティングにより、ユーザーはメールアドレスに基づいて適切な IdP に自動的に誘導されます。
ドメインベースの SSO ルーティング
SAML 2.0 接続
SAML 接続を作成するには、SSO ページに移動して SAML タブを選択し、次の項目を入力します:
| フィールド | 説明 |
|---|---|
connectionName | この接続の、人が読める名前(例:「Acme Corp Okta」) |
entityId | SP のエンティティ ID。この値をそのまま、IdP 側でアプリケーションの識別子(エンティティ ID)として登録してください。アサーションでは、この値が Audience として指定されている必要があります |
metadataLocation | IdP の SAML メタデータ XML ドキュメントの URL |
metadataXml | 貼り付けた IdP メタデータ XML。メタデータ URL を持たない IdP(Google Workspace)や、URL にインターネットから到達できない IdP 向けです。これと metadataLocation のどちらか一方を指定し、両方は指定しないでください |
nameIdFormat | IdP に要求する NameID フォーマット(任意)。省略すると emailAddress がデフォルトになります。「none」を指定すると NameIDPolicy 自体を省略します(ADFS で推奨) |
allowedDomains | この接続にルーティングされるメールドメイン(例:acme.com)。API で設定します。ポータルでは、接続カードと「ドメインルーティング」タブに表示されます |
接続を保存すると、Authagonal はメタデータドキュメントを取得し、IdP の署名証明書、SSO エンドポイント URL、名前識別子のフォーマットをインポートします。メタデータは定期的に更新され、証明書のローテーションが反映されます。


SAML 2.0 SSO 接続を作成します
OIDC 接続
OIDC フェデレーション接続を作成するには、OIDC タブを選択し、次の項目を入力します:
| フィールド | 説明 |
|---|---|
connectionName | この接続の、人が読める名前 |
metadataLocation | OpenID Connect のディスカバリー URL(例:https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration) |
clientId | このフェデレーション用に外部 IdP に登録されたクライアント ID |
clientSecret | 外部 IdP の登録に対応するクライアントシークレット |
allowedDomains | この接続にルーティングされるメールドメイン(例:acme.com)。API で設定します。ポータルでは、接続カードと「ドメインルーティング」タブに表示されます |


OIDC フェデレーション接続を作成します
ドメインルーティング
ドメインルーティングは、メールアドレスのドメインに基づいて、ユーザーを適切な ID プロバイダーへ自動的にリダイレクトします。ユーザーがログインページでメールアドレスを入力すると、Authagonal はドメイン部分(例:acme.com)がいずれかの SSO 接続の allowedDomains と一致するかを確認します。一致した場合、ユーザーは所属組織の IdP にシームレスにリダイレクトされます。
| メールドメイン | SSO プロバイダー | プロトコル |
|---|---|---|
| acme.com | Acme Corp Okta | SAML 2.0 |
| contoso.com | Contoso Azure AD | OIDC |
| example.org | Example OneLogin | SAML 2.0 |


ドメインルーティングは、メールドメインを ID プロバイダーに対応付けます
SP 起点フロー
/saml/{connectionId}/login または /oidc/{connectionId}/login を使って、特定の接続へユーザーを直接ディープリンクすることもできます。JIT プロビジョニング
ユーザーが初めて SSO でサインインし、テナントにまだ存在しない場合、Authagonal はアカウントを自動的に作成できます(ジャストインタイムプロビジョニング)。JIT プロビジョニングはデフォルトでオフです。接続の作成時に JIT プロビジョニングを有効にする をオンにすることで、接続ごとに有効化できます。
JIT プロビジョニングが無効な場合、その接続でサインインできるのは、SCIM、ポータルのユーザーページ、または API によって事前にプロビジョニングされたユーザーだけです。不明なユーザーには access_denied エラーが返され、管理者に問い合わせるよう案内されます。
接続ごとの設定
展開前にテストする
組織スコープの接続
接続は、テナント全体ではなく、テナント内の 1 つの 組織 に属させることもできます。そうした接続が提示されるのは、その組織がすでに特定されている場合だけです。特定の方法は、その組織に紐付けられたカスタムドメイン、サインインリンクの organization パラメーター、またはその 1 つの組織に登録されたクライアントのいずれかで、テナント全体のログインページで提示されることはありません。これらのうちどれが優先されるかは、この順序(先に挙げたものが最優先)で判定されます。
サインインでメンバーシップが作成される
ドメインの一意性はスコープごと
acme.com は、テナント全体の接続にルーティングすると同時に、組織がすでに選択されている場合はその組織独自の接続にもルーティングできます。できないのは、同じスコープ内の 2 つの接続に属することです。その場合、Authagonal は接続の保存時に拒否します。ユーザー
ユーザーページでは、テナント内のすべてのエンドユーザーを管理できます。ユーザーの検索、詳細の確認、新しいユーザーの招待ができ、各ユーザーがどのようにプロビジョニングされたかも確認できます。
検索とページ分割
検索バーは、ユーザー ID またはメールアドレスの完全一致、あるいはメールアドレス、名、姓の前方一致で検索します。また、「すべて」「有効」「無効」のフィルターでステータスごとに一覧を絞り込めます。検索には 300ms のデバウンスがかかっているため、API に過度な負荷をかけずに、入力に合わせて結果が更新されます。結果は 1 ページあたり 50 ユーザーずつ表示されます。ページ間の移動には、表の下部にあるナビゲーションを使用します。
ユーザーテーブル
ユーザーテーブルには、各ユーザーについて次の列が表示されます:
| 列 | 説明 |
|---|---|
| ユーザー | ユーザーの名前(名前が設定されていない場合はメールアドレス)。その下にメールアドレスが表示され、メールアドレスが確認されるまで「未確認」バッジが付きます |
| ステータス | Active または Inactive :アカウントが有効かどうかを示します |
| 作成元 | SCIM または Local :ユーザーの作成方法 |
| ロール | ユーザーに割り当てられたロール |
| MFA | Enabled :多要素認証に登録済みの場合に表示されます。未登録の場合はダッシュ(-)が表示されます |
| 作成日 | ユーザーアカウントが作成された日付 |


検索バーとページ分割を備えたユーザー一覧
ユーザーの招待
ユーザーを招待 をクリックして、テナントにユーザーを招待します。招待されたユーザーには、自分でパスワードを設定するためのメールが届きます。フォームの項目は次のとおりです:
| フィールド | 説明 |
|---|---|
email | ユーザーのメールアドレス(テナント内で一意である必要があります) |
firstName | ユーザーの名 |
lastName | ユーザーの姓 |
locale | 優先言語。ユーザーの UI とメールの言語を設定します。任意で、未設定の場合は英語になります。 |
organizationId | ユーザーを追加する組織(任意)と、その組織でのロール。テナントに組織がある場合に表示されます |


新しいユーザーを招待します
SCIM でプロビジョニングされたユーザー
優先言語
すべてのユーザーには優先言語があり、ホスト型 UI と、Authagonal が送信するトランザクションメール(確認、パスワードリセット、ウェルカムなど)の両方の言語を決定します。ユーザーの招待時に設定でき、ユーザーの詳細ページからいつでも変更できます。優先言語が設定されていない場合、Authagonal は英語を使用します。セレクターでは、サポートされているすべてのロケール(英語、簡体字中国語、ドイツ語、フランス語、スペイン語、ベトナム語、ポルトガル語、日本語、アラビア語、ヒンディー語、アフリカーンス語)を選択できます。


詳細ページでユーザーの優先言語を設定します
ユーザーの詳細
ユーザー一覧の行をクリックすると、その詳細ページが開きます。そこでプロフィールデータの編集、ロールの管理、MFA のリセット、カスタム属性の確認、ユーザーの削除ができます。


プロフィール
メールアドレス、名と姓、電話番号、会社、言語、外部 ID を編集し、ユーザーの有効フラグを切り替えます。メールアドレスまたはメール確認済みフラグを変更するには、管理者またはオーナーの権限が必要です。メールアドレスを変更する場合も、テナント内で一意である必要があります。すでに使用されている場合、API は email_already_in_use を返します。
ロール
ロール ページで定義したロールを割り当てたり解除したりします。クライアントが roles スコープを要求した場合、割り当てられたロールは ID トークンとアクセストークンに roles クレームとして出力されます。
多要素認証
ユーザーに登録されているすべての MFA 認証情報(認証アプリ(TOTP)、WebAuthn/パスキー、リカバリーコード)を、それぞれの登録日時と最終使用日時とともに確認できます。個々の認証情報を削除することも、MFA をすべてリセットすることもできます。どちらも管理者またはオーナーの権限が必要です。リセットすると、ユーザーは次回ログイン時に再登録が必要になります。
カスタム属性
ユーザーに付加される任意のキーと値のデータです。キーは一意である必要があります。属性はユーザープロフィール API と SCIM を通じて公開され、カスタムスコープの userClaims を設定することで、アクセストークンのクレームにマッピングできます。
組織
このユーザーが所属する組織です。これはお客様独自の自由記述の識別子で、ユーザーのトークンと /connect/userinfo に org_id クレームとして出力されます(profile スコープの場合)。Authagonal がこの値を推測して設定することはありません。値を設定するのは、プロビジョニングアプリ、ユーザーを作成した SCIM 認証情報、またはこの画面での手動入力です。
フィールドの横にあるリンクから、同じ値を持つ全員を一覧表示できます。同じ絞り込みは API でも GET /api/v1/users?organizationId= として利用できます。ディレクトリ全体をページ送りせずに、特定の顧客に誰が所属しているかを確認できます。
ユーザーの削除
ユーザーとそのすべての MFA 認証情報を完全に削除します。確認のためユーザーのメールアドレスを入力してください。元に戻すことはできません。
グループ
グループを使うと、ユーザーを整理し、グループメンバーシップをトークンに含めることができます。グループはポータルで手動作成することも、外部の ID プロバイダーから SCIM で自動的にプロビジョニングすることもできます。
グループ一覧
グループは SCIM ページの「グループ」タブに一覧表示され、次の情報が表示されます:
| 列 | 説明 |
|---|---|
| グループ名 | グループの表示名 |
| メンバー | 現在グループに所属しているユーザー数 |
| 作成元 | SCIM または Manual :グループの作成方法 |
| 作成日 | グループが作成された日付 |


作成元インジケーター付きのグループ一覧
グループの作成
新しいグループ をクリックし、グループの 表示名 を入力します。グループ名はわかりやすく、テナント内で一意にしてください(例:「エンジニアリング」、「請求管理者」、「ベータテスター」)。
グループの詳細とメンバー
グループをクリックすると、詳細ビューが開きます。ここでは現在のメンバー全員を確認し、メンバーシップを管理できます:
- メンバーを追加:メールアドレスまたは名前でユーザーを検索し、グループに追加します。
- メンバーを削除:各メンバーの横にある削除ボタンをクリックして確定します。グループを通じて付与されていたロールはすべて取り消されます。


詳細ビューでグループメンバーシップを管理します
トークン内のグループ
クライアントで トークンにグループを含める が有効で、かつ groups スコープが要求された場合、発行されるトークンには、ユーザーのグループの表示名を列挙した groups クレームが含まれます:
{
"sub": "user-123",
"email": "[email protected]",
"groups": ["Engineering", "Beta Testers"]
}クライアントごとに有効化
groups スコープも許可されている必要があります。ロール
ロールは、アプリケーションでのロールベースのアクセス制御(RBAC)を支えます。Authagonal でロールを定義してユーザーに割り当て、トークンの roles クレームを使って、アプリケーションロジックで認可を適用します。
ロールの管理
ロールページには、定義済みのすべてのロールが表で表示され、その場で編集できます。各ロールには次の項目があります:
| 列 | 説明 |
|---|---|
| 名前 | ロールの一意の識別子(例:「admin」、「editor」、「viewer」) |
| 説明 | ロールが付与する内容の、人が読める説明 |
| 作成日 | ロールが作成された日付 |
ロールの作成
新しいロール をクリックし、名前と説明を入力します。ロール名は簡潔にし、アプリケーション全体で一貫した命名規則に従ってください(例:小文字とハイフン:billing-admin)。
インライン編集
ロールは表の中で直接編集できます。ロールの鉛筆アイコンをクリックすると編集モードになり、名前と説明のフィールドが編集可能になります。値を変更したら、チェックマークアイコンをクリックして保存します。変更は直ちに反映されます。
ロールの削除
ロールの削除アイコンをクリックすると、そのロールを削除できます。ロールが完全に削除される前に確認を求められます。ロールを削除しても、既存のトークンがさかのぼって無効になることはありません。削除後に発行される新しいトークンには、そのロールが含まれなくなります。


ロール表でのロールのインライン編集
トークン内のロール
クライアントが roles スコープを要求した場合、ユーザーに割り当てられたロールは ID トークンとアクセストークンに roles クレームとして含まれます。アプリケーションはこのクレームを読み取って、認可の判断を行えます:
{
"sub": "user-123",
"email": "[email protected]",
"roles": ["admin", "billing-admin"]
}SCIM プロビジョニング
SCIM 2.0(System for Cross-domain Identity Management)を使うと、Okta、Azure AD、OneLogin、JumpCloud などのエンタープライズ ID プロバイダーから、ユーザーとグループを自動的にプロビジョニングできます。設定すると、ユーザーアカウントとグループメンバーシップが、上流の IdP から Authagonal テナントへ自動的に同期されます。
下流へのプロビジョニングを伴う SCIM ユーザーライフサイクル同期
セットアップ手順
クライアントで SCIM プロビジョニングを有効にするには、次の手順に従います:
- クライアントアプリケーションを選択する:SCIM プロビジョニングを関連付ける OAuth クライアントを選択します。
- SCIM トークンを生成する:説明と有効期間(日数)を入力し、トークンを生成します。
- トークンをすぐにコピーする:トークンの生の値は一度しか表示されません。ダイアログを閉じる前にコピーしてください。
- IdP を設定する:ID プロバイダーの SCIM 設定で、ベース URL とベアラートークンを入力します。
- ユーザー同期をテストする:IdP からテスト同期を実行し、Authagonal ポータルにユーザーが表示されることを確認します。
SCIM ベース URL
ID プロバイダーに次のベース URL を設定します:
https://{slug}.authagonal.io/scim/v2{slug} をテナントのスラッグに置き換えてください。


トークン生成を備えた SCIM セットアップページ
トークンの管理
SCIM トークンは、IdP からのプロビジョニングリクエストを認証します。クライアントごとに複数のトークンを管理できます:
| フィールド | 説明 |
|---|---|
| 説明 | トークンを識別するためのラベル(例:「Okta Production SCIM」) |
| 有効期間 | トークンの有効期間(日数、1 から 3650、デフォルトは 365)。 |
| ステータス | アクティブなトークンは使用中です。取り消されたトークンには Revoked バッジが表示され、リクエストを認証できなくなります。 |
トークンを取り消すには、その横にある 取り消す ボタンをクリックします。取り消されたトークンは監査のために一覧に表示されたままになりますが、直ちにリクエストを受け付けなくなります。


アクティブなトークンと取り消されたトークンのインジケーターを備えたトークン管理
トークンをすぐにコピーする
接続のテスト
ServiceProviderConfig エンドポイントにクエリを送信して、SCIM 統合が機能していることを確認します:
curl -H "Authorization: Bearer YOUR_TOKEN" \ https://acme.authagonal.io/scim/v2/ServiceProviderConfig
成功すると、サポートされている SCIM 機能を説明する JSON ドキュメントが返されます。PATCH とフィルタリングはサポートされていますが、一括操作、パスワード変更、並べ替え、ETag はサポートされていません。
優先言語
preferredLanguage 属性(ない場合は locale)は、ユーザーに保存される言語にマッピングされます。SCIM でプロビジョニングされた SSO ユーザーには、IdP から送られた言語でローカライズされたメールが自動的に届きます。認証情報から見える範囲
SCIM 認証情報から見えるのは、その認証情報がプロビジョニングしたユーザーとグループだけです。別のコネクターが作成したユーザーの読み取り、更新、削除には 404 が返され、一覧には自分のものだけが返されます。また、グループのメンバーシップに指定できるのは、同じコネクターがプロビジョニングしたユーザーだけです。それ以外の方法(管理者、セルフサービスのサインアップ、SSO のジャストインタイムプロビジョニング)で作成されたアカウントは、SCIM からは一切見えません。
この境界はトークンごとではなく、クライアントごとです。同じクライアントに対して発行された 2 つの認証情報は、シークレットが 2 つある 1 つの ID であり、どちらももう一方が作成したものを変更できます。互いに信頼できないコネクターには、それぞれ別のクライアントを割り当ててください。externalId も同じ範囲で区切られるため、2 つのコネクターがそれぞれ別の人物に ext-001 を使っても衝突しません。
プロビジョニング解除
DELETE /scim/v2/Users/{id} はアカウントを無効化し、削除済みとしてマークします。レコードは RFC 7644 が認めるとおり保持されますが、以降のすべての操作に 404 を返し、一覧からも除外されます。MFA の登録とグループメンバーシップは消去され、externalId のマッピングは解放され、発行済みのトークンはすべて失効するため、アクセスは次のトークン有効期限を待たずに直ちに終了します。
同じ人物が後で再雇用されて再作成された場合、その人には新しいユーザー ID が割り当てられます。識別子が再利用されることはありません。ID はこれまでに発行したすべてのトークンのサブジェクトであるため、再利用すると、それを信頼するすべてのアプリケーションで、新しく加わった人に前の保持者の履歴が知らないうちに引き継がれてしまいます。
同期ユーザーへの組織のタグ付け
SCIM には、コネクターがどの顧客を同期しているかを伝える手段がありません。コアの SCIM には組織属性が定義されていないため、通常のユーザー作成で分かるのはその人の名前とメールアドレスだけで、誰に属しているかは分かりません。複数の顧客があなたのテナントにプロビジョニングすると、各顧客のユーザーは区別できない状態で届きます。
この問題には、リクエストではなく認証情報が答えます。SCIM トークンを作成するときに、組織 でテナントの組織を 1 つ選択します(この選択欄は、テナントに組織があると表示されます)。そのトークンを通じてプロビジョニングされたユーザーはすべてその組織のアクティブなメンバーになり、以降、ユーザーのトークンにはその組織が org_id クレームとして含まれます。同じクライアントに対して顧客ごとに認証情報を 1 つずつ発行すれば、顧客ごとにクライアントを登録しなくても、同期されたユーザーが正しく顧客に紐付けられます。空欄のままにするとユーザーにはタグが付きません。
タグ付けは分離ではない
タグはユーザーの作成時に適用され、その後の更新で適用されることはありません。そのため、定期的な差分同期で既存のアカウントが知らないうちに移動することはありません。プロビジョニングアプリも併用している場合は、認証情報に明示的に設定したタグが優先されます。/try レスポンスが組織を埋めるのは、組織がまだ空の場合だけです。
サポートされるスキーマ
コアの SCIM 2.0 の User スキーマと Group スキーマ(RFC 7643)を実装しています。サポートされるユーザー属性は、userName、name.givenName、name.familyName、displayName、emails、active、externalId、preferredLanguage / locale です。
エンタープライズユーザー拡張は実装していないため、department、manager、employeeNumber、costCenter、division、organization は、作成、置換、PATCH のいずれでも、保存されずに受け入れられたうえで無視されます。Entra と Okta はどちらもデフォルトでこれらの一部をマッピングしますが、属性マッピングから削除する必要はありません。ユーザーを顧客のいずれかに紐付けるには、代わりに SCIM 認証情報に組織を設定してください。エンタープライズの organization 属性は顧客の ID プロバイダーが主張する値であり、意図的にユーザーの org_id にはならないようにしています。
OAuth スコープ
スコープを使うと、クライアントはユーザーのデータや権限の特定の部分を要求できます。Authagonal は、標準の OIDC スコープと、API 用に独自に定義するカスタムスコープの両方をサポートします。
組み込みスコープ
| スコープ | 説明 |
|---|---|
openid | すべての OpenID Connect フローで必須です。ID トークンを発行します。 |
profile | 標準のプロフィールクレーム(name、given_name、family_name、locale、org_name)を返します。 |
email | ユーザーのメールアドレスと確認状態を返します。 |
phone | ユーザーの電話番号(phone_number)を返します。 |
offline_access | アクセストークンと併せてリフレッシュトークンを発行します。 |
roles | ユーザーの roles クレームを出力します。このスコープがない場合、ロールは出力されません。 |
groups | ユーザーの groups クレーム(SCIM グループのメンバーシップ)を出力します。このスコープがない場合、グループは出力されません。 |
カスタムスコープ
スコープページで独自のスコープを定義します。各スコープは、クライアントが要求できる権限またはリソースを表します(例:billing.read、orders.write)。


| フィールド | 説明 |
|---|---|
name | トークンリクエストで送信されるスコープ識別子(例:billing.read)。 |
displayName | 同意画面に表示される、人が読める形式のラベル。 |
description | 同意画面で表示名の下に表示される、より詳しい説明。 |
userClaims | このスコープが付与されたときにアクセストークンと ID トークンに追加されるクレーム。 |
showInDiscoveryDocument | オンにすると、スコープが /.well-known/openid-configuration に表示されます。 |
emphasize | 同意画面でスコープを機密性の高いものとして強調表示します。 |
required | 同意時にユーザーがスコープの選択を解除できないようにします。 |
group | 同意グループ:見出しを共有するスコープは、同意画面で 1 つのチェックボックスの下にまとめて表示されます。表示上の設定のみです。 |
allowedRoles | このスコープを付与されるためにユーザーが持っている必要があるロール。空の場合は全員に許可されます。これらのロールのいずれも持たないユーザーは、拒否されるのではなく、トークンからこのスコープが除外されます。 |
同意との連携
トークンのカスタムクレーム
カスタムクレームは2つの要素から成ります。ソースはユーザーごとのデータです。各 AuthUser には customAttributes ディクショナリがあり、ポータル(ユーザー → 対象ユーザー → カスタム属性)、SCIM、または TCC プロビジョニングフックから値を設定できます。送出はスコープごとです。各スコープの userClaims リストが、サーバー外への送出を許可するキーを指定します。
クライアントがスコープを要求すると、Authagonal は付与されたスコープを順に調べ、それらの userClaims リストの和集合を取り、ユーザーの customAttributes からそのキーだけを出力します。不明なキーは何も通知せずに破棄されるため、クライアントが名前を推測して属性を読み取ることはできません。標準の OIDC クレーム(sub、email、name など)は仕様に従い、このホワイトリストの対象外です。
# 1. On the user (Portal → Users → {user} → Custom Attributes)
department = "engineering"
employee_id = "E-1042"
seat_tier = "enterprise"
# 2. On a custom scope (Portal → Scopes → projects.read)
name = "projects.read"
userClaims = ["department", "seat_tier"] # <-- whitelist
# 3. Client requests scope=openid projects.read
# Decoded access token (relevant fields only):
{
"sub": "u-9b…",
"scope": "openid projects.read",
"department": "engineering",
"seat_tier": "enterprise"
// employee_id is NOT emitted; it's not in the whitelist for any granted scope.
}フェデレーションのクレームはセッション単位で不足分を補う
department 属性)は同じスコープのホワイトリストを通過しますが、不足分を補うだけです。キーが重複した場合は、永続化された customAttributes の値が優先されます。これらはこのセッションのトークンに出力され(リフレッシュのローテーション後も維持されます)、ユーザーレコードには書き戻されません。クライアントへのスコープの割り当て
クライアント → スコープとグラントタブで、許可するスコープを追加します。クライアントは付与されたスコープしか要求できず、不明なスコープは invalid_scope で拒否されます。
ブランディング
テナントのログインページのルック&フィールをカスタマイズします。ブランディング設定を使うと、ロゴやカラーから高度な CSS オーバーライドまで、認証体験を自社製品のビジュアルアイデンティティに合わせられます。
外観
| 設定 | 説明 |
|---|---|
appName | ログインページのヘッダー(ロゴが設定されていない場合)とトランザクションメールに表示されるアプリケーション名 |
logoUrl | ロゴ画像の URL。ログインページの上部に表示されます。推奨サイズ:200x60px または同程度の縦横比。 |
primaryColor | ボタン、リンク、フォーカス状態に使われるプライマリのブランドカラー。カラーピッカーまたは 16 進数の入力で設定します。値を変更するとライブプレビューが更新されます。 |
customCssUrl | デフォルトのスタイルの後に読み込まれる CSS ファイルの URL。ログインページと同じオリジンから配信される必要があります。他のオリジンの URL は無視されます。 |


カラーのライブプレビュー付きの外観設定
連絡先情報
| 設定 | 説明 |
|---|---|
supportEmail | ログインページに表示されるサポート用メールアドレス。ユーザーがアカウントについてサポートを必要とするときに表示されます。 |
ログインページの表示切り替え
テナントのログインページに表示する要素を制御します。
| 切り替え | 説明 | デフォルト |
|---|---|---|
showForgotPassword | ログインフォームに「パスワードをお忘れですか?」リンクを表示 | オン |
showRegistration | セルフサービスのユーザー登録用に「サインアップ」リンクを表示 | オン |
poweredBy | ログインページの下部に「Powered by Authagonal」バッジを表示 | オン |


カスタムブランディングを適用したログインページの例
カスタム CSS
ログインページの外観を完全に制御するには、ブランディング設定で CSS ファイルの URL を指定します。このファイルはデフォルトのスタイルの後に読み込まれるため、指定したルールが優先されます。URL はログインページと同じオリジンである必要があり、他のオリジンのスタイルシートは読み込まれません。
CSS カスタムプロパティ
| 変数 | 説明 | デフォルト |
|---|---|---|
--auth-bg | ページの背景色 | #f3f4f6 |
--auth-card-bg | ログインカードの背景 | white |
--auth-heading | 見出しのテキストカラー | #111827 |
--auth-radius | カードの角の丸み | 0.5rem |
--auth-font | フォントファミリー | inherit |
ダークモード
ログインアプリには、ライト、ダーク、システムの各テーマが用意されています。ブランディングページの ダークモード 設定でデフォルトを選択します:オフ、自動(システムの設定に従います。これがデフォルトです)、常にダークのいずれかです。ユーザーは引き続きログインページの切り替えで選択でき、その選択はセッションをまたいで保持されます。system に設定すると、SPA は prefers-color-scheme をリアルタイムに追従します。
ライトの値は :root で宣言され、ダークのオーバーライドは .dark にスコープされます。customCssUrl で設定したテナントのブランディングが常に優先されるため、ユーザーのテーマにかかわらずカラーは維持されます。
要素セレクター
data-auth 属性を使って特定の要素を対象にします。これらのセレクターはアップデートをまたいで安定しており、内部のクラス名を変更しても壊れません。| セレクター | 要素 |
|---|---|
[data-auth="page"] | ページ全体の背景コンテナー |
[data-auth="header"] | ロゴとアプリ名の領域 |
[data-auth="logo"] | ロゴ画像 |
[data-auth="app-name"] | アプリ名の見出し(ロゴが未設定の場合) |
[data-auth="content"] | メインコンテンツ領域(フォーム、メッセージ) |
[data-auth="login-form"] | ログインフォーム要素 |
[data-auth="email-field"] | メール入力欄のラッパー |
[data-auth="password-field"] | パスワード入力欄のラッパー |
[data-auth="submit-button"] | サインインボタン |
[data-auth="languages"] | 言語選択バー |
設定
テナント全体のセキュリティポリシー、ウェブフック、環境設定を構成します。これらの設定は、クライアント単位で上書きされない限り、すべてのクライアントにグローバルに適用されます。
パスワードポリシー
ユーザー → 設定 で、テナントのすべてのユーザーに適用するパスワードの複雑さの要件を定義します:
| 設定 | 範囲 | デフォルト |
|---|---|---|
minPasswordLength | 6 – 128 | 8 |
requireUppercase | オン / オフ | オン |
requireLowercase | オン / オフ | オン |
requireDigit | オン / オフ | オン |
requireSpecialChar | オン / オフ | オン |


パスワードポリシーの設定
MFA ポリシー
ユーザー → 設定 で設定するテナント全体の MFA ポリシーは、多要素認証のデフォルトの動作を決めます。個々のクライアントでこの設定を上書きできます。
| ポリシー | 動作 |
|---|---|
Disabled | MFA は利用できません。ユーザーは MFA に登録できません。 |
Enabled | MFA は任意です。ユーザーは登録するかどうかを選択でき、登録済みの場合はログイン時に求められます。 |
Required | MFA は必須です。すべてのユーザーが MFA に登録し、ログインのたびに第 2 要素を完了する必要があります。 |
セッションとロックアウト
セッションの有効期間とアカウントロックアウトの動作を制御します。
| 設定 | 範囲 | デフォルト |
|---|---|---|
sessionLifetimeMinutes | 5 – 43,200(30 日) | 60 |
maxFailedAttempts | 1 – 100 | 5 |
lockoutDurationMinutes | 1 – 1,440(24 時間) | 10 |


セッションとロックアウトの設定
ウェブフック
ウェブフックを使うと、認証イベントにリアルタイムで対応できます。2 つのイベント(onUserAuthenticated、onTokenIssued)は強制可能です。デフォルトでは非同期に発火してユーザーをブロックしませんが、イベントごとに強制をオプトインでき、その場合は 2xx 以外のレスポンスまたは {"allow": false} の本文でアクションが拒否されます。残りのイベントは通知で、常にファイア・アンド・フォーゲットであり、ブロックすることはありません。
| イベント | 種類 | 説明 |
|---|---|---|
onUserAuthenticated | 強制可能 | ログインが成功した後に発火します。デフォルトはファイア・アンド・フォーゲットのため、ログインのレイテンシーには影響しません。<code>webhookEnforceUserAuthenticated</code> を切り替えるとブロッキングになり、2xx 以外のレスポンスまたは <code>{"allow": false}</code> の本文でログインが拒否されます。 |
onTokenIssued | 強制可能 | トークンの発行前に発火します(authorization_code、refresh_token、client_credentials)。デフォルトはファイア・アンド・フォーゲットです。<code>webhookEnforceTokenIssued</code> を切り替えるとブロッキングになり、2xx 以外のレスポンスまたは <code>{"allow": false}</code> の本文でトークンの発行が阻止されます。 |
onUserCreated | 通知 | 新しいユーザーが登録された、または SCIM でプロビジョニングされたときのファイア・アンド・フォーゲットの通知。 |
onUserUpdated | 通知 | ユーザーレコードが更新されたとき(プロファイルの変更、ロールの変更、SCIM による更新)のファイア・アンド・フォーゲットの通知。 |
onUserDeleted | 通知 | ユーザーが Portal/SCIM 経由または保持ポリシーによって削除されたときのファイア・アンド・フォーゲットの通知。 |
onLoginFailed | 通知 | 誤った認証情報、ロックアウト、またはポリシーによる拒否でログインの試行が失敗したときのファイア・アンド・フォーゲットの通知。 |
その他のウェブフック設定:
| 設定 | 範囲 | デフォルト | 説明 |
|---|---|---|---|
webhookTimeoutSeconds | 1 – 30 | 5 | 強制ウェブフックのレスポンスを待つ最大時間。超えるとタイムアウトします |
webhookFailOpen | オン / オフ | オン | 有効にすると、強制ウェブフックに到達できない場合やタイムアウトした場合でも、操作の続行が許可されます |


ウェブフックイベントの設定
強制ウェブフックの可用性
webhookFailOpen が無効になっていると、どのユーザーもログインできなくなります。ウェブフックの障害時にブロックすることを義務づける厳格なコンプライアンス要件がない限り、フェイルオープンモードを使用してください。ウェブフックの検証
いずれかのウェブフック URL が設定されると、Authagonal はテナントごとの署名シークレット(whsec_… の値で、設定 → ウェブフックに読み取り専用で表示されます)を発行します。すべての送信配信には X-Authagonal-Signature: t=<unix>,v1=<hex> ヘッダーが付き、v1 は未加工のリクエスト本文に対して計算した HMAC-SHA256(secret, "{t}.{body}") です。エンドポイント側でこれを再計算して定数時間で比較し、リクエストが本当に Authagonal から送られ、改ざんされていないことを確認してください。また、リプレイを防ぐため、t が古すぎる配信は拒否してください。
import crypto from 'node:crypto';
// rawBody MUST be the exact bytes Authagonal sent: verify before any JSON re-serialization.
function verifyAuthagonalWebhook(signatureHeader, rawBody, signingSecret) {
const parts = Object.fromEntries(signatureHeader.split(',').map((p) => p.split('=')));
const { t, v1 } = parts;
// Replay protection: reject deliveries older than 5 minutes.
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto
.createHmac('sha256', signingSecret)
.update(`${t}.${rawBody}`)
.digest('hex');
return v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}署名シークレットのローテーション
メンテナンス時間帯
テナントのデータをストレージシャード間で移動するなど、影響の大きい操作を行うメンテナンス時間帯の希望を設定します。UTC の時(0–23)を選択します。利便性のため、ポータルにはローカルタイムゾーンでの対応する時刻も表示されます。
サインアップとアクセス
誰がテナントのユーザーになれるか、またどのような条件でサインインできるか。
| 設定 | デフォルト | 説明 |
|---|---|---|
| 公開サインアップ | オン | 誰でも自分で登録できるかどうか。オフにすると登録ページが非表示になり、登録 API も拒否されます。これは重要です。リンクを隠すだけではエンドポイントが開いたままになるからです。SCIM、API、招待でユーザーを自分でプロビジョニングする場合に使用します。 |
| サインインにメール確認を必須にする | オン | 未確認のアドレスではサインインできません。自社のアプリ側で確認状態を判定する場合はオフにしてください。どちらの場合も email_verified クレームはトークンに含まれるため、その情報は失われません。 |
| 動的クライアント登録 | オフ | クライアントが RFC 7591 に基づいて実行時に自身を登録できるようにします。これは AI エージェントや MCP コネクターがフローを開始する前に必要なものです。デフォルトはオフで、有効にしても開放されるのは自分のテナントだけです。登録には、設定にかかわらずレート制限、PKCE、同意が常に求められます。 |
| ポータルの MFA ポリシー | 無効 | 自社チームがポータルにサインインする際の多要素認証。エンドユーザー向けのポリシーとは独立して設定します。無効、ログイン時に提示、必須のいずれかです。 |
| 最大ユーザー数 | なし | デフォルトではユーザー総数に上限はなく、上限を設けるプランもありません。テナントオーナーのメールアドレスが未確認の間は、5 ユーザーという一時的な上限が適用されます。メールアドレスが確認されると、この上限は恒久的に解除されます。 |
非アクティブユーザーの保持
使われなくなったアカウントを任意で無効化し、その後削除できます。これにより、ディレクトリに休眠中の ID がいつまでも溜まることを防げます。どちらも設定しない限りオフで、削除は元に戻せません。
| 設定 | デフォルト | 説明 |
|---|---|---|
| 無効化までの期間(非アクティブ日数) | なし | この期間サインインしていないアカウントを無効化します。レコードは保持され、再度有効化できます。 |
| 削除までの期間(非アクティブ日数) | なし | アカウントを完全に削除します。元に戻せないため、オンにする前に下記の警告期間とウェブフックを設定してください。 |
| 警告日数 | 7 | 無効化または削除の何日前に警告ウェブフックを発火させるか。介入するための時間を確保できます。 |
| 保持ウェブフック | - | 警告と実行されたアクションの送信先。本人に通知したり、アカウントを維持したりできます。 |
監査エクスポートとリモートバックアップ
要求に応じてではなく、スケジュールに従ってデータを取り出す 2 つの方法です。監査エクスポートは、完了した 1 日分の監査イベントを指定した URL に送信します。送信元が当社であることを検証できるよう署名されており、SIEM やコンプライアンスアーカイブへの取り込みに使えます。リモートバックアップは、日次および週次バックアップのコピーを自分が管理する送信先に送ります。認証なし、Basic 認証、ベアラートークンのいずれかを選べます。監査エクスポートは監査ログページの エクスポート タブで、リモートバックアップは バックアップ ページで構成します。どちらも、当社が保持するバックアップとは独立して、お客様自身が保持するものです。
サンドボックス環境
環境ページでは、サンドボックス環境を管理します。サンドボックス環境は名前付きの分離された環境で、それぞれ独自のユーザー、クライアント、署名鍵、MFA 登録、グラントを持ち、個別の URL でアクセスできます。ブランディング、プラン、請求はライブと共有されます。ライブのユーザーに影響を与えずに、設定変更、SSO 連携、ウェブフックのエンドポイントをテストするのに使用します。デフォルトで最大 5 つまで作成でき、アクティブなサンドボックスユーザーは MAU にカウントされます。
| 操作 | 説明 |
|---|---|
| 環境を追加 | 新しい環境を作成します。名前は 1 から 20 文字の英小文字と数字で、「live」は予約されています。環境は空の状態で始まり、ライブからは何もコピーされません。 |
| リフレッシュ | 環境のデータを消去し、空の状態にリセットします。 |
| 削除 | サンドボックス環境とそのすべてのデータを完全に削除します。 |
各環境には {name}-{slug}.authagonal.io でアクセスできます。


サンドボックス環境の操作
請求
ポータルの請求ページで、サブスクリプションと請求を管理します。このページでは現在のプランの概要を確認でき、支払い方法、請求書、プラン変更を管理する Stripe の請求ポータルにアクセスできます。
サブスクリプション情報
請求ページには、現在のサブスクリプションの詳細がひと目でわかるように表示されます。サブスクリプションの状態を示すステータスバッジ(active、trialing、past_due、canceled、unpaid)とともに、プラン名、現在の請求期間(開始日と終了日)、そして現在の期間の終了時にサブスクリプションがキャンセルされる設定かどうかが表示されます。
サブスクリプションの管理
サブスクリプションを管理ボタンをクリックすると、Stripe の請求ポータルが新しいウィンドウで開きます。そこで支払い方法の更新、請求書の表示とダウンロード、プランの変更、サブスクリプションのキャンセルができます。
まだサブスクリプションがない場合は、代わりに請求をセットアップの案内が表示され、プランの選択と支払い情報の入力を順に進められます。


請求ページには現在のサブスクリプションの詳細が表示され、Stripe にアクセスできます
支払いのセキュリティ
カスタムドメイン
認証ページを、デフォルトの {slug}.authagonal.io ではなく独自のドメイン(例:auth.yourdomain.com)から配信します。カスタムドメインにより、ユーザーにシームレスでブランド化された認証体験を提供できます。
ドメインの追加
ドメイン追加フォームに、使用したいホスト名(例:auth.yourdomain.com)を入力します。追加すると、ドメインは pending_verification ステータスでドメイン一覧に表示されます。
DNS による検証
ポータルに表示される、そのドメイン用の 2 つの CNAME レコードを作成します。どちらも {slug}.authagonal.io を指します。1 つはホスト名自体のレコードで、トラフィックを処理し、プロキシ経由にしてもかまいません。もう 1 つは _authagonal-challenge. の後にホスト名を続けた名前のレコードで、所有権を証明するためのものであり、DNS のみ(プロキシなし)にする必要があります。レコードを設定したら、DNS を確認 をクリックして検証します。保留中のドメインは自動的にも再確認されます。
auth.yourdomain.com. CNAME acme.authagonal.io. _authagonal-challenge.auth.yourdomain.com. CNAME acme.authagonal.io.
DNS の反映
TLS 証明書
ドメインの検証が完了したら、ユーザーが HTTPS で安全に接続できるよう TLS 証明書が必要です。Authagonal は 2 つの方法をサポートしています。
自動(cert-manager):Authagonal が cert-manager を使って TLS 証明書を自動的にプロビジョニングし、更新します。ほとんどのユーザーにはこの方法をおすすめします。追加の設定は不要です。
持ち込み(BYO):独自の証明書と秘密鍵を PEM 形式でアップロードします。組織で特定の認証局の証明書が求められる場合に便利です。証明書の有効期限は追跡されるため、期限切れになる前に更新できます。
ドメインのステータス
各ドメインには現在の状態を示すステータスバッジが表示されます:pending_verification(DNS 未確認)、verified(DNS 確認済み、TLS 保留中)、active(完全に稼働中)。


ドメイン一覧には、各カスタムドメインとその現在のステータスが表示されます


独自の TLS 証明書と秘密鍵を PEM 形式でアップロード
BYO 証明書の更新
組織
組織とは、テナント内の顧客です。分離の境界はあくまでテナントです。テーブルプレフィックスと署名鍵はテナントごとに 1 つで、テナントの各ホストがそれぞれ独自の発行者(issuer)になります。組織はテナントの内部で ID を区分するため、顧客ごとにテナントを用意しなくても、1 つのテナントで多数の顧客組織に対応できます。
組織は、カスタムドメイン(ドメインを 1 つの組織に固定できます)やプロビジョニングアプリ(プロビジョニングアプリは新しいユーザーに組織のタグを付けられます)と並ぶ機能です。この機能の目的である「1 つのテナントで、ブランドの異なる多数の顧客」というパターンの全体像は、マルチカスタマーアプリガイドを参照してください。
モデルと ID
すべての組織には、org_id トークンクレームとして出力される安定した不変の id(org_<32 hex> 形式)と、org_slug として出力され、organization 認可パラメーターで受け付けられる、テナント内で一意な不変の slug があります。ID とスラッグは 1 つの検索名前空間を共有するため、別の組織の ID と同じスラッグは、通常のスラッグの重複とまったく同じく衝突として拒否されます。
| フィールド | 変更可能 | 説明 |
|---|---|---|
id | 不可 | org_id クレーム。org_ + GUID として発行されます。アンダースコアはスラッグに使えない文字のため、新しい ID がスラッグと衝突することはありません。 |
slug | 不可 | org_slug クレームで、organization パラメーターが受け付ける値です。リライングパーティーがハードコードするため、不変です。 |
name | 可 | <code>org_name</code> クレーム。自由に編集できます。 |
metadata | 可 | テナントが管理する自由形式のキーと値のペア。スコープのクレームセットが明示的に公開しない限り、トークンに出力されることはありません。 |
brandingJson | 可 | テナントのブランディングの上にフィールド単位でマージされる JSON オブジェクト。後述の「ブランディングのオーバーライド」を参照してください。 |
domains | ドメインエンドポイントのみ | 組織が申請したメールドメインと、それぞれの所有を証明する DNS レコード。下記のドメインエンドポイント経由でのみ変更され、更新操作では変更されません。 |
メンバーシップ
メンバーシップは、ユーザーと組織の多対多の結合で、(組織、ユーザー)の組ごとに 1 行です。ユーザーは複数のメンバーシップを持てます。組織としてサインインすることを認可するのは、従来のユーザー単位の組織タグではなく、メンバーシップの行です。
| ステータス | トークンを付与? |
|---|---|
invited | 招待済みだが未承諾。トークンの発行は認可されません。 |
active | 正常な状態のメンバー。トークンの発行を認可する唯一のステータスです。 |
suspended | レコードを削除せずにメンバーシップを取り消した状態。トークンの発行は認可されません。 |
メンバーシップの roles はテナントの既存のロールカタログから選ばれ、roles クレームに統合されます。ただし、それはリクエストによって組織が明示的に選択された場合(「トークンの組織選択」を参照)で、かつアクティブなメンバーシップ行からのみです。ある組織で保持するロールが、別の組織向けに発行されたトークンに含まれることはありません。
組織への招待
POST /api/v1/users/invite は、任意で organizationId と organizationRoles を受け付けます。1 回の呼び出しで、invited メンバーシップを持つアカウントが作成され、組織のブランディングを適用した招待メールが送信されます。組織に固定されたカスタムドメインがある場合、リンクはそのドメインで開きます。本人が承諾すると、メンバーシップは active になります。組織を指定するには、オーナーまたは管理者である必要があります。
組織への SCIM プロビジョニング
SCIM トークンは組織に紐づけることができます(POST /api/v1/scim/tokens の organizationId、またはトークン作成時の組織ピッカー)。ID はテナントの組織を指している必要があります。そのトークンが作成するすべてのユーザーは active メンバーとなり、組織を org_id として保持します。紐づけは作成時にのみ適用され、決めるのはメンバーシップであってアクセス権ではありません。1 つのクライアント上の 2 つのトークンは、互いのユーザーを引き続き参照できます。ユーザーを削除すると、どの経路であってもそのメンバーシップは削除されます。
ポリシーフラグ
enabled(デフォルトはオン):無効化された組織は自組織向けのトークンを発行しません。これは認可時とすべてのリフレッシュ時の両方でチェックされるため、組織を無効化すると、新規ログインをブロックするだけでなく、ライブのセッションも次のローテーションで停止します。
requireMembershipForTokens(デフォルトはオン):この組織向けのトークンを発行するために、ユーザーがアクティブなメンバーシップを保持している必要があるかどうか。これが効くのは明示的な選択(組織を指定したリクエスト、組織を引き継いだリフレッシュ、組織スコープの接続、またはちょうど 1 つの組織に制限されたクライアント)の場合のみです。アカウント自身の従来のタグから継承されただけの組織が、このフラグで制限されることはありません。
allowAutoMembership(デフォルトはオフ):ユーザーの確認済みメールアドレスが組織の検証済みドメインのいずれかに属する場合、招待なしで参加できるようにします。認可時とすべてのリフレッシュ時に強制されます。後述の「メールドメインと自動メンバーシップ」を参照してください。
メールドメインと自動メンバーシップ
組織はメールドメインを申請し、DNS の TXT レコードでそのドメインを管理していることを証明します。allowAutoMembership がオンの場合、確認済みメールアドレスがそのドメインに属するユーザーは、その組織として初めてサインインしたときにメンバーになります。
- 申請する。ドメインを指定して
POST /api/v1/organizations/{id}/domainsを呼び出します。レスポンスは201で、recordName(_authagonal-org.acme.com)とrecordValue(authagonal-org-verify=<token>)を返します。トークンはランダムで、申請ごとに異なります。 - レコードを公開する。ドメインの DNS に、その名前と値をそのまま使った TXT レコードを追加します。
- 検証する。
POST /api/v1/organizations/{id}/domains/{domain}/verifyがレコードを検索します。一致すると200とverified: trueを返します。一致しない場合は409 verification_failedを返し、verified: false付きの200を返すことはありません。そのため、成功をポーリングするクライアントが不一致を成功と取り違えることはありません。 - 削除する。
DELETE /api/v1/organizations/{id}/domains/{domain}は204を返します。既存のメンバーシップは残り、今後の自動参加だけが止まります。
POST /api/v1/organizations/org_7fa2c9e1.../domains
Content-Type: application/json
{ "domain": "acme.com" }
201 Created
{
"domain": "acme.com",
"verified": false,
"verifiedAt": null,
"createdAt": "2026-10-03T01:02:03Z",
"recordName": "_authagonal-org.acme.com",
"recordValue": "authagonal-org-verify=Qm9...base64url"
}拒否されるケース:400 domain_invalid(単純な DNS 名ではない)、409 domain_exists(この組織にすでに登録済み)、409 domain_taken(テナント内の別の組織が保持している)、404 organization_not_found、404 domain_not_found。1 つのドメインが属せるのはテナントごとに最大 1 つの組織で、これは検証時にも再度チェックされます。
自動メンバーシップのルール
セレクターは、アクティブなメンバーシップを持たないユーザーを、次の条件がすべて満たされる場合に受け入れます。
- 組織が明示的に選択されていること:引き継がれたリフレッシュグラント、組織スコープの接続、
organizationパラメーター(ドメインの固定によって付与されるものを含む)、またはちょうど 1 つの組織に制限されたクライアント。アカウント自身の従来のタグで自動参加することはありません。 - 組織が有効で、
allowAutoMembershipがオンであること。 - ユーザーのメールが確認済みであること。誰でも
[email protected]として登録できるためです。 - メールアドレスの最後の
@より後の部分を小文字にしたものが、組織の検証済みドメインのいずれかと完全に一致すること。サブドメインの照合はありません。検証済みのacme.comでは[email protected]は受け入れられません。各サブドメインはそれぞれ個別に申請して検証してください。
メンバーシップのゲートが実行される前に書き込まれる内容:行がない場合は、ロールなしの新しい active メンバーシップになります。invited の行は、ロールを保持したまま active に昇格します。active の行はそのままです。suspended の行が昇格することはありません。
メンバーを削除しても締め出せない
allowAutoMembership がオンの間は、削除されたメンバーでも条件を満たしていれば、次回の認可またはリフレッシュで再参加します。条件を満たすユーザーを締め出すには、そのメンバーシップを suspended に設定してください。これはルールが決して変更しない唯一の状態です。トークンの組織選択
リクエストがどの組織に解決されるかは 1 か所でのみ決定されるため、/connect/authorize、すべてのリフレッシュ、デバイスグラントで結果は同一になります。優先順位(高い順):
| # | ソース | 動作 |
|---|---|---|
| 1 | 引き継がれたグラント(リフレッシュ) | 以前のトークンの発行対象だった組織。その組織がもう存在しない場合、他にフォールバックせず、リフレッシュ自体が拒否されます。 |
| 2 | 組織スコープの接続 | セッションが 1 つの組織に属する SAML または OIDC の接続を通じてサインインしたため、その組織が選択されます。主張ではなく証明に基づく唯一のソースです。別の組織を指定したリクエストは拒否され、接続の組織がもう存在しない場合も拒否されます。 |
| 3 | organization | スラッグを先に、次に ID で解決されます。ドメインの固定も同じ分岐に到達します。リクエストが評価される前に、ミドルウェアがそれを追加するためです。指定されたのに見つからない場合は確定的な拒否となり、黙ってフォールバックすることはありません。 |
| 4 | ちょうど 1 つの組織に制限されたクライアント | 自動的に選択されます。顧客ごとのアプリケーションは、1 つの組織を一度登録するだけで、パラメーターを送る必要がありません。ヒントなしで<em>複数の</em>組織に制限されている場合は、<code>account_selection_required</code> で拒否されます。 |
| 5 | アカウント自身の従来の組織タグ | 単一のフラットな文字列で、ユーザーのメンバーシップを走査するのではなく、1 回の検索で ID によって解決されます。実在する組織の行を指していない場合は、組織機能が導入される前とまったく同じく、制限なしでそのまま出力されます。明示的な選択には当たらないため、自動参加することはありません。 |
| 6 | 上記のいずれでもない | トークンに組織はまったく含まれません。<code>org_id</code>、<code>org_slug</code>、<code>org_name</code> のいずれのクレームもありません。 |
メンバーシップがヒントになることはない
requireMembershipForTokens がチェックされ、該当する場合は自動参加が試行されます。ドメインの固定
カスタムドメインは 1 つの組織に固定でき、そのドメインを組織専用の入り口にできます。固定はテナント解決ミドルウェアによって、GET /connect/authorize(クエリ文字列に追加)と POST /connect/par(PAR は保存されたペイロードからパラメーターを読むため、代わりにプッシュされた本文を書き換えます)の両方で強制されます。仕組みの詳細はカスタムドメインを参照してください。
PUT /api/v1/custom-domains/auth.acme.com/organization
Content-Type: application/json
{ "organizationId": "org_7fa2c9e1..." }固定されたドメインは矛盾するリクエストを拒否する
400 access_denied で直接拒否されます。これがなければ、リライングパーティーが独自の organization パラメーターを送れてしまい、固定は単なる飾りになってしまいます。組織スコープの接続
SAML または OIDC の接続は、1 つの組織に属することができます。その接続を通じてサインインすると、その組織が選択され、ユーザーがメンバーシップを持っていなければ active メンバーシップが作成されます。invited の行は承諾済みとして扱われ、ロールと招待者を保持したまま active になるため、IdP を通じてサインインした招待者はメールを必要としません。suspended のメンバーは一時停止のままで、トークンの発行時に拒否されます。組織は接続によってすでに選ばれているため、これは allowAutoMembership にもドメインにも依存しません。
ログインページの組織名
ログインページでは、アプリ名の下に{name}にサインインしていますと表示されます。この名前は、ページのブランディングと同じ組織から取られます。固定されたドメインの組織、次に認可リクエストで指定された組織、次にクライアントが制限されている単一の組織の順です。組織がない場合、または組織名がアプリ名と同じ場合は非表示になるため、ヘッダーが「Acme / Acme にサインインしています」となることはありません。
ブランディングのオーバーライド
組織の brandingJson は、ログインページ用にテナントのブランディングの上へフィールド単位でマージされます。存在し null でないキーは上書きし、存在しないか null のキーは継承し、不明なキーは無視されます。不正な形式の JSON の場合は、警告をログに記録してテナント自身のブランディングにフォールバックし、ページの読み込みが失敗することはありません。
ブランディングタブでは、マージ可能な 21 個のフィールドすべてを編集できます:外観(appName、logoUrl、primaryColor、customCssUrl)、ライトモードとダークモードのカラー、メールのカラー、supportEmail、showForgotPassword、poweredBy、languages。各フィールドは、ヒントとして表示されるテナントの値を継承するか、それを上書きします。キーを削除するクリアの操作もあります。
showRegistration はオーバーライドできない
従来の組織タグからのバックフィル
組織機能が導入される前は、ユーザーは裏付けとなるレコードのない自由記述の組織タグを持つことができました。POST /api/v1/organizations/backfill は、それを従来の値ごとにグループ化して、実際の組織とメンバーシップに移行します。本文が { "dryRun": false } でない限り、ドライランとして実行されます。
- 上限あり:1 回の呼び出しでスキャンするのは最大 50,000 ユーザーです。
truncatedレスポンスはもう一度実行する必要があることを意味し、再実行時には移行済みのユーザーはスキップされます。 - 冪等:移行済みの従来の値は、組織の(編集可能な)表示名ではなく内部のスタンプで照合されるため、作成された組織の名前を後で変更しても、次回の実行で重複が生じることはありません。
{
"dryRun": true,
"organizationsCreated": 3,
"membershipsCreated": 41,
"usersSkipped": 0,
"organizations": [
{ "legacyValue": "acme-corp", "slug": "acme-corp", "users": 22 }
],
"truncated": false
}ポータル UI のウォークスルー
組織ページには、テナント内のすべての組織が 50 件ずつ表示され、さらに読み込むボタンがあります。また、新しい組織(スラッグと名前のみ。ポリシーフラグ、ドメイン、ブランディングは後で設定)と、上記のバックフィルをプレビューとして実行してから「適用」で反映する従来の組織フィールドからバックフィルフローがあります。


組織一覧には、テナント内のすべての顧客組織が、スラッグ、名前、作成日とともに表示されます
各組織の詳細ページには 3 つのタブがあります:全般(名前、読み取り専用のスラッグ、3 つのポリシーの切り替え、メールドメインの追加・検証・削除と TXT レコードのコピーを行うメールドメインカード、スラッグを入力して確認する削除)、ブランディング(オーバーライド可能なすべてのフィールド。それぞれテナントの値を継承するか上書きします)、メンバー(メールで追加し、アカウントが存在しない場合は招待を提案。行ごとのステータス変更と削除、さらに読み込む)。


メンバータブには、各メンバーシップがステータスと、それを変更または削除する行ごとの操作とともに表示されます


ブランディングタブでは、この組織向けにテナントのログインページのブランディングをフィールド単位でオーバーライドします
ドメインページには、ドメイン → 組織のセレクターがあります。各ドメインカードには、テナントの組織と、固定を解除する「テナント(なし)」の選択肢を並べたインラインのドロップダウンがあり、変更するとすぐに適用されます。ドメインを追加するときにも同じセレクターが表示されます。


ドメインカード上のインラインの組織セレクターで、そのカスタムドメインを 1 つの組織に固定します
監査イベント
organization.created · organization.updated · organization.deleted · organization.member.added · organization.member.invited · organization.member.joined · organization.member.updated · organization.member.removed · organization.domain_added · organization.domain_verified · organization.domain_removed · organization.backfill · domain.organization_set
ページング
組織一覧とメンバー一覧はカーソルでページングされ、{ items, nextCursor } を返します。limit(デフォルトは 50、1 から 200 の範囲に制限)を渡し、2 ページ目以降は前回のレスポンスの nextCursor をそのまま cursor として渡します。nextCursor が null なら最後のページです。カーソルは組織 ID(メンバーの場合はユーザー ID)に対する不透明なキーセット位置のため、呼び出しの間に行が追加または削除されても、ページがずれたり重複したりすることはありません。一覧が発行していないカーソルは 400 invalid_cursor になります。
AI アシスタントからの組織の管理
ホスト型ポータル MCP は 13 個の組織ツールを公開しており、いずれもテナント管理者ロールが必要です:組織の一覧取得、取得、作成、更新、削除。メンバーの一覧取得、追加、更新、削除。メールドメインの追加、検証、削除。そしてユーザーの所属組織の一覧取得です。これらは上記の API と同じ操作を呼び出すため、ツールの動作がルートとずれることはありません。AI アシスタントからポータルを操作するを参照してください。
ホストごとに 1 つの発行者
テナントの各ホストは、それぞれ独自の OIDC 発行者です。リクエストのホストがテナントのドメインテーブルを通じて解決された場合、発行者とディスカバリーが公開するすべてのエンドポイント URL は https://{host} になります。そのため、アクティブな各カスタムドメインは独自の iss を示し、テナントの正規ホストは変わりません。署名鍵はテナントごとのため、すべてのホストが同じ鍵セットを提供します。これにより、1 つのテナントが複数の顧客の窓口となり、各顧客がそれぞれの組織に固定されたブランド独自のドメインを持てます。カスタムドメインを参照してください。
メール設定
テナントがトランザクションメール(確認、パスワードリセット、招待メールなど)を送信する方法を設定します。デフォルトの共有送信元、Resend 経由の確認済みカスタムドメイン、独自の SMTP サーバーから選択できます。


ローカライズされたメール
トランザクションメールは、受信者の優先言語で送信されます。確認、パスワードリセット、アカウント既存通知、ウェルカム、招待、アカウント削除、サポート、請求の各メールには、英語、ドイツ語、フランス語、スペイン語、ポルトガル語、ベトナム語、簡体字中国語、日本語、アラビア語、ヒンディー語、アフリカーンス語の 11 のロケールのテンプレートがあります。受信者の言語のテンプレートがない場合は、英語で送信されます。
言語は、送信時に受信者の保存済みの言語設定から決定されます。この設定は、次のいずれかから設定されます:
- サインアップと登録:ホストされたサインイン画面でユーザーが選択した言語が記録されます。
- ポータルのユーザーページ:ユーザーの作成時または編集時に管理者が設定します。
- SCIM プロビジョニング:SCIM 経由でユーザーが同期される際に、IdP の
preferredLanguage(またはlocale)からマッピングされます。 - セルフサービスのアカウントページ:ユーザー自身が
/login/accountで選択します。
設定は不要
メールプロバイダー
| プロバイダー | 説明 | セットアップ |
|---|---|---|
| Authagonal (Default) | 共有の Resend インフラストラクチャを使い、[email protected] から送信されます。 | 設定は不要です。そのまま使えます。 |
| Custom Domain (Resend) | Resend 経由で、確認済みの独自ドメインから送信されます。 | ドメインを登録し、DNS レコードを追加して、所有権を確認します。 |
| Custom SMTP | 独自の SMTP サーバーを通じて送信されます。 | SMTP ホスト、ポート、認証情報、TLS 設定を指定します。 |
送信者情報
送信者メールアドレスと送信者名は、すべてのプロバイダーモードで共通です。カスタムドメイン(Resend)とカスタム SMTP のプロバイダーでは、送信者メールアドレスは必須です。送信者名が空の場合は、ブランディングのアプリ名が使われます。
| フィールド | 説明 |
|---|---|
emailSenderEmail | 送信メールの From アドレス。カスタムドメイン(Resend)モードでは、確認済みドメインのアドレスである必要があります。 |
emailSenderName | 受信者の受信トレイに表示される表示名。 |
カスタムドメイン(Resend)
送信ドメインを Resend で一度確認すれば、このテナントの From アドレスとして使用できます。DNS レコード(SPF、DKIM)は、設定 → メール の「カスタム送信ドメイン」パネルに表示されます。Resend は、<strong>確認状況をチェック</strong> をクリックしたときにそれらを確認します。
カスタム SMTP
独自の SMTP サーバーを利用できます。社内リレー、Resend が対応していないベンダー、規制上の理由による送信経路の固定に役立ちます。
| フィールド | 説明 |
|---|---|
smtpHost | SMTP サーバーのホスト名(例:smtp.example.com)。 |
smtpPort | 接続ポート。デフォルトは 587 です。TLS は STARTTLS でネゴシエートされ、ポート 465 の暗黙的 TLS はサポートされていません。認証なしの社内リレーには 25 を使用します。 |
smtpUsername | 認証用のユーザー名(任意。認証なしのリレーの場合は空欄のままにします)。 |
smtpPassword | 認証用のパスワード。テナント設定のシークレットに暗号化して保存されます。 |
smtpUseTls | TLS を必須にします。信頼できる社内リレーを対象とする場合を除き、オンのままにしてください。 |
カスタム送信ドメイン
カスタムドメイン(Resend)プロバイダーを使用する場合、独自のドメインを登録して、@authagonal.io ではなく自社ブランドのアドレス(例:[email protected])からメールを送信できます。
- 設定 → メール に移動し、「カスタムドメイン(Resend)」プロバイダーを選択します。
- ドメイン名を入力し、「ドメインを登録」をクリックします。
- 表示された DNS レコード(DKIM、SPF、Return-Path)をドメインの DNS に追加します。
- 「確認状況をチェック」をクリックします。DNS が反映されると(通常 1〜10 分)、ドメインのステータスが確認済みに変わります。
DNS の反映
テスト
設定 → メール の「テストメールを送信」ボタンで設定を確認します。現在保存されている設定を使って、管理者のメールアドレスにテストメールが送信されます。
監査ログ
監査ログは、テナントに対して行われたすべての管理操作を読み取り専用で記録します。ポータルまたは API を通じて行われた変更は、すべて完全なコンテキストとともに記録されます。コンプライアンス対応やトラブルシューティングに必要な証跡を漏れなく確保できます。
ログの列
| 列 | 説明 |
|---|---|
| 日時 | 操作が行われた日付と時刻 |
| 実行者 | 操作を行った管理者のメールアドレス。自動化された操作の場合は「system」 |
| 操作 | 実行された操作の種類(例:クライアントを作成、設定を更新) |
| 対象 | 操作の対象。type:id 形式で表されます(例:client:my-app) |
| 詳細 | 変更に関する追加のコンテキスト |
記録される操作
監査ログには、次の管理操作が記録されます:
| カテゴリ | 操作 |
|---|---|
| クライアント | クライアントを作成、クライアントを更新、クライアントを削除 |
| SSO 接続 | SAML 接続を作成、SAML 接続を削除、OIDC 接続を作成、OIDC 接続を削除 |
| ユーザー | ユーザーを作成、ユーザーを更新 |
| 設定 | 設定を更新、ブランディングを更新 |
| ドメイン | ドメインを追加、ドメインを検証、ドメインを削除 |
| SCIM | SCIM トークンを作成、SCIM トークンを取り消し |
| ロール | ロールを作成、ロールを更新、ロールを削除 |
| グループ | グループを作成、グループを削除 |
| チーム | チームメンバーを招待、チームメンバーを削除 |


監査ログには、すべての管理操作が漏れなく記録されます
保持
バックアップ
Authagonal は、テナントのデータを 1 時間ごとに自動でバックアップします。バックアップには、すべてのユーザー、グループ、ロール、クライアント、SSO 接続、SCIM トークン、ブランディング、設定が含まれます。バックアップページでは、バックアップ履歴を確認し、最新の完全なバックアップをダウンロードできます。


バックアップの仕組み
- 1 日 1 回、毎時の増分バックアップがまとめられて新しいフルバックアップになり、日曜日には日次のフルバックアップがまとめられて週次バックアップになります。日次バックアップは 7 個、週次バックアップは 4 個保持されます。
- 増分バックアップは 1 時間ごとに実行され、前回のバックアップ以降に変更された行のみを取得します。
- バックアップは、テナントが使用しているものと同じマネージド ID を使って Azure Blob Storage に保存されます。
- 削除されたレコードはトゥームストーンで追跡され、監査の完全性のためにバックアップに含まれます。
バックアップのダウンロード
「最新をダウンロード」をクリックすると、最新のフルバックアップに、それ以降のすべての増分バックアップをマージした ZIP ファイルを取得できます。各テーブルは JSONL ファイル(1 行に 1 つの JSON オブジェクト)としてエクスポートされます。
バックアップの形式
プロビジョニングアプリ
プロビジョニングアプリは、ユーザーが作成されるたびに Authagonal が呼び出す、お客様自身のサービスです。アカウントのセットアップ、ライセンスの割り当て、ユーザーが所属する組織の決定、あるいはサインアップそのものの拒否を行えます。
仕組み
ユーザーが作成されると、Authagonal は TCC(Try/Confirm/Cancel)パターンでプロビジョニングアプリのコールバック URL を呼び出します。いずれかのアプリがコミットされる前に、すべてのアプリが Try フェーズで受け入れる必要があります。そのため、作成途中のアカウントを残すことなく、複数のダウンストリームシステムが合意することも、1 つのシステムが拒否することもできます。
| フェーズ | エンドポイント | 目的 |
|---|---|---|
| /try | POST {callbackUrl}/try | アプリがそのユーザーを処理できるかを確認します。受け入れる場合は 200、拒否する場合は 4xx を返します。 |
| /confirm | POST {callbackUrl}/confirm | すべてのアプリが /try フェーズで受け入れた後に、操作をコミットします。 |
| /cancel | POST {callbackUrl}/cancel | /try フェーズで別のアプリが失敗した場合に、操作をロールバックします。 |
プロビジョニングが実行されるタイミング
プロビジョニングは、セルフサービスのサインアップだけでなく、ユーザーを作成するすべての経路で実行されます。プロビジョニング済みのアプリとユーザーの組み合わせはスキップされるため、各アプリが同じユーザーを受け取るのは 1 回だけです。
| 作成経路 | 実行タイミング |
|---|---|
POST /api/auth/register | セルフサービス登録 |
| SAML ACS コールバック | 新規ユーザーの初回 SSO ログイン(JIT) |
| OIDC コールバック | 新規ユーザーの初回 SSO ログイン(JIT) |
POST /scim/v2/Users | コネクターが顧客のディレクトリからユーザーをプロビジョニングしたとき |
| ポータルおよび管理画面でのユーザー作成 | オペレーターが手動でユーザーを作成または招待したとき |
Try リクエスト
Authagonal はこの JSON を <code>{callbackUrl}/try</code> に POST します。値のないフィールドは null として送信されず、省略されます。
| フィールド | 型 | 説明 |
|---|---|---|
transactionId | string | このプロビジョニングトランザクションを識別します。同じ値が /confirm と /cancel にも送信されるため、この値に紐づけて処理をステージングし、該当する呼び出しが届いた時点でコミットまたは破棄してください。 |
userId | string | ユーザーの Authagonal ID。ユーザーのトークンに含まれるサブジェクトです。 |
email | string | ユーザーのメールアドレス。 |
firstName | string | 名。作成経路で指定された場合に含まれます。 |
lastName | string | 姓。作成経路で指定された場合に含まれます。 |
organizationId | string | ユーザーがすでに所属している組織(ある場合)。以前に何らかの処理で割り当てられている場合にのみ含まれます。初回サインアップでは含まれないため、それが組織を割り当てる合図になります。 |
customAttributes | object | ユーザーに保存されているカスタム属性。SSO で作成されたユーザーの場合は federated_connection が含まれます。これは、そのユーザーの身元を保証した接続の名前です。 |
想定しておくべき典型的なケースは、SSO 経由で到着するユーザーです。このユーザーにはまだ組織がなく、federated_connection を見れば、どの顧客から来たかがわかります。
{
"transactionId": "8f14e45fceea167a5a36dedd4bea2543",
"userId": "0f6b1c8e-3d2a-4f51-9e77-2c1a4b5d6e7f",
"email": "[email protected]",
"firstName": "Ada",
"lastName": "Lovelace",
"customAttributes": {
"federated_connection": "acme-okta"
}
}Try レスポンス
アプリは 200 と JSON 本文で応答します。この本文は単なる受領確認ではありません。ダウンストリームのアプリは、この本文を使って、ユーザーのトークンに含まれる組織と属性を割り当てます。
| フィールド | 型 | 説明 |
|---|---|---|
approved | boolean | このアプリがユーザーを受け入れるかどうか。省略した場合のデフォルトは true です。false の場合はサインアップが拒否され、新しいアカウントは削除されます。 |
reason | string | ユーザーを拒否した理由。作成経路の呼び出し元に返されます。 |
organizationId | string | このユーザーが所属する組織。ユーザーに保存され、トークンの org_id クレームとして発行されます。ユーザーにまだ組織がない場合にのみ適用されるため、最初に応答したアプリが優先され、後続のアプリにはその割り当てが渡されます。 |
customAttributes | object | ユーザーにキー単位でマージする属性。スコープの UserClaims 設定を通じてトークンに含まれます。 |
emailVerified | boolean | このアドレスを確認済みであることをアプリが保証します(たとえば、そのアドレスに送った招待が使用された場合)。Authagonal はアカウントを確認済みにし、独自の確認メールを送信しません。 |
{
"approved": true,
"organizationId": "org_acme",
"customAttributes": { "org_role": "member" }
}org_id の出どころ
org_id クレームは、プロビジョニングアプリが organizationId として返した値そのものです。その値がテナント内の組織の ID である場合、トークンにはその組織の org_id、org_slug、org_name が含まれ、無効化された組織ではサインインが拒否されます。それ以外の値は org_id としてそのまま出力され、一意性のルールも形式の要件もありません。組織 ID を返しても、メンバーシップは作成されません。PUT /api/v1/users/{userId} で直接設定することも、GET /api/v1/users?organizationId= で絞り込むこともできます。ユーザーに正しい組織をタグ付けする
組織は作成経路ごとに決めるのではなく、ここ 1 か所で決定してください。SSO ユーザーは federated_connection を持っています。これにより、そのユーザーを認証した接続、つまり顧客を特定でき、1 つの顧客が複数のメールドメインをフェデレーションしている場合でも正しく判別できます。招待されたユーザーには接続がないため、発行した招待で照合してください。どちらの経路もユーザーが存在する前に /try に到達するため、1 つのロジックで両方に対応でき、食い違いかねない 2 つのルールを持つ必要もありません。
// POST {callbackUrl}/try
app.post('/provisioning/try', async (req, res) => {
const { email, customAttributes } = req.body;
// An SSO user carries the connection that vouched for them. That is the
// customer, and it stays right when one customer has several domains.
const connection = customAttributes?.federated_connection;
const org = connection
? await orgByConnection(connection)
: await orgByPendingInvite(email);
if (!org) return res.json({ approved: false, reason: 'No organization for this user' });
// Stamped on the user and emitted as org_id on every token from now on.
res.json({ approved: true, organizationId: org.id });
});拒否するとアカウントは削除される
approved: false と応答した場合、新しく作成されたユーザーは削除され、プロビジョニングが中途半端なアカウントは残りません。API の作成経路は理由とともに 422 を返し、SAML および OIDC のコールバックは 400 を返します。処理することがないユーザーに対しては approved: true を返してください。プロビジョニングアプリの追加
プロビジョニングアプリを追加するには、アプリ名、コールバック URL、任意の API キー、任意の Try のタイムアウト(秒。デフォルトは 60、範囲は 5 から 300。Confirm と Cancel には固定の短いタイムアウトが使われます)を指定します。API キーは各ウェブフックリクエストの Authorization ヘッダーで Bearer トークンとして送信されるため、アプリは Authagonal からのリクエストを認証できます。
テスト
プロビジョニングアプリの横にあるテストをクリックすると、コールバック URL にテストリクエストが送信されます。テスト結果には HTTP ステータスコードとレスポンス本文が表示されるため、アプリがウェブフックを正しく受信して処理しているかを確認できます。


プロビジョニングアプリをテストして、ウェブフックの配信とレスポンスの処理を確認
プランの上限
プロビジョニングアプリの最大数はテナントごとに設定でき、デフォルトの上限は 6 です。ワークフローでさらに多くのプロビジョニング先が必要な場合は、管理者がこの上限を調整できます。
API キー認証
チーム
チームページでは、ポータル管理者、つまり管理ポータルを通じてテナントにアクセスし、設定を行えるユーザーを管理します。各チームメンバーにはロール(オーナー、管理者、開発者、サポート)があり、それによって変更できる内容が決まります。
管理者一覧
管理者一覧には、各チームメンバーの名前、メールアドレス、ロール、追加された日付が表示されます。現在のユーザーの行には「あなた」の表示が付くため、自分のアカウントを簡単に見分けられます。
管理者の招待
新しいチームメンバーを招待するには、メールアドレス、名前、ロールを指定します。招待されたユーザーには、パスワードを設定してアカウントを有効化するためのリンクが記載されたメールが届きます。リンクの有効期間は 7 日間です。
招待のフィールド
管理者の招待では、保留中のアカウントが作成され、招待されたユーザーに有効化リンクがメールで送信されます。
| フィールド | 説明 |
|---|---|
email | 新しい管理者のメールアドレス。テナント内で一意である必要があります。 |
name | 管理者一覧に表示される表示名。 |
role | 付与するロール:tenant:admin、tenant:developer、tenant:support のいずれか。デフォルトは tenant:admin です。オーナーロールは招待では付与できません。 |
管理者の削除
テナントオーナーは、チームメンバーの横にある削除をクリックして、そのメンバーのアクセス権を取り消せます。削除が確定する前に、確認ダイアログが表示されます。自分自身を削除することはできず、テナントのオーナーは常に維持されます。


チームページでポータル管理者を管理
所有権
サポート
ポータルを離れることなく、Authagonal チームへのサポートチケットを作成できます。各チケットはスレッド形式の会話なので、最初の報告から解決まで、お客様と当社チームが同じ認識を保てます。
お客様のチケット
サポートページには、お客様が作成したすべてのチケットが、最新のアクティビティ順に一覧表示されます。ステータスバッジを見れば、お客様の対応待ちのものと当社の対応待ちのものが一目でわかります。


件名、ステータス、優先度、最終アクティビティを表示したサポートチケット一覧
- 各行には、件名、現在のステータス(オープン、保留中、解決済み、クローズ済み)、優先度、最終アクティビティの日時が表示されます。
- 新しいチケットをクリックしてチケットを作成し、件名、優先度、最初のメッセージを入力します。
- 色分けされたステータスバッジにより、対応が必要なチケットを一覧から簡単に見つけられます。
チケットのスレッド
チケットを開くと、会話全体が表示されます。返信は順番に投稿され、当社チームからの新しいメッセージはページを再読み込みしなくても表示されます。


お客様と Authagonal チームとのチケットのスレッド
- お客様と Authagonal チームとのスレッド形式のメッセージが、時系列で表示されます。
- その場で返信し、ファイルを添付してログ、スクリーンショット、設定を共有できます。
- スレッドはリアルタイムで更新されるため、当社チームからの返信は送信されるとすぐに表示されます。
- 通知メールに返信した場合も、メッセージは自動的にスレッドに追加されます。
返信が届く仕組み
ユーザー向けサポートデスク
当社から受けるサポートとは別に、Authagonal はお客様のエンドユーザー向けのサポートデスクを運用できます。エンドユーザーはテナント独自のブランド付きホスト上のアカウントページからチケットを作成し、お客様のチームはポータルから回答します。
この機能があるのは、サインインできない人こそ、サインインが必要なサポートツールにたどり着けない人だからです。デスクはログイン画面と並んで置かれているため、ロックアウトされたユーザーにも連絡手段が残ります。また、すべてのチケットは、誰かが入力したアドレスではなく、ディレクトリ内の実在するアカウントにあらかじめ紐づいた状態で届きます。
有効にする
ポータルで カスタマーサポート を開き、設定 タブに切り替えて カスタマーサポートを有効化 をオンにします。このタブはオーナーと管理者に表示されます。有効にするまで、ユーザーには何も表示されません。
| 設定 | 機能 |
|---|---|
| カスタマーサポートを有効化 | マスタースイッチです。オフの場合、エンドユーザー向けページとオペレーター用の受信トレイはどちらも非表示になり、それらの API は 404 を返します。 |
| サインインしていない訪問者からのリクエストを許可 | サインインしていない訪問者がチケットを作成できるようにします。ロックアウトされたケースに対応するためのものです。ボット対策で保護されており、サインインするアカウントがないため、やり取りはメールと非公開リンクで続きます。 |
| メール通知 | チケットが届いたときやユーザーが返信したときにメールで通知する相手です。通知しない、特定のアドレス、サポートチーム全体(オーナー、管理者、サポート)から選べるため、誰かが受信トレイを見張り続ける必要がなくなります。 |
| 顧客のデフォルト言語 | ユーザーの言語がまだわからない場合に、そのユーザーのチケットとメールで想定する言語です。ユーザー自身が保存した言語が常に優先され、何も設定されていない場合は英語になります。この設定は、設定の <strong>全般</strong> タブにあります。 |
| サポートウェブフック URL | チケットのイベントを POST する URL。イベントを自社のツールに送り込むために使います。 |
Free プランでは利用不可
ユーザーに表示される内容
サインイン済みのユーザーには、テナントホスト上のアカウントページに、お客様のブランディングが適用されたサポートエリアが表示されます。ユーザーはチケットの作成、自分が作成したすべてのチケットの確認、スレッドでの返信ができます。チームからの返信はメールでも届くため、ユーザーがページを確認し続ける必要はありません。
匿名チケットを有効にすると、サインインできない人でもチケットを作成できます。メールアドレスとメッセージを入力すると、会話への非公開リンクが返されます。このリンクが唯一のアクセス手段なので、資格情報として扱ってください。推測はできませんが、リンクを持っている人は誰でもその1つのスレッドを閲覧し、返信できます。
オペレーター用受信トレイ
チームはポータルのサイドメニューにあるカスタマーサポートから回答します。これはお客様が当社に送るチケットとは別の場所で、tenant:support ロール以上で利用できます。そのため、ポータルの他の部分へのアクセスを与えずに、担当者にデスクへのアクセスだけを与えられます。
| 操作 | 機能 |
|---|---|
| 返信 | スレッドに投稿します。ユーザーにはメールが届き、ページを開いていればリアルタイムで表示されます。 |
| 割り当て | チケットをチームの特定のメンバーに割り当て、2人が同じチケットに回答しないようにします。 |
| ステータスと優先度 | チケットをオープン、保留中、解決済み、クローズ済みの間で移動し、緊急度を設定します。クローズ済みのチケットは永久に保持されず、保持期間の経過後に削除されます。 |
| 内部メモ | チームだけに表示され、ユーザーには決して表示されないメモ。編集と削除は監査ログに記録されます。 |
| ユーザーに代わってチケットを作成 | 会話が別の場所で始まった場合に、ディレクトリからユーザーを選んで、そのユーザーとのスレッドを開始します。 |
| Authagonal にエスカレーション | チケットがお客様の製品ではなく Authagonal に関するものだと判明した場合は、エスカレーションします。当社チームとの間にリンクされたチケットが作成され、必要に応じてそれまでのスレッドも引き継がれます。2つのチケットは紐づけられるため、両方の経過を追えます。チケットのエスカレーションは1回だけです。 |
ユーザーは自分の言語で書ける
チケットはユーザーが書いた言語で保存され、スレッドの各参加者はそれぞれ自分の言語で読みます。担当者にはポータルの言語に翻訳されたメッセージが表示され、ユーザーにはお客様の返信がユーザーの言語に翻訳されて表示されます。原文は常に併せて保持されます。言語は最初のメッセージから判定され、チケットに固定されます。翻訳は言語ごとに一度だけ計算されて再利用されるため、長いスレッドでも翻訳がやり直されることはありません。
タイムゾーン
チケットには、ユーザーがチケットを作成したときのタイムゾーンが記録されます。各メッセージには、ユーザーの現地時刻がお客様の時刻と並べて表示されるため、14:32 の返信が、待っている相手にとっては実際には 02:32 だったと分かります。メールで届いたチケットなどタイムゾーンが不明な場合や、お客様のタイムゾーンと同じ場合は何も表示されません。
ウェブフック
サポートウェブフック URL を設定すると、チケットのイベントを発生と同時に受け取れます。アラートを出したり、チケットを自社のシステムにミラーしたりするために使います。ペイロードには署名が付いているため、当社から送られたものか検証できます。
| イベント | 機能 |
|---|---|
support.ticket.created | ユーザーがチケットを作成しました。 |
support.ticket.message | ユーザーまたはお客様のオペレーターによって、スレッドにメッセージが投稿されました。どちらが投稿したかは、ペイロードの fromStaff でわかります。 |
support.ticket.status_changed | チケットのステータスが変更されました(例:解決済み)。 |
support.ticket.assigned | チケットがチームメンバーに割り当てられました。 |
インポートと移行
既存の ID システムを Authagonal テナントに移行します。サポートされているソースは、Duende IdentityServer(SQL Server データベース)と Auth0(Management API)の 2 つです。どちらも読み取り専用のプレビューを実行するため、コミットする前に、コピーされる内容を正確に確認できます。
Duende IdentityServer からのインポート
既存の Duende IdentityServer の SQL Server データベースから、クライアント、スコープ、ユーザー、ロールを Authagonal テナントに移行します。インポートはプレビューとコミットの 2 段階で実行されるため、変更が加えられる前に、コピーされる内容を確認できます。
インポートされるもの
インポーターは Duende の ConfigurationDb と ASP.NET Identity のテーブルを読み取り、マッピングした行をテナントに書き込みます。永続化されたグラント、デバイスコード、署名鍵などの短命なデータはスキップされます。
| エンティティ | ソーステーブル | 備考 |
|---|---|---|
| クライアント | Clients, ClientSecrets, ClientGrantTypes, ClientScopes, ClientRedirectUris | 無効なクライアントは、無効のままインポートされます。期限切れのシークレットはスキップされます。 |
| スコープ | ApiScopes, ApiResources, IdentityResources | 認識できるユーザークレームのマッピングは保持されます。 |
| ユーザー | AspNetUsers, AspNetUserClaims | パスワードハッシュ(ASP.NET Identity V3)はそのままコピーされ、初回ログイン時に再ハッシュされます。 |
| ロール | AspNetRoles, AspNetUserRoles | ロールの割り当ては保持されます。 |
| 外部ログイン | AspNetUserLogins | 参照用に保存されます。インポート後、SSO でアップストリームの IdP を再接続してください。 |
コミット前のプレビュー
Duende の ConfigurationDb / IdentityDb の接続文字列を貼り付け、プレビューを実行をクリックします。プレビューは読み取り専用の接続を開き、インポートされるすべての行を数えます。書き込みは一切行われません。
- クライアント、スコープ、ユーザー、ロール、ロールの割り当ての各エンティティ数。
- 対象テナントにすでにクライアント(ClientId が一致するものは上書きされます)、ロール、スコープ(名前が一致するものはスキップされます)が存在する場合の競合警告。
- 不明なテーブルと、マッピングされていない列に関する警告。何が破棄されるかを把握できます。


件数と警告が表示されたプレビューパネル
パスワードハッシュ
Duende は ASP.NET Identity V3(PBKDF2)でパスワードを保存します。Authagonal の PasswordHasher はこの形式を直接検証し、初回のサインインに成功した時点でネイティブ形式に再ハッシュします。ユーザーはリセットの手続きなしで、既存のパスワードをそのまま使えます。
ユーザー ID の照合
このテナントにすでに存在するユーザーが、受信レコードと同じメールアドレスを持つ場合、インポートはその前に、そのアカウントの userId をソースの sub に付け替えます。これにより、インポートされたロール、ログイン、クレームが既存のアカウントに紐づき、ソースの sub でユーザーを参照しているアプリは、カットオーバー後も引き続き解決できます。アカウントの既存のパスワードとプロフィールは保持され、ソースのロールはその上にマージされます。照合されるすべてのアカウントは、コミット前にプレビューで一覧表示されます。
インポートの実行
プレビューを確認したら、インポートを開始をクリックします。コミットフェーズでは、クライアント、スコープ、ユーザー、ロール、外部ログインの参照がテナントのストアに書き込まれます。clientId が一致するクライアントは上書きされ、scope name、email、role name が一致する行はスキップされるため、インポーターは安全に再実行できます。
インポートされないもの
- 永続化されたグラント、デバイスコード、サーバー側セッション:短命なデータであり、自動的に再生成されます。
- 署名鍵:Authagonal はテナントごとに独自の鍵を発行します。
- カスタムの列とテーブル:Duende の標準スキーマに含まれないものはすべて警告として表示されるため、そのデータが破棄されたことを把握できます。
- 無効なクライアント:無効な状態でインポートされます。準備ができたら、クライアントページで再度有効にしてください。
サンドボックスでは利用不可
Auth0 からのインポート
Authagonal を Auth0 テナントの Management API に接続し、アプリケーション、API、ロール、ユーザー、エンタープライズ接続を移行します。インポートされたユーザー ID とアプリケーション ID は保持されるため、既存の sub と client_id の参照はカットオーバー後も引き続き解決されます。
必要なもの
Auth0 で、Management API へのアクセスを許可されたMachine-to-Machine アプリケーションを作成し、次の読み取りスコープを付与します:read:users、read:clients、read:resource_servers、read:roles、read:connections、read:client_grants。そのドメイン、クライアント ID、クライアントシークレットをインポートフォームに貼り付けてください。これらはインポートにのみ使用されます。
インポートされるもの
| エンティティ | ソーステーブル | 備考 |
|---|---|---|
| アプリケーション | clients, client-grants | パブリックかコンフィデンシャルかは自動的に検出されます。クライアントシークレットは再ハッシュされるため、引き続き機能します。 |
| API とスコープ | resource-servers | オーディエンスとスコープは、各クライアントのグラントに基づいて割り当てられます。 |
| ロール | roles + 割り当て | ユーザーごとのロールの割り当ては保持されます。 |
| ユーザー | users + identities | プロフィールとメタデータが移行されます。ソーシャル/エンタープライズ ID は、リンクされたログインになります。 |
| 接続 | connections(OIDC) | エンタープライズ OIDC 接続は、フェデレーションプロバイダーになります。SAML、ソーシャル、データベースの接続は、警告付きでスキップされます。 |
パスワード
Auth0 の Management API がパスワードハッシュを返すことはありません。Auth0 のサポートを通じた一括パスワードエクスポート(NDJSON)がある場合は、それを指定してください。bcrypt ハッシュはそのままインポートされ、ユーザーはリセットなしで既存のパスワードを使い続けられます。このファイルにはユーザー全体のデータも含まれるため、Auth0 API の一覧取得における 1,000 ユーザーの上限もなくなります。ファイルがない場合、ユーザーはプロフィールとしてインポートされ、初回サインイン時に新しいパスワードを設定します。
プレビュー、付け替え、制限は共通
API リファレンス
各テナントは、https://{slug}.authagonal.io で標準準拠の OIDC サーバーを公開しています。すべてのエンドポイントは OAuth 2.0 および OpenID Connect の仕様に準拠しています。このリファレンスでは、アプリケーションが利用する可能性のあるすべてのエンドポイントを説明します。
PKCE を使用した Authorization Code フロー
OIDC ディスカバリーと JWKS
ディスカバリードキュメントを使うと、OIDC クライアントライブラリが自動的に構成されます。どちらのエンドポイントも認証は不要です。
GET /.well-known/openid-configuration
OpenID Provider Configuration ドキュメントを返します。レスポンスには、クライアントがこのテナントとやり取りするために必要なすべてのメタデータが含まれます。
| フィールド | 説明 |
|---|---|
| issuer | テナントの発行者 URL |
| authorization_endpoint | 認可リクエストの URL |
| token_endpoint | トークン交換の URL |
| userinfo_endpoint | ユーザークレームを取得する URL |
| jwks_uri | JSON Web Key Set の URL |
| revocation_endpoint | トークン取り消しの URL |
| introspection_endpoint | トークンイントロスペクションの URL |
| end_session_endpoint | ログアウト/セッション終了の URL |
| device_authorization_endpoint | デバイス認可リクエストの URL |
| pushed_authorization_request_endpoint | Pushed Authorization Request エンドポイントの URL(RFC 9126)。 |
| require_pushed_authorization_requests | テナントがグローバルに PAR を必須としているかどうか。これが false の場合でも、個々のクライアントで RequirePushedAuthorizationRequests = true を設定できます。 |
| scopes_supported | サポートされているスコープの一覧 |
| response_types_supported | サポートされているレスポンスタイプ |
| grant_types_supported | サポートされているグラントタイプ |
| code_challenge_methods_supported | サポートされている PKCE メソッド(S256) |
| backchannel_logout_supported | バックチャネルログアウトがサポートされているかどうか |
GET /.well-known/openid-configuration/jwks
トークン署名の検証に使用する JSON Web Key Set を返します。レスポンスには EC P-256 公開鍵の keys 配列が含まれ(トークンは ES256 で署名されます)、各要素は kty(EC)、use、kid、alg、crv、x、y フィールドを持ちます。
curl https://acme.authagonal.io/.well-known/openid-configuration
認可エンドポイント
GET /connect/authorize
認可コードフローを開始します。ユーザーにアクティブなセッションがない場合は、ログインページにリダイレクトされます。成功すると、ユーザーは認可コードとともにアプリケーションにリダイレクトされます。
| パラメーター | 必須 | 説明 |
|---|---|---|
response_type | はい | "code" である必要があります |
client_id | はい | 登録済みのクライアント識別子 |
redirect_uri | はい | 登録済みのリダイレクト URI と完全に一致する必要があります |
scope | はい | スペース区切りのスコープの一覧(例:"openid profile email") |
state | 推奨 | CSRF 対策用の不透明な値。リダイレクト時に変更されずに返されます |
code_challenge | PKCE 使用時は必須 | code_verifier の SHA-256 ハッシュを Base64url エンコードした値 |
code_challenge_method | PKCE 使用時は必須 | "S256" である必要があります |
nonce | 任意 | リプレイ対策のために ID トークンに紐づけられる値 |
login_hint | 任意 | ログインページのメールアドレス欄に事前入力する値 |
成功時のレスポンス:redirect_uri への 302 リダイレクト。code と state のクエリパラメーターが付与されます。
エラー時のレスポンス:error、error_description、state のクエリパラメーターを付けた 302 リダイレクト。
PKCE は必須
code_verifier(43 文字以上のランダムな文字列)を生成し、SHA-256 でハッシュ化して、その結果を base64url エンコードし、code_challenge を作成します。Pushed Authorization Requests(PAR)
RFC 9126。すべての authorize パラメーターを URL に載せる代わりに、クライアントは通常のクライアント認証を使ってそれらを /connect/par に POST し、有効期間の短い不透明な request_uri を受け取ります。その後、ブラウザーは /connect/authorize?client_id=...&request_uri=... にアクセスします。それ以外の情報がブラウザー履歴、サーバーログ、Referer ヘッダーに残ることはなく、サーバーはクライアント認証のもとで、パラメーターの完全性をすでに確認しています。
POST /connect/par
クライアント認証は /connect/token と同じです。client_id/client_secret による HTTP Basic 認証、またはフォームエンコードされた認証情報を使用します。パブリッククライアントは、シークレットなしで POST します。本文には、通常 /connect/authorize に送信するものと同じパラメーターを含めます。request_uri 自体は拒否されます(PAR の連鎖は仕様の §2.1 で禁止されています)。201 Created を返します。
| パラメーター | 必須 | 説明 |
|---|---|---|
client_id | はい | クライアント ID。認証されたクライアントと一致する必要があります。 |
client_secret | コンフィデンシャルクライアント | クライアントシークレット。コンフィデンシャルクライアントでは必須です。 |
response_type | はい | "code" である必要があります |
redirect_uri | はい | 登録済みのリダイレクト URI と完全に一致する必要があります |
scope | はい | スペース区切りのスコープの一覧(例:"openid profile email") |
code_challenge | PKCE 使用時は必須 | code_verifier の SHA-256 ハッシュを Base64url エンコードした値 |
code_challenge_method | PKCE 使用時は必須 | "S256" である必要があります |
state | 推奨 | CSRF 対策用の不透明な値。リダイレクト時に変更されずに返されます |
nonce | 任意 | リプレイ対策のために ID トークンに紐づけられる値 |
レスポンス
| フィールド | 説明 |
|---|---|
request_uri | 1 回だけ使用できる不透明な参照(例:<code>urn:ietf:params:oauth:request_uri:abc123…</code>)。<code>/connect/authorize</code> に <code>request_uri</code> として渡します。 |
expires_in | <code>request_uri</code> の有効期間(秒)。デフォルトは 90 で、リファレンス IdP の一般的な値です。 |
後続の GET /connect/authorize?client_id=…&request_uri=… では、他のすべてのパラメーターがプッシュされたペイロードから取得され、追加のクエリパラメーターは無視されます。authorize 呼び出しの client_id は、リクエストをプッシュしたクライアントと一致する必要があります。一度使用されると(または expires_in が経過すると)、request_uri はストアから削除されます。
クライアントごとに PAR を強制する
/connect/authorize 呼び出しが拒否されます。リスクの高いクライアントに推奨される構成は、RequirePushedAuthorizationRequests = true と PKCE の組み合わせです。これにより、URL バーという攻撃対象領域が完全になくなります。# 1. Push parameters (server returns request_uri + expires_in) curl -X POST https://acme.authagonal.io/connect/par \ -u "my-app:CLIENT_SECRET" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "response_type=code" \ -d "redirect_uri=https://app.example.com/callback" \ -d "scope=openid profile email" \ -d "state=$(openssl rand -hex 16)" \ -d "code_challenge=YOUR_CODE_CHALLENGE" \ -d "code_challenge_method=S256" # 2. Send the user to /authorize with only client_id + request_uri # https://acme.authagonal.io/connect/authorize?client_id=my-app&request_uri=urn:ietf:params:oauth:request_uri:abc123...
トークンエンドポイント
POST /connect/token
認証情報をトークンと交換します。リクエストには Content-Type: application/x-www-form-urlencoded を使用する必要があります。クライアント認証は、HTTP Basic 認証(Authorization: Basic base64(client_id:client_secret))またはフォーム本文のパラメーター(client_id + client_secret)で指定できます。
Authorization Code グラント
| パラメーター | 必須 | 説明 |
|---|---|---|
grant_type | はい | "authorization_code" |
code | はい | リダイレクトで受け取った認可コード |
redirect_uri | はい | 認可リクエストで使用した URI と一致する必要があります |
code_verifier | PKCE 使用時は必須 | code_challenge の生成に使用した元のランダムな文字列 |
client_id | はい | クライアント識別子(Basic 認証を使用しない場合) |
client_secret | コンフィデンシャルクライアント | クライアントシークレット(Basic 認証を使用しない場合) |
Refresh Token グラント
| パラメーター | 必須 | 説明 |
|---|---|---|
grant_type | はい | "refresh_token" |
refresh_token | はい | 交換するリフレッシュトークン |
client_id | はい | クライアント識別子 |
client_secret | コンフィデンシャルクライアント | クライアントシークレット |
Client Credentials グラント
| パラメーター | 必須 | 説明 |
|---|---|---|
grant_type | はい | "client_credentials" |
client_id | はい | クライアント識別子 |
client_secret | はい | クライアントシークレット |
scope | 任意 | 要求するスコープ(スペース区切り) |
Device Code グラント
| パラメーター | 必須 | 説明 |
|---|---|---|
grant_type | はい | "urn:ietf:params:oauth:grant-type:device_code" |
device_code | はい | デバイス認可レスポンスで受け取ったデバイスコード |
client_id | はい | クライアント識別子 |
client_secret | コンフィデンシャルクライアント | クライアントシークレット |
トークンレスポンス:
| フィールド | 説明 |
|---|---|
access_token | API 呼び出し用のアクセストークン |
token_type | "Bearer" |
expires_in | トークンの有効期間(秒) |
id_token | OpenID Connect の ID トークン(openid スコープを要求した場合) |
refresh_token | リフレッシュトークン(offline_access スコープが付与された場合) |
curl -X POST https://acme.authagonal.io/connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=AUTHORIZATION_CODE" \ -d "redirect_uri=https://app.example.com/callback" \ -d "client_id=my-app" \ -d "code_verifier=YOUR_CODE_VERIFIER"
UserInfo エンドポイント
GET /connect/userinfo
認証済みユーザーに関するクレームを返します。openid スコープを持つ有効なアクセストークンが必要です。
| フィールド | 型 | 説明 |
|---|---|---|
sub | string | 一意のユーザー識別子 |
email | string | ユーザーのメールアドレス |
email_verified | boolean | メールアドレスが確認済みかどうか |
given_name | string | 名 |
family_name | string | 姓 |
name | string | フルネームの表示名 |
phone_number | string | 電話番号(指定されている場合)。<code>phone</code> スコープで出力されます。 |
org_id | string | ユーザーが所属する組織。お客様自身のプロビジョニングアプリが割り当てるか(プロビジョニングアプリを参照)、PUT /api/v1/users/{userId} で設定します。Authagonal がこの値を導出することはありません。profile スコープで提供され、ユーザーに組織がない場合は含まれません。 |
roles | string[] | 割り当てられたロールの配列。トークンが <code>roles</code> スコープを持つ場合にのみ出力されます。 |
groups | object[] | 所属グループの配列。各要素は id と name を持ちます。トークンが <code>groups</code> スコープを持つ場合にのみ出力されます。 |
curl https://acme.authagonal.io/connect/userinfo \ -H "Authorization: Bearer ACCESS_TOKEN"
トークンイントロスペクション(RFC 7662)
POST /connect/introspect
トークンを検証し、そのメタデータを返します。クライアント認証情報(Basic 認証またはフォーム本文のパラメーター)が必要です。
| パラメーター | 必須 | 説明 |
|---|---|---|
token | はい | イントロスペクトするトークン |
token_type_hint | 任意 | トークンの種類に関するヒント(例:"refresh_token") |
アクティブなトークンのレスポンス:
| フィールド | 説明 |
|---|---|
active | true |
sub | サブジェクト(ユーザー ID) |
client_id | トークンの発行先クライアント |
scope | 付与されたスコープ(スペース区切り) |
iss | 発行者 |
exp | 有効期限(Unix タイムスタンプ) |
iat | 発行日時(Unix タイムスタンプ) |
aud | オーディエンス |
token_type | トークンの種類(例:"Bearer") |
非アクティブなトークンのレスポンス:{ "active": false }
常に 200 OK
active: false が返されます。唯一の例外は呼び出し元自身です。認証に失敗したクライアントには 401 invalid_client が返されます。curl -X POST https://acme.authagonal.io/connect/introspect \ -u "my-app:CLIENT_SECRET" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "token=ACCESS_OR_REFRESH_TOKEN"
トークンの取り消し(RFC 7009)
POST /connect/revocation
以前に発行されたトークンを取り消します。クライアント認証情報が必要です。
| パラメーター | 必須 | 説明 |
|---|---|---|
token | はい | 取り消すトークン |
token_type_hint | 任意 | トークンの種類に関するヒント(例:"refresh_token") |
RFC 7009 の仕様に従い、このエンドポイントは、無効なトークンやすでに取り消されたトークンに対しても、常に 200 OK を返します。
アクセストークンとリフレッシュトークン
デバイス認可(RFC 8628)
POST /connect/deviceauthorization
入力手段が限られたデバイス(CLI、スマートテレビ、IoT デバイス)向けのデバイス認可フローを開始します。デバイスがユーザーにコードを表示し、ユーザーはブラウザーのある別のデバイスでリクエストを承認します。
| パラメーター | 必須 | 説明 |
|---|---|---|
client_id | はい | クライアント識別子 |
client_secret | コンフィデンシャルクライアント | クライアントシークレット |
scope | 任意 | スペース区切りのスコープ(デフォルトは "openid") |
レスポンス:
| フィールド | 説明 |
|---|---|
device_code | デバイスの検証コード(ポーリングに使用) |
user_code | ユーザーに表示する XXXX-XXXX 形式のコード |
verification_uri | ユーザーがコードを入力するためにアクセスする URL |
verification_uri_complete | user_code が事前入力された URL |
expires_in | デフォルトは 300(秒。コードの有効期間は 5 分です)。クライアントごとに設定します。 |
interval | 5(秒。ポーリングの最小間隔) |
承認フロー:ユーザーは verification_uri にアクセスし、user_code を入力してリクエストを承認します。その間、デバイスは device_code を使ってトークンエンドポイントをポーリングします。
ポーリング時のエラーコード:
| エラー | 意味 |
|---|---|
authorization_pending | ユーザーがまだ承認していません。ポーリングを続けてください |
expired_token | デバイスコードの有効期限が切れました。フローを最初からやり直してください |
access_denied | ユーザーが認可リクエストを拒否しました |
curl -X POST https://acme.authagonal.io/connect/deviceauthorization \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "client_id=my-cli" \ -d "scope=openid profile email"
セッション終了/ログアウト
GET POST /connect/endsession
現在のユーザーセッションをサインアウトし、バックチャネルまたはフロントチャネルのログアウト URI が登録されているすべてのクライアントに通知して、そのセッションに紐付いたグラントを取り消します。現在のセッションと一致する id_token_hint がない場合は、まずユーザーにサインアウトの確認が求められます。
| パラメーター | 必須 | 説明 |
|---|---|---|
id_token_hint | 任意 | ID トークン。post_logout_redirect_uri の検証に使用されます |
post_logout_redirect_uri | 任意 | ログアウト後のリダイレクト先(登録済みである必要があります) |
state | 任意 | リダイレクト時に返される不透明な値 |
有効な post_logout_redirect_uri が指定され、登録済みの URI と一致する場合、ユーザーは 302 リダイレクトされます。それ以外の場合は、セッションが終了したことを示す JSON レスポンスが返されます。
バックチャネルログアウト
BackChannelLogoutUri に署名付き JWT を送信します。JWT には、sub、aud、iss、および http://schemas.openid.net/event/backchannel-logout イベントクレームが含まれます。この通知を受け取ったら、アプリケーションはユーザーのローカルセッションを無効にしてください。SCIM 2.0 API リファレンス
Authagonal は、ユーザーとグループのプロビジョニングを自動化する SCIM 2.0 プロトコルに対応しています。Okta、Azure AD、OneLogin などの ID プロバイダーはこの API を使い、Authagonal テナントを社内ディレクトリと同期した状態に保てます。
ベース URL: https://{slug}.authagonal.io/scim/v2
認証: すべてのリクエストに Bearer トークンが必要です。SCIM トークンはポータルの SCIM ページで生成します。IdP がプロビジョニングする対象のクライアントを選択し、トークンを作成 をクリックします。
共通ヘッダー:
| ヘッダー | 値 |
|---|---|
Authorization | Bearer SCIM_TOKEN |
Content-Type | application/scim+json |
一覧エンドポイントは、count(デフォルトは 100、最大 200。0 を指定すると合計件数のみを返します)と、filter パラメーターによる絞り込み(例:userName eq "[email protected]")を受け付けます。ユーザーは cursor でページングします。前のレスポンスの nextCursor を渡してください。グループは startIndex(1 始まり)または cursor のいずれかを受け付けます。
ユーザー
GET /scim/v2/Users: ユーザーを一覧表示します。ページネーションと絞り込みは任意です。
| クエリパラメーター | 説明 |
|---|---|
startIndex | ユーザーでは 1 のみ受け付けます。代わりに cursor でページングしてください。それより大きい値を指定すると 400 invalidValue が返されます。 |
cursor | 不透明なページングカーソル:前のページの nextCursor を渡すと、次のページを取得できます |
count | 1 ページあたりの最大件数(デフォルト:100、最大:200。0 を指定すると合計件数のみを返します) |
filter | SCIM フィルター式(例:userName eq "[email protected]") |
GET /scim/v2/Users/{id}: Authagonal のユーザー ID を指定して、ユーザーを 1 件取得します。
POST /scim/v2/Users: 新しいユーザーを作成します。201 Created を返します。
| フィールド | 必須 | 説明 |
|---|---|---|
userName | はい | メールアドレス(テナント内で一意であること) |
name.givenName | いいえ | 名 |
name.familyName | いいえ | 姓 |
displayName | いいえ | フルネームの表示名 |
active | いいえ | ユーザーが有効かどうか(既定:true) |
externalId | いいえ | 上流の ID プロバイダーでの識別子 |
PUT /scim/v2/Users/{id}: ユーザーリソースを全体置換します。すべてのフィールドの指定が必要です。
PATCH /scim/v2/Users/{id}: SCIM PatchOp による部分更新です。
| 操作 | 対応パス | 値の例 |
|---|---|---|
replace | userName, active, name.givenName, name.familyName, displayName, externalId, preferredLanguage | true / false、または文字列値 |
add | userName, active, name.givenName, name.familyName, displayName, externalId, preferredLanguage | true / false、または文字列値 |
remove | name.givenName, name.familyName, displayName, externalId, preferredLanguage | (値は不要) |
DELETE /scim/v2/Users/{id}: ユーザーをソフト削除します(アカウントを無効化し、すべてのトークンを失効させます)。204 No Content を返します。
curl -X POST https://acme.authagonal.io/scim/v2/Users \
-H "Authorization: Bearer SCIM_TOKEN" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "[email protected]",
"name": {
"givenName": "Jane",
"familyName": "Smith"
},
"displayName": "Jane Smith",
"active": true,
"externalId": "ext-12345"
}'グループ
GET /scim/v2/Groups: すべてのグループを一覧表示します。ページネーションと絞り込みは任意です。
GET /scim/v2/Groups/{id}: ID を指定して、メンバー一覧を含むグループを 1 件取得します。
POST /scim/v2/Groups: 新しいグループを作成します。201 Created を返します。
| フィールド | 必須 | 説明 |
|---|---|---|
displayName | はい | グループの表示名 |
members | いいえ | メンバーオブジェクトの配列。各オブジェクトの value フィールドにユーザー ID を指定します |
externalId | いいえ | 上流の ID プロバイダーでの識別子 |
PUT /scim/v2/Groups/{id}: グループリソースを(メンバー一覧を含めて)全体置換します。
PATCH /scim/v2/Groups/{id}: 部分更新:メンバーの追加、削除、置換、または displayName と externalId の変更を行います。
DELETE /scim/v2/Groups/{id}: グループを完全に削除(ハード削除)します。204 No Content を返します。
curl -X PATCH https://acme.authagonal.io/scim/v2/Groups/GROUP_ID \
-H "Authorization: Bearer SCIM_TOKEN" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "add",
"path": "members",
"value": [
{ "value": "USER_ID_1" },
{ "value": "USER_ID_2" }
]
}
]
}'SCIM エラーレスポンス
{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], "status": "400", "detail": "..." }。主なステータスコードは 400(不正なリクエスト)、404(リソースが見つからない)、409(競合/重複)、429(レート制限)です。Portal API(自動化)
Portal API を使うと、ポータルでできることをすべて、マシン間(M2M)の認証情報で自社のバックエンドから自動化できます。ユーザー、クライアント、グループ、ロール、スコープ、SSO 接続、設定の管理が対象です。ポータル UI が呼び出しているのと同じ API です。
ベース URL: https://portal-api.<your-domain>/api/v1。リクエストは Bearer アクセストークンで認証します。テナントは URL ではなくトークンから決まります。
API 認証情報の作成
ポータルで クライアント → API 認証情報を作成 を開き、アクセスレベルを選んで名前を付けます。Authagonal が Portal API 用に構成された OAuth client_credentials クライアントを生成し、クライアント ID とシークレットを返します。
シークレットはすぐにコピー
アクセスレベル
| スコープ | 付与される権限 |
|---|---|
tenant:owner | フルアクセス。テナント全体の削除など、オーナーのみが行える破壊的な操作も含みます。 |
tenant:admin | オーナー専用の操作を除くすべてを管理できます。ユーザー、クライアント、SSO、グループ、ロール、ブランディング、設定が対象です。 |
tenant:developer | クライアント、スコープ、ブランディング、プロビジョニングアプリを管理できます。 |
tenant:support | サポート業務のためにユーザーを閲覧・管理でき、監査ログも閲覧できます。 |
付与できるのは自分が持つ権限まで
トークンの取得
テナントのトークンエンドポイント https://<your-tenant>.<your-domain>/connect/token で認証情報をアクセストークンと交換し、そのトークンを Bearer ヘッダーとして Portal API に送信します。トークンの有効期間は 1 時間です。
# 1. Exchange the credential for an access token (your tenant's token endpoint)
curl -X POST https://acme.authagonal.io/connect/token \
-d grant_type=client_credentials \
-d client_id=api-3f2a... \
-d client_secret=YOUR_CLIENT_SECRET \
-d scope=tenant:admin
# Response: { "access_token": "ey...", "token_type": "Bearer", "expires_in": 3600 }
# 2. Call the Portal API with the access token
curl https://portal-api.authagonal.io/api/v1/users \
-H "Authorization: Bearer $ACCESS_TOKEN"エンドポイント
パスはすべてベース URL からの相対パスで、Bearer アクセストークンが必要です。各グループの横に示すスコープは、そのグループに必要な認証情報の最小アクセスレベルです。ページングはリソースによって異なります。ユーザーと監査ログは count(1 から 200、デフォルトは 50)と after(前のレスポンスの continuationToken を指定)を受け付けます。グループは startIndex と count、組織は limit と cursor を受け付けます。クライアント、ロール、スコープはすべての行を返します。
tenant:developerGET/api/v1/clientsOAuth クライアントを一覧表示します。
GET/api/v1/clients/{id}ID を指定してクライアントを 1 件取得します。
POST/api/v1/clientsクライアントを作成します。クライアントのレコードとともに 201 を返します。シークレットはここでは返されません。POST /api/v1/clients/{clientId}/secrets でシークレットを発行すると、一度だけ表示されます。
PUT/api/v1/clients/{id}クライアントを更新します(リダイレクト URI、グラントタイプ、トークンの有効期間、PKCE/PAR の要件)。
DELETE/api/v1/clients/{id}クライアントを削除します。
POST/api/v1/clients/api-credentialマシン間(M2M)の Portal API 認証情報を発行します。
tenant:supportGET/api/v1/usersユーザーを一覧表示します。count、search(メールアドレス/名前の前方一致)、1 つの組織に絞り込む organizationId、カーソルページング用の after に対応しています。
GET/api/v1/users/countテナントのユーザー総数。
GET/api/v1/users/stats/mfaMFA の登録状況の統計。
GET/api/v1/users/{id}ユーザーを 1 件取得します。
POST/api/v1/users/inviteメールアドレスでユーザーを招待します。保留中のアカウントを作成し、招待されたユーザーが自分でパスワードを設定するためのリンクをメールで送信します。任意の organizationId と organizationRoles を指定すると、組織のメンバーシップも追加されます。
PUT/api/v1/users/{id}ユーザーを更新します(プロフィール、メールアドレス、isActive、emailConfirmed、organizationId)。メールアドレスまたは emailConfirmed を変更するには tenant:admin が必要です。
DELETE/api/v1/users/{id}ユーザーを削除します。
GET/api/v1/users/{id}/mfaGet a user's enrolled MFA methods.
DELETE/api/v1/users/{id}/mfaReset a user's MFA enrollment. Needs tenant:admin.
tenant:adminGET/api/v1/rolesロールを一覧表示します。
POST/api/v1/rolesロールを作成します。
DELETE/api/v1/roles/{id}ロールを削除します。
POST/api/v1/roles/assignユーザーにロールを割り当てます。
POST/api/v1/roles/unassignユーザーからロールを外します。
tenant:adminGET/api/v1/groupsグループを一覧表示します。
GET/api/v1/groups/{id}メンバーを含めてグループを取得します。
POST/api/v1/groupsグループを作成します。
POST/api/v1/groups/{id}/membersグループにメンバーを追加します。
DELETE/api/v1/groups/{groupId}/members/{userId}グループからメンバーを削除します。
DELETE/api/v1/groups/{id}グループを削除します。
GET/api/v1/group-role-mappingsグループとロールのマッピングを一覧表示します(グループのメンバーシップに基づき、トークン発行時に付与されるロール)。
tenant:developerGET/api/v1/scopesAPI スコープを一覧表示します。
POST/api/v1/scopesスコープを作成します。
DELETE/api/v1/scopes/{name}スコープを削除します。
tenant:adminGET/api/v1/saml/connectionsSAML 接続を一覧表示します。
POST/api/v1/saml/connectionsSAML 接続を作成します。
DELETE/api/v1/saml/connections/{id}SAML 接続を削除します。
GET/api/v1/oidc/connectionsOIDC 接続を一覧表示します。
POST/api/v1/oidc/connectionsOIDC 接続を作成します。
DELETE/api/v1/oidc/connections/{id}OIDC 接続を削除します。
GET/api/v1/sso/domainsSSO 接続にルーティングされるドメインを一覧表示します(ホームレルムディスカバリー)。
tenant:developerGET/api/v1/brandingテナントのブランディング(色、ロゴ、対応言語)を取得します。
PUT/api/v1/brandingテナントのブランディングを更新します。
tenant:adminGET/api/v1/settingsテナント設定(ウェブフック、公開サインアップ、トークンポリシー)を取得します。
PUT/api/v1/settingsテナント設定を更新します。
POST/api/v1/settings/webhook-secret/regenerateウェブフックの署名シークレットをローテーションします。
POST/api/v1/settings/test-email現在のメール設定でテストメールを送信します。
tenant:adminGET/api/v1/custom-domainsカスタムログインドメインとその検証状況を一覧表示します。
POST/api/v1/custom-domainsカスタムドメインを追加します。
POST/api/v1/custom-domains/{domain}/verifyカスタムドメインの DNS 検証を開始します。
DELETE/api/v1/custom-domains/{domain}カスタムドメインを削除します。
GET/api/v1/email/domains/{domainId}送信元メールドメインの DNS レコードと確認状態を取得します。
tenant:supportGET/api/v1/auditテナントの監査ログを照会します。
SCIM によるユーザーのプロビジョニング
例:ユーザーを招待する
curl -X POST https://portal-api.authagonal.io/api/v1/users/invite \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"firstName": "Ada",
"lastName": "Lovelace"
}'
# 200 OK
# { "userId": "8f3a...", "email": "[email protected]" }UI でできることはすべて可能
組織 API
以下のルートはすべて TenantAdmin ポリシーが必要で、特に記載がない限り /api/v1/organizations 配下にあります。認証情報の発行方法は Portal API を参照してください。2 つの一覧ルートはカーソルでページングします。limit(既定 50、1〜200)と、前回の nextCursor を cursor として渡してください。レスポンスは { items, nextCursor } で、不正なカーソルは 400 invalid_cursor になります。組織オブジェクトには読み取り専用の domains リストが含まれます。
| メソッド | パス | ボディ | 備考 |
|---|---|---|---|
| GET | /api/v1/organizations | – | 組織の 1 ページ分を id 順で返します。クエリ:cursor?、limit?(既定 50、1〜200)。{ items, nextCursor } を返し、nextCursor が null なら最終ページです。 |
| POST | /api/v1/organizations | slug, name, brandingJson?, enabled?, requireMembershipForTokens?, allowAutoMembership?, metadata? | 201 と組織を返します。409 slug_taken。 |
| GET | /api/v1/organizations/{idOrSlug} | – | まず id で、次に slug で検索します。 |
| PUT | /api/v1/organizations/{id} | name?, brandingJson?, slug?, enabled?, requireMembershipForTokens?, allowAutoMembership?, metadata? | 指定したフィールドだけが変更されます。異なる slug は拒否されます(作成後は変更できません)。domains はここでは変更できません。 |
| DELETE | /api/v1/organizations/{id} | – | まず組織のメンバーシップをすべて削除し、その後に組織自体を削除します。 |
| GET | /api/v1/organizations/{id}/members | – | メンバーシップの 1 ページ分をユーザー id 順で返します。メンバーの最新のメールアドレス/名前はユーザーストアから解決されます。クエリ:cursor?、limit?。 |
| POST | /api/v1/organizations/{id}/members | userId? | email?, status?, roles? | 201 とメンバーシップを返します。404 user_not_found。409 membership_exists。予約済みの tenant:* および platform:* ロールは除去されるのではなく、400 invalid_role で拒否されます。 |
| PUT | /api/v1/organizations/{id}/members/{userId} | status?, roles? | status を active に設定すると、joinedAt がまだ設定されていない場合はその時点の日時が記録されます。 |
| DELETE | /api/v1/organizations/{id}/members/{userId} | – | ステータスを変更するのではなく、行そのものを削除します。 |
| POST | /api/v1/organizations/{id}/domains | domain | メールドメインを未検証の状態で登録します。201 と { domain, verified, verifiedAt, createdAt, recordName, recordValue } を返します。400 domain_invalid。409 domain_exists、domain_taken。 |
| POST | /api/v1/organizations/{id}/domains/{domain}/verify | – | recordName の TXT レコードを参照し、recordValue と完全一致するかを照合します。検証できればドメインとともに 200 を返します(再実行しても何も変わらず 200)。一致しなければ 409 verification_failed。ほかに 409 domain_taken、404 domain_not_found。 |
| DELETE | /api/v1/organizations/{id}/domains/{domain} | – | 204。検証済みかどうかにかかわらず、ドメインの登録を取り消します。既存のメンバーはそのまま残ります。404 domain_not_found。 |
| POST | /api/v1/organizations/backfill | dryRun? = true | 従来の AuthUser.organizationId タグを、実際の Organization/OrganizationMembership 行に移行します。 |
| GET | /api/v1/users/{userId}/organizations | – | このユーザーが所属するすべての組織と、各組織内でのステータス/ロール。 |
ログイン画面
テナントの認証サーバー上でエンドユーザーに表示される、ホスト型の画面です。Authagonal はすべての画面をすぐに使える状態で提供するため、UI を一切作らずに、完全で安全なサインイン体験を実現できます。このページでは各画面と、それを制御するポータル設定を紹介します。
完全なホワイトラベル
prefers-color-scheme にも従うため、ユーザーのデバイスに合わせてライトとダークが切り替わります。サインイン


- メールアドレス先行の 2 ステップフロー:ユーザーがメールアドレスを入力して 続行 をクリックすると、パスワード欄が表示されます。
- SSO 接続がある場合は、「{provider}で続行」 のシングルサインオンボタンが自動で表示されます。
- パスワードをお忘れですか? と アカウントを作成 のリンク。どちらも表示・非表示を切り替えられます。
- 自動化されたサインイン試行を抑止する Cloudflare Turnstile キャプチャ(任意)。
ポータル管理画面での設定
- ブランディング で、ロゴ、色、アプリ名、サポート用メールアドレス、カスタム CSS を設定します。
- パスワード再設定 と 登録 のリンクの表示・非表示(ブランディング)。
- SSO 接続 を追加すると、ソーシャルサインインのボタンが加わります(SSO ページ)。
- セッションの有効期間とロックアウトのしきい値(設定 → セッション)。
登録


- 姓名(任意)、メールアドレス、パスワード を入力してもらいます。
- パスワードポリシーのチェックリスト が入力に合わせてリアルタイムに更新されるため、送信前に要件がわかります。
- Cloudflare Turnstile キャプチャ(任意)。
- すでにアカウントを持っているユーザー向けの 「サインイン」 リンク。
ポータル管理画面での設定
- 登録 リンクの表示・非表示(ブランディング)。登録を完全に無効にするには、公開サインアップを許可 をオフにします(設定 → セッション)。
- テナントの パスワードポリシー がチェックリストの内容を決めます。
- ブランディング が画面全体のスタイルを決めます。
パスワードを忘れた場合


- ユーザーがメールアドレスを入力すると、中立的な 「メールをご確認ください」 の確認が表示されます。
- この画面は アカウントが存在するかどうかを決して明かさない ため、アカウント列挙の探りを防げます。
- 「サインインに戻る」 リンクでサインイン画面に戻れます。
ポータル管理画面での設定
- パスワード再設定 リンクの表示・非表示(ブランディング)。
- テナントの メール配信 がリセット用メッセージを送信します。
- ブランディング が画面全体のスタイルを決めます。
パスワードの再設定


- 新しいパスワード と パスワードの確認 の欄に、ルールごとの要件をリアルタイムに示すチェックリスト が付きます。
- リセットトークンが有効でなくなった場合は、リンクが無効または期限切れ であることをはっきり示します。
- パスワードが変更されたことを確認する 完了表示。
ポータル管理画面での設定
- テナントの パスワードポリシー がチェックリストの内容を決めます。
- ブランディング が画面全体のスタイルを決めます。
MFA チャレンジ


- 認証アプリ、パスキー、リカバリーコードを切り替える 方式スイッチャー。
- すべての桁を入力すると自動送信される 6 桁の TOTP 入力欄。
- 認証アプリを使えなくなったユーザー向けの リカバリーコード入力。
- ハードウェアで裏付けられた検証のための パスキー ボタン。
ポータル管理画面での設定
- MFA ポリシー はアプリケーションごとに設定します(クライアント → セキュリティ)。
- 要素を登録済みのユーザーは、ポリシーにかかわらず 必ずチャレンジされます。
MFA セットアップ


- 登録済みの方式 の状態を表示し、何がすでに設定済みかをユーザーが把握できるようにします。
- QR コード、手動入力キーによる代替手段、確認ステップによる 認証アプリのセットアップ。
- ハードウェアで裏付けられた認証のための パスキー登録。
- アカウント復旧用の リカバリーコード生成。
- MFA が必須ではなくセルフサービスの場合に使える、任意の スキップ。
ポータル管理画面での設定
- MFA ポリシー はアプリケーションごとに設定します。必須 にするとログイン時にセットアップが強制されます(クライアント → セキュリティ)。
- ブランディング が画面全体のスタイルを決めます。
デバイス認可


- デバイスに表示されたコードを入力する、中央配置の ユーザーコード入力 欄。
- デバイスを認可する 承認 ステップ。
- ユーザーがまだ認証されていない場合の サインイン用の中間画面。
- デバイスが認可された後の 承認完了の確認。
ポータル管理画面での設定
- アプリケーションで デバイスコードグラント を有効にします(クライアント → スコープとグラント)。
- デバイスコードの有効期間 を設定します(クライアント → トークン)。
同意


- 要求元の クライアントのロゴと名前 を表示します。
- 権限ごとにわかりやすいラベルを付けた スコープ別の一覧。
- アクセスを許可または拒否する 許可 と 拒否 のボタン。
- その判断が何を意味するかを説明する 同意に関する補足フッター。
ポータル管理画面での設定
- アプリケーションごとに 同意を必須にする をオンにします(クライアント → 全般)。
- ロゴ、名前、URL はアプリケーション自身のメタデータから取得されます。
- ブランディング が同意カードを描画します。
連携アプリ(グラント)


- ユーザーが認可したすべてのアプリを、名前、スコープ、許可日 とともに一覧表示します。
- アプリへのアクセスを 取り消す ことができ、反映前に確認ステップがあります。
- ユーザーがまだどのアプリも認可していない場合の、わかりやすい 空の状態 の表示。
ポータル管理画面での設定
- 一覧には 同意が必須のアプリケーション が表示されます。
- ブランディング が画面全体のスタイルを決めます。
アカウント
/login/account にあるホスト型のセルフサービスアカウントページです。サインイン済みのユーザーが自分のプロフィールと使用言語を管理でき、ポータルへのアクセスは不要です。


- 姓名、会社名、電話番号 を編集できます。メールアドレスは読み取り専用で表示されます。
- 対応ロケールから 使用言語 を選べます。選択は UI に即座にプレビューされ、保存すると保持されます。
- 保存した言語は、そのユーザーのホスト型 UI と、受信するトランザクションメールの言語に使われます。
ポータル管理画面での設定
- ブランディング が画面全体のスタイルを決めます。
- 同じ使用言語は、管理者がポータルの ユーザー ページで編集することもできます。
認証フロー
認証フローは、エンドユーザーが Authagonal テナントとどうやり取りするか(ログイン、登録、パスワードの再設定、MFA のセットアップ)を扱います。これらのエンドポイントはホスト型ログインページが使用しており、独自のログイン UI を構築する場合は直接呼び出すこともできます。
ログイン
POST /api/auth/login
メールアドレスとパスワードでユーザーを認証します。成功するとセッション Cookie に署名し、ユーザープロフィールを返します。MFA が構成されている場合、セッションが完全に確立される前に第 2 要素が必要であることがレスポンスで示されます。
リクエストボディ:
{
"email": "[email protected]",
"password": "correct-horse-battery-staple"
}成功レスポンス:
| フィールド | 型 | 説明 |
|---|---|---|
userId | string | 一意のユーザー識別子 |
email | string | ユーザーのメールアドレス |
name | string | フルネームの表示名 |
mfaAvailable | boolean | ユーザーが MFA 方式を登録済みかどうか |
MFA 必須のレスポンス: ユーザーが MFA を登録済みの場合、レスポンスには mfaRequired: true と、challengeId、利用可能な MFA 方式を列挙した methods 配列が含まれます。
MFA セットアップ必須のレスポンス: アプリケーションの MFA ポリシーが「必須」なのにユーザーがまだ登録していない場合、レスポンスには mfaSetupRequired: true と、登録フロー用の setupToken が含まれます。
エラーレスポンス:
| エラーコード | HTTP ステータス | 説明 |
|---|---|---|
invalid_credentials | 401 | メールアドレスまたはパスワードが正しくありません |
account_disabled | 403 | 管理者によってアカウントが無効化されています |
email_not_confirmed | 403 | ユーザーがメールアドレスを確認していません |
locked_out | 423 | アカウントが一時的にロックされています(retryAfter を秒単位で含みます)。パスワードが正しい場合にのみ返されます。ロック中に誤ったパスワードを送信すると invalid_credentials が返されます |
sso_required | 409 | メールドメインに SSO が構成されています(redirectUrl を含みます) |
too_many_attempts | 429 | この IP から、またはこのメールアドレスに対するログイン試行が多すぎます。しばらくしてから再試行してください |
captcha_failed | 400 | Turnstile のチャレンジに失敗したか、チャレンジがありません(Turnstile が有効な場合のみ) |
SSO チェック: ユーザーのメールドメインに SSO 接続が構成されている場合、ログインエンドポイントは sso_required を redirectUrl とともに返します。クライアントはユーザーを SSO プロバイダーにリダイレクトしてください。
アカウントロックアウト: ログインに maxFailedAttempts 回連続で失敗すると、アカウントは lockoutDurationMinutes 分間ロックされます。どちらの値もテナント設定で変更できます。
ホスト型ログインページ
登録
POST /api/auth/register
新しいユーザーアカウントを作成し、確認メールを送信します。<strong>サインインにメール確認を必須にする</strong>(設定 → セッション)がオンの間は(これがデフォルトです)、ユーザーはメールアドレスを確認するまでログインできません。
リクエストボディ:
{
"email": "[email protected]",
"password": "a-strong-password-here",
"firstName": "Jane",
"lastName": "Smith"
}| フィールド | 必須 | 説明 |
|---|---|---|
email | はい | メールアドレス(一意であること) |
password | はい | テナントのパスワードポリシーを満たす必要があります |
firstName | いいえ | 名 |
lastName | いいえ | 姓 |
成功: 新しいアカウントの userId とともに 201 Created を返します。すでに使われているメールアドレスで登録した場合も 201 を返します。メールアドレスが存在するかどうかは(アカウント列挙を防ぐため)決して開示せず、代わりに実際のアカウント所有者にメールで通知します。
エラーレスポンス:
| エラーコード | HTTP ステータス | 説明 |
|---|---|---|
weak_password | 400 | パスワードがテナントのパスワードポリシーを満たしていません |
rate_limited | 429 | 登録の試行回数が多すぎます |
provisioning_rejected | 422 | プロビジョニング用ウェブフックが登録を拒否しました |
invalid_email | 400 | メールアドレスが有効ではありません |
captcha_failed | 400 | Turnstile のチャレンジに失敗したか、チャレンジがありません(Turnstile が有効な場合のみ) |
public_signup_disabled | 403 | このテナントでは公開サインアップがオフになっています(設定 → セッション) |
パスワードポリシー
/api/auth/password-policy でテナントのパスワード要件を確認してください。最小文字数と必要な文字種を含む rules リストが返されます。パスワードの再設定
POST /api/auth/forgot-password
パスワード再設定メールを要求します。メールアドレスの列挙を防ぐため、このエンドポイントはメールアドレスが存在するかどうかにかかわらず、常に成功レスポンスを返します。
{
"email": "[email protected]"
}POST /api/auth/reset-password
メールのリンクに含まれるトークンを使って、ユーザーのパスワードを再設定します。
{
"token": "RESET_TOKEN_FROM_EMAIL",
"newPassword": "new-strong-password"
}パスワードの再設定に成功したときの副作用:
- ログイン失敗回数のカウンターが 0 にリセットされます
- 既存のリフレッシュトークンはすべて失効します
- 新しいセキュリティスタンプが生成されます(既存のセッションはすべて無効になります)
MFA のセットアップと検証
Authagonal は 3 つの MFA 方式に対応しています:TOTP(認証アプリ)、WebAuthn(セキュリティキーと生体認証)、使い捨てのリカバリーコードです。
TOTP のセットアップ
POST /api/auth/mfa/totp/setup: <code>setupToken</code>、QR コードのデータ URI、手動入力キーを返します。ユーザーは認証アプリ(Google Authenticator、Authy、1Password など)で QR コードを読み取り、登録を確定します。
POST /api/auth/mfa/totp/confirm: セットアップで受け取った <code>setupToken</code> と認証アプリの 6 桁のコードを送信して、TOTP の登録を確定します。
{
"setupToken": "SETUP_TOKEN_FROM_SETUP_RESPONSE",
"code": "123456"
}WebAuthn のセットアップ
POST /api/auth/mfa/webauthn/setup:WebAuthn API 用の資格情報作成オプションを返します。ブラウザーはこのオプションを使って navigator.credentials.create() を呼び出します。
POST /api/auth/mfa/webauthn/confirm: ブラウザーからのアテステーションレスポンスを送信して、WebAuthn の登録を確定します。
リカバリーコード
POST /api/auth/mfa/recovery/generate: 10 文字(形式 <code>XXXXX-XXXXX</code>)の使い捨てリカバリーコードを 10 個生成します。各コードは、MFA を回避するためにちょうど 1 回だけ使用できます。事前に認証アプリまたはパスキーを登録しておく必要があります。
リカバリーコードは一度しか表示されません
MFA の検証
POST /api/auth/mfa/verify: パスワードによるログインに成功した後、MFA チャレンジを完了します。
| フィールド | 必須 | 説明 |
|---|---|---|
challengeId | はい | ログインレスポンスに含まれるチャレンジ ID |
method | はい | "totp"、"recovery"、"webauthn" のいずれか |
code | TOTP / リカバリー | 6 桁の TOTP コード、またはリカバリーコード(XXXXX-XXXXX) |
assertion | WebAuthn | navigator.credentials.get() から返されたアサーションレスポンス |
MFA の状態
GET /api/auth/mfa/status: ユーザーが現在登録している MFA 方式を返します。
SSO ログインフロー
Authagonal は SAML 2.0 と OIDC の両方の SSO 接続に対応しています。ドメインベースのルーティングにより、ユーザーのメールアドレスから使用すべき SSO プロバイダーが自動的に判定されます。
SSO チェック
GET /api/auth/[email protected]
| フィールド | 型 | 説明 |
|---|---|---|
ssoRequired | boolean | メールドメインで SSO が必須かどうか |
providerType | string | "saml" または "oidc" |
connectionId | string | SSO 接続の識別子 |
redirectUrl | string | SSO ログインのためにユーザーをリダイレクトする URL |
SAML フロー
ユーザーは GET /saml/{connectionId}/login にリダイレクトされ、そこから ID プロバイダーに SAML AuthnRequest が送信されます。IdP がユーザーを認証し、SAML レスポンスを Assertion Consumer Service(ACS)エンドポイントへ POST で返します。Authagonal はアサーションを検証し、ユーザーを作成または更新して、セッション Cookie に署名します。
IdP の設定に使う SAML メタデータは GET /saml/{connectionId}/metadata で取得できます。
OIDC フロー
ユーザーは GET /oidc/{connectionId}/login にリダイレクトされ、そこから PKCE を使って上流の ID プロバイダーへリダイレクトされます。ユーザーが認証すると、/oidc/callback のコールバックが認可コードを交換し、ID トークンを検証して、ユーザーを作成または更新します。
JIT プロビジョニング: SAML と OIDC のどちらのフローも、ジャストインタイムプロビジョニングに対応しています。これは各接続でデフォルトでオフです(JIT プロビジョニングを有効にする)。オンになっていて、ユーザーがテナントにまだ存在しない場合は、ID プロバイダーのクレームから自動的に作成されます。すでに存在する場合は、プロフィール属性がプロバイダーの最新の値に合わせて更新されます。
ドメインベースのルーティング
Backend-for-Frontend(BFF)
BFF は OAuth トークンをブラウザから完全に排除します。シングルページアプリが保持するのは httpOnly のセッション Cookie だけで、自社バックエンド上のコンフィデンシャルクライアントが OpenID Connect フローを実行し、トークンをサーバー側で保持します。
シングルページアプリが読み取れるものは、クロスサイトスクリプティングで盗まれる可能性があります。メモリ上のアクセストークンも、localStorage 内のリフレッシュトークンも例外ではありません。また、トークンをブラウザに保存すると、その有効期間にも上限が生じます。スクリプトの届く場所にある長寿命のリフレッシュトークンは、常に抱え続けるリスクだからです。IETF のベストカレントプラクティス OAuth 2.0 for Browser-Based Apps は、まさにその理由でこのパターンを推奨しています。
その代わりに得られるのは、トークンを一切露出させずにページの再読み込み後も維持されるセッション、サーバー側で自動的に処理されるリフレッシュ、バックチャネルログアウトによる即時の失効、そしてブラウザが改ざんできたかもしれないトークンを API が解析しなくて済む認証済みプロキシです。
クライアントを作成する
ポータルでクライアントを開き、BFF アプリを作成を選択します。アプリの配信元であるアプリケーション URL(例:https://app.acme.com)を指定すると、自分で組み立てなくても、Authagonal が正しく設定されたコンフィデンシャルクライアントを登録します。リダイレクト URL とログアウト URL は、この1つの値から導出されます。
| 設定 | 値 |
|---|---|
| リダイレクト URI | {appBaseUrl}/bff/callback |
| ログアウト後のリダイレクト URI | {appBaseUrl}/ |
| バックチャネルログアウト URI | {appBaseUrl}/bff/backchannel-logout |
| グラントタイプ | authorization_code, refresh_token |
| スコープ | openid, profile, email, offline_access |
| PKCE とクライアントシークレット | どちらも必須 |
シークレットは一度だけ表示される
clientId、clientSecret、authority が含まれます。保存されるのはハッシュだけなので、シークレットは後から取り戻せません。すぐにバックエンドの設定またはシークレットストアに保存してください。紛失した場合は、このクライアントの復旧を試みるのではなく、新しいクライアントを作成してください。バックエンドに組み込む
2つのランタイムがサポートされ、同じコアプロトコルを共有しています。.NET 向けの Authagonal.Bff と Node 向けの @authagonal/bff で、後者には Express と Next.js 用のアダプターがあります。どちらにも、ポータルで受け取った値を設定します。Node パッケージには、Cookie の暗号化に使用する独自の cookieSecret も必要です。
// dotnet add package Authagonal.Bff
builder.Services.AddAuthagonalBff(o =>
{
o.Authority = "https://acme.authagonal.io"; // your tenant auth host
o.ClientId = builder.Configuration["Bff:ClientId"]!;
o.ClientSecret = builder.Configuration["Bff:ClientSecret"]!;
o.Scope = ["openid", "profile", "email", "offline_access"];
o.PostLogoutRedirectUri = "https://app.acme.com/";
});
// Trust X-Forwarded-Proto from your ingress. With no options, UseForwardedHeaders() changes nothing.
builder.Services.Configure<ForwardedHeadersOptions>(o =>
{
o.ForwardedHeaders = ForwardedHeaders.XForwardedProto;
o.KnownNetworks.Clear();
o.KnownProxies.Clear();
});
var app = builder.Build();
app.UseForwardedHeaders(); // required behind a proxy or ingress, see the note below
app.MapAuthagonalBff();
app.MapFallbackToFile("index.html"); // your SPA
app.Run();// npm install @authagonal/bff
import express from 'express';
import { authagonalBff } from '@authagonal/bff/express';
const app = express();
app.use(authagonalBff({
authority: 'https://acme.authagonal.io',
clientId: process.env.BFF_CLIENT_ID,
clientSecret: process.env.BFF_CLIENT_SECRET,
cookieSecret: process.env.BFF_COOKIE_SECRET, // encrypts the session and login cookies
scope: ['openid', 'profile', 'email', 'offline_access'],
postLogoutRedirectUri: 'https://app.acme.com/',
}));
app.listen(8080);プロキシの背後では転送ヘッダーを信頼する
__Host- セッション Cookie を Secure 属性なしで発行し、ブラウザはそれを何も通知せずに破棄します。症状としては、ログインは問題なく完了するのに、セッションがいつまでも現れません。.NET では、上記のとおり ForwardedHeadersOptions で XForwardedProto を有効にし、app.UseForwardedHeaders() を MapAuthagonalBff() より前に呼び出します。オプションなしで呼び出すだけでは、どのヘッダーも信頼されません。Node のアダプターは X-Forwarded-Proto を自ら読み取り、__Host- Cookie には常に Secure を付けます。API に転送されるクライアントアドレスが実際のものになるよう、フレームワークの trust proxy 設定を行ってください。エンドポイント
デフォルトでは /bff 配下にマウントされます。セッション Cookie は httpOnly かつ同一オリジンなので、これらはSPA と同じオリジンから配信する必要があります。別の API ドメインではなく、同じホスト名の背後に配置してください。
| ルート | 用途 |
|---|---|
GET /bff/login?returnUrl=/ | ログインを開始し、Authagonal にリダイレクトします。完了後、ユーザーを returnUrl に戻します。 |
GET /bff/callback | OIDC のリダイレクト URI です。自動的に処理されるため、自分で実装することはありません。 |
GET /bff/user | isAuthenticated、セッションのクレーム、sessionExpiresAt を返します。偽造防止ヘッダーが必要です。 |
GET|POST /bff/logout | ローカルと Authagonal の両方でセッションを終了します。 |
POST /bff/backchannel-logout | Authagonal からのログアウト通知を受け取ります。これにより、別の場所でサインアウトすると、このセッションも終了します。 |
ブラウザから
ナビゲーション以外のすべてのリクエストには、固定の偽造防止ヘッダーを付ける必要があります。これは Cookie の SameSite 属性と組み合わせてクロスサイトリクエストフォージェリを防ぎます。クロスサイトのフォーム送信ではカスタムヘッダーを設定できないため、このヘッダーのないリクエストは拒否されます。
const me = await fetch('/bff/user', {
headers: { 'X-Authagonal-Bff': '1' },
}).then(r => r.json());
if (!me.isAuthenticated) {
// Navigate, do not fetch: this is a redirect to your identity provider.
window.location.href = '/bff/login?returnUrl=' + encodeURIComponent(location.pathname);
}ログインとログアウトは、fetch ではなくナビゲーションで行います:location.href = '/bff/login'。これらのルートは ID プロバイダーへのリダイレクトで応答しますが、リダイレクトチェーンは fetch では意味のある形でたどれません。
API を呼び出す
BFF は、API を自身のベースパス配下で転送し、その途中でセッションのアクセストークンを付与できます。ブラウザは Cookie を送信し、API は通常どおり検証するベアラートークンを受け取ります。そのトークンはページからは一切見えず、偽造もできません。アップストリームを登録すると、/bff/api/** へのリクエストが認証済みの状態でそこに届きます。リストを空のままにすると、プロキシは完全に無効になります。
o.Upstreams.Add(new BffUpstream
{
Prefix = "/orders", // matches /bff/api/orders/**
TargetBaseUrl = "https://api.internal.acme.com",
StripPrefix = false, // keep /orders in the forwarded path
});| オプション | デフォルト | 機能 |
|---|---|---|
Upstreams | [] | プロキシの転送先となる API。空の場合、プロキシエンドポイントは無効になります。 |
Prefix | / | このアップストリームが処理する、/bff/api 以降のパスプレフィックス(例:/orders)。 |
TargetBaseUrl | - | リクエストの転送先となるベース URL。 |
StripPrefix | false | 転送前に、一致したプレフィックスを取り除きます。合成のルーティングプレフィックスを使い、パスの名前空間を共有する複数のバックエンドへ1つの BFF から振り分けられます。 |
AllowAnonymousProxyRequests | false | 利用可能なセッションのないリクエストを、拒否する代わりに Authorization ヘッダーなしで転送します。サインイン済みと匿名の両方の呼び出し元に応答する API 向けです。 |
RequiredAuthority | [] | type:action のペアで指定する権限ゲート(例:email:send)。設定すると、プロキシは転送前に、送信するトークンの RFC 9396 認可詳細を確認します。 |
AuthorityLocation | - | このアップストリームを識別する RFC 9396 の locations ルート。プロキシが呼び出す内部アドレスとは異なる公開リソース識別子に対して権限が付与されている場合に使います。 |
StrictAuthority | false | プロキシが評価できないグラント制約を含む呼び出しを、転送せずに拒否します。プロキシは中身を判断せずに転送し、制約のコンテキストを導出しないため、デフォルトではオフです。 |
ExchangeRoutes | [] | アップストリームへの呼び出しに、セッションのプライマリアクセストークンではなく、コンテキストにバインドされた交換済みトークンを使うプロキシルート。最初に一致したパターンが優先されます。 |
WebSocket
WebSocket のハンドシェイクにはカスタムヘッダーもベアラートークンも載せられないため、偽造防止ヘッダーもプロキシも役に立ちません。チケットを有効にすると、SPA は GET /bff/ws-ticket を呼び出し、有効期間の短い使い捨てのチケットを接続 URL に付け、API 側でそれを引き換えられます。チケットは毎回、接続の直前に発行してください。初回の使用で削除され、数秒で期限切れになります。
| オプション | デフォルト | 機能 |
|---|---|---|
WsTicketsEnabled | false | ws-ticket エンドポイントを有効にします。デフォルトはオフです。 |
WsTicketLifetime | 30s | チケットの有効期間。URL に載せて送られるため、意図的に短くしています。 |
TicketExchangeParams | [] | チケットリクエストがトークン交換に転送できるクエリパラメーター。これにより、チケットはあらゆる用途に有効になるのではなく、そのコンテキストにバインドされます。 |
意図的にブラウザにトークンを渡す
BFF の要点はブラウザがトークンを保持しないことなので、この機能はオプトインで、範囲も限定されています。これは Cookie モデルでは対応できない唯一のケース、つまりベアラーで呼び出す必要がある別のオリジン上のリソースサーバー(iframe に埋め込むアプリなど)のための機能です。有効にすると、GET /bff/token?resource=… が交換済みトークンを返します。これはセッションのトークンを、許可リストにある1つのリソースにダウンスコープし、許可リストにあるコンテキストパラメーターにバインドしたものです。ブラウザがセッション自体のトークンを目にすることはなく、受け取るトークンは短寿命で、オーディエンスも1つだけです。許可リスト外のリソースを指定したリクエストは拒否され、これによって汎用のトークン発行手段になることを防いでいます。
| オプション | デフォルト | 機能 |
|---|---|---|
TokenEndpointEnabled | false | token エンドポイントを有効にします。デフォルトはオフです。 |
TokenEndpointResources | [] | トークンの宛先として指定できる resource の値。それ以外は拒否されます。 |
TokenEndpointExchangeParams | [] | コンテキストバインディングとして交換に転送されるクエリパラメーター(例:project_id)。 |
1つの BFF で複数のテナントに対応する
テナントのクエリパラメーターを設定すると、1つのデプロイメントで多数のテナントに対応できます。/bff/login?slug=acme がテナントを選択し、リゾルバーがそのテナントのオーソリティとクライアント資格情報を提供し、キーは相関 Cookie に載ってセッションへ引き継がれ、バックチャネルログアウトではトークンの発行者からテナントを解決します。デフォルトのリゾルバーは単一テナントの動作をバイト単位で同一に保つため、この機能を使わない限りコストは一切かかりません。
複数のインスタンスを実行する
セッションは IBffSessionStore の背後に保存され、そのデフォルトはプロセス内キャッシュです。単一インスタンスなら問題ありませんが、複数インスタンスでは誤りです。次のリクエストが別のレプリカに届いたユーザーはサインアウトされてしまいます。BFF を追加する前に、IDistributedCache 経由の Redis などの共有ストアを登録してください。
共有ストアだけでは不十分
ILeaseProvider を登録するか、セッションストアに IBffRefreshLockStore を実装します。後者は有効期限付きの条件付き書き込みで、すでに Redis を運用しているならこちらが近道です。ストアが共有されているように見えるのにロックがない BFF は、サポートチケットで発覚するまで放置せず、起動時に警告を出します。知っておくべきオプション
全オプションの一覧です(.NET の表記)。Node パッケージはコアオプションを camelCase で受け付けるため、BasePath は basePath、SessionLifetime は sessionLifetimeSeconds となります。PersistentCookie、CorrelationLifetime(Node では 15 分に固定)、LoginPassthroughParams は .NET のみです。
| オプション | デフォルト | 機能 |
|---|---|---|
Authority | - | テナントの認証ホスト。OIDC メタデータはここから検出されます。リゾルバーが提供するマルチテナント構成の場合を除き、必須です。 |
ClientId | - | この BFF 用に登録されたコンフィデンシャルクライアントの ID。 |
ClientSecret | - | クライアントシークレット。BFF はコンフィデンシャルクライアントなので必須です。 |
Scope | openid profile offline_access | 要求するスコープ。offline_access を含めないとリフレッシュトークンが発行されず、アクセストークンの期限切れとともにセッションが終了します。 |
BasePath | /bff | BFF のルートをマウントする場所。 |
CallbackPath | /bff/callback | OIDC のリダイレクト URI のパス。クライアントの登録内容と一致している必要があります。 |
CookieName | __Host-agbff | セッション Cookie の名前。__Host- プレフィックスには HTTPS が必要なため、プレーン HTTP でのローカル開発では別の名前が必要です。 |
SessionLifetime | 8h | セッションの最大有効期間。リフレッシュトークンの絶対有効期間に合わせてください。そうしないと、アイドル状態のユーザーが、まだ有効な資格情報を保持したままサインアウトされます。 |
PersistentCookie | false | ブラウザを閉じても Cookie を維持するかどうか。どちらの場合も、リフレッシュトークンはサーバー側に保持されます。 |
CorrelationLifetime | 30m | ログインの開始からコールバックまでに許容される時間。state、nonce、PKCE verifier を運ぶ Cookie の有効期間を制限します。ログイン画面を開いたまま離れて、後で戻ってきたユーザーにも対応できる長さが必要です。 |
RefreshThresholdSeconds | 60 | アクセストークンを有効期限の何秒前にリフレッシュするか。 |
AntiForgeryHeader | X-Authagonal-Bff | ナビゲーション以外のリクエストでブラウザが送信しなければならないヘッダー名。 |
PostLogoutRedirectUri | - | ログアウト完了後にブラウザが移動する先。 |
ReturnUrlAllowlist | [] | 相対パスでない returnUrl の対象として許可される絶対オリジン。相対パスは常に許可され、それ以外はすべて / に置き換えられるため、ログインルートを通じたオープンリダイレクトは起こりません。 |
LoginPassthroughParams | [] | /bff/login から authorize リクエストへ転送するクエリパラメーター。例えば prompt を転送すると、「はじめる」リンクをサインインではなく登録に振り分けられます。 |
TenantQueryParam | - | 設定すると、1つの BFF で複数のテナントに対応します。上記を参照してください。 |
どちらのランタイムも同じ動作
StripPrefix、authority のゲート、匿名プロキシは .NET のみです。上記の名前は .NET の表記で、Node では対応する camelCase の名前を使います。すべて差し替え可能
IBffSessionStore、Cookie の暗号化には ICookieProtector(デフォルトは ASP.NET Data Protection)、トークンエンドポイントおよび失効エンドポイントとの通信には ITokenClient を使います。また、IBffTenantResolver を使えば1つの BFF で複数のテナントに対応でき、ログイン時はクエリパラメーターからテナントを選択し、バックチャネルログアウト時はトークンの発行者からテナントを解決します。AI アシスタントからポータルを操作する
AI アシスタントをテナントに接続すると、普段はクリックして行う作業を頼めるようになります。サインインできないユーザーを探す、そのユーザーにまだ第 2 要素が残っているかを確認する、誰かを招待する、管理者ロールを持っているのが誰かを調べる、といった作業です。
これは API キーではなく、通常の OAuth 接続です。各メンバーは本人としてサインインしてアクセスを承認するため、アシスタントはその人がポータルで実行できる操作だけを実行でき、それ以上のことはできません。漏洩しうるものは新たに作成されず、あるアシスタントを取り消しても他の人には一切影響しません。
有効化する
設定 を開き、AI アシスタントのアクセス を有効にします。有効にするまではオフのままで、オフの間はエンドポイントが単に拒否するのではなく、存在しない状態になります。有効にすると、AI クライアントに貼り付ける URL がパネルに表示されます。
https://portal-api.authagonal.io/api/v1/mcp/{your-tenant}アシスタントが権限を得る仕組み
アシスタントにできること
接続した本人ができることとまったく同じで、呼び出しのたびにその人自身のトークンに基づいて判定されます。tenant:support のエージェントには診断用ツールと日常業務用ツールが提供されます。管理者用ツールはそのエージェントから単に隠されているだけではなく、名前を直接指定しても拒否されます。ポータル内で制限されている操作はここでも制限されたままです。ユーザーのメールアドレスの変更にはポータルで管理者ロールが必要であり、ここでも同様に必要です。
通常のグラントなので、管理も通常の方法で行えます。アカウントの 承認済みアプリ ページでアシスタントを削除するとリフレッシュできなくなり、現在のアクセストークンの有効期限が切れた時点で動作しなくなります。アシスタントが行った変更はすべて、代理で操作した本人の操作として監査ログに記録されるため、確認する記録はいつも読んでいるものと同じです。
ツール
このリリースには33個のツールがあります。どのツールを有効にするかは AI クライアント側で決めるため、読み取りだけをさせたい場合は読み取り用ツールだけをアシスタントに渡すこともできます。
| ツール | ロール | 機能 |
|---|---|---|
find_user | サポート | メールアドレス、名前の先頭部分、または ID でユーザーを検索します。他のすべての操作の出発点です。 |
get_user | サポート | 1 人のユーザーの全情報を取得します。有効かどうか、確認済みかどうか、ロックアウトされているかどうかも含まれます。 |
get_user_mfa | サポート | ユーザーが登録している第 2 要素を取得します。 |
get_user_sessions | サポート | ユーザーが現在どこでサインインしているかを取得します。 |
search_audit | サポート | 実行者、アクション、または操作対象で監査ログを検索します。 |
list_users | サポート | ディレクトリを一覧表示します。必要に応じて 1 つの組織に絞り込めます。 |
get_user_stats | サポート | ユーザー数と、そのうち第 2 要素を使っている人数を取得します。 |
invite_user | サポート | メールアドレスで誰かを招待します。 |
resend_invite | サポート | 招待を再送します。 |
send_verification_email | サポート | メールアドレス確認メッセージを再送します。 |
update_user | サポート | プロファイルを更新します。メールアドレスの変更には引き続き管理者権限が必要です。 |
revoke_user_sessions | サポート | ユーザーをすべての場所からサインアウトさせます。 |
list_roles | 管理者 | テナントで定義されているロールを取得します。 |
list_role_members | 管理者 | 特定のロールを持っているユーザーを取得します。 |
assign_role | 管理者 | ユーザーにロールを付与します。 |
unassign_role | 管理者 | ロールを外します。 |
reset_user_mfa | 管理者 | 認証アプリを紛失したユーザーのために、すべての第 2 要素を削除します。 |
get_settings | 管理者 | テナントの設定を取得します。 |
list_sso_connections | 管理者 | SSO 接続と、それぞれが対象とするドメインを取得します。 |
list_organizations | 管理者 | テナント内の組織を 1 ページずつ取得します。 |
get_organization | 管理者 | ID またはスラッグで 1 つの組織をメールドメインとともに取得します。 |
create_organization | 管理者 | 組織を作成します。スラッグは変更できません。 |
update_organization | 管理者 | 組織の名前、ポリシーフラグ、メタデータ、またはブランディングを変更します。スラッグは変更できません。 |
delete_organization | 管理者 | 組織とそのすべてのメンバーシップを削除します。 |
list_organization_members | 管理者 | 組織のメンバーを 1 ページずつ取得します。 |
add_organization_member | 管理者 | ユーザーを組織に追加します。 |
update_organization_member | 管理者 | 組織内でのメンバーのステータスまたはロールを変更します。 |
remove_organization_member | 管理者 | ユーザーを組織から削除します。 |
add_organization_domain | 管理者 | 組織のメールドメインを申請します。公開すべき DNS TXT レコードが返されます。 |
verify_organization_domain | 管理者 | TXT レコードを確認し、ドメインを検証済みにします。繰り返し実行しても安全です。 |
remove_organization_domain | 管理者 | ドメインの申請を取り下げます。既存のメンバーはそのまま残ります。 |
list_user_organizations | 管理者 | ユーザーが所属する組織を、各組織でのステータスとロールとともに取得します。 |
list_clients | 開発者 | テナントに登録されている OAuth クライアントを取得します。 |
読み取りと書き込みは明示されています
まだ含まれていないもの
ユーザーの削除、SSO 接続の作成や編集、請求、バックアップ、クライアントシークレットは、いずれもこのリリースには含まれていません。削除は消去キューの横ではなく、消去キューの中で扱うべきものです。SSO 接続は規模が大きく、編集を誤ると従業員全員がロックアウトされかねないため、当面は読み取り専用です。また、クライアントシークレットを返すツールがあると、シークレットがアシスタントのトランスクリプトに残ってしまいます。これらのうちどれが必要か、どの順番で欲しいかをお知らせください。
MCP サーバーの認証
Model Context Protocol サーバーを公開している場合、Authagonal をその背後の認可サーバーにできます。AI アシスタントが接続すると、その利用者がサインインしてアクセスを許可し、お客様のサーバーは他の API と同じように検証できる通常のベアラートークンを受け取ります。
代わりの方法はアシスタントの設定に API キーを貼り付けることですが、これは背後にユーザーがおらず、有効期限も同意の手順もなく、全員分をローテーションせずに1つのコネクターだけを取り消す方法もない資格情報です。OAuth で行えば、グラントは特定の個人に属し、監査ログで確認でき、他に一切影響を与えずにポータルから取り消せます。
接続の流れ
やり取り全体がディスカバリーによって進むため、仕様に準拠したクライアントには、お客様のサーバーの URL 以外の設定は不要です。
| ステップ | 処理内容 |
|---|---|
| 1 | コネクターがトークンなしで MCP サーバーを呼び出し、参照先を示す 401 を受け取ります。 |
| 2 | 保護リソースのメタデータを取得します。そこには、お客様の Authagonal テナントが認可サーバーとして記載されています。 |
| 3 | テナントの認可サーバーメタデータを取得し、まだどこにも登録されていないため、自身を登録します。 |
| 4 | ユーザーをサインインさせてアクセスを承認してもらいます。その際、トークンを求めるリソースとして MCP サーバーを指定します。 |
| 5 | 得られたベアラートークンを使ってサーバーを再度呼び出します。このトークンはそのサーバーとそのユーザーにスコープされています。 |
この流れに Authagonal 固有のものは何もありません。MCP の認可仕様そのもので、リソースメタデータには RFC 9728、認可サーバーの検出には RFC 8414、登録には RFC 7591、リソースの指定には RFC 8707 を使っています。仕様に従うコネクターなら、当社向けの特別な対応なしで動作します。
コネクターに自身を登録させる
面識のないコネクターは手動で作成したクライアントを使えないため、実行時にクライアントを登録します。これはデフォルトではオフです。設定で動的クライアント登録をオンにすると、登録エンドポイントがディスカバリードキュメントに表示されます。オフのままならエンドポイントは公開されず、リクエストを拒否します。有効にしても、登録が開かれるのはお客様のテナントだけで、他のテナントでは決して開かれません。
| ガード | 処理内容 |
|---|---|
| グラントタイプ | 登録できるのは認可コードフローとリフレッシュフローだけです。自己登録で、ユーザーを完全に迂回するマシン間クライアントを作成することはできません。 |
| PKCE | 登録時の要求内容にかかわらず、登録されたすべてのクライアントで強制されます。 |
| 同意 | これも強制されます。登録されたコネクターは、要求内容を人が確認して承認するまでトークンを取得できません。 |
| スコープ | OIDC の組み込みスコープは常に利用できます。それ以外に自己登録するクライアントが要求できるのは mcp という名前のスコープだけで、それもテナントがそのスコープをロール制限なしで定義している場合に限られます。roles と groups は自己登録では要求できません。 |
| レート制限 | 登録は IP アドレスごとに1時間あたり10件までです。そのため、公開されたエンドポイントを使ってクライアントストアを埋め尽くすことはできません。 |
両方のディスカバリーパスに対応
/.well-known/oauth-authorization-server(RFC 8414)を通じて認可サーバーを解決し、OIDC クライアントは /.well-known/openid-configuration を使います。テナントは両方に同じメタデータで応答するため、MCP 仕様に従うコネクターは、参照先を教えられなくてもお客様のテナントを見つけられます。MCP サーバーが実装するもの
必要なのは小さなことが2つだけで、それ以外は通常のリソースサーバーです。1つ目は、お客様のテナントを認可サーバーとして記載した保護リソースメタデータを公開することです。これを well-known パスで配信し、MCP エンドポイントがサブパスにある場合は、パスを末尾に付けた形式でも配信してください。クライアントは両方を試すからです。
GET https://your-app.example/.well-known/oauth-protected-resource
{
"resource": "https://your-app.example/mcp",
"authorization_servers": ["https://acme.authagonal.io"],
"bearer_methods_supported": ["header"],
"scopes_supported": ["mcp"]
}2つ目は、有効なトークンのない呼び出しが届いたときに 401 で応答し、そのメタデータを指す WWW-Authenticate ヘッダーを付けることです。このヘッダーこそが拒否を接続に変えます。これがないと、クライアントは認証先を知る手段がなく、ただ失敗します。
// Validate the connector's token like any other resource server.
builder.Services.AddAuthentication().AddJwtBearer("McpBearer", o =>
{
o.Authority = "https://acme.authagonal.io"; // your tenant
o.TokenValidationParameters.ValidAudience = "https://your-app.example/mcp";
});
// Unauthenticated? Point the connector at the metadata rather than just refusing.
http.Response.Headers.WWWAuthenticate =
"Bearer resource_metadata=\"https://your-app.example/.well-known/oauth-protected-resource\"";
return Results.Unauthorized();署名だけでなくオーディエンスも確認する
スコープ、プラン、失効
スコープページで mcp という名前のスコープをロール制限なしで定義すると、自己登録するコネクターがそれを要求できるようになります。このスコープは同意画面に表示され、ユーザーは何を承認するのかを確認できます。トークンのサブジェクトはサインインした本人なので、サーバーはすべてのコネクターを同じように扱うのではなく、この特定の人物に何を許可するかを判断できます。自己登録したコネクターは roles や groups スコープを要求できないため、これらがトークンに含まれることを期待せず、サーバー側で参照してください。
通常の OAuth グラントなので、失効も通常どおり機能します。ユーザーがアカウントの 承認済みアプリ ページでコネクターを削除すると、そのグラントとリフレッシュトークンが破棄され、更新できなくなります。既存のアクセストークンは /connect/introspect と /connect/userinfo によって直ちに拒否されますが、JWT をローカルで検証するだけのサーバーは有効期限が切れるまでそれを受け入れます。監査ログには、各サインインが対象のクライアントとともに記録されます。
| 設定 | 処理内容 |
|---|---|
Dynamic client registration | コネクターによる自己登録を許可するポータル設定。デフォルトはオフです。 |
mcp | 自己登録するクライアントが要求できる、OIDC の組み込み以外の唯一のスコープ。提供するには、テナントでロール制限なしで定義します。 |
resource | コネクターが MCP サーバーを指定するために送信するパラメーター。トークンのオーディエンスをそのサーバーに絞り込みます。 |
独自のログイン UI を構築する
Authagonal がホストするログイン、登録、パスワード再設定、MFA の画面を独自の UI に置き換えられます。認証、MFA、SSO、セッション、トークン発行は引き続き Authagonal が担います。方法は 2 つあります。React コンポーネントライブラリを使うか、任意のフレームワークから認証 API を直接呼び出すかです。この機能はオプトインです。まず 設定 → セッション で カスタムログイン UI を有効にしてください。


前提条件:ルートドメイン上のカスタムドメイン
ログインセッションはファーストパーティ Cookie なので、UI と Authagonal の認証サーバーは同じ登録可能ドメインを共有する必要があります。アプリが動いているのと同じルートドメインで、カスタム認証ドメインを Authagonal に向けてください。例:認証は login.acme.com、アプリは app.acme.com。有効なカスタムドメインが存在するまで、カスタムログイン UI の設定は無効のままです。
| 自社の UI | 認証ホスト | 動作 |
|---|---|---|
| app.acme.com | login.acme.com | ✅ 同じルート |
| acme.com | auth.acme.com | ✅ 同じルート |
| app.acme.com | acme.authagonal.io | ❌ クロスサイト |
| myapp.io | login.acme.com | ❌ クロスサイト |
カスタムドメインが必要な理由
/api/auth の呼び出しには、クライアントの CORS 設定は不要です。カスタムログイン UI をオンにすると、認証ドメインと同じ登録可能ドメイン上のすべてのオリジンが自動的に許可されます。UI のオリジン(例:https://app.acme.com)をクライアントの 許可する CORS オリジン(クライアント → URI)に追加する必要があるのは、ブラウザがトークン交換も行う場合だけです。
React:@authagonal/login
npm i @authagonal/login は、認証ロジックと UI を 1 つのパッケージで提供します。Authagonal のホスト型ログイン自体もこのパッケージで構築されています。使い方の粒度を選んでください:
- アプリ全体:
Appを組み込み、ブランディングでテーマを設定します。 - ページを組み合わせる:
LoginPage、MfaChallengePage、ResetPasswordPageなどを独自のレイアウト内で使います。 - プリミティブとロジック:
AuthLayout/Button/Inputと API クライアント(login、mfaVerify、forgotPasswordなど)で独自の画面を構築します。
import { AuthLayout, Input, Button, login, ApiRequestError } from '@authagonal/login';
// returnUrl: the /connect/authorize URL your login page was opened with
function MyLogin({ returnUrl }: { returnUrl: string }) {
async function onSubmit(email: string, password: string) {
try {
const res = await login(email, password, returnUrl); // POST /api/auth/login (sets the session cookie)
if (res.mfaRequired) {/* render your MFA step, then mfaVerify(res.challengeId!, 'totp', code) */}
else if (res.mfaSetupRequired) {/* enrol first: mfaTotpSetup(res.setupToken) */}
else window.location.href = returnUrl; // resume /connect/authorize
} catch (e) {
if (e instanceof ApiRequestError) {/* show e.message; e.error is the error code */}
}
}
return <AuthLayout>{/* your own markup + <Input/> <Button/> */}</AuthLayout>;
}任意のフレームワーク:認証 API を呼び出す
React を使っていない場合は、認証フローのエンドポイント(/api/auth 配下)を直接呼び出し、その後で標準の OIDC /connect/authorize フローに引き渡します。セッション Cookie が保存されるよう、credentials: 'include' を送信してください。
| エンドポイント | 用途 |
|---|---|
POST /api/auth/login | 認証します。mfaRequired または戻り先 URL を返します |
POST /api/auth/register | セルフサービス登録(有効な場合) |
POST /api/auth/forgot-password | パスワード再設定を開始 |
POST /api/auth/reset-password | パスワード再設定を完了 |
GET /api/auth/password-policy | パスワードポリシー(ルールの表示用) |
POST /api/auth/mfa/* | MFA のセットアップと検証(TOTP、WebAuthn、リカバリー) |
credentials: 'include' を使用する
# 1. Authenticate (browser fetch; credentials:'include' so the session cookie is stored)
curl -i -X POST https://login.acme.com/api/auth/login \
-H "Content-Type: application/json" \
-H "Origin: https://app.acme.com" \
--data '{"email":"[email protected]","password":"..."}'
# (handle {"mfaRequired":true} → POST /api/auth/mfa/verify, then continue)
# 2. Hand off to the OAuth flow: top-level navigation to the authorize endpoint with PKCE:
# https://login.acme.com/connect/authorize?client_id=my-app&redirect_uri=...&response_type=code
# &scope=openid%20profile%20email&code_challenge=...&code_challenge_method=S256
# The session cookie (same-site) authenticates the user; you get back a code → exchange at /connect/token.1つのテナント、多数の顧客
1社のインテグレーター、1つのテナントで、それぞれ独自のログインドメインと独自のユーザーを持つ N 社のブランド付き顧客を、顧客ごとにテナントを作らずに扱うためのパターンです。宣言的プロビジョニングと組織は、これをエンジニアリング作業ではなく設定変更で済ませるために存在します。
構成
- 顧客ごとに1つの組織を、単一のテナント内に作成します。
- 顧客ごとに1つのブランド付きログインドメインを用意し、それぞれをその顧客の組織に固定します。そのドメインでサインインしても、その組織向けのトークンしか発行されません。
- アプリケーションも顧客ごとのホストで配信しますが、すべて同じデプロイメントからです。コード、ビルド、イメージのいずれも顧客間で違いはありません。
- リライングパーティーは、ビルド時の定数ではなく、自身が動作しているホストからオーソリティを選びます。同じバンドルが、どの顧客ホストから配信されたかに応じて、異なるログインドメインに自らを接続します。
手順
顧客をプロビジョニングします。新しい組織とそのドメインを指定したスペックで宣言的プロビジョニングエンドポイントを呼び出します。この呼び出しは冪等で、セクション単位で適用されます。
{
"organizations": [
{ "slug": "acme", "name": "Acme Pty Ltd" }
],
"customDomains": [
{ "domain": "login.acme.example", "organizationSlug": "acme" }
]
}顧客の DNS をテナントに向けます。顧客自身のゾーンに CNAME を1つ設定するだけで、管理権限と意図の両方を証明できます。TXT トークンは不要です。
_authagonal-challenge.login.acme.example. CNAME <slug>.<platformDomain>.
プラットフォームと同じ Cloudflare アカウントの場合
アプリケーションを顧客のホストに向けます。リライングパーティーは、現在配信しているホストに基づいて、リクエストごとに自身の OIDC オーソリティを解決します。顧客マップにエントリがないホストは従来の単一テナントの導出方法にフォールバックするため、顧客の追加は既存に影響しない純粋な追加になります。
export function resolveCustomer(): { authority: string; clientId: string } {
const cfg = getConfig();
const customer = cfg.customers?.[window.location.host];
if (customer) return customer;
const baseDomain = cfg.baseDomain || window.location.hostname.replace(/^consumer\./, '');
return { authority: `https://${cfg.tenantSlug}.${baseDomain}`, clientId: cfg.clientId };
}クライアントは組織固有のものを何も要求しません。organization パラメーターも、顧客ごとのスコープもありません。組織の選択はドメインの固定によって完全にサーバー側で行われます。だからこそ「アプリはすべての顧客で同じコード」が実際に成り立ちます。
顧客に表示される内容
ログインページは、テナントのブランディングに各組織独自のブランディングを重ねて表示します。ブランディングの上書きを参照してください。各顧客は、他の顧客に影響を与えることなく、独自のアプリ名、ロゴ、色、サポートメールを持てます。
顧客 A のユーザーが顧客 B のホストでサインインしようとすると、顧客 B のデータが表示されるのではなく、拒否されます。競合がどのように生じたかに応じて、拒否は次の2つの形のいずれかになります。
- リライングパーティーは何も送らず、固定されたドメインにアクセスするだけです。固定がユーザーに代わって組織を指定するため選択は明示的になり、B のメンバーシップを持たない顧客 A のユーザーは、トークンが発行される時点で拒否されます。
- リライングパーティー自身が別の組織を指定する場合です。ログインページが表示される前に、ドメイン固定ミドルウェアによって
400で直接拒否されます。
メンバーシップによる拒否はアプリにリダイレクトされる
redirect_uri への通常の error=access_denied OIDC リダイレクトであり、どの組織のメンバーシップが欠けていたかを正確に示す説明が付きます。N+1 社目の顧客のオンボーディング
Terraform でプロビジョニングの呼び出しを行っていれば、次の顧客のオンボーディングは1つのファイルの編集で済みます。organizations 配列にエントリを1つ、それを固定するドメインエントリを1つ、DNS レコードを1つ追加するだけです。アプリケーション、そのデプロイメント、ビルドは一切変わりません。ホストベースのリゾルバーは、設定エントリが存在した瞬間に新しい顧客を認識します。
リファレンス実装
永続的な開発用テナントが、2つの実在する顧客ドメインに対してこのパターン全体をエンドツーエンドで実行しています。そのエンドツーエンドテストスイートは、メンバーをプロビジョニングし、ブランディングと org_id クレームを確認し、上記の2つの拒否の形をどちらも検証します。単なる説明ではなく、実行可能なドキュメントです。
cd e2e-consumer && DOMAIN=authagonal.dev npx playwright test organizations-domains
このスイートは他のすべてのスペックと同様にデフォルトで実行されます。リポジトリ自体の管理外にあるインフラに依存する唯一のスペックであるため、リファレンスドメインがプロビジョニングされていない環境ではスキップできます。
プランと上限
Authagonal には Free プランと 4 つの有料プランがあります。すべてのプランにすべての認証機能が含まれています。プランの違いは月間アクティブユーザー(MAU)の上限と超過料金です。また、Free プランはコミュニティサポートのみで、テナントサポートデスクは含まれません。
プラン一覧
| プラン | MAU 上限 | 超過 | 超過料金/ユーザー |
|---|---|---|---|
| Free | 250 | いいえ | - |
| Starter | 1,000 | いいえ | - |
| Pro | 5,000 | はい | $0.04/ユーザー |
| Scale | 25,000 | はい | $0.025/ユーザー |
| Enterprise | 100,000 | はい | $0.015/ユーザー |
月間アクティブユーザー(MAU)
月間アクティブユーザーとは、暦月(UTC)の間に少なくとも 1 回認証に成功した一意のユーザーです。SCIM でプロビジョニングされていても、ログインしていないユーザーは MAU の合計にカウントされません。
超過:プランが超過に対応しており(Pro 以上)、テナントで超過が有効になっている場合(デフォルトではオフ)、MAU の上限を超えたユーザーには、上のプラン表に記載されたユーザー単価で請求されます。超過の上限は、上限を超えて許可する追加ユーザーの最大数を設定するものです。
適用:プランが超過に対応していない場合(Free、Starter)、または超過が有効になっていない場合、今月すでにサインインしたユーザーは常にアクセスを維持できます。テナントが初めて上限を超えると 10 日間の猶予期間が始まり、その間は新しいユーザーもサインインできます。猶予期間が過ぎると、今月まだサインインしていないユーザーは、翌月になるかアップグレードするまで拒否されます。
すべてのプランで全機能を利用可能