Entrada de aplicativo de página única usando o fluxo implícito do OAuth 2.0 no Azure Active Directory B2C

Muitos aplicativos modernos têm um SPA (aplicativo de página única) de front-end que é escrito principalmente em JavaScript. Geralmente, o aplicativo é escrito usando uma estrutura como React, Angular ou Vue.js. Os SPAs e outros aplicativos JavaScript que são executados principalmente em um navegador impõem alguns desafios adicionais para autenticação:

  • As características de segurança desses aplicativos são diferentes dos aplicativos Web tradicionais baseados em servidor.

  • Muitos servidores de autorização e provedores de identidade não dão suporte para solicitações CORS (compartilhamento de recursos entre origens).

  • O navegador de página inteira redirecionando para longe do aplicativo pode ser invasivo para a experiência do usuário.

A maneira recomendada de dar suporte a SPAs é o fluxo de código de autorização do OAuth 2.0 (com PKCE).

Algumas estruturas, como MSAL.js 1.x, dão suporte apenas ao fluxo de concessão implícita. Nesses casos, o Azure AD B2C (Azure Active Directory B2C) dá suporte ao fluxo de concessão implícita de autorização OAuth 2.0. O fluxo três é descrito na seção 4.2 da especificação do OAuth 2.0. No fluxo implícito, o aplicativo recebe tokens diretamente do ponto de extremidade de autorização do Azure AD B2C, sem nenhuma troca entre servidores. Toda a lógica de autenticação e manipulação de sessão são feitas inteiramente no cliente JavaScript com um redirecionamento de página ou uma caixa pop-up.

O Azure AD B2C estende o fluxo implícito do OAuth 2.0 padrão para mais que autenticação e autorização simples. O Azure AD B2C introduz o parâmetro de política. Com o parâmetro de política, é possível usar o OAuth 2.0 para adicionar políticas ao seu aplicativo, como fluxos de usuários de inscrição, conexão e gerenciamento de perfil. No exemplo de solicitações HTTP neste artigo, usamos {tenant}.onmicrosoft.com como ilustração. Substitua {tenant} pelo nome do locatário caso haja algum. Além disso, você precisa ter criado um fluxo de usuário.

Usamos a figura a seguir para ilustrar o fluxo de entrada implícito. Cada etapa é descrita detalhadamente mais adiante no artigo.

Diagrama de estilo de raia mostrando o fluxo implícito do OpenID Connect

Enviar solicitações de autenticação

Quando o aplicativo Web precisa autenticar o usuário e executar um fluxo de usuário, ele pode direcionar o usuário para o ponto de extremidade /authorize do Azure AD B2C. O usuário executa a ação dependendo do fluxo do usuário.

Nesta solicitação, o cliente indica as permissões que precisa obter do usuário no parâmetro scope e o fluxo de usuário a ser executado. Para ter uma ideia de como funciona cada solicitação, tente colar a solicitação em um navegador e executá-la. Substitua:

  • {tenant} pelo nome do locatário do Azure AD B2C.

  • 90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6 pela ID do aplicativo que você já havia registrado no locatário.

  • {policy} pelo nome de uma política que você criou no locatário, por exemplo b2c_1_sign_in.

GET https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/authorize?
client_id=90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6
&response_type=id_token+token
&redirect_uri=https%3A%2F%2Faadb2cplayground.azurewebsites.net%2F
&response_mode=fragment
&scope=openid%20offline_access
&state=arbitrary_data_you_can_receive_in_the_response
&nonce=12345

Os parâmetros na solicitação HTTP GET são explicados na tabela a seguir.

