Migrar aplicativos para MSAL para iOS e macOS

A Biblioteca de Autenticação do Azure Active Directory (ADAL Objective-C) foi criada para funcionar com contas do Microsoft Entra por meio do endpoint v1.0.

A Microsoft Authentication Library para iOS e macOS (MSAL) foi desenvolvida para funcionar com todas as identidades da Microsoft, como contas Microsoft Entra, contas pessoais da Microsoft e contas do Azure AD B2C, por meio da plataforma de identidade da Microsoft (anteriormente o endpoint do Azure AD v2.0).

O plataforma de identidade da Microsoft tem algumas diferenças importantes com Azure AD v1.0. Este artigo destaca essas diferenças e fornece diretrizes para migrar um aplicativo da ADAL para a MSAL.

Diferenças de funcionalidade do aplicativo ADAL e MSAL

Quem pode fazer login

  • A ADAL só dá suporte a contas corporativas e de estudante, também conhecidas como contas Microsoft Entra.
  • A MSAL dá suporte a contas de Microsoft pessoais (contas MSA), como Hotmail.com, Outlook.com e Live.com.
  • A MSAL oferece suporte a contas corporativas e escolares e a contas do Azure AD B2C.

Conformidade com padrões

  • O plataforma de identidade da Microsoft segue os padrões OAuth 2.0 e OpenId Connect.
  • O plataforma de identidade da Microsoft permite que você solicite permissões dinamicamente. Os aplicativos podem solicitar permissões apenas conforme necessário e solicitar mais conforme o aplicativo precisar. Para obter mais informações, consulte permissões e consentimento.

Diferenças de biblioteca de ADAL e MSAL

A API pública msal reflete algumas diferenças importantes entre Azure AD v1.0 e o plataforma de identidade da Microsoft.

MSALPublicClientApplication em vez de ADAuthenticationContext

ADAuthenticationContext é o primeiro objeto que um aplicativo ADAL cria. Representa uma instanciação da ADAL. Os aplicativos criam uma nova instância de ADAuthenticationContext para cada combinação de nuvem e locatário (autoridade) do Microsoft Entra. O mesmo ADAuthenticationContext pode ser usado para obter tokens para vários aplicativos cliente públicos.

Na MSAL, a interação principal ocorre por meio de um objeto MSALPublicClientApplication, que é baseado em OAuth 2.0 Public Client. Uma instância de MSALPublicClientApplication pode ser usada para interagir com várias nuvens e locatários do Microsoft Entra, sem precisar criar uma nova instância para cada autoridade. Para a maioria dos aplicativos, uma MSALPublicClientApplication instância é suficiente.

Escopos em vez de recursos

Na ADAL, um aplicativo precisava fornecer um identificador de recurso como https://graph.microsoft.com para adquirir tokens do ponto de extremidade do Azure AD v1.0. Um recurso pode definir um número de escopos ou oAuth2Permissions no manifesto do aplicativo que ele compreende. Isso permitiu que os aplicativos cliente solicitassem tokens desse recurso para um determinado conjunto de escopos predefinidos durante o registro do aplicativo.

No MSAL, em vez de um único identificador de recurso, os aplicativos fornecem um conjunto de escopos por solicitação. Um escopo é um identificador de recurso seguido de um nome de permissão na forma recurso/permissão. Por exemplo, https://graph.microsoft.com/user.read

Há duas maneiras de fornecer escopos na MSAL:

  • Forneça uma lista de todas as permissões de que seus aplicativos precisam. Por exemplo:

    @[@"https://graph.microsoft.com/directory.read", @"https://graph.microsoft.com/directory.write"]

    Nesse caso, o aplicativo solicita as permissões directory.read e directory.write. O usuário será solicitado a consentir essas permissões se não tiver consentido com elas antes para este aplicativo. O aplicativo também pode receber permissões adicionais que o usuário já consentiu para o aplicativo. O usuário só será solicitado a consentir com novas permissões ou permissões que não foram concedidas.

  • O /.default escopo.

