ステップアップ認証 (Step-up authentication)
ステップアップ認証 (Step-up authentication) を利用すると、アプリケーションはユーザーをサインアウトさせることなく、支払いの認可、機密記録の閲覧、アカウントのセキュリティ設定の変更などの機密操作を行う前に、最近のユーザー認証やより強力な認証保証レベルを要求できます。
Logto は OpenID Connect Core、RFC 9470 (OAuth 2.0 Step Up Authentication Challenge Protocol)、RFC 8176 (Authentication Method Reference Values) に基づいた標準準拠のステップアップ認証 (Step-up authentication) を実装しています:
- 保護されたリソースサーバーは、不十分なトークンに対して
401 Unauthorizedと、acr_valuesおよびmax_ageを含む RFC 9470 のWWW-Authenticateヘッダーでチャレンジします。 - アプリケーションは
acr_valuesとmax_ageを指定して認可コードフローを開始します。すでに認証済みセッションが存在する場合、Logto はサインイン済みユーザーを固定し、不足している検証のみを促します。 - Logto は達成された認証コンテキスト(
acr、amr、auth_time)をセッションに記録し、ID トークン、JWT アクセストークン、不透明トークン (opaque-token) のイントロスペクション応答に出力します。
認証コンテキストモデル
Logto 体験 (Experience) を通じて完了したすべてのサインイン、登録、ステップアップは、アプリケーションが acr_values を要求したかどうかに関わらず、OIDC セッションに 3 つの標準クレームを記録します:
| クレーム | 型 | 説明 |
|---|---|---|
acr | string | 認証コンテキストクラス参照 (Authentication Context Class Reference) — 達成した保証レベル。満たされない場合は省略。 |
amr | string[] | 認証方法参照 (Authentication Methods References) — そのやり取りで使用された検証方法。 |
auth_time | number | エンドユーザー認証が完了した時点のエポックタイムスタンプ(秒単位)。 |
Logto はこれらの機能を OIDC Discovery(/.well-known/openid-configuration および /.well-known/oauth-authorization-server)で公開しています:
{
"acr_values_supported": ["urn:logto:acr:1fa", "urn:logto:acr:mfa"],
"claims_supported": ["sub", "acr", "amr", "auth_time"]
}
ID トークンでは、acr、amr、auth_time はセッションに存在する場合、標準の openid スコープ下で含まれます。ユーザーアクセストークンでは、Logto はこれらを認可コード、デバイスコード、またはリフレッシュトークンから JWT ペイロードや不透明トークン (opaque-token) のイントロスペクション応答にコピーします。リフレッシュトークンのローテーションは元の acr、amr、auth_time を保持します — トークンのリフレッシュで auth_time が進むことはありません。他のグラントタイプ(クライアントクレデンシャルやトークンエクスチェンジなど)は認証コンテキストクレームを出力しません。
サポートされる ACR 値
Logto は 2 つの認証コンテキストクラス参照 (Authentication Context Class Reference, acr) 値を定義しています:
| ACR 値 | 意味 | 満たすクラス |
|---|---|---|
urn:logto:acr:1fa | Logto が直接検証またはやり取りで確立した少なくとも 1 つの要素:パスワード、主要メールまたは電話の認証コード、マジックリンク(サインイン時のワンタイムトークン)、または登録済み MFA 要素。 | urn:logto:acr:1fa |
urn:logto:acr:mfa | Logto で検証可能なファーストファクター(1fa ロール)証明と、異なる要素による mfa ロール証明の組み合わせ、またはユーザー検証付き WebAuthn / パスキー単独。 | urn:logto:acr:mfa, urn:logto:acr:1fa |
満足関係は urn:logto:acr:mfa → urn:logto:acr:1fa です:urn:logto:acr:mfa を持つセッションやトークンは urn:logto:acr:1fa の要件も満たします。標準の phr や phrh ACR 値はサポートされていません。WebAuthn やパスキーのセレモニーはユーザー検証が必要で、urn:logto:acr:mfa にマッピングされます。
urn:logto:acr:mfa を導出する際、Logto は各検証方法をペアリングロールで分類します:
- ファーストファクター(
1faロール):パスワード、主要メール認証コード、主要電話認証コード、ワンタイムトークン(サインインのみ)。 - セカンドファクター(
mfaロール):認証アプリ OTP(TOTP)、バックアップコード、MFA メール認証コード、MFA 電話認証コード。Logto で検証可能なファーストファクターなしでmfaロール要素のみを検証した場合(例:ソーシャルサインイン + TOTP)はurn:logto:acr:1faとなり、urn:logto:acr:mfaにはなりません。 - 自己完結型(
bothロール):パスキーサインインやユーザー検証付き WebAuthn MFA は 1 回のセレモニーで両方のロールを満たし、単独でurn:logto:acr:mfaとなります。 - 異なる要素ルール:
urn:logto:acr:mfaには 2 つの異なる要素が必要です。2 つのファーストファクター(例:登録時のメール認証コード + パスワード)、2 つのmfaロール要素(例:TOTP + バックアップコード)、または同じチャネルの 2 つの証明(例:主要メールコード + MFA メールコード)は 1 つの要素またはロールと見なされ、urn:logto:acr:1faとなります。 - 信頼済みデバイスと適応型 MFA:信頼済みデバイス の充足や適応型 MFA のスキップは現在のやり取りで何も証明せず、
acrに寄与しません(信頼済みデバイスで MFA をスキップしたパスワードサインインはacr="urn:logto:acr:1fa"、amr=["pwd"]となります)。
登録も同じルールで認証コンテキストを記録します。なぜなら、アカウント作成時に書き込まれる認証情報がそのアカウントを証明するからです。例えば、ユーザー名とパスワードで登録した場合は acr="urn:logto:acr:1fa"、amr=["pwd"] となります。
AMR マッピング
Logto は RFC 8176 の値に加え、フェデレーテッド認証 (federated authentication) 用に fed を amr に設定します:
| Logto 検証方法 | amr 値 | acr への寄与 |
|---|---|---|
| パスワード(検証済み、または登録/ステップアップ時に新規設定) | pwd | Yes(1fa ロール) |
| 主要メール認証コード | otp | Yes(1fa ロール) |
| 主要電話認証コード | sms | Yes(1fa ロール) |
| ワンタイムトークン / マジックリンク(サインインのみ、ステップアップ不可) | otp | Yes(1fa ロール) |
| 認証アプリ OTP(TOTP、検証済みまたは新規バインド) | otp | Yes(mfa ロール) |
| MFA メール認証コード | otp | Yes(mfa ロール) |
| MFA 電話認証コード | sms | Yes(mfa ロール) |
| バックアップコード | otp | Yes(mfa ロール) |
| WebAuthn MFA またはパスキーサインイン(ユーザー検証付き、検証済みまたは新規バインド) | pop, user, mfa | Yes(both ロール) |
| ソーシャルサインインまたはエンタープライズ SSO | fed | No |
達成した acr が urn:logto:acr:mfa のやり取り | mfa を追加 | — |
フェデレーテッド認証 (fed)
Logto は、ユーザーが Logto で直接検証できない上流のソーシャルまたはエンタープライズ SSO 証明で認証されたことを示すために fed を出力します。
- 純粋なソーシャルまたはエンタープライズ SSO サインインや登録は
amr=["fed"]と新しいauth_timeを記録し、acrクレームはありません。 fedはファーストファクターではなく、上流ログインを繰り返してもacrは上がりません。ソーシャルサインイン後に Logto で検証可能な要素(例:TOTP)を完了するとacr="urn:logto:acr:1fa"、amr=["fed", "otp"]となります。auth_time単独では保証を持たないため、必ずacrも併せて確認してください。- どの上流プロバイダーで認証されたかは
amrではなく、identitiesやsso_identitiesクレームで確認できます。
ステップアップによるセッションとトークンクレームの更新
既存の OIDC セッションで acr_values を伴う認可リクエストが到着し、やり取りが必要な場合、体験 (Experience) はステップアップモードに入ります:
- サブジェクト固定と累積 ACR:Logto は現在のセッションの
subを固定し(アカウント切り替え、識別子入力、登録は不可)、不足している保証のみを要求します。明確なセッション方法はそのペアリングロールをステップアップに持ち込みます:pwdやsmsで認証されたセッションはすでに1faを満たしているため、urn:logto:acr:mfaへのステップアップでは登録済み MFA 要素のみを要求します(max_age=0やprompt=loginで新規認証を強制しても同様)。- ソーシャルやエンタープライズ SSO セッション(
amr=["fed"])は1faを満たさないため、urn:logto:acr:mfaには MFA の前にファーストファクターの証明(または確立)、もしくは WebAuthn パスキーの検証が必要です。
amrとauth_timeは現在のやり取りのみを反映:パスワードセッションでステップアップ時に TOTP を検証すると、acr="urn:logto:acr:mfa"、amr=["otp", "mfa"]、新しいauth_timeとなります。リライングパーティはacrから保証を読み取り、amrでファーストファクターを探してはいけません。- セッションの置き換え、マージなし:ステップアップ完了後、セッションの
acr、amr、auth_timeは新しいやり取りで達成されたコンテキストに置き換えられます。例えば、urn:logto:acr:1faのためにパスワード再認証を行うと、セッションはacr="urn:logto:acr:1fa"、amr=["pwd"]となります。以前発行されたトークンは発行時のクレームを保持します。 - ポリシーの上書きと副作用:
urn:logto:acr:1faを要求すると、1 つの有効な検証のみが必要で、テナントのサインイン MFA ポリシーは再実行されません。urn:logto:acr:mfaを要求すると、信頼済みデバイスの充足、ユーザーのskipMfaOnSignIn設定、適応型 MFA の非トリガー結果は無視されます。純粋なステップアップではPostSignInWebhook やアクションなどのサインイン副作用は実行されません。
acr_values 要求時に認証済み OIDC セッションが存在しない場合、Logto は通常のサインインまたは登録フローを実行し、認可コード発行前に要求された ACR を完了要件として強制します。
ステップアップ認証 (Step-up authentication) のリクエスト
認可コードフローリクエストで /oidc/auth に acr_values と max_age を渡します。
acr_values の順序付きリストセマンティクス
acr_values は呼び出し側の優先順で並べたスペース区切りの ACR 値リストです(例:urn:logto:acr:mfa urn:logto:acr:1fa)。Logto は未認識の値を無視します。いずれの値もサポートされていない場合(例:acr_values=phr)、Logto は UI を表示せず即座に redirect_uri へ error=unmet_authentication_requirements でリダイレクトします。
少なくとも 1 つのサポートクラスが要求された場合:
- 最初のクラスがすでに満たされている:認証済みセッションが
acr_valuesの最初のサポートクラスを満たし、max_ageも満たし、prompt=loginが要求されていなければ、Logto は UI なしで即座に認可コードを発行します。 - 後ろのクラスのみ満たされている:セッションが後ろのクラスのみ満たしている場合(例:
acr_values="urn:logto:acr:mfa urn:logto:acr:1fa"で1faセッション)、Logto は先頭クラス(urn:logto:acr:mfa)を目指してステップアップやり取りを開始します。- ユーザーが
urn:logto:acr:mfaに到達できる場合(登録済み MFA 要素の検証や新規登録)、体験 (Experience) でそれを促します。 urn:logto:acr:mfaに到達できない場合(MFA 要素未登録か、テナントで登録可能な TOTP や WebAuthn 要素が無効)、Logto は次に到達可能なクラス(urn:logto:acr:1fa)にフォールバックします。セッションがすでにそのクラスを満たし、新規認証が強制されていなければ、Logto は UI を表示せずセッションの元のauth_timeを保持します。
- ユーザーが
unmet_authentication_requirementsで厳格に失敗:Logto はやり取りで目指すクラスより弱い ACR でトークンを発行しません。いずれのクラスも到達不可能な場合のみ、Logto はredirect_uriへerror=unmet_authentication_requirementsでリダイレクトします。
厳格なリクエストと弱いクラスでの再試行パターン
ユーザーが MFA を満たせない場合のアプリケーションの扱い方に応じて、2 つのパターンから選択できます:
- 特定クラスを厳格に要求し、アプリ側で再試行や分岐:
acr_values=urn:logto:acr:mfaのみを要求します。Logto はmfaトークンまたはerror=unmet_authentication_requirementsリダイレクトのいずれかを保証します。unmet_authentication_requirements受信時、コールバックハンドラーでacr_values=urn:logto:acr:1faで再認可するか、操作をブロックするか、承認ワークフローにルーティングするかを明示的に判断できます。 - 1 回のリクエストで順序付きフォールバックを宣言:
acr_values="urn:logto:acr:mfa urn:logto:acr:1fa"を要求します。Logto は到達可能な場合はmfaを追求し、ユーザーやテナントでmfaに到達できない場合のみ自動的に1faにフォールバックします。結果のアクセストークンのacrを検証して、どのレベルが達成されたかを確認してください。
ステップアップ画面を放棄してもフォールバックやアプリへの通知は行われません — キャンセルエンドポイントはなく、放棄されたやり取りは単に期限切れになるか、次の認可リクエストで置き換えられます。保留中のアクション状態はアプリケーション側で管理し、ユーザーがコールバックを完了せずに戻った場合はクリアしてください。
max_age と acr_values の組み合わせ
max_age はユーザーの直近のアクティブ認証(auth_time)からの経過秒数の最大値を指定します:
max_ageはauth_timeをチェックし、トークンのexpではありません。トークンのリフレッシュではauth_timeはリセットされません。max_age=0(またはprompt=login)は、セッションが要求されたacrをすでに保持していても新規インタラクティブ検証を強制します。max_ageのみ(acr_valuesなし)は通常の/sign-inフローとなり、保証レベルは強制されません — ユーザーはソーシャルサインインで再認証でき、auth_timeは更新されてもacrはありません。操作に新鮮さと Logto で検証された保証が両方必要な場合は、必ずacr_valuesとmax_ageの両方を送信してください。
prompt=none でのサイレントギャップ検出
ユーザーの現在の Logto セッションが保証と新鮮さの要件をすでに満たしているかを UI を表示せず、登録も促さずに確認するには、prompt=none と acr_values(および任意で max_age)を組み合わせます:
- 満たされている場合:
prompt=noneは UI なしで優先順を追求するため、セッションがacr_values内のいずれかのサポートクラスをmax_age内で満たしていれば認可コードを発行します。 - 認証済みセッションだが要件未満または古い場合:Logto は
error=unmet_authentication_requirementsでリダイレクトします(max_ageエラーより優先)。 - 認証済みセッションがない場合:Logto は
error=login_requiredでリダイレクトします。
認可 URL と SDK の例
保護された API リソースに対し、直近 5 分(300 秒)以内の MFA を要求する生の認可リクエスト例:
GET /oidc/auth?client_id=my-web-app
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&response_type=code
&scope=openid%20offline_access%20payment%3Awrite
&resource=https%3A%2F%2Fapi.example.com
&acr_values=urn%3Alogto%3Aacr%3Amfa
&max_age=300
&state=8f3d9c1b2a...
&nonce=4e1a7b9c0f...
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256 HTTP/1.1
Host: [tenant-id].logto.app
Logto の JavaScript / TypeScript SDK(@logto/browser、@logto/react、@logto/vue、@logto/node など)では、extraParams で acr_values と max_age を渡します。シングルページアプリケーションでユーザーがすでにサインインしている場合、clearTokens: false を設定すると、ユーザーがステップアップを放棄したり OIDC エラーで戻った場合でもキャッシュされたトークンが保持されます:
await signIn({
redirectUri: 'https://app.example.com/callback',
clearTokens: false,
extraParams: {
acr_values: 'urn:logto:acr:mfa',
max_age: '300',
},
});
コールバックルートでは、handleSignInCallback() を呼ぶ前に error を確認します:
const params = new URLSearchParams(window.location.search);
const error = params.get('error');
if (error === 'unmet_authentication_requirements') {
// ユーザーが要求された ACR に到達できない(または prompt=none でギャップを検出)。
// 必要に応じて 'urn:logto:acr:1fa' など弱いクラスで再試行するか、説明を表示してください。
return;
}
認証コンテキストは Logto セッションに属し、単一の API リソースに限定されません。resource インジケーターでステップアップを要求すると、そのリソース用に昇格したトークンが発行されます(スコープ未許可の場合は同意画面を表示)。他の API リソース用に以前発行されたトークンは変更されません。各リソースサーバーは提示されたトークンの acr と auth_time を評価します。
保護されたリソースサーバーでのチャレンジと検証
認可 (Authorization) の判断はバックエンドや保護されたリソースサーバーで行います:
- アクセストークン を必ずリソースサーバーで検証し、ID トークンでは検証しないでください。
- ブラウザアプリケーションはアクセストークンを不透明トークン (opaque token) として扱うべきです。アプリケーションは UI 状態の調整のために ID トークンから
acrやauth_timeを読むことはできますが、セキュリティ強制のためにクライアント側デコードに依存してはいけません。
RFC 9470 チャレンジの返却
アクセストークンがベアラートークンとして有効(署名、iss、aud、exp、scope が有効)だが、必要な acr がない、または max_age を超えている場合は、401 Unauthorized と RFC 9470 の WWW-Authenticate ヘッダーで応答します:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="insufficient_user_authentication",
error_description="直近 5 分以内の多要素認証が必要です",
acr_values="urn:logto:acr:mfa",
max_age="300"
アプリケーションが error="insufficient_user_authentication" の 401 を受信した場合、WWW-Authenticate から acr_values と max_age をパースし、ユーザーの保留中ルートや意図をローカルに保持し、それらのパラメータで signIn() をトリガーし、新たに発行されたアクセストークンで API コールを 1 回だけ再試行します。コールバック後の再試行でも 401 を受け取った場合は、2 回目のステップアップを開始しないことでリトライループを防いでください。
JWT アクセストークンの検証
API リソースインジケーター(resource)が要求された場合、Logto は acr、amr、auth_time を含む署名付き JWT アクセストークンを発行します:
{
"iss": "https://[tenant-id].logto.app/oidc",
"sub": "user-id",
"aud": "https://api.example.com",
"client_id": "my-web-app",
"scope": "payment:write",
"exp": 1787749200,
"iat": 1787745601,
"auth_time": 1787745600,
"acr": "urn:logto:acr:mfa",
"amr": ["pwd", "otp", "mfa"]
}
標準 JWT クレームの検証(JWKS での署名、iss、aud、exp、scope)後、満足関係で acr を検証し、auth_time(iat ではなく)をポリシーと比較します:
import { createRemoteJWKSet, jwtVerify } from 'jose';
const issuer = 'https://[tenant-id].logto.app/oidc';
const jwks = createRemoteJWKSet(new URL(`${issuer}/jwks`));
type LogtoAcr = 'urn:logto:acr:1fa' | 'urn:logto:acr:mfa';
const satisfiedAcrs: Record<string, readonly LogtoAcr[]> = {
'urn:logto:acr:1fa': ['urn:logto:acr:1fa'],
'urn:logto:acr:mfa': ['urn:logto:acr:mfa', 'urn:logto:acr:1fa'],
};
const acrSatisfies = (achieved: unknown, required: LogtoAcr): boolean => {
if (typeof achieved !== 'string') {
return false;
}
return Boolean(satisfiedAcrs[achieved]?.includes(required));
};
export async function verifySensitiveRequest(
bearerToken: string,
requiredAcr: LogtoAcr = 'urn:logto:acr:mfa',
maxAgeSeconds = 300
) {
const { payload } = await jwtVerify(bearerToken, jwks, {
issuer,
audience: 'https://api.example.com',
});
const authTime = payload.auth_time;
const nowSeconds = Date.now() / 1000;
const isFresh =
typeof authTime === 'number' &&
Number.isInteger(authTime) &&
nowSeconds - authTime >= 0 &&
nowSeconds - authTime <= maxAgeSeconds;
if (!acrSatisfies(payload.acr, requiredAcr) || !isFresh) {
const challenge =
`Bearer error="insufficient_user_authentication", ` +
`error_description="Recent user authentication is required", ` +
`acr_values="${requiredAcr}", max_age="${maxAgeSeconds}"`;
return { authorized: false as const, wwwAuthenticate: challenge };
}
return { authorized: true as const, payload };
}
不透明アクセストークン (opaque access token) のイントロスペクションによる検証
API resource が要求されていない場合、Logto は 不透明アクセストークン (opaque token) を発行します。これを検証するには、RFC 7662 のイントロスペクションエンドポイント(POST /oidc/token/introspection)にクライアント認証付きで呼び出します。Logto はアクティブな応答のトップレベルで acr、amr、auth_time を返します:
curl -X POST https://[tenant-id].logto.app/oidc/token/introspection \
-u "<client_id>:<client_secret>" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "token=<opaque_access_token>" \
--data-urlencode "token_type_hint=access_token"
イントロスペクション応答例:
{
"active": true,
"client_id": "my-web-app",
"exp": 1787749200,
"iat": 1787745601,
"iss": "https://[tenant-id].logto.app/oidc",
"scope": "openid offline_access profile",
"sub": "user-id",
"token_type": "Bearer",
"acr": "urn:logto:acr:1fa",
"amr": ["pwd"],
"auth_time": 1787745600
}
まず active === true を確認し、上記と同様に acrSatisfies と auth_time のチェックを適用してください。
カスタム JWT の予約クレーム
ユーザーアクセストークンの acr、amr、auth_time は予約済みです。カスタムアクセストークンスクリプト でこれらを上書きしたり、Logto が認証コンテキストを導出しない場合に追加したりすることはできません。
ファーストファクターの確立と MFA 登録
urn:logto:acr:1fa や urn:logto:acr:mfa を要求されたユーザーが、そのクラスに到達するための認証情報をまだ持っていない場合があります。例えば、パスワードのみのユーザーで MFA を登録したことがない場合や、ソーシャルのみのユーザーでパスワードや主要メール/電話コード、MFA 要素を持たない場合です。Logto では、同じサインインまたはステップアップやり取りの中で 不足しているファーストファクターの確立や MFA の登録が可能です。ただし、厳格な新鮮さの前提条件で制御されているため、盗まれたセッションクッキーだけで登録や確立はできません:
- MFA 要素の登録:ユーザーが
urn:logto:acr:mfaに到達できる登録済み MFA 要素を持っていない場合のみ、かつ現在のやり取りで Logto で検証可能なファーストファクター(1faまたはbothクラス)が検証または確立された後にのみ提供されます。- セッションの保存済み
acrや信頼済みデバイスのクッキーはこのゲートを満たしません。MFA 未登録のパスワードユーザーは、まずステップアップでパスワードを再入力し、その後 TOTP や WebAuthn パスキーをバインドできます(TOTP や WebAuthn と一緒にバックアップコードもオプションで登録可能。バックアップコード単独での登録は不可)。
- セッションの保存済み
- ファーストファクターの確立:ユーザーが追求するクラスに到達できるファーストファクターを持っていない場合(例:ソーシャルのみのユーザーが
1faを要求、または TOTP のみでmfaを要求)かつ現在のやり取りで新鮮なサブジェクト証明がある場合のみ提供されます:- 既存セッションでのステップアップ中は、ユーザーはサインイン体験 (Sign-in Experience) で有効なすでにリンク済みのソーシャルまたはエンタープライズ SSO コネクターで再認証してサブジェクトを証明します。上流コールバックが別ユーザーや未リンクアカウントに解決した場合、Logto は
403で拒否します — 登録やアカウントリンクは許可されません。 - サブジェクト証明が成功すると、テナントでサインイン用に有効なファーストファクター(パスワード、主要メールまたは電話番号の検証済み設定)を確立できます。例えば、Google で再認証しパスワードを設定したソーシャルのみのユーザーは
acr="urn:logto:acr:1fa"、amr=["fed", "pwd"]で完了します。 - すでに検証可能な方法を持つ場合は、確立は代替手段として提供されません。
- 既存セッションでのステップアップ中は、ユーザーはサインイン体験 (Sign-in Experience) で有効なすでにリンク済みのソーシャルまたはエンタープライズ SSO コネクターで再認証してサブジェクトを証明します。上流コールバックが別ユーザーや未リンクアカウントに解決した場合、Logto は
Logto はやり取り中に確立・バインドされた認証情報や MFA 要素を、そのやり取りで検証されたものと同等に扱うため、ユーザーはセットアップ直後に再度チャレンジされることなくステップアップを完了できます。純粋なステップアップ中に新しい認証情報や要素を確立した場合、Logto は User.Data.Updated Webhook イベントを発行します。テナントでユーザーが検証・確立・登録できるものが何も有効でない場合(またはリンク済みソーシャル/SSO コネクターがない場合)、Logto は error=unmet_authentication_requirements でやり取りを終了します。
アカウント API とアカウントセンター
アカウント API の認可ポリシー
機密性の高い Account API 操作(パスワード、主要メール、主要電話、ユーザー名の更新、ソーシャル ID のリンク/解除、MFA 要素や設定の管理、パーソナルアクセストークンの管理、アクティブセッション・アプリグラント・信頼済みデバイスの閲覧や取り消しなど)は、以下を要求します:
- ファーストパーティアプリケーションからのアクセス:サードパーティ OIDC アプリケーション(
isThirdParty: true)や Client ID Metadata Document (CIMD) クライアントは、機密性の高い Account API リソースの変更や Account API ステップアップチャレンジの受信ができません(urn:logto:acr:mfaでも不可)。 - 直近のアイデンティティ検証、以下のいずれかで満たされます:
- OIDC 認証コンテキスト:不透明アクセストークンが
urn:logto:acr:1fa(urn:logto:acr:1faまたはurn:logto:acr:mfa)を満たすacrを持ち、かつnow - auth_time <= maximumAuthenticationAgeInSeconds(auth_timeから厳密に評価、iatではない)。 - 検証レコード(
logto-verification-id):直接 Account API を統合する場合、Logto はPOST /api/verifications/passwordまたはPOST /api/verifications/verification-code+/verifyで作成された有効かつ未期限切れの 10 分間有効な検証レコード ID をlogto-verification-idリクエストヘッダーで受け付け続けます。
- OIDC 認証コンテキスト:不透明アクセストークンが
デフォルトでは、maximumAuthenticationAgeInSeconds は**600 秒(10 分)**です。テナントごとに 1 ~ 120 分(60~7,200 秒) の範囲で コンソール > サインイン & アカウント > アカウントセンター の Recent authentication で、または Management API(PATCH /api/account-center で maximumAuthenticationAgeInSeconds)で設定できます。
OIDC 認証コンテキストの場合、Logto で検証可能な方法で直前にサインインまたは登録したユーザーは、このウィンドウ内で追加の検証プロンプトなしに機密性の高い Account API 操作を実行できます。Verification API で作成された logto-verification-id レコードは後方互換性のため固定 10 分 TTL を維持します。
Account API では初期パスワード例外も維持しています:現在パスワード、主要メール、主要電話を持たないユーザーは、POST /api/my-account/password で直近のアイデンティティ検証なしに初期パスワードを設定できます。Account API でパスワードを設定しても OIDC セッションの acr は更新されず、その後の機密操作の認可にはなりません。
アカウント API の WWW-Authenticate チャレンジ
ファーストパーティの Account API リクエストで新鮮な urn:logto:acr:1fa アクセストークンと有効な logto-verification-id ヘッダーの両方が欠如している場合、Logto は互換性のため既存の JSON エラーボディを保持しつつ、テナント設定の max_age を含む RFC 9470 の WWW-Authenticate ヘッダー付きで 401 Unauthorized を返します:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="insufficient_user_authentication", error_description="Recent user authentication is required", acr_values="urn:logto:acr:1fa", max_age="600"
Content-Type: application/json
{
"code": "verification_record.permission_denied",
"message": "Permission denied, please re-authenticate."
}
組み込みアカウントセンター
組み込みアカウントセンター UI(/account/*)は OIDC ステップアップ認証 (Step-up authentication) のみを使用し、logto-verification-id 権限レコードは作成しません:
- ローカル ID トークンの
acrとauth_timeを確認し、サインインがurn:logto:acr:1faを満たさない場合や古い場合は、機密なインライン操作や複数ステップのサブページの前に積極的にステップアップを開始し、Account API からの RFC 9470401チャレンジもフォールバックとして処理します。 - ステップアップ完了後、アカウントセンターはトークンセットを置き換え、保留中のアクションを最大 1 回まで再開します。
関連リソース
多要素認証 (Multi-factor authentication)API サービスやバックエンドでのアクセストークン検証方法
不透明トークン (Opaque token) とイントロスペクション Account API によるアカウント設定組み込みアカウントセンター UI によるアカウント設定