Parâmetro Obrigatório Descrição
{tenant} Sim O nome de seu locatário do Azure AD B2C
{policy} Sim O nome do fluxo de usuário que você deseja executar. Especifique o nome de um fluxo de usuário que você criou em seu locatário do Azure AD B2C. Por exemplo: b2c_1_sign_in, b2c_1_sign_up ou b2c_1_edit_profile
client_id Sim A ID do aplicativo que o portal do Azure atribuiu a seu aplicativo.
response_type Sim É necessário incluir id_token para conexão do OpenID Connect. O tipo de resposta token também será incluído. Se utilizar token, seu aplicativo poderá receber imediatamente um token de acesso do ponto de extremidade autorizado, sem fazer uma segunda solicitação para o ponto de extremidade autorizado. Se utilizar o tipo de resposta token, o scope parâmetro deverá conter um escopo indicando para quais recursos o token será emitido.
redirect_uri Não O URI de redirecionamento do seu aplicativo, onde as respostas de autenticação podem ser enviadas e recebidas pelo aplicativo. Ele precisa corresponder exatamente a um dos URIs de redirecionamento adicionados a um aplicativo registrado no portal, exceto que ele precisa ser codificado como URL.
response_mode Não Especifica o método que deve ser usado para enviar o token resultante de volta ao aplicativo. Para fluxos implícitos, utilize fragment.
scope Sim Uma lista de escopos separados por espaços. Um valor de escopo único indica a ID do Microsoft Entra que ambas as permissões estão sendo solicitadas. O escopo openid indica uma permissão para entrar no usuário e obter dados sobre ele na forma de tokens de ID. O escopo offline_access é opcional para aplicativos Web. Isso indica que seu aplicativo precisa de um token de atualização para acesso de longa vida para recursos.
state Não Um valor incluído na solicitação que também é retornado na resposta de token. Pode ser uma cadeia de caracteres de qualquer conteúdo que você deseje usar. Geralmente, um valor exclusivo gerado aleatoriamente é utilizado para evitar ataques de solicitação intersite forjada. O estado também é usado para codificar as informações sobre o estado do usuário no aplicativo antes da solicitação de autenticação ocorrida, como a página em que o usuário estava ou o fluxo do usuário em execução.
nonce Sim Um valor incluído na solicitação, gerado pelo aplicativo, incluído no token de ID resultante como uma declaração. O aplicativo pode, então, verificar esse valor para atenuar os ataques de reprodução de token. Normalmente, o valor é uma cadeia de caracteres aleatória e exclusiva que pode ser usada para identificar a origem da solicitação.
prompt Não O tipo de interação do usuário que é necessária. Atualmente, o único valor válido é login. Esse parâmetro força o usuário a inserir suas credenciais nessa solicitação. O logon único não entra em vigor.

Esta é a parte interativa do fluxo. É solicitado que o usuário conclua o fluxo de trabalho da política. O usuário pode precisar inserir o nome de usuário e a senha, entrar com uma identidade social, inscrever-se em uma conta local ou realizar outras etapas. As ações do usuário dependem de como o fluxo de usuário é definido.

Depois que o usuário completar o fluxo do usuário, o Azure AD B2C retornará uma resposta ao aplicativo por meio do redirect_uri. Ele usa o método especificado no parâmetro response_mode. A resposta é exatamente a mesma para cada um dos cenários de ação do usuário, independentemente de qual fluxo de usuário foi executado.

Resposta bem-sucedida

Uma resposta bem sucedida que utiliza response_mode=fragment e response_type=id_token+token é semelhante à seguinte, com quebras de linha para legibilidade:

GET https://aadb2cplayground.azurewebsites.net/#
access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&token_type=Bearer
&expires_in=3599
&scope="90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6 offline_access",
&id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&state=arbitrary_data_you_sent_earlier
Parâmetro Descrição
access_token O token de acesso que o aplicativo solicitou do Azure AD B2C.
token_type O valor do tipo de token. O único tipo compatível com o Azure AD B2C é Portador.
expires_in O período de tempo pelo qual o token de acesso é válido (em segundos).
scope Os escopos para os quais o token é válido. Você também pode usar os escopos para armazenar tokens em cache para uso posterior.
id_token O token de ID que o aplicativo solicitou. Você pode usar o token de ID para verificar a identidade do usuário e iniciar uma sessão com o usuário. Para obter mais informações sobre tokens de identificação e seus conteúdos, consulte a referência de token do Azure AD B2C.
state Se um parâmetro state for incluído na solicitação, o mesmo valor deverá aparecer na resposta. O aplicativo deve verificar se os valores state na solicitação e na resposta são idênticos.

Resposta de erro

As respostas de erro também podem ser enviadas ao URI de redirecionamento, de modo que o aplicativo possa tratá-las adequadamente:

GET https://aadb2cplayground.azurewebsites.net/#
error=access_denied
&error_description=the+user+canceled+the+authentication
&state=arbitrary_data_you_can_receive_in_the_response
Parâmetro Descrição
erro Um código usado para classificar os tipos de erros que ocorrem.
error_description Uma mensagem de erro específica que pode ajudar você a identificar a causa raiz de um erro de autenticação.
state Se um parâmetro state for incluído na solicitação, o mesmo valor deverá aparecer na resposta. O aplicativo deve verificar se os valores state na solicitação e na resposta são idênticos.