Este é o escopo integrado de cada aplicativo. Ele se refere à lista estática de permissões configuradas quando o aplicativo foi registrado. Seu comportamento é semelhante ao de resource. Isso pode ser útil ao migrar para garantir que um conjunto semelhante de escopos e experiência do usuário seja mantido.

Para usar o /.default escopo, acrescente /.default ao identificador de recurso. Por exemplo: https://graph.microsoft.com/.default. Se o recurso terminar com uma barra (/), você ainda deverá adicionar /.default, incluindo uma barra à esquerda, o que resulta em um escopo com duas barras (//).

Você pode ler mais informações sobre como usar o escopo "/.default" em permissões e escopos.

Suporte a diferentes tipos de WebView e navegadores

A ADAL só dá suporte a UIWebView/WKWebView para iOS e WebView para macOS. A MSAL para iOS dá suporte a mais opções para exibir conteúdo da Web ao solicitar um código de autorização e não dá mais suporte UIWebView; o que pode melhorar a experiência e a segurança do usuário.

Por padrão, a MSAL no iOS usa ASWebAuthenticationSession, que é o componente Web que a Apple recomenda para autenticação em dispositivos iOS 12+. Ele fornece benefícios de SSO (logon único) por meio do compartilhamento de cookie entre aplicativos e o navegador Safari.

Você pode optar por usar um componente Web diferente, dependendo dos requisitos do aplicativo e da experiência do usuário final desejada. Consulte os tipos de exibição da Web com suporte para obter mais opções.

Ao migrar da ADAL para a MSAL, WKWebView fornece a experiência do usuário mais semelhante à ADAL no iOS e no macOS. Recomendamos que você migre para ASWebAuthenticationSession no iOS, se possível. Para macOS, incentivamos você a usar WKWebView.

Diferenças de API de gerenciamento de conta

Ao chamar os métodos acquireToken() ou acquireTokenSilent() da ADAL, você recebe um objeto ADUserInformation que contém uma lista de declarações do id_token que representam a conta que está sendo autenticada. Além disso, ADUserInformation retorna uma userId com base na declaração upn. Após a aquisição inicial interativa do token, a ADAL espera que o desenvolvedor forneça userId em todas as chamadas silenciosas.

A ADAL não fornece uma API para recuperar identidades de usuário conhecidas. Ele depende do aplicativo para salvar e gerenciar essas contas.

A MSAL fornece um conjunto de APIs para listar todas as contas conhecidas como MSAL sem precisar adquirir um token.

Assim como a ADAL, a MSAL retorna informações de conta que contêm uma lista de declarações do id_token. Faz parte do MSALAccount objeto dentro do MSALResult objeto.

A MSAL fornece um conjunto de APIs para remover contas, tornando as contas removidas inacessíveis para o aplicativo. Depois que a conta for removida, chamadas posteriores de aquisição de token solicitarão que o usuário faça a aquisição interativa de tokens. A remoção da conta só se aplica ao aplicativo cliente que a iniciou e não remove a conta dos outros aplicativos em execução no dispositivo ou no navegador do sistema. Isso garante que o usuário continue a ter uma experiência de SSO no dispositivo mesmo depois de sair de um aplicativo individual.

Além disso, a MSAL também retorna um identificador de conta que pode ser usado para solicitar um token silenciosamente mais tarde. No entanto, o identificador de conta (acessível por meio identifier da MSALAccount propriedade no objeto) não é exibivel e você não pode assumir em que formato ele está nem deve tentar interpretá-lo ou analisá-lo.

Migrando o cache da conta

Ao migrar da ADAL, os aplicativos normalmente armazenam o userId da ADAL, que não tem o identifier exigido pela MSAL. Como uma etapa de migração única, um aplicativo pode consultar uma conta MSAL usando a userId da ADAL com a seguinte API:

- (nullable MSALAccount *)accountForUsername:(nonnull NSString *)username error:(NSError * _Nullable __autoreleasing * _Nullable)error;

Essa API lê os caches da MSAL e da ADAL para encontrar a conta pelo userId da ADAL (UPN).

