O blog da AWS
Explorando a concessão Client Credentials do OAuth 2.0 na AWS
Por Gerson Itiro Hidaka, Arquiteto de Soluções para Enterprise na AWS
Introdução
Quando construímos uma arquitetura baseada em APIs, é necessário implementar camadas de segurança para protegê-las. Existem várias maneiras de construir essas camadas de segurança e um dos protocolos mais utilizado é o OAuth 2.0 para a autorização. O objetivo deste blog post é explorar a integração entre o Gateway de API e o serviço de autenticação / autorização na Nuvem para então verificarmos o fluxo de concessão de tokens de acesso do tipo Client Credentials.
O OAuth 2.0 é um protocolo padrão da indústria para autorização que permite aos usuários ter acesso limitado a recursos de um website sem precisar expor suas credenciais. Podemos fazer uma analogia do uso do OAuth 2.0 com a chamada “valet key” que alguns carros possuem. A “valet key” permite que os manobristas conduzam o seu carro por até 2km para estacioná-los, ou seja, essa chave especial provê o acesso limitado e temporário ao seu veículo. Com essa chave especial você não precisará entregar ao manobrista a chave original do carro evitando dar a permissão total para ele. Análogo à “valet key”, para obtermos acesso limitado a recursos na aplicação, pode-se utilizar o OAuth 2.0 e um token de acesso (access token).
O fluxo para obter os tokens de acesso varia ligeiramente com base no tipo de concessão (grant type) que você escolhe. Há três tipos de concessão de tokens: Authorization Code Grant, Implicit Grant, e o Client Credentials Grant. Antes de colocar a “mão na massa” e configurar os recursos da Nuvem vamos entender as diferenças entre os 3 tipos de concessão.
Authorization Code Grant
O Authorization Code Grant, ou concessão do código de autorização, é o método preferido e mais utilizado para autorizar usuários finais. Em vez de fornecer tokens de acesso diretamente para um usuário final após a autenticação, um código de autorização é fornecido junto a URL de redirecionamento. Esse código é então utilizado pela aplicação que irá trocá-lo pelo token de acesso. Como os tokens nunca são expostos diretamente a um usuário final, é menos provável que sejam comprometidos.
Na “Figura 1 – Authorization Code Grant” podemos verificar o fluxo da concessão tipo Authorization Code.
- Usuário recebe a tela de login (user/password) e realiza a autenticação.
- Realizado o login com sucesso, o serviço de autenticação retorna ao usuário/aplicação uma URL de redirecionamento juntamente com um código de autorização.
- Através do endpoint do Amazon Cognito a aplicação poderá realizar a requisição do token de acesso enviando o código de autorização recebido no passo anterior.
- O sistema valida o código de autorização e fornece o token de acesso.
- Utilizando o token de acesso, a aplicação envia o request para o endpoint da API.
- O API Gateway valida o token de acesso. Caso seja válido envia o request para a função AWS Lambda.
- O Lambda recebe o request e faz o processamento do mesmo.
- O Lambda retorna uma resposta ao Amazon API Gateway, normalmente, com um dado em anexo na mensagem.
- API Gateway retorna uma resposta com status 200 à aplicação juntamente com o dado em anexo.
Implicit Grant
Use a Implicit Grant, ou concessão implícita, apenas quando houver um motivo específico para que a Authorization Code Grant não possa ser utilizado. Em uma Implicit Grant, os tokens de acesso são expostos diretamente ao usuário final. Como resultado, tokens de acesso têm mais potencial de serem comprometidos antes de expirarem. Por outro lado, se sua configuração não contém nenhuma lógica do lado do servidor, você pode querer usar a Implicit Grant para evitar que tokens de atualização (refresh token) sejam expostos ao cliente, já que a concessão implícita não gera tokens de atualização.
Na “Figura 2 – Implicit Grant” podemos verificar o fluxo de concessão tipo Implicit.
- Usuário recebe a tela de login (user/password) e realiza a autenticação.
- Diferente do Authorization Code Grant, no modo Implicit recebemos diretamente o token de acesso.
- Utilizando o token de acesso, a aplicação envia o request para o endpoint da API.
- O API Gateway valida o token. Caso seja válido envia o request para a função Lambda.
- O Lambda recebe o request e faz o processamento do mesmo.
- O Lambda retorna uma resposta ao API Gateway, normalmente, com um dado em anexo na mensagem.
- O API Gateway retorna uma resposta com status 200 à aplicação juntamente com o dado em anexo.
Client Credentials Grant
A Client Credentials Grant, ou concessão de credenciais do cliente, é muito mais direta do que os dois tipos de concessões anteriores. Ao contrário das concessões anteriores, que tem o objetivo de obter tokens para usuários finais, a Client Credentials Grant, normalmente, se destina a fornecer credenciais a um aplicativo para autorizar solicitações de M2M (Machine to Machine). Observe que, para usar a Client Credentials Grant, o aplicativo deve utilizar um ID e um Secret para autenticação.
- Aplicação realiza autenticação utilizando o App client ID e o App client secret.
- O App recebe o token de acesso.
- Utilizando o token de acesso, a aplicação envia o request para o API endpoint.
- O API Gateway valida o token. Caso seja válido envia o request para a função Lambda.
- O Lambda recebe o request e faz o processamento do mesmo.
- O Lambda retorna uma resposta ao API Gateway, normalmente, com um dado em anexo na mensagem.
- O API Gateway retorna uma resposta com status 200 à aplicação juntamente com o dado em anexo.
Mão na Massa
Agora que entendemos os 3 modos de concessão do token de acesso e suas diferenças, vamos configurar os serviços na nuvem para testar o tipo Client Credentials Grant. Para isso utilizaremos os serviços listados na “Figura 3 – Client Credentials Grant”.
Lambda Function
Primeiramente vamos criar uma função Lambda utilizando o Python 3.9 como runtime. Essa função será responsável pelo processamento e resposta da nossa API.
- Na console de gerenciamento da AWS, procurar pelo serviço AWS Lambda. Criar uma função simples e com o código padrão:
- Selecionar o botão Create function. Selecionar a opção Author from scratch, digitar o nome da função no campo Function name e selecionar o Python 3.9 como Runtime.
- Utilizaremos o arm64 como arquitetura do Lambda. Essa função irá permitir que a função seja executada utilizando os processadores Graviton 2 (ARM) que possuem mais performance e menor custo quando comparado a plataforma x86 64 bits.
- Selecionar o botão Create Function.
Amazon Cognito
O próximo passo será configurar o Amazon Cognito que será responsável pela autenticação e fornecimento do token de acesso.
- Na console de gerenciamento da AWS, selecionar o serviço “Cognito” através do campo search.
- Selecionar o botão Manage User Pools e depois Create a user pool.
- Determinar um nome para o user pool no campo Pool name. Para este exemplo vamos manter todas as configurações padrão do user pool. Selecionar Review defaults para revisar as configurações do user pool. Selecionar Create pool.
- Vamos agora criar o App clients. No menu a esquerda, selecionar App Clients e Add an app client. Determinar o nome do App Client através do campo App client name. Selecionar o botão Create app client. Anote o App client id e o App client secret que utilizaremos na sessão Smoke Test.
- Selecione o item Domain Name no menu. No campo Your domain name, digitar o nome do domínio. Você poderá utilizar o botão Check Availability para verificar se o nome do domínio escolhido está disponível para uso. Selecionar o botão Save changes. Anote o nome completo do domínio. Esse parâmetro será utilizado na sessão Smoke Test para conseguirmos o token de acesso.
- Selecione o item Resource servers no menu, em seguida Add a resource server. No nosso exemplo utilizei os seguintes parâmetros:
- Resource Server / Name: blog
- Resource Server / Identifier: blog
- Scope / Name: json.read
- Scope / Description: read json data
- Selecionar o botão Save changes.
- Selecionar o item App client settings no menu. Utilizei os seguintes parâmetros em nosso exemplo:
- Enabled Identity Providers: Cognito User Pool
- Callback URL(s): https://localhost:3000
- Sign out URL(s): https://localhost:3000
- Allowed OAuth Flows: Client credentials
- Allowed Custom Scopes: blog/json.read
- Selecionar o botão Save changes.
- Para a configuração da integração do API Gateway e do Amazon Cognito precisaremos do parâmetro Pool Id. No menu clicar em General Settings e anotar o Pool ID.
API Gateway
O próximo passo será configurar o API Gateway.
- Na console de gerenciamento da AWS, selecionar o API Gateway através do campo Search.
- Selecionar o botão Create API. Vamos criar uma API do tipo HTTP API. Selecionar o botão Build correspondente ao HTTP API.
- Selecionar o botão Add Integration. Selecionar o Lambda e procurar pela função que acabamos de criar no item anterior.
- Preencher o nome da API no campo API name e selecionar o botão Next.
- Na configuração de rotas, o Resource Path deverá ser modificado para “/”. Selecionar o botão Next.
- Manter a configuração padrão em Define Stages. Selecionar o botão Next.
- Revisar as configurações e selecionar o botão Create.
- Anotar a URI apresentada em Invoke URL, que será utilizada na sessão Smoke Test.
Integração entre API Gateway e Cognito
- Agora vamos configurar a integração do API Gateway com o Amazon Cognito.
- Selecionar o item Develop / Authorization no menu do lado esquerdo da console de gerenciamento do API Gateway.
- Selecionar o método ANY e selecionar o botão Create and attach an authorizer. Utilizamos os seguintes parâmetros no nosso exemplo.
- Authorizer type: JWT
- Name: blog
- Identity source: $request.header.Authorization
- Issuer URL: https://cognito-idp.us-west-2.amazonaws.com/<pool-id> (parâmetro anotado no item 10 da sessão Mão na Massa/Amazon Cognito).
- Audience: <client-id> (parâmetro anotado no item 4 da sessão Mão na Massa/Amazon Cognito).
- Selecionar o botão Create and attach.
As configurações do API Gateway, Lambda e Amazon Cognito estão prontas, agora vamos partir para os testes na sessão: “Smoke Test”.
Smoke Test
Agora que temos o ambiente da aplicação configurado vamos para os testes iniciais. Para isso utilizaremos o aplicativo Postman instalado no desktop/laptop.
O primeiro teste é realizar a chamada da API sem o token de acesso. O resultado esperado é receber uma mensagem: “Unauthorized” já que não vamos enviar as credenciais de acesso na requisição da API.
- Abrir o app Postman. Abrir uma nova Tab e manter o método GET.
- Digitar a URL do API Gateway (parâmetro anotado no passo 10 da sessão Mão na Massa/API Gateway) e selecionar o botão Send.
- Como podemos verificar na Figura 4, abaixo, recebemos uma mensagem “Unauthorized”, pois não passamos o token como parâmetro.
No segundo teste iremos seguir o fluxo completo descrito na “Figura 3 – Client Credentials grant”. O resultado esperado é receber a mensagem emitida pela função Lambda (“Hello from Lambda” no nosso exemplo).
- Abrir uma nova tab no Postman. Utilizar os seguintes parâmetros:
- Method: POST
- Request URL (URL coletada no passo 5 da sessão Mão na Massa / Amazon Cognito): https//<URL>/oauth2/token
- Selecionar a aba Body e o item x-www-form-urlencoded. Inserir duas chaves (configuradas durante a sessão “Mão na Massa”):
- Key: grant_type, Value: client_credentials
- Key: scope, Value: blog/json.read
- Selecionar a aba Authorization. Aqui iremos inserir o App client ID e o App client secret para envio ao Amazon Cognito. Esses parâmetros foram coletados durante a sessão “Mão na Massa / Amazon Cognito”, passo 4. Utilizar os seguintes parâmetros:
- Type: Basic Auth
- Username: <App client ID>
- Password: <App client secret>
- Selecionar o botão Send. Você receberá o token de acesso na área de respostas do Postman.
- Anote o access_token, pois iremos utilizá-lo na próxima etapa.
- Agora iremos realizar um request no API Gateway. Para isso abrir uma nova aba no Postman e utilizar os seguintes parâmetros:
- Método: GET
- Request URL: <endereço do api gateway> (endereço coletado no passo 8 da sessão Mão na Massa / API Gateway)
- Aba authorization. Type: Bearer token
- Token: <colar o token>. OBS: Não incluir as aspas duplas.
- Selecionar o botão Send. O resultado esperado é recebermos um “Hello from Lambda” com status 200.
Estimativa de Preço
Todo os passos listado na sessão “Mão na Massa” e “Smoke Test” foram realizados utilizando o tier gratuito da AWS. Abaixo listamos as informações sobre o Tier gratuito de cada serviço.
Serviços Utilizados | Tier Gratuito |
Amazon API Gateway | · 1M de chamadas de APIs recebidas. · 1M de chamadas de API HTTP recebidas. · 1M de Mensagens. · 750.000 minutos de conexão. |
AWS Lambda | · 1 milhão de solicitações gratuitas por mês e, · 400.000 GB/segundos de tempo de computação por mês. |
Amazon Cognito | · 50.000 MAUs para usuários que fazem login diretamente em Grupos de usuários do Amazon Cognito. · 50 MAUs para usuários federados (SAML 2.0). |
OBS: Recomenda-se a utilização do AWS Pricing Calculator para a elaboração de estimativa de consumo para o seu cenário de uso.
Conclusão
Neste blog post, exploramos os 3 tipos básicos de concessão do token de acesso no fluxo do OAuth 2.0 e tivemos a oportunidade de testar o tipo Client Credencials Grant com o Amazon Cognito, API Gateway, e o Lambda. Entender e implementar a camada de segurança de autorizações do OAuth 2.0 na sua API é primordial para controlarmos quem pode usar as suas APIs e quais recursos estão autorizados a acessar. Esse tipo de proteção poderá ser utilizado nas mais diversas aplicações da indústria como varejo, financeiro, industrial, e start ups. E como puderam verificar, a implementação fica fácil com os serviços gerenciados da AWS.
Referências
Listamos aqui algumas referências adicionais para que possa se aprofundar no tema:
- https://oauth.net/2/
- https://thinkwithwp.com/blogs/mobile/understanding-amazon-cognito-user-pool-oauth-2-0-grants/
- https://www.postman.com/
- https://jwt.io/
Sobre o autor
Gerson Itiro Hidaka atualmente trabalha como Enterprise Solution Architect na AWS e atua no atendimento a clientes na área de Mid-Enterprise no Brasil. Entusiasta de tecnologias como Internet das Coisas (IoT), Drones, Devops e especialista em tecnologias como virtualização, serverless, container e Kubernetes. Trabalha com soluções de TI há mais de 24 anos, tendo experiência em inúmeros projetos de otimização de infraestrutura, redes, migração, disaster recovery e DevOps em seu portifólio.