Introdução

Para reforçar a segurança do Web Service padrão REST do Protheus, está disponível o modelo de autenticação através de token de acesso, também conhecido como Bearer token.
A obtenção desse token de acesso é realizada através de uma requisição à uma API (Application Programming Interface) específica.
Existe uma configuração* que define se é necessário realizar a autenticação do usuário para se ter acesso às API’s e caso essa autenticação esteja habilitada, é necessário utilizar um dos modelo de autenticação.
O modelo mais simples de autenticação disponível é conhecido como Basic Auth, mas ele não pode ser considerado como seguro pois trafega em cada requisição, o usuário e a senha que está se autenticando. Para evitar que o usuário e a senha sejam trafegados no cabeçalho de cada requisição REST, pode-se então optar por esse novo modelo proposto.

* Mais detalhes sobre a configuração e dos modelos de autenticação disponível no link: https://tdn.totvs.com.br/pages/viewpage.action?pageId=75268866

Fluxo

Esse token é resultado de um POST no endpoint /token e tem uma validade de curta duração. Seu contexto de acesso pode variar de acordo com o usuário que está se autenticando.

Nesse modelo fica necessário então o tráfego de usuário e senha apenas nessa requisição de acesso (que é fortemente recomendado que seja protegida por SSL - Secure Sockets Layer para não ser interceptada por terceiros), e após a obtenção, basta incluir o token no cabeçalho de cada requisição para garantir o acesso às demais API’s que o usuário tenha direito.

Após a expiração da validade do token de acesso é necessário repetir a requisição através do fornecimento de usuário e senha ou, melhor ainda, também é possível a utilização de um token de refresh para obter outro token de acesso sem a necessidade de trafegar a senha novamente.

Esse token de refresh é obtido juntamente com o token de acesso na primeira requisição e tem um tempo de expiração bem superior ao do token de acesso. Atualmente o tempo de expiração do token de acesso está definido em uma hora e o de refresh em vinte e quatro horas.

Uma vez que é requisitada a atualização dos tokens, o prazo de validade de ambos é renovado e com isso é possível manter o acesso garantido pelo tempo que for necessário de forma circular.

Caso a atualização não seja requisitada até o momento de expiração do token de refresh, não será mais possível obter acesso por atualização, sendo então necessário solicitar o token de acesso informando usuário e senha novamente.


O Endpoint /token

Devido ao trafego de usuário e senha para esse endpoint, ele é um servido que recomendamos fortemente que seja acessado pelo protocolo seguro https. Caso seja utilizado sem o uso do SSL, uma mensagem é impressa no console do servidor a cada requisição que é respondida.

Seus parâmetros são trafegados via http headers conforme exemplo abaixo:

https://localhost:8080/rest/api/oauth2/v1/token?grant_type=password

POST /api/oauth2/v1/token
Host exemplo: https://localhost:8080/rest
Query Params: ?grant_type=password
Headers
password : senha do usuario
username : usuario do sistema

Parâmetro

Valor

grant_type

password

password

Senha do usuário

username

Usuário para autenticação


Reposta da requisição 

Caso as credenciais sejam válidas, a resposta será retornada no seguinte formato:

{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJUT1RWUy1BRFZQTC1GV0pXVCIsInN1YiI6Im1hcmlvIiwiaWF0IjoxNTUzMDIyMjYwLCJleHAiOjE1NTMwMjU4NjAsInJlc3RyaWN0ZWR0byI6WyJhcGkvcHJvdGhldXMvIiwiYXBpL2ZyYW1ld29yay8iXX0.jgvejFxPYDchLtj04r7mizRZCerb7xFXhB8Ihk+kFqg=",
    "refresh_token": "YEv3dtFbNCisITD3yDtKi5/x.T0jkPv12SWK/JjWS0xI01YbIXWM10KWw2ehCxG9yRVkXCiItBYN57Rizh4OH67m7H3-Jd-3ruC4/pBAWBkXVO251HPiS91KAh7FfbZqWaiDPmvYBvoiaP4KRR1gYcvCr9ES7wC3iRA2wQrQvODlH7b3FCTmvHzCVmRMi4eApgy4iOGVpBK7-ryI=.fD77MI4MBk1rW6eBjMq9EutN1ZIC1YKKuKqdEhbLf/k=",
    "scope": "default",
    "token_type": "Bearer",
    "expires_in": 3600
}


Acesso às API’s REST

De posse então do access_token, basta fazer a requisição à API desejada incluindo no cabeçalho a parâmetro Authorization com o valor Bearer mais o token de acesso.

Mais detalhes podem ser obtidos no link http://tdn.totvs.com.br/pages/viewpage.action?pageId=465386127

 

A atualização do token

Após a expiração do token de acesso, ao tentar requisitar alguma API protegida, será retornado o status 401 de não autorizado, como se não houvesse sido enviado um token de acesso.

É o momento então de requisitar para a mesma API de token a atualização conforme o exemplo abaixo:

https://localhost:8081/rest/api/oauth2/v1/token?grant_type=refresh_token&refresh_token=YEv3dtFbNCisITD3yDtKi5/x.T0jkPv12SWK/JjWS0xI01YbIXWM10KWw2ehCxG9yRVkXCiItBYN57Rizh4OH67m7H3-Jd-3ruC4/pBAWBkXVO251HPiS91KAh7FfbZqWaiDPmvYBvoiaP4KRR1gYcvCr9ES7wC3iRA2wQrQvODlH7b3FCTmvHzCVmRMi4eApgy4iOGVpBK7-ryI=.fD77MI4MBk1rW6eBjMq9EutN1ZIC1YKKuKqdEhbLf/k=

