Authentication
StacksFinder uses session-based authentication with httpOnly cookies.
Authentication
StacksFinder uses session-based authentication with httpOnly cookies.
Overview
sequenceDiagram
participant C as Client
participant S as Server
participant DB as Database
C->>S: POST /auth/login (email, password)
S->>DB: Verify credentials (Argon2id)
DB-->>S: User found
S->>DB: Create session
S-->>C: Set-Cookie: session=xxx (httpOnly)
C->>S: GET /api/v1/projects (Cookie: session=xxx)
S->>DB: Validate session
S-->>C: 200 OK (projects)
Registration
Create a new user account.
Request
POST /api/v1/auth/register
Content-Type: application/json
{
"email": "user@example.com",
"password": "securePassword123",
"name": "John Doe" // optional
}Response (201 Created)
{
"success": true,
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"name": "John Doe"
}
}A session cookie is automatically set.
Validation Rules
| Field | Rule |
|---|---|
email |
Valid email format |
password |
8-128 characters |
name |
1-100 characters (optional) |
Errors
| Status | Code | Cause |
|---|---|---|
| 400 | VALIDATION_ERROR |
Invalid input |
| 409 | USER_EXISTS |
Email already registered |
| 429 | RATE_LIMITED |
Too many attempts |
Login
Authenticate and receive a session cookie.
Request
POST /api/v1/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "securePassword123"
}Response (200 OK)
{
"success": true,
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"name": "John Doe"
}
}Session Cookie
The response includes a Set-Cookie header:
Set-Cookie: session=abc123...; Path=/; HttpOnly; Secure; SameSite=Strict; Max-Age=2592000| Attribute | Value | Purpose |
|---|---|---|
HttpOnly |
true | Prevent XSS access |
Secure |
true (production) | HTTPS only |
SameSite |
Strict | Prevent CSRF |
Max-Age |
30 days | Session duration |
Errors
| Status | Code | Cause |
|---|---|---|
| 401 | INVALID_CREDENTIALS |
Wrong email or password |
| 429 | RATE_LIMITED |
Too many attempts |
Logout
Invalidate the current session.
Request
POST /api/v1/auth/logout
Cookie: session=abc123...Response (200 OK)
{
"success": true
}The session cookie is cleared.
Get Current Session
Check if the user is authenticated and get user info.
Request
GET /api/v1/auth/session
Cookie: session=abc123...Response (200 OK)
{
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"name": "John Doe"
}
}Response (401 Unauthorized)
If no valid session exists:
{
"user": null
}Using Authentication in Requests
Include the session cookie in all authenticated requests:
cURL
# Login and save cookie
curl -X POST https://stacksfinder.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"secret123"}' \
-c cookies.txt
# Use cookie in subsequent requests
curl https://stacksfinder.com/api/v1/projects \
-b cookies.txtJavaScript (fetch)
// Login
const loginResponse = await fetch('/api/v1/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
credentials: 'include' // Important: include cookies
});
// Authenticated request
const projectsResponse = await fetch('/api/v1/projects', {
credentials: 'include' // Include session cookie
});SvelteKit
In SvelteKit, the session is automatically available via locals.user:
// +page.server.ts
export const load = async ({ locals }) => {
if (!locals.user) {
redirect(302, '/login');
}
return { user: locals.user };
};Security Measures
Password Hashing
Passwords are hashed using Argon2id (memory-hard algorithm):
- Memory: 64 MB
- Iterations: 3
- Parallelism: 4
This makes brute-force attacks extremely expensive.
Session Security
| Measure | Implementation |
|---|---|
| Token Generation | Cryptographically secure random bytes |
| Storage | Server-side only (hashed in database) |
| Cookie Flags | httpOnly, Secure, SameSite=Strict |
| Expiration | 30 days (rolling) |
Rate Limiting
| Endpoint | Limit | Window |
|---|---|---|
/auth/register |
5 requests | 1 hour |
/auth/login |
10 requests | 15 minutes |
Common Issues
"401 Unauthorized" on Every Request
- Ensure
credentials: 'include'is set in fetch - Check that cookies are not blocked by browser
- Verify the session hasn't expired (30 days)
"CORS Error" on Login
In development, ensure you're using the same origin:
- Frontend:
http://localhost:5173 - API:
http://localhost:5173/api/v1
Session Not Persisting
- Check browser settings for blocking third-party cookies
- Ensure
Secureflag is only set in production (HTTPS)