이 문서에서는 일반적인 로그인 오류를 처리하기 위한 다양한 유형의 오류 및 권장 사항에 대한 개요를 제공합니다.
MSAL 오류 처리 기본 사항
MSAL(Microsoft 인증 라이브러리 예외)은 앱 개발자가 최종 사용자에게 표시하는 것이 아니라 문제를 해결하기 위한 것입니다. 예외 메시지는 지역화되지 않습니다.
예외 및 오류를 처리할 때 예외 유형 자체와 오류 코드를 사용하여 예외를 구분할 수 있습니다. 오류 코드 목록은 Microsoft Entra 인증 및 권한 부여 오류 코드를 참조하세요.
로그인 환경 중에 동의, 조건부 액세스(MFA, 장치 관리, 위치 기반 제한), 토큰 발급 및 상환 및 사용자 속성에 대한 오류가 발생할 수 있습니다.
다음 섹션에서는 앱에 대한 오류 처리에 대한 자세한 내용을 제공합니다.
iOS/macOS용 MSAL에서 오류 처리
iOS 및 macOS 오류에 대한 MSAL의 전체 목록은 MSALError 열거형에 나열됩니다.
생성된 모든 MSAL 오류는 도메인과 함께 MSALErrorDomain 반환됩니다.
시스템 오류의 경우 MSAL은 시스템 API에서 원본 NSError 을 반환합니다. 예를 들어 네트워크 연결이 부족하여 토큰 획득에 실패하면 MSAL은 도메인 및 NSURLErrorDomain 코드와 함께 NSURLErrorNotConnectedToInternet 오류를 반환합니다.
클라이언트 쪽에서 다음 두 개의 MSAL 오류를 처리하는 것이 좋습니다.
MSALErrorInteractionRequired: 사용자가 대화형 요청을 수행해야 합니다. 만료된 인증 세션 또는 추가 인증 요구 사항의 필요성과 같이 이 오류가 발생할 수 있는 여러 조건이 있습니다. MSAL 대화형 토큰 획득 API를 호출하여 복구합니다.MSALErrorServerDeclinedScopes: 일부 또는 모든 범위가 거부되었습니다. 부여된 범위만 계속 진행할지 아니면 로그인 프로세스를 중지할지 결정합니다.
메모
MSALInternalError 열거형은 참조 및 디버깅 용도로만 사용해야 합니다. 런타임에 이러한 오류를 자동으로 처리하지 마세요. 앱에서 MSALInternalError에 해당하는 오류가 발생하면 무슨 일이 발생했는지 설명하는 일반적인 사용자 대상 메시지를 표시하는 것이 좋습니다.
예를 들어 MSALInternalErrorBrokerResponseNotReceived 사용자가 인증을 완료하지 않았고 앱에 수동으로 반환됨을 의미합니다. 이 경우 앱은 인증이 완료되지 않았음을 설명하는 일반 오류 메시지를 표시하고 다시 인증을 시도하도록 제안해야 합니다.
다음 Objective-C 샘플 코드는 몇 가지 일반적인 오류 조건을 처리하기 위한 모범 사례를 보여 줍니다.
MSALInteractiveTokenParameters *interactiveParameters = ...;
MSALSilentTokenParameters *silentParameters = ...;
MSALCompletionBlock completionBlock;
__block __weak MSALCompletionBlock weakCompletionBlock;
weakCompletionBlock = completionBlock = ^(MSALResult *result, NSError *error)
{
if (!error)
{
// Use result.accessToken
NSString *accessToken = result.accessToken;
return;
}
if ([error.domain isEqualToString:MSALErrorDomain])
{
switch (error.code)
{
case MSALErrorInteractionRequired:
{
// Interactive auth will be required
[application acquireTokenWithParameters:interactiveParameters
completionBlock:weakCompletionBlock];
break;
}
case MSALErrorServerDeclinedScopes:
{
// These are list of granted and declined scopes.
NSArray *grantedScopes = error.userInfo[MSALGrantedScopesKey];
NSArray *declinedScopes = error.userInfo[MSALDeclinedScopesKey];
// To continue acquiring token for granted scopes only, do the following
silentParameters.scopes = grantedScopes;
[application acquireTokenSilentWithParameters:silentParameters
completionBlock:weakCompletionBlock];
// Otherwise, instead, handle error fittingly to the application context
break;
}
case MSALErrorServerProtectionPoliciesRequired:
{
// Integrate the Intune SDK and call the
// remediateComplianceForIdentity:silent: API.
// Handle this error only if you integrated Intune SDK.
// See more info here: https://aka.ms/intuneMAMSDK
break;
}
case MSALErrorUserCanceled:
{
// The user cancelled the web auth session.
// You may want to ask the user to try again.
// Handling of this error is optional.
break;
}
case MSALErrorInternal:
{
// Log the error, then inspect the MSALInternalErrorCodeKey
// in the userInfo dictionary.
// Display generic error message to the end user
// More detailed information about the specific error
// under MSALInternalErrorCodeKey can be found in MSALInternalError enum.
NSLog(@"Failed with error %@", error);
break;
}
default:
NSLog(@"Failed with unknown MSAL error %@", error);
break;
}
return;
}
// Handle no internet connection.
if ([error.domain isEqualToString:NSURLErrorDomain] && error.code == NSURLErrorNotConnectedToInternet)
{
NSLog(@"No internet connection.");
return;
}
// Other errors may require trying again later,
// or reporting authentication problems to the user.
NSLog(@"Failed with error %@", error);
};
// Acquire token silently
[application acquireTokenSilentWithParameters:silentParameters
completionBlock:completionBlock];
// or acquire it interactively.
[application acquireTokenWithParameters:interactiveParameters
completionBlock:completionBlock];
let interactiveParameters: MSALInteractiveTokenParameters = ...
let silentParameters: MSALSilentTokenParameters = ...
var completionBlock: MSALCompletionBlock!
completionBlock = { (result: MSALResult?, error: Error?) in
if let result = result
{
// Use result.accessToken
let accessToken = result.accessToken
return
}
guard let error = error as NSError? else { return }
if error.domain == MSALErrorDomain, let errorCode = MSALError(rawValue: error.code)
{
switch errorCode
{
case .interactionRequired:
// Interactive auth will be required
application.acquireToken(with: interactiveParameters, completionBlock: completionBlock)
case .serverDeclinedScopes:
let grantedScopes = error.userInfo[MSALGrantedScopesKey]
let declinedScopes = error.userInfo[MSALDeclinedScopesKey]
if let scopes = grantedScopes as? [String] {
silentParameters.scopes = scopes
application.acquireTokenSilent(with: silentParameters, completionBlock: completionBlock)
}
case .serverProtectionPoliciesRequired:
// Integrate the Intune SDK and call the
// remediateComplianceForIdentity:silent: API.
// Handle this error only if you integrated Intune SDK.
// See more info here: https://aka.ms/intuneMAMSDK
break
case .userCanceled:
// The user cancelled the web auth session.
// You may want to ask the user to try again.
// Handling of this error is optional.
break
case .internal:
// Log the error, then inspect the MSALInternalErrorCodeKey
// in the userInfo dictionary.
// Display generic error message to the end user
// More detailed information about the specific error
// under MSALInternalErrorCodeKey can be found in MSALInternalError enum.
print("Failed with error \(error)");
default:
print("Failed with unknown MSAL error \(error)")
}
}
// Handle no internet connection.
if error.domain == NSURLErrorDomain && error.code == NSURLErrorNotConnectedToInternet
{
print("No internet connection.")
return
}
// Other errors may require trying again later,
// or reporting authentication problems to the user.
print("Failed with error \(error)");
}
// Acquire token silently
application.acquireToken(with: interactiveParameters, completionBlock: completionBlock)
// or acquire it interactively.
application.acquireTokenSilent(with: silentParameters, completionBlock: completionBlock)
조건부 액세스 및 클레임 문제
토큰을 자동으로 가져오는 경우 액세스하려는 API에서 MFA 정책과 같은 조건부 액세스 클레임 챌린지 가 필요한 경우 애플리케이션에 오류가 발생할 수 있습니다.
이 오류를 처리하는 패턴은 MSAL을 사용하여 토큰을 대화형으로 획득하는 것입니다. 이렇게 하면 사용자에게 프롬프트가 표시되고 필요한 조건부 액세스 정책을 충족할 수 있는 기회가 표시됩니다.
조건부 액세스가 필요한 API를 호출하는 경우 API의 오류에서 클레임 챌린지를 받을 수 있습니다. 예를 들어 조건부 액세스 정책에 관리 디바이스(Intune)가 있는 경우 오류 는 AADSTS53000 같은 것입니다. 이 리소스에 액세스하려면 디바이스를 관리해야 합니다. 이 경우 사용자에게 적절한 정책을 충족하라는 메시지가 표시되도록 토큰 획득 호출에서 클레임을 전달할 수 있습니다.
iOS 및 macOS용 MSAL을 사용하면 대화형 및 자동 토큰 획득 시나리오 모두에서 특정 클레임을 요청할 수 있습니다.
사용자 지정 클레임을 요청하려면 MSALSilentTokenParameters 또는 MSALInteractiveTokenParameters에 claimsRequest을 지정하세요.
자세한 내용은 iOS 및 macOS용 MSAL을 사용하여 사용자 지정 클레임 요청을 참조하세요.
오류 및 예외 후 다시 시도
MSAL을 호출할 때 사용자 고유의 재시도 정책을 구현해야 합니다. MSAL은 Microsoft Entra 서비스에 대한 HTTP 호출을 수행하며 경우에 따라 오류가 발생할 수 있습니다. 예를 들어 네트워크가 다운되거나 서버가 오버로드될 수 있습니다.
HTTP 429
STS(서비스 토큰 서버)가 너무 많은 요청으로 오버로드되면 응답 필드에서 다시 시도할 수 있을 때까지의 기간에 대한 힌트와 함께 HTTP 오류 429를 Retry-After 반환합니다.
다음 단계
문제를 진단하고 디버그하는 데 도움이 되도록 iOS/macOS용 MSAL에서 로깅 을 사용하도록 설정하는 것이 좋습니다.