Skip to content

Commit

Permalink
auth decision record
Browse files Browse the repository at this point in the history
  • Loading branch information
vhscom committed Jan 10, 2025
1 parent bbcb52e commit 00005d9
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 35 deletions.
58 changes: 27 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,32 @@

Authentication experiment using Hono + Cloudflare Workers.

## Security Features

See [ADR-001: Authentication Implementation](docs/adr/001-auth-implementation.md) for detailed technical decisions and security features.

## Database Schema

```mermaid
erDiagram
account {
text id PK
text email UK "not null"
text password_data "not null"
text created_at "default current_timestamp"
}
session {
text id PK
text user_id FK "not null"
text user_agent "not null"
text ip_address "not null"
text expires_at "not null"
text created_at "not null"
}
account ||--o{ session : "has"
account {
integer id PK
text email UK "not null"
text password_data "not null"
text created_at "default current_timestamp"
}
session {
text id PK
integer user_id FK "not null"
text user_agent "not null"
text ip_address "not null"
text expires_at "not null"
text created_at "not null"
}
account ||--o{ session : "has"
```

## Security Features

- NIST SP 800-132 compliant password hashing
- Secure session management with HTTP-only cookies
- Cookie signing for tamper protection
- IP address tracking for session security
- Automatic session expiration
- SQLite with a Turso distributed database

## Prerequisites

1. Install [Turso CLI](https://docs.turso.tech/reference/cli)
Expand All @@ -56,10 +51,6 @@ turso db tokens create auth-db

The database can be managed using SQL scripts in the `src/db` directory:

- `schema.sql`: Creates tables and sets up the schema
- `reset.sql`: Drops all tables for testing/reset
- `migration.sql`: Handles schema updates

```bash
# First time setup: Create tables
turso db shell auth-db < src/db/schema.sql
Expand All @@ -77,8 +68,6 @@ turso db shell auth-db "select name from sqlite_master where type='table'"
turso db shell auth-db ".schema account"
```

Passwords are stored salted and hashed as described in the data format below.

## Password Data Format

Passwords are stored in a combined format using industry standard algorithms and NIST SP 800-132 recommendations:
Expand Down Expand Up @@ -106,6 +95,13 @@ All binary data (salt, hash, digest) is stored as Base64. The format allows for
- Your `TURSO_URL` and `TURSO_AUTH_TOKEN` will be automatically available
3. Use strong password for the `COOKIE_SIGNING` secret.

Required environment variables:
```bash
TURSO_URL="libsql://your-db.turso.io"
TURSO_AUTH_TOKEN="your-auth-token"
COOKIE_SIGNING="your-cookie-secret" # For session management
```

## Development

```bash
Expand Down
120 changes: 120 additions & 0 deletions docs/adr/001-auth-implementation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# ADR-001: Authentication Implementation

## Status

Accepted

## Context

We need to implement a secure authentication system for our web application targeting ~100 users. While we have no specific compliance requirements, the system should follow security best practices and provide a good user experience. This aligns with typical early-stage startup needs.

## Decision

### Password Storage

- Using PBKDF2 with SHA-384 for password hashing
- 100,000 iterations for key stretching
- 128-bit (16 byte) random salt per NIST SP 800-132
- Additional integrity digest using SHA-384
- Version tracking for future algorithm upgrades
- Storage format: `$pbkdf2-shaXXX$v1$iterations$salt$hash$digest`

### Session Management

- Session IDs generated using nanoid
- 21 characters (vs 36 for UUID)
- URL-safe by default
- Better distribution for database indexes
- ~121 bits of randomness (sufficient for session IDs)
- Efficient cookie storage
- Fast generation
- HTTP-only, secure, Host-only cookies (no Domain attribute) with strict same-site policy
- Server-side session storage in SQLite database
- Signed cookies using HMAC SHA-256
- Sliding expiration with 7-day default timeout
- IP address and user agent tracking
- Session limits per user (default: 3)
- Automatic cleanup of expired sessions

### Security Features

- Constant-time comparisons for password verification
- NIST SP 800-63-3 compliant password requirements
- Protection against timing attacks
- Secure cookie attributes (httpOnly, secure, sameSite)
- Database-backed session validation
- Automatic session pruning
- Rate limiting ready

## Consequences

### Positive

- Strong security following industry standards
- Future-proof with version tracking
- Clean separation of concerns
- Maintainable codebase
- Type-safe implementation
- Easy to upgrade security parameters

### Negative

- More complex than simple password hashing
- Additional database storage requirements
- Slightly higher computational overhead

## Notes

- OWASP guidelines recommend 210,000 iterations
- Cloudflare limits us to 100,000 iterations
- Password format designed for upgradability
- Digest may be used to prevent tampering
- Session management considers scalability
- All security parameters are configurable
- Implementation follows NIST guidelines

## Alternatives Considered

### Bcrypt

- Pros:
- Well-established and battle-tested
- Adaptive work factor
- Built-in salt generation
- Memory-hard function making hardware acceleration difficult
- Cons:
- Fixed output size (60 characters)
- Less flexible than PBKDF2
- Limited to 72 bytes of password data
- No version tracking built into format

### Argon2

- Pros:
- Winner of the Password Hashing Competition
- Memory-hard and highly resistant to GPU attacks
- Configurable memory, parallelism, and iterations
- Modern algorithm with strong security properties
- Cons:
- Relatively newer compared to PBKDF2 and Bcrypt
- Less widespread library support
- More complex implementation
- Higher system requirements for memory usage

We chose PBKDF2 because:

- Widespread support across languages and platforms
- FIPS-140 compliance if needed in future
- Simpler implementation while still meeting security requirements
- Flexibility in hash function selection
- Easy to adjust iterations as computational power increases
- Built-in support in many cryptographic libraries

## References

- [IETF RFC 2898 §5.2](https://datatracker.ietf.org/doc/html/rfc2898#section-5.2)
- [IETF RFC 9106](https://datatracker.ietf.org/doc/rfc9106/) (informational)
- [NIST SP 800-132](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf)
- [NIST SP 800-63-3](https://pages.nist.gov/800-63-3/)
- [OWASP Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html)
- [Cookie Security: SameSite FAQ](https://web.dev/samesite-cookies-explained/)
4 changes: 2 additions & 2 deletions src/accounts/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ interface AuthResult {
const passwordConfig: PasswordConfig = {
algorithm: "PBKDF2",
bits: 384,
saltBytes: 16, // NIST recommended minimum (128 bits)
iterations: 100000,
saltBytes: 16, // NIST recommended minimum (128 bits) (2025)
iterations: 100000, // OWASP guidance for SHA-512 is 210,000 (2025)
version: 1,
};

Expand Down
4 changes: 2 additions & 2 deletions src/accounts/session-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ export interface SessionConfig {

/**
* Default session configuration.
* - 5 max sessions per user
* - 3 max sessions per user
* - 7 day session duration
* - 30 day maintenance window
* - Secure cookie settings with HTTP-only and strict same-site policy
*/
export const defaultSessionConfig: SessionConfig = {
maxSessions: 5,
maxSessions: 3,
sessionDuration: 60 * 60 * 24 * 7, // 7 days in seconds
maintenanceWindow: 30, // days
cookie: {
Expand Down

0 comments on commit 00005d9

Please sign in to comment.