POST /api/oauth2/v1/token
Host exemplo: https://localhost:8080/rest
Query Params: ?grant_type=refresh_token&refresh_token=YEv3dtFbNCisITD3yDtKi5/x.T0jkPv12SWK/JjWS0xI01YbIXWM10KWw2ehCxG9yRVkXCiItBYN57Rizh4OH67m7H3-Jd-3ruC4/pBAWBkXVO251HPiS91KAh7FfbZqWaiDPmvYBvoiaP4KRR1gYcvCr9ES7wC3iRA2wQrQvODlH7b3FCTmvHzCVmRMi4eApgy4iOGVpBK7-ryI=.fD77MI4MBk1rW6eBjMq9EutN1ZIC1YKKuKqdEhbLf/k=

Parâmetro

Valor

grant_type

refresh_token

refresh_token

Token de refresh


Reposta da requisição 

Caso o refresh token seja válido, a resposta será retornada no mesmo formato anterior e esse ciclo pode se repetir inúmeras vezes, desde que o tempo de expiração não seja excedido:

{     
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJUT1RWUy1BRFZQTC1GV0pXVCIsInN1YiI6Im1hcmlvIiwiaWF0IjoxNTUzMDIyOTQ0LCJleHAiOjE1NTMwMjY1NDQsInJlc3RyaWN0ZWR0byI6WyJhcGkvcHJvdGhldXMvIiwiYXBpL2ZyYW1ld29yay8iXX0.XsS38RdeJIetwh6Zq2DLQs0PhyLSRxCxOnCgp4SaoeY=",
    "refresh_token": "YEv3dtFbNCisMST1yztKi5/x.T0jkPv12SWK/JjWS0xI01YbIXWM10KWw2ehCxG9yRVkXCiItBYN57Rizh4OH67m7H3-Jd-3ruC4/pBAWBkXVO251HPiS91KAh7FfbZqWaiDPmvYBvoiaP4KRR1hUct67vFah2VLUSymyfLQtOjltqqzVPkqZMBaVtyVl4c4pxTw4IQtpHw==.tIUbpKC8sWcB6oIMhXcbOhq/bveF216m9gmboBrxJ7U=",
    "scope": "default",
    "token_type": "Bearer",
    "expires_in": 3600
}


Disponível a partir da LIB versão 20210517

Assinatura da Requisição

Os tokens gerados no protheus são assinados por uma chave privada e podem ser conferidos utilizando uma chave pública. A partir da LIB versão 20210517 será possível recuperar a chave pública para verificar a assinatura do token recebido. A chave pública para o algoritmo RSA fica na propriedade "n" do objeto de definição. Para mais informações sobre o formato da resposta consulte https://tools.ietf.org/html/rfc7517

https://localhost:8081/rest/api/oauth2/v1/jwks

GET/api/oauth2/v1/jwks
Host exemplo: https://localhost:8080/rest
{
    "keys": [
        {
            "e": "AQAB",
            "alg": "RS256",
            "n": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp0Lg4RLzX2NrsFj4i9lIxgzCmMQU4p4FdsWAzFm8S5YUTyEaDmk1J36bdrj3YXM5VJTA6IhbLOvEE9UAMRWWgrpOEsEN+sVijFgha0SflKQhY4XJUv45zCP/pZbfhr0N6M1AD3Up+yA/TYq9gUQoEOsf/x0G9Wsi4UHDxQCVpLPUfrlHUAOUksqZZhAO6bU2jqH7Y2EchBMe4tMydoQ6xn8+n2yEe5oZijaAVDM4V8oYE5zyGDTodMUsbau8uqQM5KykL/RyGCZGlQlEsDFwcFu8NP/Y+zyUTE+fyqWBR0YEG0I0gZwSNMK40PaoiKtee28+nh9gqfRfvmwwQaFEYwIDAQAB",
            "kid": "protheus jwt public key for RS256",
            "use": "sig",
            "kty": "RSA"
        },
        {
            "e": "AQAB",
            "alg": "RS512",
            "n": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp0Lg4RLzX2NrsFj4i9lIxgzCmMQU4p4FdsWAzFm8S5YUTyEaDmk1J36bdrj3YXM5VJTA6IhbLOvEE9UAMRWWgrpOEsEN+sVijFgha0SflKQhY4XJUv45zCP/pZbfhr0N6M1AD3Up+yA/TYq9gUQoEOsf/x0G9Wsi4UHDxQCVpLPUfrlHUAOUksqZZhAO6bU2jqH7Y2EchBMe4tMydoQ6xn8+n2yEe5oZijaAVDM4V8oYE5zyGDTodMUsbau8uqQM5KykL/RyGCZGlQlEsDFwcFu8NP/Y+zyUTE+fyqWBR0YEG0I0gZwSNMK40PaoiKtee28+nh9gqfRfvmwwQaFEYwIDAQAB",
            "kid": "protheus jwt public key for RS512",
            "use": "sig",
            "kty": "RSA"
        }
    ]
}

Não é possível alterar o tempo de expiração do token (expires_in), esse valor é definido internamente, assim como também não é possível alterar o valor de expiração do refresh_token.
O valores suportados para grant_type são password e refresh_token, qualquer outra valor enviado resultará em erro na requisição.

Disponível a partir da LIB versão 20190705