Obter um token para um aplicativo móvel que chama APIs da Web

Antes que seu aplicativo possa chamar APIs da Web protegidas, ele precisa de um token de acesso. Este artigo orienta você pelo processo de obter um token usando a MSAL (biblioteca de autenticação da Microsoft).

Definir um escopo

Ao solicitar um token, defina um escopo. O escopo determina quais dados seu aplicativo pode acessar.

A maneira mais fácil de definir um escopo é combinar as APIs da Web desejadas App ID URI com o escopo .default . Essa definição informa à plataforma de identidade da Microsoft que seu aplicativo requer todos os escopos definidos no Portal.

Android

String[] SCOPES = {"https://graph.microsoft.com/.default"};

iOS

let scopes = ["https://graph.microsoft.com/.default"]

Xamarin

var scopes = new [] {"https://graph.microsoft.com/.default"};

Obter tokens

Adquirir tokens via MSAL

O MSAL permite que os aplicativos adquiram tokens de forma silenciosa e interativa. Quando você chama AcquireTokenSilent() ou AcquireTokenInteractive(), MSAL retorna um token de acesso para os escopos solicitados. O padrão correto é fazer uma solicitação silenciosa e, em seguida, retornar a uma solicitação interativa.

Android

String[] SCOPES = {"https://graph.microsoft.com/.default"};
PublicClientApplication sampleApp = new PublicClientApplication(
                    this.getApplicationContext(),
                    R.raw.auth_config);

// Check if there are any accounts we can sign in silently.
// Result is in the silent callback (success or error).
sampleApp.getAccounts(new PublicClientApplication.AccountsLoadedCallback() {
    @Override
    public void onAccountsLoaded(final List<IAccount> accounts) {

        if (accounts.isEmpty() && accounts.size() == 1) {
            // TODO: Create a silent callback to catch successful or failed request.
            sampleApp.acquireTokenSilentAsync(SCOPES, accounts.get(0), getAuthSilentCallback());
        } else {
            /* No accounts or > 1 account. */
        }
    }
});

[...]

// No accounts found. Interactively request a token.
// TODO: Create an interactive callback to catch successful or failed requests.
sampleApp.acquireToken(getActivity(), SCOPES, getAuthInteractiveCallback());

iOS

Primeiro, tente adquirir um token silenciosamente:


NSArray *scopes = @[@"https://graph.microsoft.com/.default"];
NSString *accountIdentifier = @"my.account.id";

MSALAccount *account = [application accountForIdentifier:accountIdentifier error:nil];

MSALSilentTokenParameters *silentParams = [[MSALSilentTokenParameters alloc] initWithScopes:scopes account:account];
[application acquireTokenSilentWithParameters:silentParams completionBlock:^(MSALResult *result, NSError *error) {

    if (!error)
    {
        // You'll want to get the account identifier to retrieve and reuse the account
        // for later acquireToken calls
        NSString *accountIdentifier = result.account.identifier;

        // Access token to call the web API
        NSString *accessToken = result.accessToken;
    }

    // Check the error
    if (error && [error.domain isEqual:MSALErrorDomain] && error.code == MSALErrorInteractionRequired)
    {
        // Interactive auth will be required, call acquireTokenWithParameters:error:
        return;
    }
}];

let scopes = ["https://graph.microsoft.com/.default"]
let accountIdentifier = "my.account.id"

guard let account = try? application.account(forIdentifier: accountIdentifier) else { return }
let silentParameters = MSALSilentTokenParameters(scopes: scopes, account: account)
application.acquireTokenSilent(with: silentParameters) { (result, error) in

    guard let authResult = result, error == nil else {

    let nsError = error! as NSError

    if (nsError.domain == MSALErrorDomain &&
        nsError.code == MSALError.interactionRequired.rawValue) {

            // Interactive auth will be required, call acquireToken()
            return
         }
         return
     }

    // You'll want to get the account identifier to retrieve and reuse the account
    // for later acquireToken calls
    let accountIdentifier = authResult.account.identifier

    // Access token to call the web API
    let accessToken = authResult.accessToken
}