Se a conta for encontrada, o desenvolvedor deverá usar a conta para fazer a aquisição de token silencioso. A primeira aquisição de token silenciosa atualizará a conta e o desenvolvedor obterá um identificador de conta compatível com a MSAL no resultado da MSAL (identifier). Depois disso, só identifier deve ser usado para pesquisas de conta usando a seguinte API:

- (nullable MSALAccount *)accountForIdentifier:(nonnull NSString *)identifier error:(NSError * _Nullable __autoreleasing * _Nullable)error;

Embora seja possível continuar usando o userId do ADAL para todas as operações no MSAL, como userId se baseia em UPN, ele está sujeito a várias limitações que resultam em uma má experiência do usuário. Por exemplo, se o UPN for alterado, o usuário precisará entrar novamente. Recomendamos que todos os aplicativos usem a conta não exibível identifier para todas as operações.

Leia mais sobre a migração de estado de cache.

Alterações na obtenção de token

A MSAL introduz algumas alterações nas chamadas para aquisição de token:

  • Como a ADAL, acquireTokenSilent sempre resulta em uma solicitação silenciosa.
  • Ao contrário da ADAL, acquireToken sempre resulta em uma interface que exige ação do usuário, seja por meio da exibição da Web ou do aplicativo Microsoft Authenticator. Dependendo do estado do SSO dentro do webview/Microsoft Authenticator, o usuário pode ser solicitado a inserir suas credenciais.
  • Na ADAL, acquireToken com AD_PROMPT_AUTO primeiro tenta fazer uma aquisição de token silenciosa e somente mostra a interface do usuário se a solicitação silenciosa falhar. Na MSAL, essa lógica pode ser implementada primeiro chamando acquireTokenSilent e chamando acquireToken somente se a aquisição silenciosa falhar. Isso permite que os desenvolvedores personalizem a experiência do usuário antes de iniciar a aquisição interativa de token.

Diferenças de tratamento de erros

A MSAL fornece mais clareza entre os erros que podem ser tratados pelo seu aplicativo e aqueles que exigem intervenção do usuário. Há um número limitado de erros que o desenvolvedor deve tratar:

  • MSALErrorInteractionRequired: o usuário deve fazer uma solicitação interativa. Isso pode ser causado por vários motivos, como uma sessão de autenticação expirada, a política de Acesso Condicional foi alterada, um token de atualização expirou ou foi revogado, não há tokens válidos no cache e assim por diante.
  • MSALErrorServerDeclinedScopes: A solicitação não foi totalmente concluída e alguns escopos não tiveram acesso concedido. Isso pode ser causado por um usuário recusando o consentimento para um ou mais escopos.

O tratamento de todos os outros erros na MSALError lista é opcional. Você pode usar as informações nesses erros para melhorar a experiência do usuário.

Consulte Como lidar com exceções e erros usando a MSAL para saber mais sobre o tratamento de erros da MSAL.

Suporte ao agente

A MSAL, começando com a versão 0.3.0, fornece suporte para autenticação agenciada usando o aplicativo Microsoft Authenticator. Microsoft Authenticator também permite suporte para cenários de Acesso Condicional. Exemplos de cenários de Acesso Condicional incluem políticas de conformidade do dispositivo que exigem que o usuário registre o dispositivo por meio do Intune ou registre-se com Microsoft Entra ID para obter um token. E políticas de Acesso Condicional do MAM (Gerenciamento de Aplicativos Móveis), que exigem uma prova de conformidade antes que seu aplicativo possa obter um token.

