この記事では、さまざまな種類のエラーの概要と、一般的なサインイン エラーを処理するための推奨事項について説明します。
MSAL エラー処理の基本
Microsoft Authentication Library (MSAL) の例外は、エンド ユーザーに表示されるのではなく、アプリ開発者がトラブルシューティングを行うために使用されます。 例外メッセージはローカライズされません。
例外とエラーを処理する場合は、例外の種類自体とエラー コードを使用して例外を区別できます。 エラー コードの一覧については、認証と承認のエラー コードMicrosoft Entra参照してください。
サインイン エクスペリエンス中に、同意、条件付きアクセス (MFA、デバイス管理、場所ベースの制限)、トークンの発行と利用、およびユーザー プロパティに関するエラーが発生する場合があります。
次のセクションでは、アプリのエラー処理の詳細について説明します。
MSAL.NET でのエラー処理
例外の種類
ライブラリ自体が不適切な構成などのエラー状態を検出すると、MsalClientException がスローされます。
MsalServiceException は、ID プロバイダー (Microsoft Entra ID) がエラーを返すときにスローされます。 サーバー エラーの翻訳です。
MsalUIRequiredException は MsalServiceException の種類であり、ユーザーの操作が必要であることを示します。 たとえば、多要素認証 (MFA) が必要な場合や、ユーザーが自分のパスワードを変更し、トークンをサイレントで取得できない場合などです。
例外の処理
例外.NET処理するときは、例外の種類自体とErrorCodeメンバーを使用して例外を区別できます。
ErrorCode 値は MsalError 型の定数です。
MsalClientException、MsalServiceException、MsalUIRequiredException の各フィールドを見ることもできます。
MsalServiceException がスローされた場合は、認証と承認のエラー コードを試して、コードが一覧表示されているかどうかを確認します。
MsalUIRequiredException がスローされた場合、ユーザーがその問題を解決するには対話型フローを実行する必要があることを示しています。 デスクトップ アプリやモバイル アプリなどのパブリック クライアント アプリでは、ブラウザーを表示する AcquireTokenInteractive を呼び出すことによって解決されます。 機密クライアント アプリでは、Web アプリはユーザーを承認ページにリダイレクトし、Web API は認証エラーを示す HTTP 状態コードとヘッダー (401 Unauthorized と WWW-Authenticate ヘッダー) を返す必要があります。
一般的な.NET例外
スローされる可能性がある一般的な例外と、可能な軽減策を次に示します。
| 例外 | エラー コード | 緩和策 |
|---|---|---|
| MsalUiRequiredException | AADSTS65001: ユーザーまたは管理者は、'{appName}' という名前の ID '{appId}' のアプリケーションの使用に同意していません。 このユーザーとリソースに、対話形式の承認要求を送信してください。 | 最初にユーザーの同意を取得します。 .NET Core(Web UI を備えていない)を使用していない場合は、AcquireTokenInteractive を 1 回だけ呼び出してください。 .NETコアを使用している場合、またはAcquireTokenInteractiveを行いたくない場合、ユーザーは URL に移動して同意を与えることができます:https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={clientId}&response_type=code&scope=user.read。
AcquireTokenInteractiveを呼び出す場合:app.AcquireTokenInteractive(scopes).WithAccount(account).WithClaims(ex.Claims).ExecuteAsync(); |
| MsalUiRequiredException | AADSTS50079: ユーザーは 多要素認証 (MFA) を使用する必要があります。 | 軽減策はありません。 MFA がテナントに対して構成されており、Microsoft Entra ID がその適用を決定した場合は、AcquireTokenInteractive などの対話型フローに切り替えます。 |
| MsalServiceException | AADSTS90010: グラントの種類は、/common または /consumers エンドポイントではサポートされていません。 /organizations またはテナント固有のエンドポイントを使用します。 /common を使用しました。 | Microsoft Entra IDからのメッセージで説明されているように、機関にはテナントが必要です。それ以外の場合は /organizations が必要です。 |
| MsalServiceException | AADSTS70002: 要求本文には、次のパラメーターが含まれている必要があります: client_secret or client_assertion。 |
この例外は、アプリケーションが Microsoft Entra ID でパブリック クライアント アプリケーションとして登録されていなかった場合にスローされる可能性があります。 Microsoft Entra 管理センターで、アプリケーションのマニフェストを編集し、allowPublicClientを true に設定します。 |
| MsalClientException |
unknown_user Message: ログインしているユーザーを識別できませんでした |
ライブラリは、現在 Windows にログインしているユーザーを照会できなかったか、このユーザーが Active Directory または Microsoft Entra に参加していません(ワークプレース参加ユーザーはサポートされていません)。 軽減策: ユーザー名 (たとえば john@contoso.com) を取得する独自のロジックを実装し、ユーザー名を引数として受け取る AcquireTokenByIntegratedWindowsAuth 形式を使用します。 |
| MsalClientException | 管理対象ユーザーでは統合 Windows 認証はサポートされていません | このメソッドは、Active Directory (AD) によって公開されるプロトコルに依存します。 ユーザーが AD バッキング ("マネージド" ユーザー) なしでMicrosoft Entra IDで作成された場合、このメソッドは失敗します。 AD で作成され、Microsoft Entra ID ("フェデレーション" ユーザー) によってサポートされているユーザーは、この非対話型の認証方法の恩恵を受けることができます。 軽減策: 対話型認証を使用します。 |
MsalUiRequiredException
AcquireTokenSilent()の呼び出し時に MSAL.NET から返される一般的な状態コードの 1 つがMsalError.InvalidGrantError。 この状態コードは、アプリケーションが認証ライブラリを再度呼び出す必要があることを意味しますが、対話型モード (パブリック クライアント アプリケーションの場合は AcquireTokenInteractive または AcquireTokenByDeviceCodeFlow、Web アプリでは課題があります)。 これは、認証トークンを発行する前に追加のユーザー操作が必要になるためです。
ほとんどの場合、 AcquireTokenSilent が失敗するのは、トークン キャッシュに要求に一致するトークンがないためです。 アクセス トークンは 1 時間で期限切れになり、 AcquireTokenSilent は更新トークンに基づいて新しいトークンをフェッチしようとします (OAuth2 の用語では、これは "更新トークン" フローです)。 このフローは、テナント管理者がより厳格なサインイン ポリシーを構成する場合など、さまざまな理由で失敗する場合もあります。
この操作は、ユーザーにアクションを実行してもらうことを目的としています。 これらの条件の中には、ユーザーが簡単に解決できる条件 (たとえば、1 回のクリックで使用条件に同意する) と、現在の構成で解決できない条件があります (たとえば、該当するマシンは特定の企業ネットワークに接続する必要があります)。 ユーザーが多要素認証を設定したり、デバイスにMicrosoft Authenticatorをインストールしたりするのに役立つものもあります。
MsalUiRequiredException 分類列挙
MSAL は Classification フィールドを公開します。これを読んで、ユーザー エクスペリエンスを向上させることができます。 たとえば、パスワードの有効期限が切れたことをユーザーに伝えたり、一部のリソースを使用するために同意する必要があることをユーザーに伝えたりします。 サポートされている値は、 UiRequiredExceptionClassification 列挙型の一部です。
| Classification | Meaning | 推奨される処理 |
|---|---|---|
| BasicAction | 条件は、対話型認証フロー中にユーザーの操作によって解決できます。 | AcquireTokenInteractively() を呼び出します。 |
| 追加アクション | 条件は、対話型認証フローの外部で、システムとの追加の修復操作によって解決できます。 | AcquireTokenInteractively() を呼び出して、修復アクションを説明するメッセージを表示します。 呼び出し元のアプリケーションでは、ユーザーが修復アクションを完了する可能性が低い場合に、additional_actionを必要とするフローを非表示にすることができます。 |
| MessageOnly | 現時点では、条件を解決できません。 対話型認証フローを起動すると、条件を説明するメッセージが表示されます。 | AcquireTokenInteractively() を呼び出して、条件を説明するメッセージを表示します。 AcquireTokenInteractively() は、ユーザーがメッセージを読んでウィンドウを閉じた後に UserCanceled エラーを返します。 呼び出し元のアプリケーションは、ユーザーがメッセージの恩恵を受ける可能性が低い場合にmessage_onlyになるフローを非表示にすることを選択できます。 |
| 同意が必要です | ユーザーの同意がないか、取り消されています。 | ユーザーが同意を得るために AcquireTokenInteractively() を呼び出します。 |
| UserPasswordExpired | ユーザーのパスワードの有効期限が切れています。 | ユーザーが自分のパスワードをリセットできるように AcquireTokenInteractively() を呼び出します。 |
| PromptNeverFailed | パラメーター prompt=never を使用して対話型認証が呼び出され、MSAL はブラウザーの Cookie に依存し、ブラウザーを表示しないように強制されました。 これは失敗しました。 | Prompt.None を指定せずに AcquireTokenInteractively() を呼び出す |
| AcquireTokenSilentFailed | MSAL SDK には、キャッシュからトークンをフェッチするための十分な情報がありません。 これは、キャッシュにトークンが存在しないか、アカウントが見つからなかったことが原因である可能性があります。 エラー メッセージに詳細が表示されます。 | AcquireTokenInteractively() を呼び出します。 |
| なし | 詳細は提供されません。 条件は、対話型認証フロー中にユーザーの操作によって解決される場合があります。 | AcquireTokenInteractively() を呼び出します。 |
.NETコード例
AuthenticationResult res;
try
{
res = await application.AcquireTokenSilent(scopes, account)
.ExecuteAsync();
}
catch (MsalUiRequiredException ex) when (ex.ErrorCode == MsalError.InvalidGrantError)
{
switch (ex.Classification)
{
case UiRequiredExceptionClassification.None:
break;
case UiRequiredExceptionClassification.MessageOnly:
// You might want to call AcquireTokenInteractive(). Azure AD will show a message
// that explains the condition. AcquireTokenInteractively() will return UserCanceled error
// after the user reads the message and closes the window. The calling application may choose
// to hide features or data that result in message_only if the user is unlikely to benefit
// from the message
try
{
res = await application.AcquireTokenInteractive(scopes).ExecuteAsync();
}
catch (MsalClientException ex2) when (ex2.ErrorCode == MsalError.AuthenticationCanceledError)
{
// Do nothing. The user has seen the message
}
break;
case UiRequiredExceptionClassification.BasicAction:
// Call AcquireTokenInteractive() so that the user can, for instance accept terms
// and conditions
case UiRequiredExceptionClassification.AdditionalAction:
// You might want to call AcquireTokenInteractive() to show a message that explains the remedial action.
// The calling application may choose to hide flows that require additional_action if the user
// is unlikely to complete the remedial action (even if this means a degraded experience)
case UiRequiredExceptionClassification.ConsentRequired:
// Call AcquireTokenInteractive() for user to give consent.
case UiRequiredExceptionClassification.UserPasswordExpired:
// Call AcquireTokenInteractive() so that user can reset their password
case UiRequiredExceptionClassification.PromptNeverFailed:
// You used WithPrompt(Prompt.Never) and this failed
case UiRequiredExceptionClassification.AcquireTokenSilentFailed:
default:
// May be resolved by user interaction during the interactive authentication flow.
res = await application.AcquireTokenInteractive(scopes)
.ExecuteAsync(); break;
}
}
条件付きアクセスと要求の課題
トークンをサイレントで取得すると、アクセスしようとしている API で MFA ポリシーなどの 条件付きアクセス要求チャレンジ が必要な場合、アプリケーションでエラーが発生する可能性があります。
このエラーを処理するパターンは、MSAL を使用して対話形式でトークンを取得することです。 これにより、ユーザーにプロンプトが表示され、必要な条件付きアクセス ポリシーを満たす機会が提供されます。
場合によっては、条件付きアクセスが必要な API を呼び出す際に、API から返されるエラー内でクレーム チャレンジを受け取ることがあります。 たとえば、条件付きアクセス ポリシーでマネージド デバイス (Intune) を使用する場合、エラーは AADSTS53000 のようになります。このリソースや同様のリソースにアクセスするには、デバイスを管理する必要があります 。 この場合、取得トークン呼び出しで要求を渡して、ユーザーが適切なポリシーを満たすように求めることができます。
MSAL.NET からの条件付きアクセスを必要とする API を呼び出す場合、アプリケーションは要求チャレンジの例外を処理する必要があります。 これは、MsalServiceException として表示され、その Claims プロパティは空ではありません。
要求チャレンジを処理するには、 WithClaims(String)を使用します。
エラーと例外の後の再試行
MSAL を呼び出すときに、独自の再試行ポリシーを実装する必要があります。 MSAL では、Microsoft Entra サービスへの HTTP 呼び出しが行われ、エラーが発生することがあります。 たとえば、ネットワークがダウンしたり、サーバーが過負荷になったりする可能性があります。
HTTP 429
サービス トークン サーバー (STS) が多すぎる要求でオーバーロードされると、HTTP エラー 429 が返され、 Retry-After 応答フィールドで再試行できるまでの時間に関するヒントが返されます。
HTTP エラー コード 500 から 600
MSAL.NET は、HTTP エラー コード 500 から 600 のエラーに対する単純な再試行 1 回のメカニズムを実装します。
MsalServiceException では、System.Net.Http.Headers.HttpResponseHeaders がプロパティ namedHeaders として公開されます。 エラー コードの追加情報を使用して、アプリケーションの信頼性を向上させることができます。 このケースでは、(RetryAfter 型の) RetryConditionHeaderValue プロパティを使用して、再試行するタイミングを計算できます。
クライアント資格情報フローを使用するデーモン アプリケーションの例を次に示します。 これは、トークンを取得するための任意のメソッドに適応させることができます。
bool retry = false;
do
{
TimeSpan? delay;
try
{
result = await publicClientApplication.AcquireTokenForClient(scopes, account).ExecuteAsync();
}
catch (MsalServiceException serviceException)
{
if (serviceException.ErrorCode == "temporarily_unavailable")
{
RetryConditionHeaderValue retryAfter = serviceException.Headers.RetryAfter;
if (retryAfter.Delta.HasValue)
{
delay = retryAfter.Delta;
}
else if (retryAfter.Date.HasValue)
{
delay = (retryAfter.Date.Value – DateTimeOffset.Now).TotalMilliseconds;
}
}
}
// . . .
if (delay.HasValue)
{
Thread.Sleep((int)delay.Value.TotalMilliseconds); // sleep or other
retry = true;
}
} while (retry);
次のステップ
問題の診断とデバッグに役立つ MSAL.NET のログ記録を有効にすることを検討してください。