Este diagrama mostra, de forma clara e enxuta, todo o fluxo de autenticação do sistema:
- Registro de novos usuários com senha criptografada
- Login por credenciais e via OAuth2 (GitHub/Google)
- Recuperação de senha (esqueci senha + redefinição) sem expor existência de conta
- Logout via blacklist de token
- Acesso a rotas protegidas validando JWT e blacklist
---
config:
theme: redux-dark-color
---
sequenceDiagram
autonumber
participant FE as Front-end
participant API as REST API
participant DB as MySQL
participant REDIS as Redis (Blacklist)
participant SES as Serviço de Email
participant OAUTH as OAuth2 Provider
%% 1) REGISTRO
rect rgba(0, 0, 255, 0.1)
FE->>API: POST /auth/register {email, senha, confirmação, nome, termos}
API->>DB: cria usuário com senha criptografada
DB-->>API: usuário criado (id)
API-->API: gera JWT + Refresh
API-->>FE: 201 Created {access, refresh}
end
%% 2) LOGIN POR CREDENCIAIS
rect rgba(0, 128, 0, 0.1)
FE->>API: POST /auth/login {email, senha}
API->>DB: busca usuário por email e compare hash
alt credenciais válidas
API-->API: gera JWT + Refresh
API-->>FE: 200 OK {access, refresh}
else inválido
API-->>FE: 401 Unauthorized {"Email ou senha inválidos"}
end
end
%% 3) LOGIN VIA OAUTH2
rect rgba(0, 128, 128, 0.1)
FE->>OAUTH: redirect para login externo
OAUTH-->>FE: Callback OAuth2 com ccódigo
FE->>API: GET /auth/oauth2/success?code=…
API-->API: troca código por userInfo
API->>DB: busca ou cria usuário via provider
API-->API: gera JWT
API-->>FE: 200 OK {access}
end
%% 4) ESQUECI SENHA → RESET
rect rgba(255, 165, 0, 0.1)
FE->>API: POST /auth/forgot-password?email=…
API->>DB: tenta buscar usuário por email
alt email cadastrado
API-->API: cria token (UUID + hash) e persiste
API-->API: monta link de reset
API->>SES: envia email com link
else não cadastrado
Note right of API: ignora e retorna mesma resposta
end
API-->>FE: 200 OK {"Confira seu email para instruções"}
end
rect rgba(255, 140, 0, 0.1)
FE->>API: POST /auth/reset-password {key, token, novaSenha}
API->>DB: busca token de reset por key
alt token válido e não expirado
API-->API: atualiza senha (hash) e marca token usado
API-->>FE: 200 OK {"Senha redefinida com sucesso"}
else inválido ou expirado
API-->>FE: 400 Bad Request {"Token inválido ou expirado"}
end
end
%% 5) LOGOUT
rect rgba(220, 20, 60, 0.1)
FE->>API: POST /auth/logout (Bearer JWT)
API-->API: extrai jti + exp do token
API->>REDIS: adiciona jti na blacklist até expirar
REDIS-->>API: OK
API-->>FE: 200 OK {"Logout realizado"}
end
%% 6) ACESSO A RECURSOS PROTEGIDOS
rect rgba(128, 0, 128, 0.1)
FE->>API: GET /api/recurso (Bearer JWT)
API-->API: JwtAuthFilter intercepta
API->>REDIS: verifica se jti está blacklist
alt token válido e não blacklist
API-->>FE: 200 OK {dados…}
else inválido ou blacklist
API-->>FE: 401 Unauthorized {"Token inválido ou expirado"}
end
end
Este diagrama ilustra o fluxo completo de comunicação fim-a-fim criptografada implementado na nossa API usando o protocolo Signal:
- Mostra como o cliente gera e publica chaves na primeira inicialização (ou quando o storage local é perdido).
- Descreve o handshake de sessão entre usuários, com fetch seguro de bundles.
- Explica o envio de mensagens cifradas via WebSocket, totalmente opacas ao servidor.
- Detalha como o backend monitora pre-keys e signedPreKeys, enviando alertas automáticos para reposição ou rotação.
- Representa a segurança baseada em IndexedDB local com trust-on-first-use.
---
config:
theme: redux-dark-color
---
sequenceDiagram
autonumber
participant FE_A as Frontend A
participant SC_A as SignalClient A
participant WS as WebSocket Broker
participant API as REST API
participant FE_B as Frontend B
participant SC_B as SignalClient B
rect rgba(0, 0, 255, 0.1)
FE_A->>SC_A: bootstrap()
alt Primeiro login OU IndexedDB limpo/perdido
SC_A->>API: POST /signal/keys/save
API-->>SC_A: 201 Created
else Já tem chaves locais
SC_A-->SC_A: Load keys from IndexedDB
end
end
rect rgba(0, 100, 0, 0.1)
FE_A->>SC_A: ensureSession(B)
SC_A->>API: GET /signal/keys/fetch/{B}
API-->>SC_A: {identity_B, SPK_B, PK₁}
SC_A-->SC_A: SessionBuilder.processPreKey()
end
rect rgba(128, 0, 128, 0.1)
FE_A->>SC_A: encrypt("Olá")
SC_A->>WS: SEND /chat (ciphertext, type=WHISPER)
WS->>FE_B: MESSAGE (ciphertext)
FE_B->>SC_B: decrypt()
SC_B-->FE_B: "Olá"
end
rect rgba(255, 165, 0, 0.1)
Note over API: Monitor de PreKeys
API->>WS: toUser(B) {type: LOW_PREKEY, remaining:18}
WS->>FE_B: evento LOW_PREKEY
FE_B->>SC_B: replenishBundle() (+100 PK)
SC_B->>API: POST /signal/keys/save (novos PKs)
API-->>SC_B: 201 Created
end
rect rgba(220, 20, 60, 0.1)
Note over API: Scheduler detecta SPK expirada
API->>WS: toUser(B) {type: SPK_EXPIRED}
WS->>FE_B: evento SPK_EXPIRED
FE_B->>SC_B: rotateSignedPreKey()
SC_B->>API: POST /signal/keys/rotate-spk (nova SPK₁)
API-->>SC_B: 200 OK
end
Note over FE_A,FE_B: 🛡️ Próxima mensagem usa SPK₁ de B
| MySQL | Hibernate | Spring Boot | Java | Redis | JWT | WebSocket |
| 🔖 8.1.0 | 🔖 6.3 | 🔖 3.3.2 | 🔖 17 | 🔖 7.4.2 | 🔖 0.12.6 | 🔖 3.4.2 |
| IntelliJ IDEA | DataGrip | Postman | Docker | Maven | GitHub Actions |
| 🔖 2024.3.2 | 🔖 2024.3 | 🔖 11.32.1 | 🔖 27.5.1 | 🔖 3.9.6 | 🔖 - |
| AWS S3 | AWS SES | AWS CloudWatch |
| Swagger | Cucumber | JUnit | ArchUnit | TestContainers |
| 🔖 2.8.5 | 🔖 7.21.1 | 🔖 5 | 🔖 1.4.0 | 🔖 1.20.4 |