Validar o token de ID

Receber um token de ID não é suficiente para autenticar o usuário. Valide a assinatura do token de ID e verificar as reivindicações no token pelos requisitos de seu aplicativo. O Azure AD B2C usa JWTs (Tokens Web JSON) e criptografia de chave pública para assinar tokens e verificar se eles são válidos.

Muitas bibliotecas de software livre estão disponíveis para validar JWTs, dependendo do idioma de sua preferência. Considere explorar bibliotecas de software livre disponíveis em vez de implementar sua própria lógica de validação. As informações contidas neste artigo podem ser utilizadas para ajudá-lo a aprender como utilizar essas bibliotecas corretamente.

O Azure AD B2C tem um ponto de extremidade de metadados OpenID Connect. Um aplicativo pode usar o ponto de extremidade para buscar informações sobre o Azure AD B2C em runtime. Essas informações incluem pontos de extremidade, conteúdos de token e chaves de assinatura de token. Há um documento de metadados JSON para cada fluxo de usuário no locatário do Azure AD B2C. Por exemplo, o documento de metadados de um fluxo do usuário chamado b2c_1_sign_in em um locatário do fabrikamb2c.onmicrosoft.com está localizado em:

https://fabrikamb2c.b2clogin.com/fabrikamb2c.onmicrosoft.com/b2c_1_sign_in/v2.0/.well-known/openid-configuration

Uma das propriedades deste documento de configuração é jwks_uri. O valor para o mesmo fluxo de usuário seria:

https://fabrikamb2c.b2clogin.com/fabrikamb2c.onmicrosoft.com/b2c_1_sign_in/discovery/v2.0/keys

Para determinar qual fluxo do usuário foi usado para assinar um token de ID (e onde buscar os metadados), há duas opções:

  • O nome do fluxo de usuário está incluído na declaração acr em id_token. Para obter informações sobre como analisar as declarações de um token de ID, consulte a referência de token do Azure AD B2C.

  • Codifique o fluxo de usuário no valor do parâmetro state quando emitir a solicitação. Em seguida, decodifique o parâmetro state para determinar qual fluxo de usuário foi usado.

Após ter adquirido o documento de metadados a partir do ponto de extremidade de metadados OpenID Connect, você poderá utilizar as chaves públicas RSA-256 (localizadas nesse ponto de extremidade) para validar a assinatura do token de ID. Poderá haver várias chaves listadas nesse ponto de extremidade em qualquer momento, cada uma identificada por um kid. O cabeçalho de id_token também contém uma declaração kid. Ele indica qual dessas chaves foi utilizada para assinar o token de ID. Para obter mais informações, incluindo aprender sobre tokens de validação, consulte a referência de token do Azure AD B2C.

Após validar a assinatura do token de ID, várias declarações exigirão verificação. Por exemplo:

  • Valide a declaração nonce para evitar ataques de reprodução de token. Seu valor deve ser o que você especificou na solicitação de conexão.

  • Valide aud para garantir que o token de ID foi emitido para seu aplicativo. Seu valor deve ser a ID do aplicativo do seu aplicativo.

  • Valide as declarações iat e exp para garantir que o token de ID não expirou.

Várias outras validações que você deve executar são descritas em detalhes na Especificação do OpenID Connect Core. Você também pode querer validar declarações adicionais, dependendo do seu cenário. Algumas validações comuns incluem:

  • Garanta que o usuário ou a organização tenha se inscrito no aplicativo.

  • Garanta que o usuário tenha autorização e privilégios adequados.

  • Garantir que uma determinada força de autenticação tenha ocorrido, como usar a autenticação multifator do Microsoft Entra.

Para obter mais informações sobre as reivindicações em um token de ID, consulte a referência de token do Azure AD B2C.

Após validar o token de ID, você poderá iniciar uma sessão com o usuário. No seu aplicativo, use as declarações no token de ID para obter informações sobre o usuário. Essas informações podem ser usadas para exibição, registros, autorizações e outros.

Obter tokens de acesso

Se os seus aplicativos Web precisam apenas executar fluxos de usuários, você pode ignorar as próximas seções. As informações contidas nas seções a seguir são aplicáveis apenas a aplicativos Web que precisam fazer chamadas autenticadas a uma API Web e que são protegidos pelo Azure AD B2C.

Agora que você autenticou o usuário no seu SPA, você pode obter tokens de acesso para chamar APIs Web protegidas pela ID do Microsoft Entra. Mesmo que já tenha recebido um token utilizando o tipo de resposta token, você poderá utilizar esse método para adquirir tokens para recursos adicionais sem redirecionar o usuário para conectar novamente.

