Identidade (OIDC / OAuth 2.1)
https://auth.asender.net · OAuth 2.1 + PKCE · 13 operações · openapi.yaml
Identidade — OIDC / OAuth 2.1
O Authorization Server do Asender. É daqui que sai o token que todas as outras APIs exigem: seu app não guarda a senha de ninguém nem valida um segundo fator — ele delega o login para auth.asender.net pelo fluxo padrão OpenID Connect / OAuth 2.1 + PKCE e recebe de volta dois tokens: um que prova quem logou (o ID token) e um que abre as APIs (o access token).
- Base URL:
https://auth.asender.net - Perfil: OAuth 2.1 — Authorization Code com PKCE
S256obrigatório. Sem implicit, sem password grant, semplain. - Assinatura: RS256. As chaves públicas ficam no JWKS; você valida os tokens sozinho, sem chamar o servidor a cada request.
É só isto que é público. Esta página cobre os 6 endpoints de protocolo que um integrador usa. O resto do serviço de identidade (usuários, sessões, 2FA, autorização por ferramenta) é control plane interno, reservado aos serviços da casa — não é superfície de integração e não se documenta aqui.
Antes de começar: registre um client
Um client é o seu app do ponto de vista do login. Cada client tem um client_id e uma allowlist EXATA de redirect_uri — a comparação é caractere a caractere, sem curinga, porque é ela que impede que um code de login seja desviado para um endereço que não é seu.
- Client público (SPA, mobile, CLI): não tem segredo. Quem prova que a troca do code é legítima é o PKCE. É o caso da maioria das integrações.
- Client confidencial (backend que guarda segredo com segurança): autentica no
/tokenpor HTTP Basic (client_secret_basic) ou pelos campos do corpo.
O registro do client (id, redirect_uris, post-logout, tipo) é feito pela equipe da plataforma. Peça com: os redirect_uri exatos, se é público ou confidencial, e os post_logout_redirect_uri.
Discovery: descubra os endpoints, não os crave
O primeiro request de um client bem-feito é o de discovery. Em vez de cravar URLs, leia-as de:
curl 'https://auth.asender.net/.well-known/openid-configuration'
{
"issuer": "https://auth.asender.net",
"authorization_endpoint": "https://auth.asender.net/authorize",
"token_endpoint": "https://auth.asender.net/token",
"userinfo_endpoint": "https://auth.asender.net/userinfo",
"jwks_uri": "https://auth.asender.net/.well-known/jwks.json",
"end_session_endpoint": "https://auth.asender.net/logout",
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"id_token_signing_alg_values_supported": ["RS256"],
"code_challenge_methods_supported": ["S256"],
"scopes_supported": ["openid", "profile", "email", "offline_access"]
}
Toda biblioteca OIDC séria consome esse documento — aponte a sua para o issuer https://auth.asender.net e ela se autoconfigura. O documento é cacheável (Cache-Control: public, max-age=300); só muda em deploy ou rotação de chave.
Escopos
| escopo | o que traz |
|---|---|
openid | obrigatório — é o que faz o fluxo ser OIDC; é sempre garantido |
profile | o name do usuário no ID token / /userinfo |
email | o email e o email_verified |
offline_access | um refresh_token — peça só se o app precisa agir com a sessão fora da presença do usuário |
O fluxo, passo a passo (Authorization Code + PKCE)
1. Gere o par PKCE
Antes de mandar o usuário para o login, gere um code_verifier aleatório (43–128 caracteres, base64url) e o seu code_challenge:
code_verifier = base64url(random 32 bytes)
code_challenge = base64url( SHA-256( code_verifier ) )
Guarde o code_verifier do lado do app (na sessão do browser, por exemplo). Gere também um state aleatório (anti-CSRF) e, opcionalmente, um nonce (anti-replay do ID token). state e nonce vêm de um CSPRNG, nunca de Math.random().
2. Mande o browser para /authorize
Redirecione o usuário (navegação de browser, não fetch) para:
https://auth.asender.net/authorize
?response_type=code
&client_id=app-exemplo
&redirect_uri=https://app.exemplo.com.br/callback
&scope=openid%20profile%20email%20offline_access
&state=xyz123
&nonce=n-0S6_WzA2Mj
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
O servidor valida o client_id e a redirect_uri, reaproveita a sessão do usuário no domínio de auth (ou o manda logar e volta) e redireciona de volta ao seu redirect_uri:
https://app.exemplo.com.br/callback?code=cod_9f8e7d…&state=xyz123
Confira o state antes de qualquer coisa: se não for o que você enviou, aborte. Se o login falhar depois da validação do redirect, a volta traz ?error=…&error_description=…&state=… em vez do code.
3. Troque o code por tokens em /token
Do backend (ou BFF), troque o code pelos tokens, provando o PKCE com o code_verifier que você guardou. Corpo x-www-form-urlencoded:
curl -X POST 'https://auth.asender.net/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=authorization_code' \
-d 'code=cod_9f8e7d…' \
-d 'redirect_uri=https://app.exemplo.com.br/callback' \
-d 'code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk' \
-d 'client_id=app-exemplo'
Resposta 200 (Cache-Control: no-store):
{
"access_token": "eyJhbGciOiJSUzI1Ni…",
"token_type": "Bearer",
"expires_in": 900,
"id_token": "eyJhbGciOiJSUzI1Ni…",
"refresh_token": "rft_1a2b3c…",
"scope": "openid profile email offline_access"
}
O redirect_uri aqui tem de ser idêntico ao do passo 2 (o servidor amarra o code àquele valor — é o que barra a injeção de code). O refresh_token só vem se o scope pediu offline_access. Client confidencial acrescenta a autenticação:
-u 'app-exemplo:CLIENT_SECRET' # HTTP Basic (client_secret_basic)
Os dois tokens, e o que fazer com cada um
O /token devolve dois JWT RS256, e a diferença entre eles é de segurança, não de detalhe:
- ID token (
id_token) — prova quem logou. É para o SEU app consumir: valide-o e leia os claims (sub,email,name). Nunca o mande para uma API como credencial. - Access token (
access_token) — é a credencial para chamar as APIs do Asender. Vai emAuthorization: Bearer …. Traztok_use: "access"; o/userinfoe as APIs recusam um ID token apresentado no lugar dele.
Validar o ID token (faça no client)
Não confie num token só porque ele chegou. Valide, nesta ordem:
- Assinatura — pegue a chave do JWKS (
/.well-known/jwks.json) cujokidcasa com o header do token; verifique a assinatura RS256. Rejeite qualqueralgfora deRS256(nunca aceitenone). iss— exatamentehttps://auth.asender.net.aud— exatamente o seuclient_id.exp/nbf— dentro da validade.nonce— igual ao que você enviou no/authorize.
curl 'https://auth.asender.net/.well-known/jwks.json'
{ "keys": [ { "kty": "RSA", "use": "sig", "alg": "RS256", "kid": "2026-08a", "n": "0vx7…", "e": "AQAB" } ] }
Cacheie o JWKS e recarregue quando aparecer um kid desconhecido — é assim que uma rotação de chave funciona sem downtime: a chave nova entra no JWKS antes de ser usada, e a antiga fica até os tokens que ela assinou expirarem. Uma boa biblioteca OIDC faz tudo isto para você a partir do issuer.
Claims disponíveis no ID token: sub, iss, aud, exp, iat, nonce, auth_time, email, name, tenant. O sub é o ID interno imutável do usuário — é por ele que você o identifica no seu lado, nunca pelo e-mail (uma pessoa pode ter vários e-mails, e o primário pode mudar).
/userinfo — o perfil a partir do access token
Alternativa (ou complemento) ao ID token para hidratar o perfil:
curl 'https://auth.asender.net/userinfo' \
-H 'Authorization: Bearer eyJhbGciOiJSUzI1Ni…'
{ "sub": "usr_01J…", "email": "pessoa@empresa.com.br", "email_verified": true, "name": "Fulana" }
Bearer ausente, inválido, expirado — ou um ID token no lugar do access — devolve 401 invalid_token.
Manter a sessão viva: refresh token
Com offline_access, você recebe um refresh_token opaco. Quando o access expirar (expires_in), troque o refresh por tokens novos:
curl -X POST 'https://auth.asender.net/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=refresh_token' \
-d 'refresh_token=rft_1a2b3c…' \
-d 'client_id=app-exemplo'
Rotação com detecção de reuso. Cada refresh é de uso único: usá-lo invalida aquele e devolve um novo — guarde sempre o mais recente. Se um refresh já usado for reapresentado (sinal clássico de token roubado), o servidor revoga a família inteira e responde 400 invalid_grant; a partir daí, o usuário precisa logar de novo. Trate invalid_grant no refresh como "recomece o fluxo do /authorize", não como erro a repetir.
Sair: logout
Para encerrar a sessão, mande o browser ao end_session_endpoint:
https://auth.asender.net/logout
?client_id=app-exemplo
&post_logout_redirect_uri=https://app.exemplo.com.br/adeus
&state=xyz123
O logout é server-side e irreversível (piso 17): revoga a sessão e a família de refresh, não só apaga o cookie — um refresh emitido antes não volta a valer. O redirecionamento só vai para o post_logout_redirect_uri se ele estiver na allowlist do client; senão, cai na tela de login.
Erros
/token e /userinfo usam o envelope OAuth ({ "error", "error_description" }). No /authorize, o erro volta por 302 com ?error= depois que a redirect_uri foi validada; antes disso (client/redirect desconhecidos) a falha é mostrada, não redirecionada — devolver a uma URI não registrada seria open-redirect.
error | onde | quando |
|---|---|---|
invalid_request | /authorize, /token | falta PKCE S256, parâmetro ou corpo inválido |
unsupported_response_type | /authorize | response_type ≠ code |
invalid_client | /authorize, /token | client_id desconhecido ou client não autenticado (401 no /token) |
unsupported_grant_type | /token | grant_type fora de authorization_code/refresh_token |
invalid_grant | /token | code/refresh inválido, expirado, já usado; redirect_uri/PKCE não conferem; refresh reusado (família revogada) |
invalid_token | /userinfo | access token ausente/inválido, ou um ID token no lugar dele |
server_error | /authorize, /token | falha interna ao emitir |
Checklist de integração segura
- Cliente OIDC que consome o discovery e o JWKS, apontado para o
issuerhttps://auth.asender.net— não crave URLs nem chaves. - PKCE
S256sempre;stateenoncede CSPRNG, conferidos na volta. - Valide o ID token por inteiro (assinatura RS256 +
iss+aud+exp+nonce); rejeitealgfora de RS256. - Identifique o usuário pelo
sub, nunca pelo e-mail. - O access token chama as APIs; o ID token fica no app. Não troque os papéis.
- A troca do
codee orefreshmoram no backend/BFF; guarde o refresh mais recente e trateinvalid_grantcomo "refaça o login".
Referência
Toda operação registrada no código, com o que faz, o que recebe e o que devolve.
acoes-sensiveis
Consultar atende GET /v1/acoes-sensiveis/{id}: o solicitante ou um admin do tenant.
Exemplo
curl -X GET 'https://auth.asender.net/acoes-sensiveis/id_AQUI' \
-H 'Authorization: Bearer SEU_TOKEN'
Discovery
Chaves públicas (JWKS)
As chaves públicas RS256 do provedor. O client busca aqui para validar a assinatura do ID token (e de qualquer JWT deste AS), escolhendo a chave pelo kid do header do token. Cacheável; numa rotação, o JWKS traz a chave nova e a antiga convivem até os tokens velhos expirarem.
| Onde é usada | verificação no client. |
|---|
Respostas
| código | significado |
|---|---|
200 | O JWK Set. |
Exemplo
curl -X GET 'https://auth.asender.net/.well-known/jwks.json' \
-H 'Authorization: Bearer SEU_TOKEN'
Metadados do Authorization Server (RFC 8414)
O MESMO documento de /.well-known/openid-configuration (uma fonte só, nunca divergem), servido no caminho do RFC 8414 para clientes OAuth/MCP que não falam OIDC. Anuncia token_endpoint_auth_methods_supported (client_secret_basic, client_secret_post, none) e authorization_response_iss_parameter_supported. Anuncia registration_endpoint (RFC 7591, POST /register) quando OAUTH_DCR_ATIVO=true e client_id_metadata_document_supported: true (CIMD) quando OAUTH_CIMD_ATIVO=true — cada um some do documento se desligado.
| Onde é usada | clientes MCP (spec 2025-11-25) descobrem o AS aqui a partir do authorization_servers do recurso (RFC 9728). |
|---|
Respostas
| código | significado |
|---|---|
200 | Os metadados do Authorization Server. |
Exemplo
curl -X GET 'https://auth.asender.net/.well-known/oauth-authorization-server' \
-H 'Authorization: Bearer SEU_TOKEN'
Metadados do provedor OIDC (discovery)
Anuncia os endpoints e as capacidades do Authorization Server. É o primeiro request de um client: ele se autoconfigura a partir daqui, em vez de ter as URLs cravadas. Só response_type=code, só PKCE S256, só RS256 — o perfil OAuth 2.1 da casa.
| Onde é usada | os clients leem isto no bootstrap para se autoconfigurar. Cacheável (muda só em deploy). |
|---|
Respostas
| código | significado |
|---|---|
200 | Os metadados do provedor. |
Exemplo
curl -X GET 'https://auth.asender.net/.well-known/openid-configuration' \
-H 'Authorization: Bearer SEU_TOKEN'
meta
Identidade do serviço.
| Onde é usada | rota raiz. |
|---|---|
| Efeitos | escreve a resposta. Serve para saber QUAL binário está rodando quando o comportamento diverge do esperado — a primeira pergunta de todo diagnóstico de deploy. |
Respostas
| código | significado |
|---|---|
200 | OK |
Exemplo
curl -X GET 'https://auth.asender.net/' \
-H 'Authorization: Bearer SEU_TOKEN'
Versão e commit do binário em execução.
| Onde é usada | rota pública, usada por ops e por quem investiga incidente. Pública porque a primeira pergunta de todo incidente é "que versão está no ar?", e ela tem de ser respondível sem credencial — quem investiga muitas vezes ainda não tem uma. O que sai é só isso: nunca configuração, nunca endereço interno. |
|---|
Respostas
| código | significado |
|---|---|
200 | OK |
Exemplo
curl -X GET 'https://auth.asender.net/version' \
-H 'Authorization: Bearer SEU_TOKEN'
OAuth 2.1
Início do login (Authorization Code + PKCE)
O endpoint para onde o app manda o browser iniciar o login. Valida o client_id e a redirect_uri (allowlist EXATA do client) e exige PKCE S256. Se houver sessão viva no domínio de auth, emite um authorization code de uso único e devolve por 302 ao redirect_uri (?code=…&state=…). Sem sessão, redireciona para a tela de login e, após autenticar, volta para cá.
client_id em forma de URL (CIMD, ADR-0130 D5). Se o client_id é uma URL https (porta 443, sem credencial nem fragmento), o AS busca o documento JSON de metadados naquela URL (só IP público; sem redirect; 5 s; ≤ 64 KiB; client_id do documento igual à URL), cria/atualiza o client (origem=cimd, público, não verificado, só escopos de leitura) e segue o fluxo. Cache de 5 min a 24 h (Cache-Control: max-age); se a rebusca falhar por rede, usa a cópia de até 7 dias. Documento inválido, destino interno ou domínio bloqueado => 400 invalid_client (sem redirect). Muitas buscas do mesmo IP => 429.
Apps de terceiro (ADR-0128): o scope é validado contra o catálogo e contra o que o app pode pedir (invalid_scope por redirect); na 1ª vez o usuário passa pela tela de consentimento (302 para <authfront>/consentir?pedido=…), onde escolhe UMA conta; nas seguintes, com sessão viva e um consentimento que cobre os escopos, o code sai na hora (o "1 clique"). prompt=none devolve login_required / consent_required; prompt=consent força a tela; prompt=login força o login. Toda resposta ao app de terceiro (code ou erro) traz iss (RFC 9207). Recurso por audiência (RFC 8707): resource (repetível) escolhe a(s) API(s) que o token vai acessar; cada valor tem de estar na allowlist OIDC_RECURSOS_PERMITIDOS (padrão https://api.asender.net e https://api.asender.net/mcp), senão error=invalid_target por redirect (com state e iss). Sem resource o aud é o recurso público padrão.
Loopback (RFC 8252 §7.3): para client PÚBLICO, redirect_uri de loopback (http://127.0.0.1, http://[::1], http://localhost) casa com a cadastrada ignorando só a porta; esquema, host, caminho e query seguem exatos. Confidencial continua exato.
Este endpoint é uma navegação de browser, não uma chamada de API: a resposta normal é 302. Erros só voltam por 302 com ?error= DEPOIS que a redirect_uri foi validada; antes disso (client/redirect desconhecidos) a falha é mostrada, não redirecionada — devolver a uma URI não registrada seria open-redirect.
| Onde é usada | o browser é redirecionado para cá pelo client (app) que quer logar. |
|---|
Parâmetros
| nome | em | obrigatório | descrição |
|---|---|---|---|
response_type | query | sim | único valor aceito (OAuth 2.1: sem implicit) |
client_id | query | sim | id do client OAuth registrado |
redirect_uri | query | sim | tem de casar EXATAMENTE com uma URI registrada no client |
scope | query | não | lista separada por espaço; `openid` é sempre garantido; `offline_access` pede refresh token |
state | query | não | opaco, devolvido intacto; use para amarrar a resposta ao request e barrar CSRF |
nonce | query | não | ligado ao ID token (anti-replay); o client confere que o `nonce` do id_token é o que enviou |
prompt | query | não | só apps de terceiro: `none` (sem tela; `login_required`/`consent_required`), `consent` (força a tela), `login` (força o login). `none` não combina com outros |
resource | query | não | RFC 8707, repetível, só apps de terceiro: recurso(s) do token; fora da allowlist => `invalid_target` |
code_challenge | query | sim | PKCE: base64url(SHA-256(code_verifier)) |
code_challenge_method | query | sim | único método aceito |
Respostas
| código | significado |
|---|---|
302 | Redireciona ao `redirect_uri` com `code` e `state` (sucesso) ou com `error`/`error_description` e `state` (falha após validar o redirect); ou à tela de login quando não há sessão. |
400 | `client_id` desconhecido ou `redirect_uri` não registrada — a falha é mostrada aqui, não redirecionada. |
Exemplo
curl -X GET 'https://auth.asender.net/authorize' \
-H 'Authorization: Bearer SEU_TOKEN'
Logout iniciado pelo app (end session)
O end_session_endpoint (RP-initiated logout). Revoga a sessão server-side (piso 17: irreversível — não só o cookie) e a família de refresh dela, limpa o cookie e redireciona. Vai para o post_logout_redirect_uri SOMENTE se ele estiver na allowlist do client; caso contrário, para a tela de login. É uma navegação de browser.
| Onde é usada | o client manda o browser para cá ao sair. |
|---|
Parâmetros
| nome | em | obrigatório | descrição |
|---|---|---|---|
post_logout_redirect_uri | query | não | destino após sair; precisa estar registrado no client, senão é ignorado |
client_id | query | não | o client dono da allowlist de post-logout |
state | query | não | opaco, anexado ao `post_logout_redirect_uri` quando ele é aceito |
Respostas
| código | significado |
|---|---|
302 | Redireciona ao `post_logout_redirect_uri` (se permitido) ou à tela de login. |
Exemplo
curl -X GET 'https://auth.asender.net/logout' \
-H 'Authorization: Bearer SEU_TOKEN'
Introspecção de token (RFC 7662)
Diz se um token do próprio client está ativo. Só aceita client confidencial autenticado (Basic ou corpo): um client público não prova quem é. Token inválido, expirado, revogado, de outro client — ou de um grant que o usuário revogou — responde {"active": false} e nada mais. Access token de terceiro só é ativo enquanto o grant segue ativo.
Respostas
| código | significado |
|---|---|
200 | Estado do token. |
400 | `invalid_request` — corpo inválido ou sem `token`. |
401 | `invalid_client` — client não autenticado ou não confidencial. |
Exemplo
curl -X POST 'https://auth.asender.net/oauth/introspect' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: <uuid-v4>' \
-d '{ }'
Revoga um refresh token (RFC 7009)
O client revoga um refresh token seu. Token desconhecido, de outro client ou já revogado responde 200 igual (RFC 7009 §2.2 — não vaza se existe). O access token é stateless e vive no máximo 15 min: a revogação efetiva do acesso é a do refresh (ou do grant, na tela "Apps conectados"). O client se autentica por HTTP Basic (client_secret_basic) ou pelos campos client_id/client_secret do corpo.
| Saídas | 200 vazio; 401 invalid_client se o client não se autentica. |
|---|
Respostas
| código | significado |
|---|---|
200 | Revogado (ou nada a revogar). |
400 | `invalid_request` — corpo inválido ou sem `token`. |
401 | `invalid_client` — client não autenticado. |
Exemplo
curl -X POST 'https://auth.asender.net/oauth/revoke' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: <uuid-v4>' \
-d '{ }'
Registro dinâmico de client (RFC 7591)
Registra um client público sem cadastro prévio (clientes MCP como Claude, ChatGPT e Cursor que ainda não fazem CIMD). Corpo application/json (≤ 64 KiB) com os metadados do RFC 7591: redirect_uris (obrigatório; https ou http em 127.0.0.1, localhost, [::1], sem credencial nem fragmento, até 10), client_name, client_uri, logo_uri (https), grant_types (⊆ authorization_code, refresh_token), response_types (code), token_endpoint_auth_method (só none; outro valor, inclusive private_key_jwt, é invalid_client_metadata) e scope (o que não é identidade ou leitura é descartado; a resposta traz o scope efetivo).
O client nasce origem=dcr, publicado, não verificado (a tela de consentimento mostra o selo "Não verificado" e o domínio dos redirects). Resposta 201 com client_id (dcr_…, CSPRNG) e client_id_issued_at. Não há client_secret (cliente público) e não há registration_access_token nem registration_client_uri: a gestão do registro (RFC 7592) não é suportada — para mudar, registre de novo; a equipe suspende pelo backoffice. Limite de 10 registros por hora por IP (429 + Retry-After). Domínio de redirect_uris bloqueado => 400 invalid_redirect_uri. Desligado (OAUTH_DCR_ATIVO=false) => 404.
Respostas
| código | significado |
|---|---|
201 | Client registrado (sem segredo). |
400 | `{"error":"invalid_redirect_uri"|"invalid_client_metadata","error_description":"…"}` (RFC 7591 §3.2.2). |
404 | Registro dinâmico desligado. |
429 | Limite de registros por hora do IP atingido (`Retry-After`). |
Exemplo
curl -X POST 'https://auth.asender.net/register' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: <uuid-v4>' \
-d '{ }'
Troca de code/refresh por tokens
Troca o authorization_code por tokens (provando o PKCE code_verifier) ou rotaciona um refresh_token. Chamado servidor-a-servidor (ou pelo BFF), com corpo application/x-www-form-urlencoded.
Autenticação do client. Client público (SPA/mobile) não tem segredo — o PKCE prova a posse. Client confidencial autentica por HTTP Basic (client_secret_basic) ou pelos campos client_id/client_secret do corpo.
Apps de terceiro (ADR-0128): client confidencial (segredo) ou público (sem segredo; PKCE; mandar client_secret => invalid_client; refresh de no máximo 30 dias). O access token sai com aud = os recursos concedidos (RFC 8707; sem resource, a API pública OIDC_RECURSO_PUBLICO), azp = o client, tenant = a conta do consentimento, scope = o escopo EFETIVO (pedido ∩ permitido no app ∩ concedido), ext: true (nunca vale como sessão) e jti; vive 15 min. O refresh é preso ao grant (não à sessão do navegador), vive o TTL do app e é revogado quando o usuário remove o app. Grant revogado ou usuário sem acesso à conta → invalid_grant.
Rotação de refresh com detecção de reuso. Cada uso do refresh o invalida e emite um novo. Reapresentar um refresh já usado revoga a família inteira e responde invalid_grant — o sinal de token roubado.
| Onde é usada | o client troca aqui, servidor-a-servidor (ou pelo BFF), o code/refresh por tokens. |
|---|
Respostas
| código | significado |
|---|---|
200 | Tokens emitidos. |
400 | `invalid_grant` (code/refresh inválido, expirado, já usado, ou redirect_uri/PKCE que não conferem; refresh reusado → família revogada; refresh de SESSÃO encerrada — revogada ou expirada — → família revogada, "sessão encerrada"), `invalid_request` (corpo inválido) ou `unsupported_grant_type`, ou `invalid_target` (apps de terceiro: `resource` fora do concedido ou da allowlist). |
401 | `invalid_client` — client não autenticado. |
Exemplo
curl -X POST 'https://auth.asender.net/token' \
-H 'Authorization: Bearer SEU_TOKEN' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: <uuid-v4>' \
-d '{ }'
OpenID Connect
Claims do usuário do access token
Devolve os claims do usuário dono do access token apresentado. Valida o Bearer por inteiro (RS256, iss, exp) e exige tok_use: "access" — um ID token NÃO é aceito aqui. Use para hidratar o perfil depois do login.
| Onde é usada | o client chama para hidratar o perfil. Sem token válido -> 401 invalid_token. |
|---|
Respostas
| código | significado |
|---|---|
200 | Os claims do usuário. |
401 | `invalid_token` — Bearer ausente, inválido, ou não é um access token. |
Exemplo
curl -X GET 'https://auth.asender.net/userinfo' \
-H 'Authorization: Bearer SEU_TOKEN'