Serviço de autenticação e autorização em Go (só stdlib + x/crypto):
JWT HS256 escrito à mão, senhas com bcrypt, RBAC (papéis →
permissões) e rotação de refresh token com detecção de reuso. Arquitetura
hexagonal e cobertura de testes 100%.
POST /register ─▶ cria usuário (senha em bcrypt)
POST /login ─▶ access token (15min) + refresh token (24h)
GET /me ─▶ exige permissão me:read (Bearer)
GET /admin ─▶ exige permissão admin:access (Bearer)
POST /refresh ─▶ rotaciona: emite novo par e revoga o antigo
- JWT HS256 à mão — assinar/verificar sobre a stdlib (
crypto/hmac,crypto/sha256), para mostrar o que um JWT realmente é. A verificação checa o algoritmo (barra o ataquealg:none) e compara a assinatura em tempo constante (hmac.Equal). - RBAC — papéis (
user,admin) concedem permissões (me:read,admin:access); os endpoints exigem uma permissão, não um papel fixo. - Rotação de refresh token — cada refresh emite um par novo e revoga o anterior; reusar um refresh já usado é rejeitado (detecção de reuso).
- Senhas com bcrypt — nunca em texto; o hashing fica atrás de uma porta
(
Hasher), então os testes de caso de uso rodam rápido com um fake. - Arquitetura hexagonal — domínio (usuário, RBAC, validação) → aplicação
(
AuthService+ ports) → infraestrutura (repos em memória, bcrypt, HTTP). - Cobertura 100% — inclusive os caminhos de erro do JWT (assinatura
adulterada,
alginválido, expiração) e do RBAC (403). - OpenAPI/Swagger em
/docs.
- Linguagem: Go 1.25 (stdlib +
golang.org/x/crypto/bcrypt) - Tokens: JWT HS256 próprio · Autz: RBAC
- Testes/cobertura:
go test -cover(gate de 100%)
cmd/api/ # bootstrap (semeia um admin de exemplo)
internal/
├── token/ # JWT HS256 (sign/verify) — sem libs externas
├── domain/ # User, RBAC (papéis→permissões), validação, erros
├── application/ # AuthService + ports (UserRepo, RefreshStore, Hasher)
└── infrastructure/
├── memory/ # repositórios em memória
├── security/ # BcryptHasher
└── httpapi/ # rotas, DTOs, Swagger
go run ./cmd/api # http://localhost:8080 (Swagger em /docs)Fluxo completo:
curl -X POST localhost:8080/register -H "content-type: application/json" \
-d '{"email":"ada@example.com","password":"senha-forte-123"}'
TOKENS=$(curl -s -X POST localhost:8080/login -H "content-type: application/json" \
-d '{"email":"ada@example.com","password":"senha-forte-123"}')
ACCESS=$(echo "$TOKENS" | jq -r .accessToken)
curl localhost:8080/me -H "Authorization: Bearer $ACCESS"Um usuário admin (admin@example.com / admin-123456) é semeado para você
testar o /admin. Configure via ADMIN_EMAIL, ADMIN_PASSWORD e JWT_SECRET.
docker compose up --build| Método | Rota | Protegido | Descrição |
|---|---|---|---|
| POST | /register |
— | Cria usuário (papel user) |
| POST | /login |
— | Emite access + refresh token |
| POST | /refresh |
— | Rotaciona o refresh token |
| GET | /me |
Bearer | Perfil (permissão me:read) |
| GET | /admin |
Bearer | Área admin (permissão admin:access) |
| GET | /docs |
— | Swagger UI |
alg:noneé rejeitado: a verificação exigealg == HS256.- Comparação da assinatura em tempo constante (
hmac.Equal) — evita timing. - Refresh rotation: um refresh só vale uma vez; o próximo uso é negado.
- Segredo, TTLs e credenciais do admin vêm de ambiente — nada hardcoded em prod.
Nota: este é um template de referência. Em produção, use um segredo forte (ou chaves assimétricas), persistência real e HTTPS na borda.
go test ./internal/... -covermode=atomic -coverprofile=coverage.out
go tool cover -func=coverage.out # total: 100.0%MIT.