Este projeto demonstra a utilização do Authorization Code Flow com PKCE (Proof Key for Code Exchange) entre duas aplicações, utilizando autenticação via OAuth 2.0 / OpenID Connect.
O Authorization Code Flow é um dos fluxos de autenticação mais seguros do OAuth 2.0. Ele permite que um cliente (ex.: app-client) obtenha um código de autorização junto ao servidor de identidade (ex.: Keycloak) e o troque por um token de acesso. Esse token pode então ser utilizado para consumir recursos protegidos em outra aplicação (ex.: app-resource).
O PKCE (Proof Key for Code Exchange) adiciona uma camada extra de segurança, exigindo que o cliente gere um código de verificação (code_verifier) e um desafio criptográfico (code_challenge). Assim, mesmo que o código de autorização seja interceptado, ele não poderá ser reutilizado sem o code_verifier correto.
👉 Ou seja: o app-client autentica o usuário no Keycloak, obtém o token e o utiliza para acessar a API do app-resource em segurança.
sequenceDiagram
autonumber
participant U as Usuário
participant C as app-client (Cliente Público)
participant AS as Authorization Server (Keycloak)
participant R as app-resource (Resource Server)
U->>C: Inicia autenticação
C-->>C: Gera code_verifier e code_challenge
C->>AS: Authorization Request (+ code_challenge)
AS->>U: Exibe tela de login
U->>AS: Envia credenciais
AS-->>C: Redireciona com Authorization Code (redirect_uri)
C->>AS: Troca Code + code_verifier por tokens (/token)
AS-->>C: Retorna access_token (e id_token)
C->>R: Chama API com Authorization: Bearer <access_token>
R-->>C: 200 OK (dados protegidos)
C-->>U: Exibe dados da API para o usuário
1. Cliente gera valores iniciais
- Cria
code_verifier(string aleatória e secreta) - Gera
code_challengea partir decode_verifier(SHA-256 + Base64URL)
2. Início da autenticação
Cliente redireciona o usuário para o AS com: client_id, redirect_uri, response_type=code, scope, code_challenge, code_challenge_method=S256
👉 O AS guarda o code_challenge
3. Autenticação do usuário AS mostra tela → Usuário envia login/senha (ou MFA) → AS valida credenciais
4. Emissão do authorization code
AS gera authorization_code → redireciona para redirect_uri?code=...
5. Troca de código por token
Cliente chama o token endpoint com: client_id, redirect_uri, grant_type=authorization_code, code, code_verifier
6. Validação no Authorization Server
AS verifica se code_verifier → hash == code_challenge guardado. Se válido → devolve access_token.
7. Acesso à API
Cliente chama API com: Authorization: Bearer <access_token>
- Cliente: gera
code_verifier→ criacode_challenge→ inicia fluxo → enviacode_verifierno final. - Authorization Server (AS): guarda
code_challenge→ autentica usuário → emiteauthorization_code→ validacode_verifier→ entrega tokens. - Usuário: apenas autentica (login/senha, MFA, etc.).
Mesmo que alguém intercepte o authorization_code, não consegue trocar por token sem o code_verifier. Isso protege contra ataques de interceptação (como authorization code interception attack).
💡 Observações
- O Authorization Server (AS) ou Identity Provider (IdP) emite um
authorization code— um “ticket” de uso único, vinculado ao cliente (e ao redirect_uri), com validade curta (30–60 segundos).
- No PKCE, o
code verifieré uma string aleatória e secreta gerada no cliente. Ocode challengeé derivado do code verifier — normalmenteBASE64URL(SHA-256(verifier)).
- COM PKCE o
client_secretfica no Authorization Server.
- SEM PKCE o
client_secretfica no Client.
- Service:
keycloak - Porta:
8081:8081e9000:9000 - Issuer:
http://keycloak:8080/realms/app-pks-realm - UI/Admin: http://keycloak:8080/
- health/ready: http://keycloak:9000/health/ready
- Service:
app-client - Porta:
8081:8081 - URL: http://localhost:8081
- Service:
app-resource - Porta:
8082:8082 - URL: http://localhost:8082
docker compose up -d-
🌐 Keycloak (Admin UI): http://localhost:8080
-
👤 Login no app-client: acesse http://localhost:8081
- Usuário:
appclient - Senha:
appclient
- Usuário:
Após o login, o app-client redireciona para o Keycloak para autenticação. Depois do login bem-sucedido, retorna ao app-client, onde é possível clicar em Chamar API Protegida.
O app-client usará o Access Token obtido no Keycloak para consumir a API protegida do app-resource em http://localhost:8082.
