Azure AD B2C / Azure AD, usando Client Credencial

Aplicações que Autenticam em outras aplicações

Wilson Santos
5 min readJun 29, 2021

O Azure AD B2C não fornece diretamente o fluxo Client Credencial, mas como todo B2C tem um AD por traz dele trabalhando em conjunto, podemos usar esse recurso para suprir esse fluxo OAuth2.

O Fluxo Client Credencial não autentica um usuário como o Autorization Code Flow , ou o Fluxo Implícito, esse fluxo autentica uma aplicação, desse modo podemos proteger nossas APIs autorizando apenas o APIM a fazer requisições nela.

A primeira coisa que precisamos fazer é criar as aplicações no AD, para isso vamos analisar o modelo;

Então precisamos de pelo menos três aplicações para representar esses clientes sendo que dois deles precisam ter Client /Secret Configurados no Azure AD.

Vamos precisar criar as aplicações, mas nesse caso vamos cria-las diretamente no Azure AD do tenant do Azure B2C.

Saiba mais sobre criar aplicações aqui

tela do Azure AD onde devemos criar as Aplicações

Não se esqueça de configurar as devidas permissões,normalmente precisamos ter uma App que representa o Servidor e uma que representa o Cliente, ai expomos uma URI na aplicação do Server e damos permissão na aplicação cliente nessa URI.

Essa permissão quando o fluxo é de usuário usamos Escopos, e quando o fluxo é de aplicação usamos Roles.

No caso do nosso cenário precisamos criar uma Role por se tratar de fluxo entre aplicações ;

nessa imagem podemos ver uma role criada chamada ALL do tipo Appications

Depois de criar as aplicações o primeiro passo e proteger a API com o código Abaixo;

Vou criar uma controller protegida com o atributo Authorize, chamada SecurityDataController

[ApiController]
[Route("[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class SecretDataController : ControllerBase
{
public IActionResult Index()
{
return Ok(new
{
msg = "My Secret"
});
}
}

Vou usar um console para fazer um teste Inicial, nele precisamos obter um token e passar na requisição ;

olha ai tudo funciona;

Agora a cereja do bolo, como podemos fazer o APIM obter um token CC e chamar esse backend, permitindo que o cliente do APIM use outro fluxo de Autenticação por exemplo.

APIM repassando o token para o Backend

Importei a API no APIM , e configurei a police validate-jwt

Mas diferente do ultimo exemplo que nosso .well-known vinha do B2C com esse endpoint

https://seedazb2c.b2clogin.com/seedazb2c.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1_seed_sso

Dessa vez vamos usar outra url

https://login.microsoftonline.com/b5882312-aafa-467b-b071-96db714bd4f5/v2.0/.well-known/openid-configuration

Encontrei essa url abrindo o token pelo jwt.io

Peguei o valor da claim iss e completei com .well-known/openid-configuration

<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Acesso negado">
<openid-config
url="https://login.microsoftonline.com/b5882312-aafa-467b-b071-96db714bd4f5/v2.0/.well-known/openid-configuration" />
</validate-jwt>

funcionou perfeitamente

obtive o token debugando a aplicação console

Obtive o token debugando a aplicação console, passei esse token no header Authorization e consegui acessar minha controller protegida SecretData

APIM obtendo o token e repassando para o backend

Nesse exemplo vamos fazer a chamada para o AD , obter o token e repassar o mesmo para o backend

  1. Bate na url do AD/token” com método post, content type application/x-www-form-urlencoded e o body com os campos client_id, client_secret, grant_type e scope
  2. Extrai a da variável tokenResponse o acces_token
  3. Sobrescreve o header da requisição ao backend com o access token

Obtendo dados do usuário da Assinatura

Podemos obter algumas informações do usuário da assinatura utilizada na requisição as APIs, quando os consumidores acessam as APIs do APIM é comum que o header Ocp-Apim-Subscription-Key seja fornecido. Quando essa chave é associada à um usuário de assinatura, podemos obter informações como o e-mail quem fez a assinatura no portal do desenvolvedor.

Por exemplo adicionando esse código no outbound

<set-header name="useId" exists-action="override">
<value>@(JsonConvert.SerializeObject(context.User != null ? context.User.Email: "-"))</value>
</set-header>

Vamos ter esse retorno no postman;

Podemos colocar o mesmo código no inbound e vamos enviar esse valor para o backend.

Named Values

Todos os valores Hardcode nas politicas acima podem ser transferidos para o Named Value, um espaço de chave valor no APIM que pode ser usado para centralizar esse tipo de coisa facilitando a manutenção assim como a mudança de ambientes.

criando a chave ClientIDAPIM do tipo texto puro
criando a chave do tipo Secret

e depois para acessar basta fazer uma interpolação, assim;

<set-body>@{
var result = String.Concat
(
"client_id={{ClientIDAPIM}}&",
"client_secret={{SecretAPIM}}&",
"grant_type=client_credentials&",
"scope=https://seedazb2c.onmicrosoft.com/services/.default"
);
return result;
}</set-body>

bem mais bonito!

Cache

Uma boa pratica para escalar um back-end é o uso de cache, com o APIM podemos habilitar cache de duas formas, uma mais simples apenas copiando e colando duas politicas cache-lookup e cache-store veja aqui, e outra onde podemos controlar o cache com uma chave parecido com o que faríamos com o Redis.

No caso do send-request vamos precisar gerenciar o cache através de uma chave via código usando a diretiva cache-lookup-value, observe o código abaixo;

  1. Verificamos no cache a chave tokenCCV1 e jogamos para variável accessToken usando a politica cache-lookup-value
  2. Verificamos se a variável accessToken foi criada usando a politica when
  3. Caso não tenha sido criado fazemos o send-request e armazenamos o aceestoken no cache usando a politica cache-store-value
  4. Caso tenha sido criado pulamos o send-request e passamos para o backend a variável de contexto accessToken

Controle de Expiração baseado no token

Para a implementação final de produção talvez seja uma boa ideia ler o token acessar a claim exp e verificar se a mesma expirou ou não, esse critério deve fazer parte da verificação inicial da política When, de modo que caso exista um token no cache mas o mesmo esteja expirado devemos fazer o request novamente

Referencias

  1. Sample Azure API management policy — Use OAuth2 for authorization between gateway and backend — Azure API Management | Microsoft Docs
  2. Client Credentials Grant Flow with Azure AD B2C · Hossam Barakat
  3. Azure API Management policy expressions | Microsoft Docs
  4. Repositorio GIT backend
  5. Custom caching in Azure API Management | Microsoft Docs

--

--

Wilson Santos
Wilson Santos

Written by Wilson Santos

Nos últimos 15 anos, venho desenvolvendo , aperfeiçoando e integrando sistemas, sou apaixonado por desenvolver e ensinar, nem tanto por escrever!.

No responses yet