The authentication system is implemented as a REST API on the backend. Since the frontend UI is not yet implemented (Phase 2.3 in the implementation strategy), you can test the API directly using HTTP clients.
-
Start all services with Docker Compose:
docker compose up -d
This will start:
- PostgreSQL database on port 5432
- Backend API on http://localhost:3001
- Frontend on http://localhost:3000
The database migrations will run automatically on startup.
-
Check logs if needed:
docker compose logs backend
-
Stop services:
docker compose down
-
Start the backend server:
cd backend npm install cp .env.example .env # Edit .env to configure DATABASE_URL npm run prisma:generate npm run dev
The server will run on http://localhost:3001
-
Set up the database:
# Create PostgreSQL database createdb carrots_dev # Run migrations cd backend npm run prisma:migrate:dev
curl -X POST http://localhost:3001/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"email": "test@example.com",
"password": "Password123"
}'Expected response:
{
"message": "User registered successfully",
"user": {
"id": "uuid-here",
"username": "testuser",
"email": "test@example.com",
"createdAt": "2025-11-09T..."
},
"accessToken": "eyJhbGc...",
"refreshToken": "eyJhbGc..."
}curl -X POST http://localhost:3001/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "test@example.com",
"password": "Password123"
}'# Replace YOUR_ACCESS_TOKEN with the token from register/login
curl -X GET http://localhost:3001/api/auth/me \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"# Replace YOUR_REFRESH_TOKEN with the refresh token from register/login
curl -X POST http://localhost:3001/api/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "YOUR_REFRESH_TOKEN"
}'curl -X POST http://localhost:3001/api/auth/logout \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"-
Import the endpoints:
- POST
http://localhost:3001/api/auth/register - POST
http://localhost:3001/api/auth/login - POST
http://localhost:3001/api/auth/refresh - POST
http://localhost:3001/api/auth/logout - GET
http://localhost:3001/api/auth/me
- POST
-
Set headers:
- Content-Type:
application/json - Authorization:
Bearer YOUR_ACCESS_TOKEN(for protected endpoints)
- Content-Type:
-
Use the JSON request bodies shown in the curl examples above.
Run the automated tests:
cd backend
npm testThis runs 18 test cases covering all authentication flows.
Register a new user.
Request body:
{
"username": "string (3-30 chars, alphanumeric)",
"email": "string (valid email)",
"password": "string (8+ chars, must contain uppercase, lowercase, and number)"
}Response: 201 Created
{
"message": "User registered successfully",
"user": { "id", "username", "email", "createdAt" },
"accessToken": "string",
"refreshToken": "string"
}Login with email and password.
Request body:
{
"email": "string",
"password": "string"
}Response: 200 OK (same as register)
Get current user info. Requires authentication.
Headers:
Authorization: Bearer YOUR_ACCESS_TOKEN
Response: 200 OK
{
"user": {
"id": "string",
"username": "string",
"email": "string",
"createdAt": "datetime",
"updatedAt": "datetime"
}
}Refresh access token using refresh token.
Request body:
{
"refreshToken": "string"
}Response: 200 OK
{
"message": "Token refreshed successfully",
"accessToken": "string",
"refreshToken": "string"
}Logout (client should remove tokens). Requires authentication.
Headers:
Authorization: Bearer YOUR_ACCESS_TOKEN
Response: 200 OK
{
"message": "Logout successful"
}Authentication endpoints are rate limited:
- Register/Login/Refresh: 5 requests per 15 minutes per IP
- Logout/Me: 100 requests per 15 minutes per IP
If you exceed the limit, you'll get a 429 Too Many Requests response.
- ✅ Password strength validation (8+ chars, mixed case, numbers)
- ✅ Passwords hashed with bcrypt
- ✅ JWT tokens with expiration (access: 24h, refresh: 7d)
- ✅ Rate limiting on all endpoints
- ✅ Protected routes require valid access token
- ✅ Token type validation (access vs refresh)
The frontend UI (login/register pages) will be implemented in Phase 2.3 of the implementation strategy. For now, the API is fully functional and can be tested using the methods above.
If you get connection errors when using Docker Compose:
-
Check if the backend container is running:
docker ps
You should see
carrots-backend-1in the list. -
Check backend logs for errors:
docker compose logs backend
Look for any startup errors or database connection issues.
-
Restart the services:
docker compose down docker compose up -d
-
Wait a moment for initialization: The backend needs time to run migrations and start up. Wait 10-15 seconds after
docker compose up -dbefore testing. -
Rebuild if needed: If you pulled new code, rebuild the containers:
docker compose down docker compose build docker compose up -d
Make sure the backend server is running:
cd backend
npm run devEnsure PostgreSQL is running and the database exists:
createdb carrots_dev
cd backend
npm run prisma:migrate:devThe email or username is already registered. Try a different one or use the login endpoint instead.
Your access token may be expired or invalid. Login again to get a new token.