Authentication System
This page documents the authentication system implementation for contributors
working in internal/auth/. If you’re an operator configuring authentication
for a server, see the operator auth guide
instead.
The authentication system spans three layers: a protocol handler in the gateway that calls core gRPC services, service implementations that enforce security invariants (timing-safe comparisons, argon2id hashing), and a repository layer that persists tokens and sessions to PostgreSQL. The sections below trace each layer from the wire inward.
Overview
Section titled “Overview”HoloMUSH uses a three-layer authentication architecture:
Service Responsibilities
Section titled “Service Responsibilities”AuthService
Section titled “AuthService”Handles core authentication operations.
| Method | Purpose | Source |
|---|---|---|
Login | Authenticate player, create session | internal/auth/auth_service.go:81 |
Logout | Invalidate session | internal/auth/auth_service.go:197 |
ValidateSession | Verify token, update last-seen | internal/auth/auth_service.go:215 |
SelectCharacter | Bind character to session | internal/auth/auth_service.go:254 |
CharacterService
Section titled “CharacterService”Manages character creation with validation.
| Method | Purpose | Source |
|---|---|---|
Create | Create character (default limit) | internal/auth/character_service.go:56 |
CreateWithMaxCharacters | Create with custom limit | internal/auth/character_service.go:61 |
Character creation validates:
- Name format (2-32 chars, letters and spaces, normalized to Initial Caps)
- Name uniqueness (case-insensitive)
- Player character limit (default: 5)
- Starting location assignment
PasswordResetService
Section titled “PasswordResetService”Handles password reset flow.
| Method | Purpose | Source |
|---|---|---|
RequestReset | Generate reset token for email | internal/auth/reset_service.go:80 |
ValidateToken | Verify token validity and expiration | internal/auth/reset_service.go:118 |
ResetPassword | Update password, invalidate tokens | internal/auth/reset_service.go:148 |
Security Implementation
Section titled “Security Implementation”Timing Attack Prevention
Section titled “Timing Attack Prevention”The auth service uses a dummy hash for non-existent users to prevent username enumeration:
Login(username, password): 1. Look up user by username 2. If not found -> use dummy hash (still verify to maintain constant time) 3. Verify password against hash (real or dummy) 4. Return same error for "user not found" and "wrong password"See internal/auth/auth_service.go:67-76 for the dummy hash constant and internal/auth/auth_service.go:81-130
for the timing-safe implementation.
Password Hashing
Section titled “Password Hashing”Passwords are hashed using argon2id with OWASP-recommended parameters:
| Parameter | Value |
|---|---|
| Time | 1 iteration |
| Memory | 64 MB |
| Parallelism | 4 threads |
| Salt | 16 bytes (random) |
| Output | 32 bytes |
Implementation: internal/auth/hasher.go:30-36
Constant-Time Token Comparison
Section titled “Constant-Time Token Comparison”Session token verification uses crypto/subtle.ConstantTimeCompare to prevent
timing attacks that could leak token prefixes.
See internal/auth/session.go:115-125 for the implementation with security comments.
Session Token Design
Section titled “Session Token Design”Sessions use opaque random tokens rather than signed JWTs. Key design choices:
| Aspect | Implementation |
|---|---|
| Token size | 32 bytes (256 bits of entropy) |
| Storage | SHA256 hash in database |
| Expiry | TTL after detach (per-role, default 24h) |
| Revocation | Instant (delete database row) |
| Character bind | Mutable (update session row) |
See ADR 0001 for the rationale behind choosing opaque tokens over signed JWTs.
Authentication Flows
Section titled “Authentication Flows”Telnet Flow
Section titled “Telnet Flow”Key Protocol Handler Methods
Section titled “Key Protocol Handler Methods”The telnet handler calls through the gRPC CoreClient interface, not service methods directly:
| Command | Handler Method | gRPC RPC | Source |
|---|---|---|---|
connect | handleConnect | AuthenticatePlayer | internal/telnet/gateway_handler.go |
create | handleCreate | CreateCharacter | internal/telnet/gateway_handler.go |
play | handlePlay | SelectCharacter | internal/telnet/gateway_handler.go |
quit | handleQuit | Logout | internal/telnet/gateway_handler.go |
Repository Interfaces
Section titled “Repository Interfaces”PlayerRepository
Section titled “PlayerRepository”internal/auth/player.go:128-151Manages player account persistence including username lookups, email lookups, and password updates.
WebSessionRepository
Section titled “WebSessionRepository”internal/auth/session.go:127-156Manages session persistence including token hash lookups, last-seen updates, character binding, and expiration cleanup.
PasswordResetRepository
Section titled “PasswordResetRepository”internal/auth/reset.goManages reset token persistence with token hash lookups and player-based cleanup.
Related Documentation
Section titled “Related Documentation”- Design Spec - Full authentication design
- ADR 0001 - Token design decision
- Operator Guide - Deployment and configuration