Visão Geral
Com a crescente necessidade de segurança adaptativa, o Microsoft Entra ID oferece recursos avançados para aplicar políticas dinâmicas de acesso. Em cenários corporativos, autenticação e autorização tradicionais, baseadas apenas em roles e claims estáticos, nem sempre são suficientes. Imagine que um usuário já está logado e possui permissão para acessar uma API, mas você precisa garantir que, para uma operação crítica como deletar um registro, ele esteja dentro da rede corporativa, em um dispositivo gerenciado ou tenha assinado um termo de confidencialidade. É exatamente isso que os contextos de autenticação do Microsoft Entra ID resolvem.
Neste artigo vou detalhar todo o processo, desde a habilitação do Continuous Access Evaluation (CAE), passando pela configuração dos contextos e das políticas de acesso condicional no portal do Entra ID, até a integração prática com uma aplicação .NET dividida em frontend web e API de backend. No código, veremos como o MSAL intercepta o fluxo, verifica se o token contém a claim acrs com o contexto exigido e, caso não contenha, dispara um challenge que leva o usuário de volta ao Entra ID para cumprir o requisito adicional. Se o contexto já estiver satisfeito, o fluxo é transparente para o usuário.
O objetivo é destacar a granularidade no controle de acesso, a estrutura de contexto, os desafios de implementação e potenciais aplicações práticas.
Diagrama de Arquitetura
1. Caso de Uso
Para exemplificar, utilizamos uma aplicação .NET simples, dividida em dois componentes:
- API de backend, que expõe endpoints protegidos
- Aplicação web frontend, que consome a API via tokens
Fluxo Básico
- A aplicação web é protegida pelo Entra ID
- Ao iniciar, o MSAL (SDK de identidade da Microsoft) verifica se o usuário está autenticado
- Se não estiver, solicita a autenticação
- Após autenticado, a aplicação armazena um token para consumir a API
O Diferencial
Não basta um token de acesso convencional para consumir um endpoint específico da API. É necessário um token com uma claim especial (acrs), contendo exatamente o valor do contexto esperado.
2. Configuração do Entra ID
App Registration e Contextos
O processo inicia com o registro das aplicações (cliente e API) no Entra ID, mantendo as etapas tradicionais de permissionamento e definição de escopos.
A novidade está na configuração de contextos, que são pares chave-valor criados no Entra ID e utilizados em políticas de acesso condicional.
Pré-requisito: Licença Entra ID P1 para uso de acesso condicional.
O contexto é configurado em uma aba específica dentro das políticas de acesso condicional.
Ao criar um novo contexto, define-se o nome, descrição e o ID sequencial (ex: c1). O checkbox "Publish to apps" torna o contexto disponível para as aplicações consumirem:
Estrutura e Limitações dos Contextos
| Aspecto | Detalhe |
|---|---|
| Identificação | Número sequencial (ex: c1, c2, até c99) |
| Limite | Vinculado ao número máximo de regras de acesso condicional (195) |
| Composição | Nome + Descrição |
| Utilidade | Depende da implementação na aplicação |
Aplicação Prática dos Contextos
O contexto permite granularidade adicional além das tradicionais roles e claims do token JWT:
- Rede corporativa: restringir acesso a uma área apenas para usuários dentro da rede interna
- Dispositivos gerenciados: exigir que o dispositivo esteja em compliance
- Assinatura de termos: exigir ações adicionais (ex: NDA) antes do acesso a dados sensíveis, mesmo que o token permita o acesso
Por fim, o contexto é vinculado a uma política de acesso condicional. No exemplo abaixo, a policy "Teste - C10" associa o contexto "Teste WebApp" como target resource:
3. Implementação no Código
3.1 Configuração no Cliente (Startup.cs)
No processo de inicialização, utiliza-se o método AddMicrosoftIdentityWebAppAuthentication para configurar a autenticação, incluindo o parâmetro ClientCapabilities, que habilita o uso de contexto.
Além disso, é adicionado o handler MicrosoftIdentityConsentAndConditionalAccessHandler para gerenciar o fluxo de acesso condicional.
// Habilita autenticação com suporte a contexto e acesso condicional
services.AddMicrosoftIdentityWebAppAuthentication(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi(
Configuration.GetSection("TodoList:Scopes").Get<string[]>()
)
.AddInMemoryTokenCaches();
// Handler para gerenciar challenge de acesso condicional
services.AddScoped<MicrosoftIdentityConsentAndConditionalAccessHandler>();
3.2 Configuração (appsettings.json)
O ponto-chave é o ClientCapabilities: ["cp1"], que habilita o suporte a Continuous Access Evaluation:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "cyber.meudominio.com.br",
"TenantId": "...-8888-4400-8c9c-...",
"ClientId": "...-e635-...-bb9f-...",
"CallbackPath": "/signin-oidc",
"SignedOutCallbackPath": "/signout-oidc",
"ClientCapabilities": [ "cp1" ],
"ClientSecret": "XHm8Q~6_rNy_ib-....~KbcvF"
}
}
A classe Configuration, passada para AddMicrosoftIdentityWebAppAuthentication, localiza e carrega automaticamente a seção AzureAd do arquivo de configuração.
3.3 Método Crítico: Validação do Contexto
No endpoint crítico (ex: deletar item), o código verifica se o token do usuário contém a claim acrs com o valor do contexto exigido:
// GET: TodoList/Delete/5
public async Task<ActionResult> DeleteItem(int id)
{
string requiredAuthContextId = "c10";
string acrsClaimType = "acrs";
// Construção do claimsChallenge
var claimsChallengeObj = new
{
id_token = new
{
acrs = new
{
essential = true,
value = requiredAuthContextId
}
}
};
string claimsChallenge = System.Text.Json.JsonSerializer.Serialize(claimsChallengeObj);
// Verifica se o usuário possui o claim necessário
Claim acrsClaim = User.FindAll(acrsClaimType)
.FirstOrDefault(x => x.Value == requiredAuthContextId);
if (acrsClaim?.Value != requiredAuthContextId)
{
// Dispara challenge para cumprir o contexto exigido
_consentHandler.ChallengeUser(
new[]
{
"api://ce845259-3c67-43c1-9816-43f82f4d7704/ToDoList.Read",
"api://ce845259-3c67-43c1-9816-43f82f4d7704/ToDoList.ReadWrite"
},
claimsChallenge
);
}
try
{
var todo = await _downstreamApi.GetForUserAsync<Todo>(
"TodoList",
options => options.RelativePath = $"api/todolist/{id}");
if (todo == null) return NotFound();
return View(todo);
}
catch (Exception)
{
return RedirectToAction("Index");
}
}
Lógica do Fluxo
- Claim presente e válida: a operação é permitida normalmente
- Claim ausente: o ChallengeUser() abre a tela do Entra ID para o usuário cumprir o requisito (ex: MFA, assinatura de termo)
- Contexto já satisfeito: o fluxo é transparente para o usuário
4. Fluxo de Challenge e Resposta
Do lado da API (Backend)
Quando o contexto não é atendido, a API retorna:
- 401 Unauthorized com headers customizados
- Informações sobre o contexto exigido no corpo/headers da resposta
Do lado do Cliente (Frontend)
- O cliente captura exceções específicas (WebApiMsalUiRequiredException)
- Extrai informações do header da resposta
- Executa o fluxo de challenge conforme necessário
- Após cumprido o requisito, o token é renovado com a claim acrs
5. Considerações Finais
- O uso de contextos no Entra ID amplia as possibilidades de controle de acesso, permitindo requisitos dinâmicos e contextuais além das roles tradicionais
- A implementação exige integração cuidadosa entre backend e frontend, além de testes para garantir o correto tratamento dos fluxos de challenge e resposta
- A documentação limitada reforça a importância de compartilhar experiências e boas práticas para fomentar o uso do recurso
- Requer licença Entra ID P1 para acesso condicional