Para habilitar o broker para o seu aplicativo:

  1. Registre um formato de URI de redirecionamento compatível com o agente para o aplicativo. O formato de URI de redirecionamento compatível com o broker é msauth.<app.bundle.id>://auth. Substitua <app.bundle.id> pela ID do pacote do aplicativo. Se você estiver migrando da ADAL e seu aplicativo já era compatível com broker, não é necessário fazer nada além disso. Seu URI de redirecionamento anterior é totalmente compatível com a MSAL, portanto, você pode pular para a etapa 3.

  2. Adicione o esquema de URI de redirecionamento do aplicativo ao arquivo info.plist. Para o URI de redirecionamento msal padrão, o formato é msauth.<app.bundle.id>. Por exemplo:

    <key>CFBundleURLSchemes</key>
    <array>
        <string>msauth.<app.bundle.id></string>
    </array>
    
  3. Adicione os seguintes esquemas ao arquivo info.plist do aplicativo em LSApplicationQueriesSchemes:

    <key>LSApplicationQueriesSchemes</key>
    <array>
         <string>msauthv2</string>
         <string>msauthv3</string>
    </array>
    
  4. Adicione o seguinte ao arquivo AppDelegate.m para lidar com retornos de chamada: Objective-C:

    - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options`
    {
        return [MSALPublicClientApplication handleMSALResponse:url sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]];
    }
    

    Swift:

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        return MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String)
    }
    

Entre empresas (B2B)

No ADAL, você cria instâncias separadas de ADAuthenticationContext para cada locatário para o qual o aplicativo solicita tokens. Isso não é mais um requisito na MSAL. No MSAL, você pode criar uma única instância de MSALPublicClientApplication e usá-la para qualquer nuvem e organização do Microsoft Entra, ao especificar uma autoridade diferente nas chamadas acquireToken e acquireTokenSilent.

SSO em parceria com outros SDKs

O MSAL para iOS pode oferecer SSO por meio de um cache unificado com o ADAL Objective-C 2.7.x+.

O SSO é obtido por meio do compartilhamento de conjunto de chaves do iOS e só está disponível entre aplicativos publicados na mesma conta do Desenvolvedor da Apple.

O SSO por meio do compartilhamento de conjunto de chaves do iOS é o único tipo de SSO silencioso.

No macOS, a MSAL pode alcançar SSO com outros aplicativos baseados em MSAL para iOS e macOS e com aplicativos baseados em ADAL para Objective-C.

A MSAL no iOS também dá suporte a dois outros tipos de SSO:

  • SSO via navegador da Web. O MSAL para iOS dá suporte a ASWebAuthenticationSession, que fornece SSO por meio de cookies compartilhados com outros aplicativos no dispositivo e, especificamente, o navegador Safari.
  • SSO por meio de um intermediário de autenticação. Em um dispositivo iOS, Microsoft Authenticator atua como o agente de Autenticação. Ele pode seguir políticas de Acesso Condicional, como exigir um dispositivo em conformidade, e fornece SSO para dispositivos registrados. Os SDKs da MSAL começando com a versão 0.3.0 dão suporte a um agente por padrão.

Intune MAM SDK

O SDK do MAM do Intune dá suporte à MSAL para iOS a partir da versão 11.1.2

MSAL e ADAL no mesmo aplicativo

A versão 2.7.0 da ADAL e posteriores não podem coexistir com a MSAL no mesmo aplicativo. O principal motivo é devido ao código comum de submódulo compartilhado. Como Objective-C não dá suporte a namespaces, se você adicionar estruturas ADAL e MSAL ao seu aplicativo, haverá duas instâncias da mesma classe. Não é possível determinar qual delas será escolhida no runtime. Se ambos os SDKs estiverem usando a mesma versão da classe conflitante, seu aplicativo ainda poderá funcionar. No entanto, se for uma versão diferente, seu aplicativo poderá sofrer falhas inesperadas que são difíceis de diagnosticar.

Não há suporte para executar a ADAL e a MSAL no mesmo aplicativo de produção. No entanto, se você estiver apenas testando e migrando seus usuários da ADAL Objective-C para a MSAL para iOS e macOS, poderá continuar usando a ADAL Objective-C 2.6.10. É a única versão que funciona com MSAL no mesmo aplicativo. Não haverá novas atualizações de recursos para essa versão da ADAL, portanto, ela deve ser usada apenas para fins de migração e teste. Seu aplicativo não deve depender da coexistência da ADAL e da MSAL a longo prazo.

Não há suporte para coexistência de ADAL e MSAL no mesmo aplicativo. Há suporte total para a coexistência de ADAL e MSAL entre vários aplicativos.

Etapas práticas de migração

Migração de registro de aplicativo

Você não precisa alterar seu aplicativo Microsoft Entra existente para alternar para MSAL e habilitar Microsoft Entra contas. No entanto, se o aplicativo baseado em ADAL não der suporte à autenticação agenciada, você precisará registrar um novo URI de redirecionamento para o aplicativo antes de mudar para MSAL.

O URI de redirecionamento deve estar nesse formato: msauth.<app.bundle.id>://auth. Substitua <app.bundle.id> pela ID do pacote do aplicativo. Especifique o URI de redirecionamento no centro de administração do Microsoft Entra.

Somente para iOS, para dar suporte à autenticação baseada em certificado, um URI de redirecionamento adicional precisa ser registrado em seu aplicativo e o centro de administração do Microsoft Entra no seguinte formato: msauth://code/<broker-redirect-uri-in-url-encoded-form>. Por exemplo, msauth://code/msauth.com.microsoft.mybundleId%3A%2F%2Fauth

Recomendamos que todos os aplicativos registrem ambas as URIs de redirecionamento.

Se você quiser adicionar suporte para consentimento incremental, selecione as APIs e as permissões às quais seu aplicativo está configurado para solicitar acesso no registro do aplicativo na guia permissões de API .

Se você estiver migrando da ADAL e quiser dar suporte a contas Microsoft Entra ID e MSA, o registro de aplicativo existente precisará ser atualizado para dar suporte a ambos. Não recomendamos que você atualize seu aplicativo de produção existente para dar suporte ao Microsoft Entra ID e à MSA imediatamente. Em vez disso, crie outra ID de cliente compatível com Microsoft Entra ID e MSA para teste e depois de verificar se todos os cenários funcionam, atualize o aplicativo existente.

Adicionar MSAL ao seu aplicativo

Você pode adicionar o SDK da MSAL ao seu aplicativo usando sua ferramenta de gerenciamento de pacotes preferencial. Veja as instruções detalhadas aqui.

Atualizar o arquivo Info.plist do aplicativo

Somente para iOS, adicione o esquema de URI de redirecionamento do seu aplicativo no arquivo info.plist. Para aplicativos compatíveis com o agente da ADAL, ele já deve constar lá. O esquema de URI de redirecionamento padrão do MSAL estará no formato: msauth.<app.bundle.id>.

<key>CFBundleURLSchemes</key>
<array>
    <string>msauth.<app.bundle.id></string>
</array>

Adicione os seguintes esquemas ao Info.plist do seu aplicativo em LSApplicationQueriesSchemes.

<key>LSApplicationQueriesSchemes</key>
<array>
     <string>msauthv2</string>
     <string>msauthv3</string>
</array>

Atualizar seu código AppDelegate

Somente para iOS, adicione o seguinte ao arquivo AppDelegate.m:

Objective-C:

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options`
{
    return [MSALPublicClientApplication handleMSALResponse:url sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]];
}

