OAuth 2.0: fluxos de obtenção de access token
OAuth 2.0[1] é um protocolo de autorização de padrão aberto que permite a terceiros (aplicações) acessarem dados de um usuário sem a obrigatoriedade de informar suas credenciais. Apps usam esse método para obter acesso à conta de um determinado usuário através de um client ID ou client secret (chaves de autenticação do OAuth).
Para saber mais, visite o site http://oauth.net/2/. |
Tipos de clientes
No OAuth, há dois tipos de clientes:
-
Cliente confidencial: clientes que conseguem garantir que nenhum usuário mal intencionado irá obter um client secret ou client ID para tentar se passar por uma aplicação válida.
-
Cliente não confidencial: clientes que não conseguem garantir que um usuário mal intencionado irá obter seu client secret ou client ID para tentar se passar por uma aplicação válida. Nesses casos, é informada uma URL de callback para garantir que as informações só retornem à aplicação verdadeira. Alternativamente, pode-se reduzir o tempo de vida útil do client ID com a utilização de um refresh token.
Formas de se obter um access token
Há diferentes fluxos OAuth 2.0, que demandam formas distintas de obtenção de um token de acesso.
Há formas que requerem o envio de extraInfo .
Valores enviados como extraInfo são exibidos no campo Extra Fields do Overview de um token, que pode ser acessado ao clicar sobre o nome de um token na página Access Tokens.
|
Authorization Code
1. Gerando o authorization code:
Primeiramente, é necessário ter uma app criada.
Com ela, temos acesso ao client ID, que será o primeiro item passado para o endpoint <URL do gateway>/oauth/grant-code
via POST.
O header deve conter a seguinte informação:
Content-Type: application/json
No corpo, devemos enviar os seguintes itens:
{
"client_id": "f9212173-e705-373b-a698-61923e378359",
"extraInfo": {},
"redirect_uri": "string",
"state": "string"
}
O client ID a ser passado deve ser o mesmo da app criada. |
Feito isso, espera-se uma resposta contendo um authorization code, como no exemplo abaixo.
{
"redirect_uri": "string?state=string&code=8748d39f-1d4f-311f-92c6-4b279db1b317"
}
2. Informando o authorization code para gerar o access token:
Em seguida, deve-se realizar uma nova requisição do tipo POST para o endpoint <URL do gateway>/oauth/access-token
.
O header deve conter as seguintes informações:
Authorization: Basic client_id:client_secret
No corpo, devemos passar o authorization code gerado pelo endpoint anterior.
Você pode utilizar o formato x-www-form-urlencoded ou JSON para o corpo, lembrando apenas de incluir o header de Content-Type
correspondente (application/x-www-form-urlencoded
ou application/json
).
Inclua no corpo as seguintes informações:
-
grant_type
, com valorauthorization_code
-
code
, com o valor recebido do endpoint anterior.
O access token será gerado e haverá um retorno como este:
{
"access_token": "57f10f0e-3d2e-311f-a797-4011f66e1cbf",
"refresh_token": "ca81cb16-43e4-3e96-aaea-4861e7791dc7",
"token_type": "access_token",
"expires_in": 3600
}
Authorization code com PKCE
A partir da release 4.6.1.0 da API Platform, damos suporte a PKCE no fluxo de Authorization Code.
PKCE (Proof Key for Code Exchange) é uma extensão de OAuth que busca tornar o fluxo de Authorization Code mais seguro, evitando ataques de interceptação — i.e., quando uma app maliciosa ganha acesso ao authorization code em uma comunicação sem TLS e usa o code para emitir um access token. Você pode ler mais sobre ele na RFC 7636.
O PKCE não é obrigatório, é o cliente que decide se fará ou não uso dele no fluxo de Authorization Code.
Se quiser usar PKCE, é preciso enviar um code_challenge
acompanhado de um code_challenge_method
na chamada de grant-code e, na chamada para obter um access token, enviar um code-verifier
:
-
code-verifier
: segundo a RFC 7636, deve ser uma string aleatória criptografada de alta entropia, com um mínimo de 43 caracteres e máximo de 128, e utilizando os caracteres [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~". -
code_challenge
: código derivado do code_verifier por meio de um método de transformação (code_challenge_method). -
code_challenge_method
: método de transformação pelo qual ocode_challenge
é gerado. Há duas opções:-
plain
: code_challenge = code_verifier -
S256
: code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))Se o code_challenge_method não for passado, ele é assumido como sendo plain
.
-
Para usar PKCE, o cliente deve incluir nas chamadas as seguintes informações:
O servidor de autorização não valida se o code_challenge está seguindo a alta entropia que é recomendada pela RFC, pois isso é de responsabilidade do cliente. Também não é obrigatório que PKCE seja utilizado no fluxo de Authorization Code. Entretanto, uma vez que o cliente envie o code_challenge na chamada de geração de authorization code, o servidor de autorização exigirá o code_verifier na chamada para obtenção do token. Esse code_verifier será validado com base no code_challenge e code_challenge_method enviados anteriormente e caso a validação não seja bem-sucedida, o token não será gerado. |
Refresh Token
O refresh token será utilizado para atualizar um access token que tenha sido expirado. Para atualizar o token, siga os passos abaixo.
Faça uma requisição do tipo POST para o endpoint <URL do gateway>/oauth/access-token
.
O header deve conter as seguintes informações:
Authorization: Basic client_id:client_secret
No corpo, devemos passar o refresh_token
recebido do endpoint anterior (que gerou o access token) e o grant type em formato x-www-form-urlencoded
, como neste exemplo:
grant_type=refresh_token&refresh_token=ca81cb16-43e4-3e96-aaea-4861e7791dc7
Por fim, o access token será gerado novamente e um código como o seguinte será retornado:
{
"access_token": "ca81cb16-43e4-3e96-aaea-4861e7791dc7",
"refresh_token": "677b881a-d0b6-3b29-b9a8-f0cdb50ce035",
"token_type": "access_token",
"expires_in": 3600
}
Implicit
O fluxo Implicit é usado para obter tokens de acesso de forma otimizada para clientes públicos. Ele pode operar por uma IRO de redirecionamento particular, acompanhado do access token. Esses clientes são normalmente implementados em um navegador usando uma linguagem de script, como JavaScript.
Como para o fluxo OAuth 2.0 Authorization Code, é necessário que a app esteja criada para que tenhamos acesso ao client ID.
Depois disso, faça uma requisição POST para o endpoint <URL do gateway>/oauth/access-token
.
O cabeçalho deve conter a seguinte informação:
Content-Type: application/json
No corpo, devemos enviar os seguintes itens:
{
"grant_type": "implicit",
"redirect_uri": "<URL>",
"client_id": "<client ID>"
}
O client ID a ser passado deve ser o mesmo da app criada. |
Note também que a app deve conter um extra field chamado redirect_uri , com o valor de URL válida, que deverá ser informada na chamada de geração do token (por exemplo: http://supermock.demo.sensedia.com/ ).
Veja mais informações sobre como criar e configurar apps, adicionando extra fields, aqui.
|
Acabado o processo, espera-se uma resposta com a URI e o access token, conforme o exemplo abaixo.
{
"redirect_uri": "www.url.com?access_token=57f10f0e-3d2e-311f-a797-4011f66e1cbf",
"expires_in": 3600
}
Client Credentials
Assim como o fluxo Implicit, o Client Credentials NÃO gera o refresh_token
.
Portanto, não é possível atualizar um access token depois de sua expiração.
Quando este fluxo for utilizado, ao criar um novo access token, deve-se inserir o nome da app e seu client ID no campo Extra Info
do access token, inserindo também todos os valores de extra fields que estiverem cadastrados na app.
Acesse aqui para ver mais informações sobre como criar e configurar apps, adicionando extra fields.
É necessário que uma app esteja criada para que possamos ter acesso ao client ID e ao client secret.
Em seguida, é necessário fazer uma requisição POST para o endpoint <URL do gateway>/oauth/access-token
.
O header deve conter as seguintes informações:
Authorization: Basic client_id:client_secret
No corpo, devemos passar o grant_type
no formato x-www-form-urlencoded
:
grant_type=client_credentials
Por fim, o seu access token será gerado e deverá ser retornado como no exemplo abaixo:
{
"access_token": "6c164a82-84a6-3bc4-8122-f777121a4f62",
"token_type": "access_token",
"expires_in": 3600
}
É possível também criar novos extra fields na criação do access token. Para isso, é necessário adicionar ao cabeçalho o seguinte header:
Content-Type: application/json
No corpo, devemos passar o grant_type
e os extra fields, como neste exemplo:
{
"grant_type": "client_credentials",
"extraInfo": {"value": "32423", "value2": "874yhgt3"}
}
Password
Como no fluxo Authorization Code, é necessário que a app esteja criada para que possamos ter acesso ao client ID e ao client secret.
Então, faça uma requisição POST para o endpoint <URL do gateway>/oauth/access-token
.
O header deve conter as seguintes informações:
Authorization: Basic client_id:client_secret
Além do grant_type
, o corpo precisa conter mais duas informações que utilizam o userDirectory
.
Essas informações são o login e a senha do usuário, que podem ser de um LDAP ou de um REST, e devem estar no formato x-www-form-urlencoded
:
grant_type=password&username=<login de usuário>&password=<senha>
Se o usuário e senha forem válidos na LDAP ou no REST, o retorno do access token deve ser semelhante ao modelo a seguir:
{
"access_token": "6c164a82-84a6-3bc4-8122-f777121a4f62",
"token_type": "refresh_token",
"expires_in": 3600
}
Para que as funcionalidades acima estejam presentes na sua app, é necessário configurar uma API Identity. |
No caso de LDAP, o usuário informado deve estar no formato User-Principal-Name (e.g., test@da.sa )
|
A propriedade oauth.grantTypes.resourceOwnerPassword.userDirectory não é mais necessária.
|
JWT
"JSON Web Token (JWT) é um padrão aberto (RFC 7519) que define uma forma compacta e auto-suficiente para a transmissão segura de informações entre as partes na forma de um objeto JSON. Essa informação pode ser verificada e confiável porque é assinada digitalmente. JWTs podem ser assinados usando um segredo (com o algoritmo HMAC) ou um par de chaves pública/privada usando RSA." (https://jwt.io/)
No fluxo JWT, também é necessário que a app esteja criada para que tenhamos acesso ao client ID e ao client secret.
Então, faça uma requisição POST para o endpoint <URL do gateway>/oauth/access-token
.
O cabeçalho deve conter as seguintes informações:
Authorization: Basic client_id:client_secret
No corpo, devemos passar o code
gerado pelo endpoint de grant-code e o grant type em formato x-www-form-urlencoded
, como neste exemplo:
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&code=8748d39f-1d4f-311f-92c6-4b279db1b317
Por fim, o seu access token será gerado novamente e deverá ser retornado conforme o exemplo abaixo.
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJsb2NhbGhvc3QiLCJpc3MiOiIxNzIuMTguMC4xIiwic3ViIjoiOWI1Zjc3MWUtNzgyZC0zNTEwLWI2YmEtMzZlOWM2NWJmZDVkIiwiZXhwIjozNjAwLCJpYXQiOjE1Mjg5MTg2MzcsIkFwcDogIjoiUmljYXJkb0FwcCIsIkNvZGU6ICI6IjRlNWIyMTEzLTJkYzYtM2RlNi1iN2ZkLWNkOTYxOTMxZWQyOSIsImxvZ2luIjoidXNlci5sb2dpbiJ9.bhvFpiZ6em9tUgpHxGQGuH7cmvMy4I7STJDRBUybuPM",
"token_type": "access_token",
"expires_in": 3600
}
Com o código gerado, será necessário adicionar o interceptor de JWT no fluxo da API. Ele será responsável por verificar se o token é valido. Veja mais sobre o interceptor aqui.
Fluxo OpenID
O fluxo OpenID permite que usuários usem uma credencial existente para acessar diversos sites e aplicações, sem a necessidade de criação de novas senhas. Isso aumenta a segurança dos usuários pois a senha de cada usuário é fornecida somente a um provedor de identificação, que então confirma a identidade e concede acesso aos sites e aplicações que o usuário deseja utilizar.
Para utilizar o fluxo OpenID, é necessário criar a API do Google OpenID. Clique aqui para ver as instruções de como criar a API.
É necessário, também, ter uma app criada.
Com ela, teremos acesso ao client ID, que será o primeiro item a ser passado no endpoint <URL do gateway>/google/oauth/openid/redirect
, via requisição POST.
O cabeçalho deve conter as seguintes informações:
Content-Type : application/json client_id : client_id
No corpo, devemos enviar o seguinte item:
{
"extraInfo": {}
}
O client_id a ser passado deve ser o mesmo da app criada.
|
Feito isso, espera-se uma resposta com um authorization code.
Em seguida, deve-se acessar a redirect_uri
, que dá acesso a uma página de autenticação do seu provedor.
{
"redirect_uri": "string?queryParams"
}
Ao realizar o login, haverá redirecionamento automático seguindo os valores do access token.
Revogação de access token e refresh token
A revogação inutiliza um token que ainda está válido mas que não é mais necessário. Após a revogação, o token não será aceito em requisições a APIs.
É possível utilizar o endpoint /revoke
da API "OAuth 2.0" para revogar um access token ou refresh token.
Em ambos os casos, todos os tokens são revogados — ou seja, se você revogar um access token e houver um refresh token associado a ele, ele também será revogado, e se você revogar um refresh token, o access token associado a ele também será revogado.
Para fazer a revogação, é necessário enviar uma requisição POST para <URL do gateway>/oauth/revoke
.
A requisição deve conter o header Authorization
:
Authorization : Basic client_id:client_secret
No corpo, passe as seguintes informações no formato x-www-form-urlencoded
:
token=<valor>&token_type_hint=access_token
OU
token=<valor>&token_type_hint=refresh_token
Note que não é obrigatório passar o token_type_hint
(pois o token é encontrado pelo valor informado), mas ele torna a operação de revogação mais rápida.
Share your suggestions with us!
Click here and then [+ Submit idea]