Se MSAL retornar MSALErrorInteractionRequired, tente adquirir tokens interativamente:

UIViewController *viewController = ...; // Pass a reference to the view controller that should be used when getting a token interactively
MSALWebviewParameters *webParameters = [[MSALWebviewParameters alloc] initWithAuthPresentationViewController:viewController];
MSALInteractiveTokenParameters *interactiveParams = [[MSALInteractiveTokenParameters alloc] initWithScopes:scopes webviewParameters:webParameters];
[application acquireTokenWithParameters:interactiveParams completionBlock:^(MSALResult *result, NSError *error) {
    if (!error)
    {
        // You'll want to get the account identifier to retrieve and reuse the account
        // for later acquireToken calls
        NSString *accountIdentifier = result.account.identifier;

        NSString *accessToken = result.accessToken;
    }
}];
let viewController = ... // Pass a reference to the view controller that should be used when getting a token interactively
let webviewParameters = MSALWebviewParameters(authPresentationViewController: viewController)
let interactiveParameters = MSALInteractiveTokenParameters(scopes: scopes, webviewParameters: webviewParameters)
application.acquireToken(with: interactiveParameters, completionBlock: { (result, error) in

    guard let authResult = result, error == nil else {
        print(error!.localizedDescription)
        return
    }

    // Get access token from result
    let accessToken = authResult.accessToken
})

O MSAL para iOS e macOS dá suporte a vários modificadores para obter um token de forma interativa ou silenciosa:

Xamarin

O exemplo a seguir mostra o código mínimo para obter um token interativamente. O exemplo usa o Microsoft Graph para ler o perfil do usuário.

string[] scopes = new string[] {"user.read"};
var app = PublicClientApplicationBuilder.Create(clientId).Build();
var accounts = await app.GetAccountsAsync();
AuthenticationResult result;
try
{
 result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
             .ExecuteAsync();
}
catch(MsalUiRequiredException)
{
 result = await app.AcquireTokenInteractive(scopes)
             .ExecuteAsync();
}

Parâmetros obrigatórios no MSAL.NET

AcquireTokenInteractive tem um parâmetro obrigatório: scopes. O parâmetro scopes enumera strings que definem os escopos para os quais um token é necessário. Caso o token seja para o Microsoft Graph, os escopos necessários poderão ser encontrados na referência de API de cada API do Microsoft Graph. Na referência, vá para a seção "permissões".

Por exemplo, para listar os contatos do usuário, o escopo "User.Read", "Contacts.Read" deve ser usado. Para obter mais informações, confira Referência de permissões do Microsoft Graph.

No Android, você pode especificar a atividade pai ao criar o aplicativo usando PublicClientApplicationBuilder. Se você não especificar a atividade principal nesse momento, poderá especificá-la posteriormente usando .WithParentActivityOrWindow como na seção a seguir. Se especificar a atividade principal, o token retorna para ela após a interação. Se você não especificá-la, a .ExecuteAsync() chamada lançará uma exceção.

Parâmetros opcionais específicos no MSAL.NET

As seções a seguir explicam os parâmetros opcionais MSAL.NET.

WithPrompt

O parâmetro WithPrompt() é usado para controlar a interatividade com o usuário por meio da especificação de um prompt.

Image showing the fields in the Prompt structure. These constant values control interactivity with the user by defining the type of prompt displayed by the WithPrompt() parameter.