Swift:

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    return MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String)
}

Se estiver usando o Xcode 11, você deverá colocar o retorno de chamada MSAL no arquivo SceneDelegate em vez disso. Se você der suporte a UISceneDelegate e UIApplicationDelegate para compatibilidade com o iOS mais antigo, o retorno de chamada da MSAL precisará ser colocado nos dois arquivos.

Objective-C:

 - (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
 {
     UIOpenURLContext *context = URLContexts.anyObject;
     NSURL *url = context.URL;
     NSString *sourceApplication = context.options.sourceApplication;
     
     [MSALPublicClientApplication handleMSALResponse:url sourceApplication:sourceApplication];
 }

Swift:

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        
        guard let urlContext = URLContexts.first else {
            return
        }
        
        let url = urlContext.url
        let sourceApp = urlContext.options.sourceApplication
        
        MSALPublicClientApplication.handleMSALResponse(url, sourceApplication: sourceApp)
    }

Permite que a MSAL manipule as respostas do agente e do componente da Web. Isso não era necessário na ADAL, já que ela arranjava os métodos de delegação de aplicativos automaticamente. Adicioná-lo manualmente é menos propenso a erros e dá ao aplicativo mais controle.

Ativar cache de token

Por padrão, a MSAL armazena em cache os tokens do aplicativo no conjunto de chaves do iOS ou macOS.

