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.txt

JavaScript (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

  1. Ensure credentials: 'include' is set in fetch
  2. Check that cookies are not blocked by browser
  3. 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 Secure flag is only set in production (HTTPS)

Last updated: December 2025