Desafios de reivindicações, solicitações de sinistros e recursos do cliente

Um desafio de declarações é uma resposta enviada de uma API que indica que um token de acesso enviado por um aplicativo cliente tem declarações insuficientes. Isso pode ocorrer porque o token não satisfaz as políticas de Acesso Condicional definidas para essa API ou porque o token de acesso foi revogado.

Uma solicitação de declarações é feita pelo aplicativo cliente para redirecionar o usuário de volta ao provedor de identidade para recuperar um novo token com declarações que satisfazem os outros requisitos que não foram atendidos.

Os aplicativos que usam recursos de segurança aprimorados como a CAE (Avaliação contínua de acesso) e o contexto de autenticação de acesso condicional devem estar preparados para lidar com os desafios das declarações.

Seu aplicativo recebe desafios de declarações de serviços populares como o Microsoft Graph somente se declarar seus recursos de cliente em suas chamadas para o serviço.

Formato de cabeçalho de desafio de declarações

O desafio de declarações é uma diretiva como um cabeçalho www-authenticate retornado por uma API quando um token de acesso apresentado a ele não é autorizado, e, em vez disso, um novo token de acesso com os recursos certos é necessário. O desafio de declarações é composto por várias partes: o código de status HTTP da resposta e o cabeçalho www-authenticate, o qual tem várias partes e deve conter uma diretiva de declarações.

Aqui está um exemplo:

HTTP 401; Unauthorized

www-authenticate =Bearer realm="", authorization_uri="https://login.microsoftonline.com/common/oauth2/authorize", error="insufficient_claims", claims="eyJhY2Nlc3NfdG9rZW4iOnsiYWNycyI6eyJlc3NlbnRpYWwiOnRydWUsInZhbHVlIjoiY3AxIn19fQ=="

Código de status HTTP: deve ser 401 não autorizado.

Cabeçalho de resposta www-authenticate que contém:

Parâmetro Obrigatório/opcional Descrição
Tipo de autenticação Obrigatório Deve ser Portador.
Realm Opcional A ID do locatário ou o nome de domínio do locatário (por exemplo, microsoft.com) sendo acessado. DEVE ser uma cadeia de caracteres vazia no caso em que a autenticação passa pelo ponto de extremidade comum.
authorization_uri Obrigatório O URI do ponto de extremidade authorize onde uma autenticação interativa pode ser executada, se necessário. Se especificado no realm, as informações do locatário DEVEM ser incluídas no authorization_uri. Se o realm for uma cadeia de caracteres vazia, o authorization_uri DEVE ser comparado ao ponto de extremidade comum.
error Obrigatório Deve ser "insufficient_claims" quando um desafio de declarações deve ser gerado.
claims Necessário quando o erro é "insufficient_claims". Uma cadeia de caracteres entre aspas que contém uma solicitação de declaraçõescodificadas de base 64. A solicitação de declarações deve solicitar declarações para o "access_token" no nível superior do objeto JSON. O valor (declarações solicitadas) será dependente de contexto e especificado posteriormente neste documento. Por motivos de tamanho, os aplicativos de terceira parte confiável DEVEM minificar o JSON antes da codificação de base 64. O JSON bruto do exemplo acima é {"access_token":{"acrs":{"essential":true,"value":"cp1"}}}.

A resposta 401 pode conter mais de um header www-authenticate. Todos os campos na tabela anterior devem estar contidos no mesmo header www-authenticate. O www-authenticate header que contém o desafio de declarações pode conter outros campos. Os campos no cabeçalho não são ordenados. De acordo com a RFC 7235, cada nome de parâmetro deve ocorrer apenas uma vez por desafio de esquema de autenticação.

Solicitação de declarações

Quando um aplicativo recebe um desafio de declarações, ele indica que o token de acesso anterior não é mais considerado válido. Nesse cenário, o aplicativo deve limpar o token de qualquer sessão de usuário ou cache local. Em seguida, ele deve redirecionar o usuário conectado de volta para o Microsoft Entra ID para recuperar um novo token usando o fluxo de código de autorização OAuth 2.0 com um parâmetro declarações que atenderá aos outros requisitos que não foram atendidos.

Veja um exemplo:

GET https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/oauth2/v2.0/authorize
?client_id=00001111-aaaa-2222-bbbb-3333cccc4444
&redirect_uri=https%3A%2F%contoso.com%3A44321%2Fsignin-oidc
&response_type=code
&scope=openid%20profile%20offline_access%20user.read%20Sites.Read.All
&response_mode=form_post
&login_hint=kalyan%ccontoso.onmicrosoft.com
&domain_hint=organizations
&claims=%7B%22access_token%22%3A%7B%22acrs%22%3A%7B%22essential%22%3Atrue%2C%22value%22%3A%22c1%22%7D%7D%7D

O desafio de declarações deve ser passado como parte de todas as chamadas para um ponto de extremidade do Microsoft Entra /authorize até que um token seja recuperado com êxito. Depois que o token é recuperado, ele não é mais necessário.

Para preencher o parâmetro de declarações, o desenvolvedor precisa:

  1. Decodifique a cadeia de caracteres base64 recebida anteriormente.
  2. A URL codifica a cadeia de caracteres e adiciona novamente ao parâmetro de declarações.

Após a conclusão desse fluxo, o aplicativo recebe um token de acesso que tem as outras declarações que comprovam que o usuário satisfez as condições exigidas.

Recursos do cliente

