b. JWT
O primeiro passo para construir a camada de segurança é entender os JSON Web Tokens (JWT) e criar o módulo de interface auth, que define o contrato da API de autenticação.
1. JSON Web Token
O JWT é uma forma compacta e segura para URLs de representar declarações (claims) entre duas partes. É o padrão usado pela plataforma para transportar a identidade do usuário autenticado entre os serviços sem guardar estado de sessão no servidor — o que o torna naturalmente compatível com escalabilidade horizontal.
Um JWT é formado por três partes codificadas em Base64Url, separadas por pontos.
Exemplo de JWT
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI1ZjNjOWEyZS04YjFkLTRjN2EtOWU2Zi0yYTRiOGMxZDNlNWYiLCJpc3MiOiJJbnNwZXI
6OlBNQSIsImVtYWlsIjoiYWNtZUBpbnNwZXIuZWR1LmJyIiwic3ViIjoiQW50b25pbyBkbyBFc3R1ZG8iLCJuYmYiOjE3ODc1NzY
0MDAsImV4cCI6MTc4NzU4MDAwMH0.KeKkcoXFaiijMekCSRk8rUrh69RXEzOZmP1U23MIb0E
O header declara o algoritmo de assinatura (alg) e pode declarar o tipo do token (typ). O JJWT, a biblioteca usada pela plataforma, só escreve o alg, a menos que se peça outra coisa — o exemplo acima é exatamente o que o JwtService produz.
{
"jti": "5f3c9a2e-8b1d-4c7a-9e6f-2a4b8c1d3e5f",
"iss": "Insper::PMA",
"email": "acme@insper.edu.br",
"sub": "Antonio do Estudo",
"nbf": 1787576400,
"exp": 1787580000
}
O payload contém as claims. Claims são declarações sobre uma entidade (normalmente, o usuário) e dados adicionais. Há três tipos de claims: registradas, públicas e privadas. As claims registradas são um conjunto de claims predefinidas, não obrigatórias, mas recomendadas, que oferecem um conjunto de claims úteis e interoperáveis. Alguns exemplos são iss (emissor), exp (instante de expiração), sub (assunto) e aud (público-alvo). As claims públicas podem ser definidas livremente por quem usa JWTs; para evitar colisões, elas devem ser registradas no IANA JSON Web Token Registry ou definidas como uma URI que contenha um namespace resistente a colisões. As claims privadas são claims personalizadas, criadas para compartilhar informações entre partes que concordam em usá-las, e não são nem registradas nem públicas.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
Base64.decode(JWT_SECRET_KEY) // 32 bytes = 256 bits
)
Para criar a assinatura, você pega o header codificado, o payload codificado, um segredo e o algoritmo indicado no header, e assina o conjunto.
HS256 é HMAC com SHA-256 e exige uma chave de pelo menos 256 bits. Na plataforma, JwtService.getKey() devolve Keys.hmacShaKeyFor(Base64.getDecoder().decode(secretKey)): a chave é a store.jwt.secretKey (variável de ambiente JWT_SECRET_KEY) decodificada de Base64, 32 bytes — gere uma com openssl rand -base64 32. O signWith(key) deixa o JJWT escolher o algoritmo pelo tamanho da chave: 256 bits → HS256 (uma chave de 384 bits daria HS384; uma de 512 bits, HS512; uma chave com menos de 256 bits é recusada com WeakKeyException). O token de exemplo acima foi assinado assim, com o valor padrão de desenvolvimento do application.yaml — cole-o no jwt.io com esse segredo (marcado como Base64) para conferir a assinatura.
Chave secreta
A chave secreta usada para assinar o JWT deve ser mantida em sigilo. Quem tiver acesso a ela consegue forjar tokens. O application.yaml do auth-service a lê da variável de ambiente JWT_SECRET_KEY e traz um valor padrão de desenvolvimento só para a stack subir sem configuração — esse valor é público (está no repositório), então fora da sua máquina defina sempre a JWT_SECRET_KEY com uma chave sua e nunca coloque fixa uma chave real no código-fonte.
As principais claims usadas nesta plataforma são:
| Claim | Campo | Descrição |
|---|---|---|
jti | id | Identificador único da conta |
sub | subject | Nome da conta |
iss | issuer | Plataforma emissora |
nbf | notBefore | O token passa a valer a partir deste instante |
exp | expiration | O token expira neste instante |
email | claims(Map.of("email", …)) | Uma claim privada: o e-mail da conta |
Após um login bem-sucedido, o servidor gera um JWT, coloca-o em um cookie HttpOnly e o devolve ao navegador. Em cada requisição seguinte, o navegador envia o cookie automaticamente — o Gateway o lê e resolve a identidade sem pedir que o usuário faça login de novo.
sequenceDiagram
autonumber
actor User as Usuário
User->>+Auth Service: login (e-mail + senha)
Auth Service->>Auth Service: valida as credenciais e gera o JWT
Auth Service->>-User: Set-Cookie: __store_jwt_token=<jwt>
User->>User: o navegador armazena o cookie
User->>Gateway: as requisições seguintes levam o cookie automaticamente 2. O módulo de interface auth
O módulo auth segue o mesmo padrão do módulo account: é uma biblioteca (não uma aplicação executável) que define o contrato da API e os DTOs compartilhados entre o auth-service e qualquer outro microsserviço que precise chamar os endpoints de autenticação via Feign.
2.1 Repositório
Crie um novo repositório git para a interface de autenticação e adicione-o como submódulo:
2.2 Código
Use o Spring Initializr para gerar um projeto Maven com as seguintes configurações:
- Group:
store - Artifact:
auth - Package name:
store.auth - Packaging: Jar
- Java: 25
Dependências a adicionar:
- Lombok — reduz código repetitivo com processamento de anotações em tempo de compilação
- OpenFeign — cliente HTTP declarativo para chamadas entre serviços
Apague AuthApplication.java, src/test/ e src/main/resources/ — este módulo é uma biblioteca, não um serviço executável.
A estrutura resultante é:
📁 api/
└── 📁 auth/
├── 📁 src/
│ └── 📁 main/
│ └── 📁 java/
│ └── 📁 store/
│ └── 📁 auth/
│ ├── AuthController.java
│ ├── LoginIn.java
│ ├── RegisterIn.java
│ └── TokenOut.java
└── pom.xml
Código-fonte
O endpoint /auth/solve
solveToken é um endpoint interno, pensado para o Gateway: recebe uma string JWT bruta e devolve o idAccount correspondente. Ele não é uma rota aberta, então o navegador não consegue usá-lo sem um cookie válido. O me (GET /auth/me) devolve a conta logada: o Gateway preenche o header id-account a partir do token.
2.3 Instalação
Instale a interface no repositório Maven local para que o auth-service possa depender dela:
Pronto! A interface auth está pronta. Na próxima seção vamos implementar o auth-service, incluindo o JwtService, que assina e valida tokens, e o AuthService, que orquestra o login e o cadastro.