Skip to content

Error Handling

Olga Dalton edited this page May 2, 2019 · 13 revisions

Error Handling in MSAL

Error handling is an essential part of sign-in experience.

This article gives an overview of the different types of errors and a recommendation for handling some of the errors during a sign-in experience.

This doc will be evolving over time. If there's an error you'd like to know more about or have questions, please create a Github issue with the error and question.

Basics

During a token acquisition, silent or interactive, apps may encounter errors generated from various parts of the sign-in experience such as errors regarding consents, conditional access (MFA, Device Management, Location-based restrictions), token issuance and redemption, and user properties.

For all such errors MSAL returns errors with MSALErrorDomain.

The following two MSAL errors are recommended to be handled on the client side:

  • MSALErrorInteractionRequired: The user must perform an interactive request. This can be caused by a many different reasons including expired auth session or additional auth requirements.
  • MSALErrorServerDeclinedScopes: Some or all scopes were declined. Developer should decide whether to continue on with the granted scopes only or stop the sign-in process.

The complete list of all errors can be found in MSALError enum.

Note: MSALInternalError enum exists only for the reference, you should not try to automatically handle these errors in runtime. If your app encounters any of the errors that fall under MSALInternalError, you may want to show a generic user facing message explaining what happened. For example, MSALInternalErrorBrokerResponseNotReceived means that user didn't complete authentication and manually returned to the app. In this example, your app should ask end user to try authentication again.

For any system errors, MSAL will return the original NSError from the system API. For example, if token acquisition fails due to no network connectivity, MSAL will return an error with NSURLErrorDomain domain and NSURLErrorNotConnectedToInternet code.

Handling Errors

In order to handle the errors above, the following sample code demonstrates the best practice in handling some of the possible conditions:

    MSALInteractiveTokenParameters *interactiveParameters = ...;
    MSALSilentTokenParameters *silentParameters = ...;
    
    MSALCompletionBlock completionBlock;
    __block __weak MSALCompletionBlock weakCompletionBlock;
    
    weakCompletionBlock = completionBlock = ^(MSALResult *result, NSError *error)
    {
        if (!error)
        {
            // Use result.accessToken
            NSLog(@"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 MSALErrorWorkplaceJoinRequired:
                {
                    // You may want to ask the user to work place join the device
                    // (open Authenticator app -> Settings -> Device Registration).
                    // Handling of this error is optional.
                    
                    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);
    };