loki-mode 5.30.0 → 5.32.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/README.md +100 -2
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +552 -14
- package/autonomy/run.sh +16 -3
- package/dashboard/__init__.py +1 -1
- package/dashboard/server.py +12 -1
- package/dashboard/static/favicon.svg +5 -0
- package/dashboard/static/index.html +260 -7
- package/docs/INSTALLATION.md +110 -8
- package/package.json +1 -1
- package/templates/README.md +2 -1
- package/templates/rest-api-auth.md +252 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# PRD: REST API with JWT Authentication
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
A production-ready REST API with JWT-based authentication, user registration, login, token refresh, protected routes, rate limiting, and input validation. Serves as a backend starter for any application requiring secure user authentication.
|
|
5
|
+
|
|
6
|
+
## Target Users
|
|
7
|
+
- Backend developers building authenticated APIs
|
|
8
|
+
- Teams needing a secure auth starter with best practices
|
|
9
|
+
- Developers learning JWT authentication patterns
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
### MVP Features
|
|
14
|
+
1. **User Registration** - Email/password signup with validation
|
|
15
|
+
2. **User Login** - Authenticate and receive JWT access + refresh tokens
|
|
16
|
+
3. **Token Refresh** - Exchange refresh token for new access token
|
|
17
|
+
4. **Protected Routes** - Middleware-guarded endpoints requiring valid JWT
|
|
18
|
+
5. **User Profile** - Get and update authenticated user profile
|
|
19
|
+
6. **Password Management** - Change password (authenticated), forgot/reset password flow
|
|
20
|
+
7. **Rate Limiting** - Per-IP and per-user rate limits on auth endpoints
|
|
21
|
+
8. **Input Validation** - Schema-based request validation on all endpoints
|
|
22
|
+
|
|
23
|
+
### User Flow
|
|
24
|
+
1. User registers via POST /api/auth/register with email and password
|
|
25
|
+
2. Server validates input, hashes password, stores user, returns tokens
|
|
26
|
+
3. User includes access token in Authorization header for protected routes
|
|
27
|
+
4. When access token expires, user calls POST /api/auth/refresh with refresh token
|
|
28
|
+
5. User can update profile, change password via protected endpoints
|
|
29
|
+
6. Forgot password sends reset token via email (or logs to console in dev)
|
|
30
|
+
|
|
31
|
+
## Tech Stack
|
|
32
|
+
|
|
33
|
+
### Option A: Node.js (Express)
|
|
34
|
+
- Runtime: Node.js 20+
|
|
35
|
+
- Framework: Express.js
|
|
36
|
+
- Database: PostgreSQL with Prisma ORM
|
|
37
|
+
- Validation: zod
|
|
38
|
+
- Auth: jsonwebtoken, bcrypt
|
|
39
|
+
- Rate Limiting: express-rate-limit
|
|
40
|
+
- Testing: Jest + supertest
|
|
41
|
+
|
|
42
|
+
### Option B: Python (FastAPI)
|
|
43
|
+
- Runtime: Python 3.11+
|
|
44
|
+
- Framework: FastAPI
|
|
45
|
+
- Database: PostgreSQL with SQLAlchemy
|
|
46
|
+
- Validation: Pydantic (built into FastAPI)
|
|
47
|
+
- Auth: python-jose, passlib[bcrypt]
|
|
48
|
+
- Rate Limiting: slowapi
|
|
49
|
+
- Testing: pytest + httpx
|
|
50
|
+
|
|
51
|
+
Choose whichever framework the agent determines is most appropriate, or default to Express.js.
|
|
52
|
+
|
|
53
|
+
### Project Structure (Express)
|
|
54
|
+
```
|
|
55
|
+
/
|
|
56
|
+
├── src/
|
|
57
|
+
│ ├── app.js # Express app setup
|
|
58
|
+
│ ├── server.js # Entry point
|
|
59
|
+
│ ├── config/
|
|
60
|
+
│ │ └── index.js # Environment config
|
|
61
|
+
│ ├── middleware/
|
|
62
|
+
│ │ ├── auth.js # JWT verification middleware
|
|
63
|
+
│ │ ├── validate.js # Request validation middleware
|
|
64
|
+
│ │ └── rateLimiter.js # Rate limiting middleware
|
|
65
|
+
│ ├── routes/
|
|
66
|
+
│ │ ├── auth.js # Auth routes (register, login, refresh, forgot, reset)
|
|
67
|
+
│ │ └── users.js # User routes (profile, update, change password)
|
|
68
|
+
│ ├── controllers/
|
|
69
|
+
│ │ ├── authController.js # Auth business logic
|
|
70
|
+
│ │ └── userController.js # User business logic
|
|
71
|
+
│ ├── services/
|
|
72
|
+
│ │ ├── authService.js # Token generation, password hashing
|
|
73
|
+
│ │ └── emailService.js # Email sending (console in dev)
|
|
74
|
+
│ └── utils/
|
|
75
|
+
│ └── errors.js # Custom error classes
|
|
76
|
+
├── prisma/
|
|
77
|
+
│ ├── schema.prisma # Database schema
|
|
78
|
+
│ └── seed.js # Seed data
|
|
79
|
+
├── tests/
|
|
80
|
+
│ ├── auth.test.js # Auth endpoint tests
|
|
81
|
+
│ ├── users.test.js # User endpoint tests
|
|
82
|
+
│ └── middleware.test.js # Middleware tests
|
|
83
|
+
├── .env.example # Environment variable template
|
|
84
|
+
├── package.json
|
|
85
|
+
└── README.md
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Database Schema
|
|
89
|
+
|
|
90
|
+
```sql
|
|
91
|
+
CREATE TABLE users (
|
|
92
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
93
|
+
email VARCHAR(255) UNIQUE NOT NULL,
|
|
94
|
+
password VARCHAR(255) NOT NULL,
|
|
95
|
+
name VARCHAR(100),
|
|
96
|
+
role VARCHAR(20) DEFAULT 'user' CHECK (role IN ('user', 'admin')),
|
|
97
|
+
is_active BOOLEAN DEFAULT true,
|
|
98
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
99
|
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
CREATE TABLE refresh_tokens (
|
|
103
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
104
|
+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
105
|
+
token VARCHAR(500) NOT NULL,
|
|
106
|
+
expires_at TIMESTAMP NOT NULL,
|
|
107
|
+
revoked BOOLEAN DEFAULT false,
|
|
108
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
CREATE TABLE password_resets (
|
|
112
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
113
|
+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
114
|
+
token VARCHAR(255) UNIQUE NOT NULL,
|
|
115
|
+
expires_at TIMESTAMP NOT NULL,
|
|
116
|
+
used BOOLEAN DEFAULT false,
|
|
117
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
118
|
+
);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## API Endpoints
|
|
122
|
+
|
|
123
|
+
### Authentication
|
|
124
|
+
|
|
125
|
+
#### POST /api/auth/register
|
|
126
|
+
- Body: `{ email, password, name? }`
|
|
127
|
+
- Validation: email format, password min 8 chars with complexity
|
|
128
|
+
- Response: `201 { user: { id, email, name, role }, accessToken, refreshToken }`
|
|
129
|
+
- Error: `400` validation, `409` email already exists
|
|
130
|
+
|
|
131
|
+
#### POST /api/auth/login
|
|
132
|
+
- Body: `{ email, password }`
|
|
133
|
+
- Response: `200 { user: { id, email, name, role }, accessToken, refreshToken }`
|
|
134
|
+
- Error: `401` invalid credentials
|
|
135
|
+
- Rate limit: 5 attempts per 15 minutes per IP
|
|
136
|
+
|
|
137
|
+
#### POST /api/auth/refresh
|
|
138
|
+
- Body: `{ refreshToken }`
|
|
139
|
+
- Response: `200 { accessToken, refreshToken }`
|
|
140
|
+
- Error: `401` invalid/expired/revoked token
|
|
141
|
+
|
|
142
|
+
#### POST /api/auth/logout
|
|
143
|
+
- Headers: `Authorization: Bearer <accessToken>`
|
|
144
|
+
- Body: `{ refreshToken }`
|
|
145
|
+
- Revokes the refresh token
|
|
146
|
+
- Response: `200 { message: "Logged out" }`
|
|
147
|
+
|
|
148
|
+
#### POST /api/auth/forgot-password
|
|
149
|
+
- Body: `{ email }`
|
|
150
|
+
- Sends password reset token (logs to console in dev)
|
|
151
|
+
- Response: `200 { message: "Reset email sent" }` (always, even if email not found)
|
|
152
|
+
|
|
153
|
+
#### POST /api/auth/reset-password
|
|
154
|
+
- Body: `{ token, newPassword }`
|
|
155
|
+
- Response: `200 { message: "Password reset successful" }`
|
|
156
|
+
- Error: `400` invalid/expired token
|
|
157
|
+
|
|
158
|
+
### Users (Protected)
|
|
159
|
+
|
|
160
|
+
#### GET /api/users/me
|
|
161
|
+
- Headers: `Authorization: Bearer <accessToken>`
|
|
162
|
+
- Response: `200 { id, email, name, role, createdAt }`
|
|
163
|
+
|
|
164
|
+
#### PATCH /api/users/me
|
|
165
|
+
- Headers: `Authorization: Bearer <accessToken>`
|
|
166
|
+
- Body: `{ name?, email? }`
|
|
167
|
+
- Response: `200 { id, email, name, role, updatedAt }`
|
|
168
|
+
|
|
169
|
+
#### POST /api/users/me/change-password
|
|
170
|
+
- Headers: `Authorization: Bearer <accessToken>`
|
|
171
|
+
- Body: `{ currentPassword, newPassword }`
|
|
172
|
+
- Response: `200 { message: "Password changed" }`
|
|
173
|
+
- Error: `400` current password incorrect
|
|
174
|
+
|
|
175
|
+
### Health Check
|
|
176
|
+
|
|
177
|
+
#### GET /health
|
|
178
|
+
- Response: `200 { status: "ok", timestamp, version }`
|
|
179
|
+
|
|
180
|
+
## Requirements
|
|
181
|
+
|
|
182
|
+
### Security
|
|
183
|
+
- Passwords hashed with bcrypt (cost factor 12)
|
|
184
|
+
- JWT access tokens expire in 15 minutes
|
|
185
|
+
- JWT refresh tokens expire in 7 days, stored in database, revocable
|
|
186
|
+
- Password reset tokens expire in 1 hour
|
|
187
|
+
- No password or token values in response bodies (except at login/register)
|
|
188
|
+
- CORS configured for allowed origins
|
|
189
|
+
- Helmet.js (Express) or equivalent security headers
|
|
190
|
+
|
|
191
|
+
### Validation
|
|
192
|
+
- Email: valid format, lowercase, trimmed
|
|
193
|
+
- Password: minimum 8 characters, at least one uppercase, one lowercase, one number
|
|
194
|
+
- Name: 1-100 characters, trimmed
|
|
195
|
+
- All request bodies validated before processing
|
|
196
|
+
|
|
197
|
+
### Rate Limiting
|
|
198
|
+
- Auth endpoints (login, register): 5 requests per 15 minutes per IP
|
|
199
|
+
- Password reset: 3 requests per hour per IP
|
|
200
|
+
- General API: 100 requests per 15 minutes per user
|
|
201
|
+
- Returns `429 Too Many Requests` with `Retry-After` header
|
|
202
|
+
|
|
203
|
+
### Error Handling
|
|
204
|
+
- Consistent error format: `{ error: { code, message, details? } }`
|
|
205
|
+
- No stack traces in production
|
|
206
|
+
- Proper HTTP status codes (400, 401, 403, 404, 409, 429, 500)
|
|
207
|
+
|
|
208
|
+
## Testing
|
|
209
|
+
|
|
210
|
+
### Unit Tests
|
|
211
|
+
- Password hashing and comparison
|
|
212
|
+
- JWT generation and verification
|
|
213
|
+
- Input validation schemas
|
|
214
|
+
- Rate limiter behavior
|
|
215
|
+
|
|
216
|
+
### Integration Tests
|
|
217
|
+
- Full registration flow
|
|
218
|
+
- Login with valid and invalid credentials
|
|
219
|
+
- Token refresh with valid, expired, and revoked tokens
|
|
220
|
+
- Protected route access with and without tokens
|
|
221
|
+
- Password change flow
|
|
222
|
+
- Forgot/reset password flow
|
|
223
|
+
- Rate limit enforcement
|
|
224
|
+
|
|
225
|
+
### Test Coverage
|
|
226
|
+
- Target: 90%+ line coverage
|
|
227
|
+
- All error paths tested
|
|
228
|
+
- All validation rules tested
|
|
229
|
+
|
|
230
|
+
## Out of Scope
|
|
231
|
+
- OAuth/social login (Google, GitHub, etc.)
|
|
232
|
+
- Two-factor authentication (2FA)
|
|
233
|
+
- Email verification on registration
|
|
234
|
+
- Role-based access control beyond user/admin
|
|
235
|
+
- API documentation (OpenAPI/Swagger)
|
|
236
|
+
- WebSocket connections
|
|
237
|
+
- File uploads
|
|
238
|
+
- Deployment configuration
|
|
239
|
+
- Frontend/UI
|
|
240
|
+
|
|
241
|
+
## Success Criteria
|
|
242
|
+
- User can register, login, and access protected routes
|
|
243
|
+
- Tokens refresh correctly and expired tokens are rejected
|
|
244
|
+
- Rate limiting prevents brute force attempts
|
|
245
|
+
- All input is validated before processing
|
|
246
|
+
- Password reset flow works end to end
|
|
247
|
+
- All tests pass with 90%+ coverage
|
|
248
|
+
- No security vulnerabilities in auth flow
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
**Purpose:** Tests Loki Mode's ability to build a secure authentication system with JWT tokens, middleware patterns, database schema design, and comprehensive test coverage. Exercises backend agent, security agent, and QA agent. Expect ~30-45 minutes for full execution.
|