A classe define as constantes a seguir:

  • SelectAccount força o STS (serviço de token de segurança) a apresentar a caixa de diálogo seleção de conta. A caixa de diálogo contém as contas para as quais o usuário tem uma sessão. Você pode usar essa opção quando quiser permitir que o usuário escolha entre identidades diferentes. Essa opção faz com que a MSAL envie prompt=select_account para o provedor de identidade.

    A constante SelectAccount é o padrão e fornece efetivamente a melhor experiência possível com base nas informações disponíveis. As informações disponíveis podem incluir conta, presença de uma sessão para o usuário e assim por diante. Não altere esse padrão, a menos que você tenha um bom motivo para fazê-lo.

  • Consent permite que você solicite o consentimento do usuário, mesmo que o consentimento tenha sido concedido antes. Nesse caso, a MSAL envia prompt=consent para o provedor de identidade.

    Talvez você queira usar a constante Consent em aplicativos com foco em segurança em que a governança da organização exige que os usuários vejam a caixa de diálogo de consentimento sempre que usarem o aplicativo.

  • ForceLogin permite que o serviço solicite as credenciais ao usuário, mesmo que o prompt não seja necessário.

    Essa opção poderá ser útil se a aquisição de token falhar e você quiser permitir que o usuário entre novamente. Nesse caso, a MSAL envia prompt=login para o provedor de identidade. Talvez você queira usar essa opção em aplicativos voltados para segurança em que a governança da organização exige que o usuário entre sempre que acessar partes específicas do aplicativo.

  • Never é apenas para .NET 4.5 e Windows Runtime (WinRT). Essa constante não solicitará ao usuário, mas tentará usar o cookie armazenado na exibição da Web inserida oculta. Para obter mais informações, consulte Usando navegadores da Web com MSAL.NET.

    Se essa opção falhar, o AcquireTokenInteractive lançará uma exceção para notificar que uma interação de interface do usuário é necessária. Em seguida, use outro parâmetro Prompt.

  • NoPrompt não enviará nenhum prompt para o provedor de identidade.

    Essa opção só é útil para as políticas de perfil de edição do Azure Active Directory B2C. Para obter mais informações, consulte Especificações do B2C.

WithExtraScopeToConsent

Use o modificador WithExtraScopeToConsent em um cenário avançado em que você deseja que o usuário forneça consentimento antecipado para vários recursos. Você pode usar esse modificador quando não quiser usar o consentimento incremental, que normalmente é usado com o MSAL.NET ou a plataforma de identidade da Microsoft. Para obter mais informações, consulte Ter o consentimento de usuário antecipado para vários recursos.

Este é um exemplo de código:

var result = await app.AcquireTokenInteractive(scopesForCustomerApi)
                     .WithExtraScopeToConsent(scopesForVendorApi)
                     .ExecuteAsync();
Outros parâmetros opcionais

Para saber mais sobre todos os outros parâmetros opcionais de AcquireTokenInteractive, consulte a documentação de referência para AcquireTokenInteractiveParameterBuilder.

Adquirir tokens por meio do protocolo

Não recomendamos o uso direto do protocolo para obter tokens. Se você fizer isso, o aplicativo não dará suporte a alguns cenários que envolvem o logon único (SSO), gerenciamento de dispositivos e acesso condicional.

Ao usar o protocolo para obter tokens para aplicativos móveis, faça duas solicitações:

  • Obter um código de autorização.
  • Trocar o código por um token.

Obter um código de autorização

https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=<CLIENT_ID>
&response_type=code
&redirect_uri=<ENCODED_REDIRECT_URI>
&response_mode=query
&scope=openid%20offline_access%20https%3A%2F%2Fgraph.microsoft.com%2F.default
&state=12345

Obter acesso e atualizar o token

POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded

client_id=<CLIENT_ID>
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&code=OAAABAAAAiL9Kn2Z27UubvWFPbm0gLWQJVzCTE9UkP3pSx1aXxUjq3n8b2JRLk4OxVXr...
&redirect_uri=<ENCODED_REDIRECT_URI>
&grant_type=authorization_code

Próximas etapas

Vá para o próximo artigo nesse cenário, Recorrendo a uma API Web.