Em um fluxo típico de aplicativo Web, você faria uma solicitação para o ponto de extremidade /token. No entanto, o ponto de extremidade não dá suporte para solicitações CORS, portanto, fazer chamadas AJAX para obter um token de atualização não é uma opção. Em vez disso, você poderá utiliza o fluxo implícito em um elemento iframe HTML oculto para obter novos tokens para outras APIs Web. A seguir está um exemplo, com quebras de linha para legibilidade:

https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/authorize?
client_id=90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6
&response_type=token
&redirect_uri=https%3A%2F%2Faadb2cplayground.azurewebsites.net%2F
&scope=https%3A%2F%2Fapi.contoso.com%2Ftasks.read
&response_mode=fragment
&state=arbitrary_data_you_can_receive_in_the_response
&nonce=12345
&prompt=none
Parâmetro Necessário? Descrição
{tenant} Obrigatório O nome de seu locatário do Azure AD B2C
{policy} Obrigatório O fluxo do usuário a ser executado. Especifique o nome de um fluxo de usuário que você criou em seu locatário do Azure AD B2C. Por exemplo: b2c_1_sign_in, b2c_1_sign_up ou b2c_1_edit_profile
client_id Obrigatório A ID do aplicativo atribuída ao seu aplicativo no portal do Azure.
response_type Obrigatório Deve incluir id_token para conexão do OpenID Connect. Também é possível incluir o tipo de resposta token. Se utilizar token aqui, seu aplicativo poderá receber imediatamente um token de acesso do ponto de extremidade autorizado, sem fazer uma segunda solicitação para o ponto de extremidade autorizado. Se utilizar o tipo de resposta token, o scope parâmetro deverá conter um escopo indicando para quais recursos o token será emitido.
redirect_uri Recomendadas O URI de redirecionamento do seu aplicativo, onde as respostas de autenticação podem ser enviadas e recebidas pelo aplicativo. Ele deve coincidir exatamente com um dos URIs de redirecionamento registrados no portal, exceto que deve ser codificado em URL.
scope Obrigatório Uma lista de escopos separados por espaços. Para obter tokens, inclua todos os escopos que necessários para o recurso pretendido.
response_mode Recomendadas Especifica o método que deve ser usado para enviar o token resultante de volta ao aplicativo. Para fluxos implícitos, use fragment. Dois outros modos podem ser especificados, query e form_post, mas não funcionam no fluxo implícito.
state Recomendadas Um valor incluído na solicitação que retorna na resposta do token. Pode ser uma cadeia de caracteres de qualquer conteúdo que você deseje usar. Geralmente, um valor exclusivo gerado aleatoriamente é utilizado para evitar ataques de solicitação intersite forjada. O estado também é usado para codificar informações sobre o estado do usuário no aplicativo, antes que a solicitação de autenticação tenha ocorrido. Por exemplo, a página ou a exibição do usuário estava ativada.
nonce Obrigatório Um valor incluído na solicitação, gerado pelo aplicativo, que está incluído no token de ID resultante como uma reivindicação. O aplicativo pode, então, verificar esse valor para atenuar os ataques de reprodução de token. Normalmente, o valor é uma cadeia de caracteres aleatória e exclusiva que identifica a origem da solicitação.
prompt Obrigatório Para atualizar e obter tokens em um iframe oculto, utilize prompt=none para garantir que o iframe não fique preso na página de entrada e retorna imediatamente.
login_hint Obrigatório Para atualizar e obter tokens em um iframe oculto, inclua o nome de usuário de usuário nesta dica para distinguir entre várias sessões que o usuário pode ter em um determinado momento. Você pode extrair o nome de usuário de uma entrada anterior usando a declaração preferred_username (o escopo profile é necessário para receber a declaração preferred_username).
domain_hint Obrigatório Pode ser consumers ou organizations. Para atualizar e obter tokens em um iframe oculto, inclua o valor domain_hint na solicitação. Extraia a declaração tid do token de ID de uma entrada anterior para determinar qual valor usar (o escopo profile é necessário para receber a declaração tid). Se o valor da declaração tid for 9188040d-6c67-4c5b-b112-36a304b66dad, use domain_hint=consumers. Caso contrário, use domain_hint=organizations.