Para habilitar o cache de token:

  1. Verifique se o aplicativo está assinado corretamente
  2. Vá para as Configurações do projeto no Xcode >guia Capacidades>Ative o Compartilhamento do Keychain
  3. Clique + e insira a seguinte entrada em Grupos de Chaves: 3.a Para iOS, insira com.microsoft.adalcache 3.b Para macOS, insira com.microsoft.identity.universalstorage

Criar a MSALPublicClientApplication e migrar para as chamadas acquireToken e acquireTokeSilent

Você pode criar MSALPublicClientApplication usando o seguinte código:

Objective-C:

NSError *error = nil;
MSALPublicClientApplicationConfig *configuration = [[MSALPublicClientApplicationConfig alloc] initWithClientId:@"<your-client-id-here>"];
    
MSALPublicClientApplication *application =
[[MSALPublicClientApplication alloc] initWithConfiguration:configuration
                                                     error:&error];

Swift:

let config = MSALPublicClientApplicationConfig(clientId: "<your-client-id-here>")
do {
  let application = try MSALPublicClientApplication(configuration: config)
  // continue on with application
            
} catch let error as NSError {
  // handle error here
}

Em seguida, chame a API de gerenciamento de conta para ver se há contas no cache:

Objective-C:

NSString *accountIdentifier = nil /*previously saved MSAL account identifier */;
NSError *error = nil;
MSALAccount *account = [application accountForIdentifier:accountIdentifier error:&error];

Swift:

// definitions that need to be initialized
let application: MSALPublicClientApplication!
let accountIdentifier: String! /*previously saved MSAL account identifier */

do {
  let account = try application.account(forIdentifier: accountIdentifier)
  // continue with account usage
} catch let error as NSError {
  // handle error here
}

ou leia todos os relatos:

Objective-C:

NSError *error = nil;
NSArray<MSALAccount *> *accounts = [application allAccounts:&error];

Swift:

let application: MSALPublicClientApplication!
do {
  let accounts = try application.allAccounts()
  // continue with account usage
} catch let error as NSError {
  // handle error here
}

Se uma conta for encontrada, chame a API MSAL acquireTokenSilent :

Objective-C:

MSALSilentTokenParameters *silentParameters = [[MSALSilentTokenParameters alloc] initWithScopes:@[@"<your-resource-here>/.default"] account:account];
    
[application acquireTokenSilentWithParameters:silentParameters
                              completionBlock:^(MSALResult *result, NSError *error)
{
    if (result)
    {
        NSString *accessToken = result.accessToken;
        // Use your token
    }
    else
    {
        // Check the error
        if ([error.domain isEqual:MSALErrorDomain] && error.code == MSALErrorInteractionRequired)
        {
            // Interactive auth will be required
        }
            
        // Other errors may require trying again later, or reporting authentication problems to the user
    }
}];

Swift:

let application: MSALPublicClientApplication!
let account: MSALAccount!
        
let silentParameters = MSALSilentTokenParameters(scopes: ["<your-resource-here>/.default"], 
                                                 account: account)
application.acquireTokenSilent(with: silentParameters) {
  (result: MSALResult?, error: Error?) in
  if let accessToken = result?.accessToken {
     // use accessToken
  }
  else {
    // Check the error
    guard let error = error else {
      assert(true, "callback should contain a valid result or error")
      return
    }
    
    let nsError = error as NSError
    if (nsError.domain == MSALErrorDomain
        && nsError.code == MSALError.interactionRequired.rawValue) {
      // Interactive auth will be required
    }
                
    // Other errors may require trying again later, or reporting authentication problems to the user
  }
}

Próximas Etapas 

Saiba mais sobre fluxos de autenticação e cenários de aplicativo