create-fluxstack 1.18.1 → 1.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +132 -0
- package/LLMD/INDEX.md +1 -1
- package/LLMD/MAINTENANCE.md +197 -197
- package/LLMD/MIGRATION.md +44 -1
- package/LLMD/agent.md +20 -7
- package/LLMD/config/declarative-system.md +268 -268
- package/LLMD/config/environment-vars.md +3 -6
- package/LLMD/config/runtime-reload.md +401 -401
- package/LLMD/core/build-system.md +599 -599
- package/LLMD/core/framework-lifecycle.md +249 -229
- package/LLMD/core/plugin-system.md +154 -100
- package/LLMD/patterns/anti-patterns.md +397 -397
- package/LLMD/patterns/project-structure.md +264 -264
- package/LLMD/patterns/type-safety.md +61 -5
- package/LLMD/reference/cli-commands.md +31 -7
- package/LLMD/reference/plugin-hooks.md +4 -2
- package/LLMD/reference/troubleshooting.md +364 -364
- package/LLMD/resources/controllers.md +465 -465
- package/LLMD/resources/live-auth.md +178 -1
- package/LLMD/resources/live-binary-delta.md +3 -1
- package/LLMD/resources/live-components.md +1192 -1041
- package/LLMD/resources/live-logging.md +3 -1
- package/LLMD/resources/live-rooms.md +1 -1
- package/LLMD/resources/live-upload.md +228 -181
- package/LLMD/resources/plugins-external.md +8 -7
- package/LLMD/resources/rest-auth.md +290 -290
- package/LLMD/resources/routes-eden.md +254 -254
- package/app/client/src/App.tsx +7 -7
- package/app/client/src/components/AppLayout.tsx +60 -23
- package/app/client/src/components/ColorWheel.tsx +195 -0
- package/app/client/src/components/DemoPage.tsx +5 -3
- package/app/client/src/components/LiveUploadWidget.tsx +1 -1
- package/app/client/src/components/ThemePicker.tsx +307 -0
- package/app/client/src/config/theme.config.ts +127 -0
- package/app/client/src/hooks/useThemeClock.ts +66 -0
- package/app/client/src/index.css +193 -0
- package/app/client/src/lib/theme-clock.ts +201 -0
- package/app/client/src/live/AuthDemo.tsx +9 -9
- package/app/client/src/live/CounterDemo.tsx +10 -10
- package/app/client/src/live/FormDemo.tsx +8 -8
- package/app/client/src/live/PingPongDemo.tsx +10 -10
- package/app/client/src/live/RoomChatDemo.tsx +10 -10
- package/app/client/src/live/SharedCounterDemo.tsx +5 -5
- package/app/client/src/pages/ApiTestPage.tsx +5 -5
- package/app/client/src/pages/HomePage.tsx +12 -12
- package/app/server/index.ts +8 -0
- package/app/server/live/auto-generated-components.ts +1 -1
- package/core/build/index.ts +1 -1
- package/core/cli/command-registry.ts +1 -1
- package/core/cli/commands/build.ts +25 -6
- package/core/cli/commands/plugin-deps.ts +1 -2
- package/core/cli/generators/plugin.ts +433 -581
- package/core/framework/server.ts +22 -8
- package/core/index.ts +6 -5
- package/core/plugins/index.ts +71 -199
- package/core/plugins/types.ts +76 -461
- package/core/server/index.ts +1 -1
- package/core/utils/logger/startup-banner.ts +26 -4
- package/create-fluxstack.ts +216 -107
- package/package.json +108 -107
- package/tsconfig.json +2 -1
- package/core/plugins/config.ts +0 -356
- package/core/plugins/dependency-manager.ts +0 -481
- package/core/plugins/discovery.ts +0 -379
- package/core/plugins/executor.ts +0 -353
- package/core/plugins/manager.ts +0 -645
- package/core/plugins/module-resolver.ts +0 -227
- package/core/plugins/registry.ts +0 -913
- package/vitest.config.live.ts +0 -69
|
@@ -1,290 +1,290 @@
|
|
|
1
|
-
# REST API Authentication
|
|
2
|
-
|
|
3
|
-
**Version:** 1.
|
|
4
|
-
|
|
5
|
-
## Quick Facts
|
|
6
|
-
|
|
7
|
-
- Dois guards disponíveis: **Session** (cookie) e **Token** (Bearer)
|
|
8
|
-
- Configuração via `AUTH_DEFAULT_GUARD` no `.env`
|
|
9
|
-
- Rate limiting automático no login (5 tentativas / 60s)
|
|
10
|
-
- Password hashing com bcrypt ou argon2id
|
|
11
|
-
- Provider in-memory por padrão (extensível para database)
|
|
12
|
-
- REST test files disponíveis em `rest-tests/`
|
|
13
|
-
|
|
14
|
-
## Endpoints
|
|
15
|
-
|
|
16
|
-
| Método | Rota | Auth | Descrição |
|
|
17
|
-
|--------|------|------|-----------|
|
|
18
|
-
| `POST` | `/api/auth/register` | Guest | Criar conta e auto-login |
|
|
19
|
-
| `POST` | `/api/auth/login` | Guest | Autenticar com email + password |
|
|
20
|
-
| `GET` | `/api/auth/me` | Required | Retorna usuário autenticado |
|
|
21
|
-
| `POST` | `/api/auth/logout` | Required | Encerrar sessão/revogar token |
|
|
22
|
-
|
|
23
|
-
## Guards
|
|
24
|
-
|
|
25
|
-
### Session Guard (padrão)
|
|
26
|
-
|
|
27
|
-
Armazena sessão no servidor e envia cookie httpOnly ao cliente.
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
Login → Servidor cria sessão → Cookie `fluxstack_session` → Browser envia automaticamente
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
**Configuração** (`.env`):
|
|
34
|
-
```bash
|
|
35
|
-
AUTH_DEFAULT_GUARD=session
|
|
36
|
-
SESSION_COOKIE=fluxstack_session
|
|
37
|
-
SESSION_LIFETIME=7200 # 2 horas
|
|
38
|
-
SESSION_HTTP_ONLY=true
|
|
39
|
-
SESSION_SECURE=false # true em produção
|
|
40
|
-
SESSION_SAME_SITE=lax
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
**Response do login** (sem campo token):
|
|
44
|
-
```json
|
|
45
|
-
{
|
|
46
|
-
"success": true,
|
|
47
|
-
"user": {
|
|
48
|
-
"id": 1,
|
|
49
|
-
"name": "John Doe",
|
|
50
|
-
"email": "john@example.com",
|
|
51
|
-
"createdAt": "2026-02-14T16:00:00.000Z"
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
**Requests autenticados**: cookie enviado automaticamente pelo browser.
|
|
57
|
-
|
|
58
|
-
### Token Guard (Bearer)
|
|
59
|
-
|
|
60
|
-
Gera token aleatório de 32 bytes, armazena hash SHA256 no cache e retorna o token plain ao cliente.
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
Login → Token gerado → Response inclui token → Cliente envia Authorization: Bearer <token>
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
**Configuração** (`.env`):
|
|
67
|
-
```bash
|
|
68
|
-
AUTH_DEFAULT_GUARD=token
|
|
69
|
-
AUTH_TOKEN_TTL=86400 # 24 horas
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
**Response do login** (com campo token):
|
|
73
|
-
```json
|
|
74
|
-
{
|
|
75
|
-
"success": true,
|
|
76
|
-
"user": {
|
|
77
|
-
"id": 1,
|
|
78
|
-
"name": "John Doe",
|
|
79
|
-
"email": "john@example.com",
|
|
80
|
-
"createdAt": "2026-02-14T16:00:00.000Z"
|
|
81
|
-
},
|
|
82
|
-
"token": "a1b2c3d4e5f6..."
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
**Requests autenticados**:
|
|
87
|
-
```
|
|
88
|
-
Authorization: Bearer a1b2c3d4e5f6...
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Quando usar cada guard
|
|
92
|
-
|
|
93
|
-
| Guard | Melhor para |
|
|
94
|
-
|-------|-------------|
|
|
95
|
-
| Session | SPAs web (same-origin), SSR |
|
|
96
|
-
| Token | Mobile apps, CLIs, API clients, integrações |
|
|
97
|
-
|
|
98
|
-
## Fluxos
|
|
99
|
-
|
|
100
|
-
### Register + Auto-login
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
POST /api/auth/register
|
|
104
|
-
Content-Type: application/json
|
|
105
|
-
|
|
106
|
-
{
|
|
107
|
-
"name": "John Doe",
|
|
108
|
-
"email": "john@example.com",
|
|
109
|
-
"password": "secret123"
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
# 201 Created
|
|
113
|
-
# Session guard: set-cookie header
|
|
114
|
-
# Token guard: token no body (via login automático)
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Login
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
POST /api/auth/login
|
|
121
|
-
Content-Type: application/json
|
|
122
|
-
|
|
123
|
-
{
|
|
124
|
-
"email": "john@example.com",
|
|
125
|
-
"password": "secret123"
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
# 200 OK → user + token (se token guard)
|
|
129
|
-
# 401 → credenciais inválidas
|
|
130
|
-
# 429 → rate limit (Retry-After header)
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### Me (Token Guard)
|
|
134
|
-
|
|
135
|
-
```bash
|
|
136
|
-
GET /api/auth/me
|
|
137
|
-
Authorization: Bearer <token>
|
|
138
|
-
|
|
139
|
-
# 200 OK → { success: true, user: {...} }
|
|
140
|
-
# 401 → não autenticado
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Logout (Token Guard)
|
|
144
|
-
|
|
145
|
-
```bash
|
|
146
|
-
POST /api/auth/logout
|
|
147
|
-
Authorization: Bearer <token>
|
|
148
|
-
|
|
149
|
-
# 200 OK → token revogado no cache
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
## Rate Limiting
|
|
153
|
-
|
|
154
|
-
Login é protegido automaticamente contra brute force:
|
|
155
|
-
|
|
156
|
-
| Config | Default | Env Var |
|
|
157
|
-
|--------|---------|---------|
|
|
158
|
-
| Max tentativas | 5 | `AUTH_RATE_LIMIT_MAX_ATTEMPTS` |
|
|
159
|
-
| Janela (segundos) | 60 | `AUTH_RATE_LIMIT_DECAY_SECONDS` |
|
|
160
|
-
|
|
161
|
-
Chave de throttle: `email|ip`. Após exceder, retorna `429 Too Many Attempts` com header `Retry-After`.
|
|
162
|
-
|
|
163
|
-
## Password Hashing
|
|
164
|
-
|
|
165
|
-
| Config | Default | Env Var |
|
|
166
|
-
|--------|---------|---------|
|
|
167
|
-
| Algoritmo | bcrypt | `AUTH_HASH_ALGORITHM` |
|
|
168
|
-
| Rounds (bcrypt) | 10 | `AUTH_BCRYPT_ROUNDS` |
|
|
169
|
-
|
|
170
|
-
Opções: `bcrypt` ou `argon2id`.
|
|
171
|
-
|
|
172
|
-
## Middleware
|
|
173
|
-
|
|
174
|
-
Três níveis de proteção disponíveis para rotas customizadas:
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
import { auth, guest, authOptional } from '@server/auth'
|
|
178
|
-
|
|
179
|
-
// Requer autenticação (401 se não autenticado)
|
|
180
|
-
app.use(auth()).get('/protected', ({ user }) => user.toJSON())
|
|
181
|
-
|
|
182
|
-
// Requer NÃO estar autenticado (409 se já logado)
|
|
183
|
-
app.use(guest()).post('/login', loginHandler)
|
|
184
|
-
|
|
185
|
-
// Auth opcional (não bloqueia, injeta user ou null)
|
|
186
|
-
app.use(authOptional()).get('/public', ({ user }) => ({ user }))
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
## Schemas TypeBox
|
|
190
|
-
|
|
191
|
-
As rotas definem schemas para validação e Swagger:
|
|
192
|
-
|
|
193
|
-
```typescript
|
|
194
|
-
// Body do register
|
|
195
|
-
RegisterBodySchema = t.Object({
|
|
196
|
-
name: t.String({ minLength: 1 }),
|
|
197
|
-
email: t.String({ format: 'email' }),
|
|
198
|
-
password: t.String({ minLength: 6 }),
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
// Body do login
|
|
202
|
-
LoginBodySchema = t.Object({
|
|
203
|
-
email: t.String({ format: 'email' }),
|
|
204
|
-
password: t.String({ minLength: 1 }),
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
// Response do login (token guard)
|
|
208
|
-
LoginResponseSchema = t.Object({
|
|
209
|
-
success: t.Literal(true),
|
|
210
|
-
user: t.Object({
|
|
211
|
-
id: t.Union([t.String(), t.Number()]),
|
|
212
|
-
name: t.Optional(t.String()),
|
|
213
|
-
email: t.Optional(t.String()),
|
|
214
|
-
createdAt: t.Optional(t.String()),
|
|
215
|
-
}),
|
|
216
|
-
token: t.Optional(t.String()),
|
|
217
|
-
})
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
## REST Test Files
|
|
221
|
-
|
|
222
|
-
Arquivos `.http` prontos para testar com a extensão REST Client do VSCode:
|
|
223
|
-
|
|
224
|
-
| Arquivo | Guard | Cobertura |
|
|
225
|
-
|---------|-------|-----------|
|
|
226
|
-
| `rest-tests/auth.http` | Session (cookie) | Register, Login, Me, Logout |
|
|
227
|
-
| `rest-tests/auth-token.http` | Token (Bearer) | Register, Login, Me, Logout + erros |
|
|
228
|
-
| `rest-tests/users-token.http` | Token (Bearer) | CRUD de usuários autenticado |
|
|
229
|
-
| `rest-tests/rooms-token.http` | Token (Bearer) | Mensagens e eventos em salas |
|
|
230
|
-
|
|
231
|
-
### Uso rápido
|
|
232
|
-
|
|
233
|
-
1. Configure `AUTH_DEFAULT_GUARD=token` no `.env`
|
|
234
|
-
2. `bun run dev`
|
|
235
|
-
3. Abra `rest-tests/auth-token.http` no VSCode
|
|
236
|
-
4. Execute **Register** → **Login** (captura token) → **Me** / **Logout**
|
|
237
|
-
|
|
238
|
-
> O token é capturado automaticamente via `@name login` e injetado com `{{login.response.body.token}}`.
|
|
239
|
-
|
|
240
|
-
## Configuração Completa
|
|
241
|
-
|
|
242
|
-
| Variável | Tipo | Default | Descrição |
|
|
243
|
-
|----------|------|---------|-----------|
|
|
244
|
-
| `AUTH_DEFAULT_GUARD` | enum | `session` | Guard padrão: `session` ou `token` |
|
|
245
|
-
| `AUTH_DEFAULT_PROVIDER` | enum | `memory` | Provider: `memory` ou `database` |
|
|
246
|
-
| `AUTH_HASH_ALGORITHM` | enum | `bcrypt` | Hash: `bcrypt` ou `argon2id` |
|
|
247
|
-
| `AUTH_BCRYPT_ROUNDS` | number | `10` | Rounds do bcrypt |
|
|
248
|
-
| `AUTH_RATE_LIMIT_MAX_ATTEMPTS` | number | `5` | Max tentativas de login |
|
|
249
|
-
| `AUTH_RATE_LIMIT_DECAY_SECONDS` | number | `60` | Janela do rate limit |
|
|
250
|
-
| `AUTH_TOKEN_TTL` | number | `86400` | TTL do token (segundos) |
|
|
251
|
-
| `SESSION_COOKIE` | string | `fluxstack_session` | Nome do cookie |
|
|
252
|
-
| `SESSION_LIFETIME` | number | `7200` | Duração da sessão (segundos) |
|
|
253
|
-
| `SESSION_HTTP_ONLY` | boolean | `true` | Cookie httpOnly |
|
|
254
|
-
| `SESSION_SECURE` | boolean | `false` | Cookie secure (HTTPS) |
|
|
255
|
-
| `SESSION_SAME_SITE` | enum | `lax` | SameSite policy |
|
|
256
|
-
|
|
257
|
-
## Arquivos de Referência
|
|
258
|
-
|
|
259
|
-
| Arquivo | Conteúdo |
|
|
260
|
-
|---------|----------|
|
|
261
|
-
| `app/server/routes/auth.routes.ts` | Endpoints de autenticação |
|
|
262
|
-
| `app/server/auth/middleware.ts` | Middleware `auth()`, `guest()`, `authOptional()` |
|
|
263
|
-
| `app/server/auth/guards/SessionGuard.ts` | Lógica do session guard |
|
|
264
|
-
| `app/server/auth/guards/TokenGuard.ts` | Lógica do token guard |
|
|
265
|
-
| `app/server/auth/AuthManager.ts` | Factory de guards e providers |
|
|
266
|
-
| `app/server/auth/providers/InMemoryProvider.ts` | Provider in-memory |
|
|
267
|
-
| `app/server/auth/RateLimiter.ts` | Rate limiting de login |
|
|
268
|
-
| `config/system/auth.config.ts` | Schema de configuração auth |
|
|
269
|
-
| `config/system/session.config.ts` | Schema de configuração session |
|
|
270
|
-
|
|
271
|
-
## Critical Rules
|
|
272
|
-
|
|
273
|
-
**ALWAYS:**
|
|
274
|
-
- Usar `AUTH_DEFAULT_GUARD=token` para APIs stateless
|
|
275
|
-
- Enviar `Authorization: Bearer <token>` em todos os requests autenticados
|
|
276
|
-
- Tratar `401` e `429` no frontend
|
|
277
|
-
- Armazenar token com segurança no cliente (httpOnly cookie ou secure storage)
|
|
278
|
-
|
|
279
|
-
**NEVER:**
|
|
280
|
-
- Expor token em URLs (query params)
|
|
281
|
-
- Armazenar token em localStorage sem necessidade (preferir httpOnly cookie)
|
|
282
|
-
- Ignorar rate limiting responses (`429`)
|
|
283
|
-
- Enviar passwords sem HTTPS em produção
|
|
284
|
-
|
|
285
|
-
## Related
|
|
286
|
-
|
|
287
|
-
- [Live Auth](./live-auth.md) - Autenticação para Live Components (WebSocket)
|
|
288
|
-
- [Routes with Eden Treaty](./routes-eden.md) - Criação de rotas type-safe
|
|
289
|
-
- [Environment Variables](../config/environment-vars.md) - Referência de variáveis
|
|
290
|
-
- [Troubleshooting](../reference/troubleshooting.md) - Problemas comuns
|
|
1
|
+
# REST API Authentication
|
|
2
|
+
|
|
3
|
+
**Version:** 1.19.0 | **Updated:** 2026-02-14
|
|
4
|
+
|
|
5
|
+
## Quick Facts
|
|
6
|
+
|
|
7
|
+
- Dois guards disponíveis: **Session** (cookie) e **Token** (Bearer)
|
|
8
|
+
- Configuração via `AUTH_DEFAULT_GUARD` no `.env`
|
|
9
|
+
- Rate limiting automático no login (5 tentativas / 60s)
|
|
10
|
+
- Password hashing com bcrypt ou argon2id
|
|
11
|
+
- Provider in-memory por padrão (extensível para database)
|
|
12
|
+
- REST test files disponíveis em `rest-tests/`
|
|
13
|
+
|
|
14
|
+
## Endpoints
|
|
15
|
+
|
|
16
|
+
| Método | Rota | Auth | Descrição |
|
|
17
|
+
|--------|------|------|-----------|
|
|
18
|
+
| `POST` | `/api/auth/register` | Guest | Criar conta e auto-login |
|
|
19
|
+
| `POST` | `/api/auth/login` | Guest | Autenticar com email + password |
|
|
20
|
+
| `GET` | `/api/auth/me` | Required | Retorna usuário autenticado |
|
|
21
|
+
| `POST` | `/api/auth/logout` | Required | Encerrar sessão/revogar token |
|
|
22
|
+
|
|
23
|
+
## Guards
|
|
24
|
+
|
|
25
|
+
### Session Guard (padrão)
|
|
26
|
+
|
|
27
|
+
Armazena sessão no servidor e envia cookie httpOnly ao cliente.
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
Login → Servidor cria sessão → Cookie `fluxstack_session` → Browser envia automaticamente
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Configuração** (`.env`):
|
|
34
|
+
```bash
|
|
35
|
+
AUTH_DEFAULT_GUARD=session
|
|
36
|
+
SESSION_COOKIE=fluxstack_session
|
|
37
|
+
SESSION_LIFETIME=7200 # 2 horas
|
|
38
|
+
SESSION_HTTP_ONLY=true
|
|
39
|
+
SESSION_SECURE=false # true em produção
|
|
40
|
+
SESSION_SAME_SITE=lax
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Response do login** (sem campo token):
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"success": true,
|
|
47
|
+
"user": {
|
|
48
|
+
"id": 1,
|
|
49
|
+
"name": "John Doe",
|
|
50
|
+
"email": "john@example.com",
|
|
51
|
+
"createdAt": "2026-02-14T16:00:00.000Z"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Requests autenticados**: cookie enviado automaticamente pelo browser.
|
|
57
|
+
|
|
58
|
+
### Token Guard (Bearer)
|
|
59
|
+
|
|
60
|
+
Gera token aleatório de 32 bytes, armazena hash SHA256 no cache e retorna o token plain ao cliente.
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Login → Token gerado → Response inclui token → Cliente envia Authorization: Bearer <token>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Configuração** (`.env`):
|
|
67
|
+
```bash
|
|
68
|
+
AUTH_DEFAULT_GUARD=token
|
|
69
|
+
AUTH_TOKEN_TTL=86400 # 24 horas
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Response do login** (com campo token):
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"success": true,
|
|
76
|
+
"user": {
|
|
77
|
+
"id": 1,
|
|
78
|
+
"name": "John Doe",
|
|
79
|
+
"email": "john@example.com",
|
|
80
|
+
"createdAt": "2026-02-14T16:00:00.000Z"
|
|
81
|
+
},
|
|
82
|
+
"token": "a1b2c3d4e5f6..."
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Requests autenticados**:
|
|
87
|
+
```
|
|
88
|
+
Authorization: Bearer a1b2c3d4e5f6...
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Quando usar cada guard
|
|
92
|
+
|
|
93
|
+
| Guard | Melhor para |
|
|
94
|
+
|-------|-------------|
|
|
95
|
+
| Session | SPAs web (same-origin), SSR |
|
|
96
|
+
| Token | Mobile apps, CLIs, API clients, integrações |
|
|
97
|
+
|
|
98
|
+
## Fluxos
|
|
99
|
+
|
|
100
|
+
### Register + Auto-login
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
POST /api/auth/register
|
|
104
|
+
Content-Type: application/json
|
|
105
|
+
|
|
106
|
+
{
|
|
107
|
+
"name": "John Doe",
|
|
108
|
+
"email": "john@example.com",
|
|
109
|
+
"password": "secret123"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
# 201 Created
|
|
113
|
+
# Session guard: set-cookie header
|
|
114
|
+
# Token guard: token no body (via login automático)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Login
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
POST /api/auth/login
|
|
121
|
+
Content-Type: application/json
|
|
122
|
+
|
|
123
|
+
{
|
|
124
|
+
"email": "john@example.com",
|
|
125
|
+
"password": "secret123"
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
# 200 OK → user + token (se token guard)
|
|
129
|
+
# 401 → credenciais inválidas
|
|
130
|
+
# 429 → rate limit (Retry-After header)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Me (Token Guard)
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
GET /api/auth/me
|
|
137
|
+
Authorization: Bearer <token>
|
|
138
|
+
|
|
139
|
+
# 200 OK → { success: true, user: {...} }
|
|
140
|
+
# 401 → não autenticado
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Logout (Token Guard)
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
POST /api/auth/logout
|
|
147
|
+
Authorization: Bearer <token>
|
|
148
|
+
|
|
149
|
+
# 200 OK → token revogado no cache
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Rate Limiting
|
|
153
|
+
|
|
154
|
+
Login é protegido automaticamente contra brute force:
|
|
155
|
+
|
|
156
|
+
| Config | Default | Env Var |
|
|
157
|
+
|--------|---------|---------|
|
|
158
|
+
| Max tentativas | 5 | `AUTH_RATE_LIMIT_MAX_ATTEMPTS` |
|
|
159
|
+
| Janela (segundos) | 60 | `AUTH_RATE_LIMIT_DECAY_SECONDS` |
|
|
160
|
+
|
|
161
|
+
Chave de throttle: `email|ip`. Após exceder, retorna `429 Too Many Attempts` com header `Retry-After`.
|
|
162
|
+
|
|
163
|
+
## Password Hashing
|
|
164
|
+
|
|
165
|
+
| Config | Default | Env Var |
|
|
166
|
+
|--------|---------|---------|
|
|
167
|
+
| Algoritmo | bcrypt | `AUTH_HASH_ALGORITHM` |
|
|
168
|
+
| Rounds (bcrypt) | 10 | `AUTH_BCRYPT_ROUNDS` |
|
|
169
|
+
|
|
170
|
+
Opções: `bcrypt` ou `argon2id`.
|
|
171
|
+
|
|
172
|
+
## Middleware
|
|
173
|
+
|
|
174
|
+
Três níveis de proteção disponíveis para rotas customizadas:
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import { auth, guest, authOptional } from '@server/auth'
|
|
178
|
+
|
|
179
|
+
// Requer autenticação (401 se não autenticado)
|
|
180
|
+
app.use(auth()).get('/protected', ({ user }) => user.toJSON())
|
|
181
|
+
|
|
182
|
+
// Requer NÃO estar autenticado (409 se já logado)
|
|
183
|
+
app.use(guest()).post('/login', loginHandler)
|
|
184
|
+
|
|
185
|
+
// Auth opcional (não bloqueia, injeta user ou null)
|
|
186
|
+
app.use(authOptional()).get('/public', ({ user }) => ({ user }))
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Schemas TypeBox
|
|
190
|
+
|
|
191
|
+
As rotas definem schemas para validação e Swagger:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
// Body do register
|
|
195
|
+
RegisterBodySchema = t.Object({
|
|
196
|
+
name: t.String({ minLength: 1 }),
|
|
197
|
+
email: t.String({ format: 'email' }),
|
|
198
|
+
password: t.String({ minLength: 6 }),
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
// Body do login
|
|
202
|
+
LoginBodySchema = t.Object({
|
|
203
|
+
email: t.String({ format: 'email' }),
|
|
204
|
+
password: t.String({ minLength: 1 }),
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
// Response do login (token guard)
|
|
208
|
+
LoginResponseSchema = t.Object({
|
|
209
|
+
success: t.Literal(true),
|
|
210
|
+
user: t.Object({
|
|
211
|
+
id: t.Union([t.String(), t.Number()]),
|
|
212
|
+
name: t.Optional(t.String()),
|
|
213
|
+
email: t.Optional(t.String()),
|
|
214
|
+
createdAt: t.Optional(t.String()),
|
|
215
|
+
}),
|
|
216
|
+
token: t.Optional(t.String()),
|
|
217
|
+
})
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## REST Test Files
|
|
221
|
+
|
|
222
|
+
Arquivos `.http` prontos para testar com a extensão REST Client do VSCode:
|
|
223
|
+
|
|
224
|
+
| Arquivo | Guard | Cobertura |
|
|
225
|
+
|---------|-------|-----------|
|
|
226
|
+
| `rest-tests/auth.http` | Session (cookie) | Register, Login, Me, Logout |
|
|
227
|
+
| `rest-tests/auth-token.http` | Token (Bearer) | Register, Login, Me, Logout + erros |
|
|
228
|
+
| `rest-tests/users-token.http` | Token (Bearer) | CRUD de usuários autenticado |
|
|
229
|
+
| `rest-tests/rooms-token.http` | Token (Bearer) | Mensagens e eventos em salas |
|
|
230
|
+
|
|
231
|
+
### Uso rápido
|
|
232
|
+
|
|
233
|
+
1. Configure `AUTH_DEFAULT_GUARD=token` no `.env`
|
|
234
|
+
2. `bun run dev`
|
|
235
|
+
3. Abra `rest-tests/auth-token.http` no VSCode
|
|
236
|
+
4. Execute **Register** → **Login** (captura token) → **Me** / **Logout**
|
|
237
|
+
|
|
238
|
+
> O token é capturado automaticamente via `@name login` e injetado com `{{login.response.body.token}}`.
|
|
239
|
+
|
|
240
|
+
## Configuração Completa
|
|
241
|
+
|
|
242
|
+
| Variável | Tipo | Default | Descrição |
|
|
243
|
+
|----------|------|---------|-----------|
|
|
244
|
+
| `AUTH_DEFAULT_GUARD` | enum | `session` | Guard padrão: `session` ou `token` |
|
|
245
|
+
| `AUTH_DEFAULT_PROVIDER` | enum | `memory` | Provider: `memory` ou `database` |
|
|
246
|
+
| `AUTH_HASH_ALGORITHM` | enum | `bcrypt` | Hash: `bcrypt` ou `argon2id` |
|
|
247
|
+
| `AUTH_BCRYPT_ROUNDS` | number | `10` | Rounds do bcrypt |
|
|
248
|
+
| `AUTH_RATE_LIMIT_MAX_ATTEMPTS` | number | `5` | Max tentativas de login |
|
|
249
|
+
| `AUTH_RATE_LIMIT_DECAY_SECONDS` | number | `60` | Janela do rate limit |
|
|
250
|
+
| `AUTH_TOKEN_TTL` | number | `86400` | TTL do token (segundos) |
|
|
251
|
+
| `SESSION_COOKIE` | string | `fluxstack_session` | Nome do cookie |
|
|
252
|
+
| `SESSION_LIFETIME` | number | `7200` | Duração da sessão (segundos) |
|
|
253
|
+
| `SESSION_HTTP_ONLY` | boolean | `true` | Cookie httpOnly |
|
|
254
|
+
| `SESSION_SECURE` | boolean | `false` | Cookie secure (HTTPS) |
|
|
255
|
+
| `SESSION_SAME_SITE` | enum | `lax` | SameSite policy |
|
|
256
|
+
|
|
257
|
+
## Arquivos de Referência
|
|
258
|
+
|
|
259
|
+
| Arquivo | Conteúdo |
|
|
260
|
+
|---------|----------|
|
|
261
|
+
| `app/server/routes/auth.routes.ts` | Endpoints de autenticação |
|
|
262
|
+
| `app/server/auth/middleware.ts` | Middleware `auth()`, `guest()`, `authOptional()` |
|
|
263
|
+
| `app/server/auth/guards/SessionGuard.ts` | Lógica do session guard |
|
|
264
|
+
| `app/server/auth/guards/TokenGuard.ts` | Lógica do token guard |
|
|
265
|
+
| `app/server/auth/AuthManager.ts` | Factory de guards e providers |
|
|
266
|
+
| `app/server/auth/providers/InMemoryProvider.ts` | Provider in-memory |
|
|
267
|
+
| `app/server/auth/RateLimiter.ts` | Rate limiting de login |
|
|
268
|
+
| `config/system/auth.config.ts` | Schema de configuração auth |
|
|
269
|
+
| `config/system/session.config.ts` | Schema de configuração session |
|
|
270
|
+
|
|
271
|
+
## Critical Rules
|
|
272
|
+
|
|
273
|
+
**ALWAYS:**
|
|
274
|
+
- Usar `AUTH_DEFAULT_GUARD=token` para APIs stateless
|
|
275
|
+
- Enviar `Authorization: Bearer <token>` em todos os requests autenticados
|
|
276
|
+
- Tratar `401` e `429` no frontend
|
|
277
|
+
- Armazenar token com segurança no cliente (httpOnly cookie ou secure storage)
|
|
278
|
+
|
|
279
|
+
**NEVER:**
|
|
280
|
+
- Expor token em URLs (query params)
|
|
281
|
+
- Armazenar token em localStorage sem necessidade (preferir httpOnly cookie)
|
|
282
|
+
- Ignorar rate limiting responses (`429`)
|
|
283
|
+
- Enviar passwords sem HTTPS em produção
|
|
284
|
+
|
|
285
|
+
## Related
|
|
286
|
+
|
|
287
|
+
- [Live Auth](./live-auth.md) - Autenticação para Live Components (WebSocket)
|
|
288
|
+
- [Routes with Eden Treaty](./routes-eden.md) - Criação de rotas type-safe
|
|
289
|
+
- [Environment Variables](../config/environment-vars.md) - Referência de variáveis
|
|
290
|
+
- [Troubleshooting](../reference/troubleshooting.md) - Problemas comuns
|