Ao configurar o parâmetro prompt=none, essa solicitação terá êxito ou falhará imediatamente e retornará ao seu aplicativo. Uma resposta bem-sucedida será enviada ao aplicativo pelo URI de redirecionamento usando o método especificado no parâmetro response_mode.

Resposta bem-sucedida

Uma resposta bem-sucedida usando response_mode=fragment é semelhante a este exemplo:

GET https://aadb2cplayground.azurewebsites.net/#
access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&state=arbitrary_data_you_sent_earlier
&token_type=Bearer
&expires_in=3599
&scope=https%3A%2F%2Fapi.contoso.com%2Ftasks.read
Parâmetro Descrição
access_token O token solicitado pelo aplicativo.
token_type O tipo de token sempre será Portador.
state Se um parâmetro state for incluído na solicitação, o mesmo valor deverá aparecer na resposta. O aplicativo deve verificar se os valores state na solicitação e na resposta são idênticos.
expires_in Por quanto tempo o token de acesso é válido (em segundos).
escopo Os escopos para os quais o access_token é válido.

Resposta de erro

As respostas de erro também podem ser enviadas para URI de redirecionamento, de modo que o aplicativo possa tratá-los adequadamente. Para prompt=none, um erro esperado é semelhante ao seguinte exemplo:

GET https://aadb2cplayground.azurewebsites.net/#
error=user_authentication_required
&error_description=the+request+could+not+be+completed+silently
Parâmetro Descrição
erro Uma cadeia de caracteres de código de erro que pode ser utilizada para classificar os tipos de erros que ocorrem. Você também pode usar a cadeia de caracteres para reagir a erros.
error_description Uma mensagem de erro específica que pode ajudar você a identificar a causa raiz de um erro de autenticação.

Se você receber esse erro na solicitação do iframe, o usuário deverá entrar novamente de forma interativa para recuperar um novo token.

Tokens de atualização

Os tokens de ID e tokens de acesso expiram após um curto período de tempo. Seu aplicativo deverá estar preparado para atualizar esses tokens periodicamente. Fluxos implícitos não permitem que você obtenha um token de atualização por motivos de segurança. Para atualizar qualquer tipo de token, use o fluxo implícito em um elemento iframe HTML oculto. Na solicitação de autorização, inclua o parâmetro prompt=none. Para receber um novo valor id_token, use response_type=id_token e scope=openid, bem como um parâmetro nonce.

Enviar uma solicitação de saída

Quando você quiser desconectar o usuário do aplicativo, redirecione-o ao ponto de extremidade de saída do Azure AD B2C. Depois, você poderá limpar a sessão do usuário no aplicativo. Se você não redirecionar o usuário, ele poderá fazer uma nova autenticação no aplicativo sem inserir as credenciais novamente, pois terá uma sessão de logon único válida com o ponto de extremidade do Azure AD B2C.

Você pode simplesmente redirecionar o usuário para end_session_endpoint que está listado no mesmo documento de metadados do OpenID Connect descrito em Validar o ID de token. Por exemplo:

GET https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/logout?post_logout_redirect_uri=https%3A%2F%2Faadb2cplayground.azurewebsites.net%2F
Parâmetro Obrigatório Descrição
{tenant} Sim O nome do seu locatário do Azure AD B2C.
{policy} Sim O fluxo de usuário que você quer usar para desconectar o usuário do aplicativo. Precisa ser o mesmo fluxo de usuário que o aplicativo usou para conectar o usuário.
post_logout_redirect_uri Não A URL para a qual o usuário deve ser redirecionado após a saída bem-sucedida. Se não estiver incluída, Azure AD B2C mostrará ao usuário uma mensagem genérica.
state No Se um parâmetro state for incluído na solicitação, o mesmo valor deverá aparecer na resposta. O aplicativo deve verificar se os valores de state da solicitação e da resposta são idênticos.

Observação

Direcionar o usuário para end_session_endpoint limpa alguns dos estados de logon único do usuário com o Azure AD B2C. No entanto, ele não desconecta o usuário da sessão do provedor de identidade social do usuário. Se o usuário selecionar o mesmo provedor de identidade em uma próxima conexão, ele será reautenticado, sem inserir as credenciais. Se um usuário quiser sair do serviço de seu aplicativo do Azure AD B2C, isso não significa necessariamente que ele deseja se desconectar completamente de sua conta do Facebook, por exemplo. No entanto, para contas locais, a sessão do usuário será encerrada corretamente.

Próximas etapas

Confira o exemplo de código: Entrar com Azure AD B2C em um SPA JavaScript.