As funcionalidades do cliente ajudam um provedor de recursos como uma API Web a detectar se o aplicativo cliente de chamada entende o desafio de declarações e, em seguida, pode personalizar sua resposta adequadamente. Essa funcionalidade pode ser útil quando nem todos os clientes de API são capazes de lidar com desafios de declaração e algumas versões anteriores ainda esperam uma resposta diferente.

Alguns aplicativos populares, como o Microsoft Graph enviam desafios de declarações somente se o aplicativo cliente de chamadas declarar que ele é capaz de lidar com eles usando as funcionalidades do cliente.

Para evitar tráfego extra ou impactos na experiência do usuário, o Microsoft Entra ID não pressupõe que seu aplicativo possa lidar com declarações contestadas, a menos que você aceite explicitamente participar. Um aplicativo não receberá desafios de declarações (e não poderá usar os recursos relacionados, como tokens CAE), a menos que declare que está pronto para lidar com eles com o recurso "cp1".

Como comunicar os recursos do cliente ao Microsoft Entra ID

O seguinte exemplo de parâmetro de declarações mostra como um aplicativo cliente comunica sua funcionalidade ao Microsoft Entra ID em um fluxo de códigos de autorização do OAuth 2.0.

Claims: {"access_token":{"xms_cc":{"values":["cp1"]}}}

Use o seguinte código se você usar a biblioteca MSAL:

_clientApp = PublicClientApplicationBuilder.Create(App.ClientId)
 .WithDefaultRedirectUri()
 .WithAuthority(authority)
 .WithClientCapabilities(new [] {"cp1"})
 .Build();

Aqueles que usam Microsoft.Identity.Web podem adicionar o seguinte código ao arquivo de configuração:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "ClientId": 'Enter_the_Application_Id_Here' 
    "ClientCapabilities": [ "cp1" ],
    // remaining settings...
},

Consulte o seguinte trecho para ver uma solicitação de exemplo para o Microsoft Entra ID:

GET https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/oauth2/v2.0/authorize
?client_id=00001111-aaaa-2222-bbbb-3333cccc4444
&redirect_uri=https%3A%2F%contoso.com%3A44321%2Fsignin-oidc
&response_type=code
&scope=openid%20profile%20offline_access%20user.read%20Sites.Read.All
&response_mode=form_post
&login_hint=kalyan%ccontoso.onmicrosoft.com
&domain_hint=organizations
&claims=%7B%22access_token%22%3A%7B%22xms_cc%22%3A%7B%22values%22%3A%5B%22cp1%22%5D%7D%7D%7D

Quando você já tiver um payload existente para o parâmetro de declarações, adicione-o ao conjunto existente.

Por exemplo, se você já tiver a seguinte resposta de uma operação de contexto de autenticação de Acesso à Condição;

{"access_token":{"acrs":{"essential":true,"value":"c25"}}}

Você poderia pré-anexar a funcionalidade do cliente no payload de declarações existente.

{"access_token":{"xms_cc":{"values":["cp1"]},"acrs":{"essential":true,"value":"c25"}}}

Receber uma declaração xms_cc em um token de acesso

Para receber informações sobre se os aplicativos cliente podem lidar com os desafios das declarações, um implementador de API deve solicitar xms_cc como uma declaração opcional em seu manifesto do aplicativo.

A declaração xms_cc com um valor de "CP1" no token de acesso é a maneira autoritativa de identificar um aplicativo cliente capaz de lidar com um desafio de declarações. xms_cc é uma declaração opcional que nem sempre será emitida no token de acesso, mesmo que o cliente envie uma solicitação de sinistro com "xms_cc". Para que um token de acesso contenha a declaração xms_cc, o aplicativo de recurso (ou seja, o implementador de API) deve solicitar xms_cc como uma declaração opcional em seu manifesto do aplicativo. Quando solicitado como uma declaração opcional, xms_cc é adicionado ao token de acesso somente se o aplicativo cliente enviar xms_cc na solicitação de declarações. O valor da solicitação de declaração de xms_cc é incluído como o valor da declaração de xms_cc no token de acesso, se for um valor conhecido. O único valor atualmente conhecido é cp1.

Os valores não diferenciam maiúsculas de minúsculas e não são ordenados. Se mais de um valor for especificado na solicitação da declaração xms_cc, esses valores serão uma coleção com vários valores, como o valor da declaração xms_cc.

Tomemos como exemplo a seguinte solicitação:

{ "access_token": { "xms_cc":{"values":["cp1","foo", "bar"] } }}

Isso resulta em uma declaração do seguinte trecho no token de acesso, se cp1, foo e bar forem recursos conhecidos.

"xms_cc": ["cp1", "foo", "bar"]

Depois que a xms_ccdeclaração opcional for solicitada, o manifesto do aplicativo será alterado para ter a seguinte aparência:

"optionalClaims":
{
    "accessToken": [
    {
        "additionalProperties": [],
        "essential": false,
        "name": "xms_cc",
        "source": null
    }],
    "idToken": [],
    "saml2Token": []
}

A API pode, então, personalizar suas respostas com base na capacidade do cliente lidar ou não com o desafio de declarações.

Claim ccClaim = context.User.FindAll(clientCapabilitiesClaim).FirstOrDefault(x => x.Type == "xms_cc");
if (ccClaim != null && ccClaim.Value == "cp1")
{
    // Return formatted claims challenge as this client understands this
}
else
{
    // Throw generic exception
    throw new UnauthorizedAccessException("The caller does not meet the authentication bar to carry our this operation. The service cannot allow this operation");
}

Exemplos de código

Próximas etapas