Verifier Dim B (homogeneity + code↔docs confrontation) flagged 5 ADRs stuck at "Partially Implemented" while the corresponding code is live. Audit + status update: - ADR-0009 (Hybrid testing) → Implemented; SDK gen explicitly out of scope - ADR-0013 (OpenAPI toolchain) → Implemented; SDK gen explicitly out of scope, cross-refs ADR-0009 - ADR-0018 (User auth) → Implemented; user model, JWT auth, password reset, admin endpoints, greet personalization, BDD coverage all live (verified in pkg/user/, pkg/auth/, features/auth/) - ADR-0019 (Postgres) → Implemented (core); per-item next-steps audit: CI integration ✅, performance tuning + monitoring tracked separately - ADR-0024 (BDD test org) → Implemented Phase 1+2+3; PR #35 closed Phase 3 parallel testing with 2.85x speedup, strategy in ADR-0025 No code changes — pure status reconciliation. The Status field is now the single source of truth for what's done vs deferred, removing the "forever Partial" doc drift the verifier flagged.
479 lines
17 KiB
Markdown
479 lines
17 KiB
Markdown
# 18. User Management and Authentication System
|
|
|
|
**Date:** 2026-04-06
|
|
**Status:** Implemented (user model, JWT auth, password-reset workflow, admin endpoints, greet personalization, BDD coverage all live; future enhancements like 2FA / email verification belong in separate ADRs)
|
|
**Authors:** Product Owner
|
|
**Decision Drivers:** Security, User Personalization, Admin Functionality
|
|
|
|
## Context
|
|
|
|
The dance-lessons-coach application currently lacks user management and authentication capabilities. To provide personalized experiences and administrative functions, we need to implement a secure user authentication system with PostgreSQL persistence.
|
|
|
|
## Decision
|
|
|
|
We will implement a user management and authentication system with the following characteristics:
|
|
|
|
### Core Features
|
|
|
|
1. **User Model**
|
|
- Username-based identification (no email/personal info)
|
|
- Password authentication with secure hashing
|
|
- User profile fields: description and current goal
|
|
- Admin flag for privileged users
|
|
|
|
2. **Authentication System**
|
|
- JWT-based authentication
|
|
- Secure password hashing (bcrypt)
|
|
- Session management
|
|
- Admin master password for non-persisted admin access
|
|
|
|
3. **Password Reset Workflow**
|
|
- Admin-assisted password reset (no email/phone required)
|
|
- Allow password reset flag for users
|
|
- Unauthenticated password reset endpoint for flagged users
|
|
|
|
4. **Integration Points**
|
|
- Greet service personalization based on authenticated user
|
|
- Admin-only endpoints for user management
|
|
- BDD test coverage for all authentication flows
|
|
- CI/CD pipeline updates for new dependencies
|
|
|
|
### Technical Implementation
|
|
|
|
#### Database Schema (PostgreSQL)
|
|
```sql
|
|
CREATE TABLE users (
|
|
id SERIAL PRIMARY KEY,
|
|
created_at TIMESTAMP WITH TIME ZONE,
|
|
updated_at TIMESTAMP WITH TIME ZONE,
|
|
deleted_at TIMESTAMP WITH TIME ZONE,
|
|
username VARCHAR(50) UNIQUE NOT NULL,
|
|
password_hash VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
current_goal TEXT,
|
|
is_admin BOOLEAN DEFAULT FALSE,
|
|
allow_password_reset BOOLEAN DEFAULT FALSE,
|
|
last_login TIMESTAMP WITH TIME ZONE
|
|
);
|
|
```
|
|
|
|
#### Technology Stack
|
|
- **ORM:** GORM (for PostgreSQL integration) - aligns with existing interface-based design
|
|
- **Authentication:** JWT with HS256 signing - stateless, scalable
|
|
- **Password Hashing:** bcrypt - industry standard for password storage
|
|
- **Validation:** go-playground/validator - consistent with existing validation approach
|
|
- **Database:** PostgreSQL (containerized) - production-ready database
|
|
- **Configuration:** Viper integration - consistent with existing config management
|
|
- **Logging:** Zerolog integration - consistent with existing logging approach
|
|
- **Telemetry:** OpenTelemetry support - consistent with existing observability
|
|
|
|
#### Architecture Alignment
|
|
|
|
The user management system follows the established dance-lessons-coach patterns:
|
|
|
|
1. **Interface-based Design:**
|
|
```go
|
|
type UserRepository interface {
|
|
CreateUser(user *User) error
|
|
GetUserByUsername(username string) (*User, error)
|
|
// ... other methods
|
|
}
|
|
|
|
type AuthService interface {
|
|
Authenticate(username, password string) (*User, error)
|
|
GenerateJWT(user *User) (string, error)
|
|
ValidateJWT(token string) (*User, error)
|
|
}
|
|
```
|
|
|
|
2. **Context-aware Services:**
|
|
```go
|
|
func (s *AuthService) Authenticate(ctx context.Context, username, password string) (*User, error) {
|
|
log.Trace().Ctx(ctx).Str("username", username).Msg("Authenticating user")
|
|
// ... authentication logic
|
|
}
|
|
```
|
|
|
|
3. **Configuration Integration:**
|
|
```go
|
|
type AuthConfig struct {
|
|
JWTSecret string `mapstructure:"jwt_secret"`
|
|
JWTExpiration time.Duration `mapstructure:"jwt_expiration"`
|
|
AdminUsername string `mapstructure:"admin_username"`
|
|
AdminMasterPassword string `mapstructure:"admin_master_password"`
|
|
}
|
|
```
|
|
|
|
4. **Chi Router Integration:**
|
|
```go
|
|
func (h *AuthHandler) RegisterRoutes(router chi.Router) {
|
|
router.Post("/register", h.handleRegister)
|
|
router.Post("/login", h.handleLogin)
|
|
// ... other routes
|
|
}
|
|
```
|
|
|
|
### Security Considerations
|
|
|
|
1. **Password Storage:** bcrypt with work factor 12
|
|
2. **JWT Security:**
|
|
- 30-minute expiration for access tokens
|
|
- Secure random signing key
|
|
- HTTPS-only cookies
|
|
- **Secret Rotation:** Multiple valid secrets with retention policy (see Issue #8)
|
|
3. **Admin Access:**
|
|
- Master password from environment variable
|
|
- Non-persisted admin user
|
|
- Full access to user management endpoints
|
|
- **Password Reset Control:** Only admins can flag users for reset
|
|
4. **Password Reset Security:**
|
|
- **Admin-Only Flagging:** Only authenticated admins can set `allow_password_reset` flag
|
|
- **Flag-Based Access:** Unauthenticated reset only works for admin-flagged users
|
|
- **Automatic Flag Clearing:** Flag is cleared after successful password reset
|
|
- **No Self-Service:** Users cannot flag themselves or others for reset
|
|
5. **Rate Limiting:** On authentication endpoints (3 attempts/hour for password reset)
|
|
6. **Input Validation:** Strict username validation (alphanumeric, 3-50 chars)
|
|
|
|
### API Endpoints
|
|
|
|
#### Public Endpoints
|
|
- `POST /api/v1/auth/register` - User registration
|
|
- `POST /api/v1/auth/login` - User login
|
|
- `POST /api/v1/auth/reset-password` - Password reset (for flagged users)
|
|
|
|
#### Authenticated Endpoints
|
|
- `GET /api/v1/users/me` - Get current user profile
|
|
- `PUT /api/v1/users/me` - Update current user profile
|
|
- `PUT /api/v1/users/me/password` - Change own password
|
|
|
|
#### Admin-Only Endpoints
|
|
- `GET /api/v1/admin/users` - List all users
|
|
- `POST /api/v1/admin/users/{username}/allow-reset` - Allow password reset
|
|
- `DELETE /api/v1/admin/users/{username}` - Delete user
|
|
|
|
### Integration with Existing Services
|
|
|
|
#### Greet Service Enhancement
|
|
|
|
The authentication system integrates seamlessly with the existing greet service by leveraging Go's context package:
|
|
|
|
```go
|
|
// Updated greet service with authentication support
|
|
func (s *Service) Greet(ctx context.Context, name string) string {
|
|
log.Trace().Ctx(ctx).Str("name", name).Msg("Greet function called")
|
|
|
|
// Extract authenticated username from context using existing auth package
|
|
if username := auth.GetUsernameFromContext(ctx); username != "" {
|
|
log.Trace().Ctx(ctx).Str("authenticated_user", username).Msg("Using authenticated username")
|
|
return "Hello " + username + "!"
|
|
}
|
|
|
|
// Fallback to original behavior for backward compatibility
|
|
if name == "" {
|
|
return "Hello world!"
|
|
}
|
|
return "Hello " + name + "!"
|
|
}
|
|
```
|
|
|
|
#### Authentication Middleware
|
|
|
|
The system includes Chi middleware for JWT validation:
|
|
|
|
```go
|
|
func (s *AuthService) Middleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
// Extract and validate JWT token
|
|
token := auth.ExtractTokenFromRequest(r)
|
|
if token == "" {
|
|
next.ServeHTTP(w, r)
|
|
return // Continue without authentication
|
|
}
|
|
|
|
// Validate token and extract user
|
|
if user, err := s.ValidateJWT(ctx, token); err == nil {
|
|
// Add user to context for downstream services
|
|
ctx = auth.SetUserInContext(ctx, user)
|
|
r = r.WithContext(ctx)
|
|
}
|
|
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
})
|
|
}
|
|
```
|
|
|
|
#### Server Integration
|
|
|
|
The authentication middleware is added to the Chi router stack:
|
|
|
|
```go
|
|
// In server.go
|
|
func (s *Server) getAllMiddlewares() []func(http.Handler) http.Handler {
|
|
middlewares := []func(http.Handler) http.Handler{
|
|
middleware.StripSlashes,
|
|
middleware.Recoverer,
|
|
s.authService.Middleware, // Add auth middleware
|
|
}
|
|
|
|
if s.withOTEL {
|
|
middlewares = append(middlewares, func(next http.Handler) http.Handler {
|
|
return otelhttp.NewHandler(next, "")
|
|
})
|
|
}
|
|
|
|
return middlewares
|
|
}
|
|
```
|
|
|
|
#### Configuration Extension
|
|
|
|
The existing Config struct is extended with authentication settings:
|
|
|
|
```go
|
|
// In config.go
|
|
type AuthConfig struct {
|
|
JWTSecret string `mapstructure:"jwt_secret"`
|
|
JWTExpiration time.Duration `mapstructure:"jwt_expiration"`
|
|
AdminUsername string `mapstructure:"admin_username"`
|
|
AdminMasterPassword string `mapstructure:"admin_master_password"`
|
|
}
|
|
|
|
type DatabaseConfig struct {
|
|
Host string `mapstructure:"host"`
|
|
Port int `mapstructure:"port"`
|
|
User string `mapstructure:"user"`
|
|
Password string `mapstructure:"password"`
|
|
Name string `mapstructure:"name"`
|
|
SSLMode string `mapstructure:"ssl_mode"`
|
|
}
|
|
|
|
// Extended Config struct
|
|
type Config struct {
|
|
Server ServerConfig `mapstructure:"server"`
|
|
Shutdown ShutdownConfig `mapstructure:"shutdown"`
|
|
Logging LoggingConfig `mapstructure:"logging"`
|
|
Telemetry TelemetryConfig `mapstructure:"telemetry"`
|
|
API APIConfig `mapstructure:"api"`
|
|
Auth AuthConfig `mapstructure:"auth"`
|
|
Database DatabaseConfig `mapstructure:"database"`
|
|
}
|
|
```
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
|
|
1. **Personalized Experience:** Users see their username in greetings
|
|
2. **Admin Capabilities:** Secure administrative functions
|
|
3. **Password Recovery:** Admin-assisted workflow without contact info
|
|
4. **Security:** Proper authentication and authorization
|
|
5. **Extensibility:** Foundation for future user-based features
|
|
|
|
### Negative
|
|
|
|
1. **Increased Complexity:** Additional dependencies and configuration
|
|
2. **Database Requirement:** PostgreSQL container needed for development
|
|
3. **Migration Complexity:** Existing tests need updates
|
|
4. **CI/CD Changes:** Pipeline needs adjustment for new dependencies
|
|
5. **Performance Impact:** Authentication middleware adds overhead
|
|
|
|
### Neutral
|
|
|
|
1. **Learning Curve:** Team needs to learn GORM and JWT
|
|
2. **Testing Overhead:** Additional BDD scenarios required
|
|
3. **Documentation Needs:** Comprehensive API documentation required
|
|
|
|
## Alternatives Considered
|
|
|
|
### Alternative 1: No Authentication
|
|
- **Pros:** Simpler, no database needed
|
|
- **Cons:** No personalization, no admin functions
|
|
- **Rejected:** Doesn't meet product requirements
|
|
|
|
### Alternative 2: Session-based Auth
|
|
- **Pros:** Traditional approach, well-understood
|
|
- **Cons:** State management complexity, scaling issues
|
|
- **Rejected:** JWT provides better scalability
|
|
|
|
### Alternative 3: OAuth/OIDC
|
|
- **Pros:** Industry standard, delegation to identity providers
|
|
- **Cons:** Complex setup, external dependencies
|
|
- **Rejected:** Overkill for current requirements
|
|
|
|
### Alternative 4: Pure SQL (no ORM)
|
|
- **Pros:** No ORM overhead, direct control
|
|
- **Cons:** More boilerplate, manual query building
|
|
- **Rejected:** GORM provides good balance of control and convenience
|
|
|
|
## Implementation Plan
|
|
|
|
This implementation builds upon the completed phases and follows the established dance-lessons-coach patterns.
|
|
|
|
### Phase 10: User Management Foundation (Next Phase)
|
|
|
|
**Objective:** Establish database models and basic user management
|
|
|
|
1. **Add Dependencies:**
|
|
- `github.com/golang-jwt/jwt/v5` for JWT authentication
|
|
- `golang.org/x/crypto` for bcrypt password hashing
|
|
- `gorm.io/gorm` and `gorm.io/driver/postgres` for ORM
|
|
|
|
2. **Create User Package:**
|
|
- `pkg/user/models.go` - User model and GORM repository
|
|
- `pkg/user/repository.go` - Interface-based repository
|
|
- `pkg/user/service.go` - User management service
|
|
|
|
3. **Database Setup:**
|
|
- Add PostgreSQL container to `docker-compose.yml`
|
|
- Create database migration scripts
|
|
- Implement GORM database connection
|
|
|
|
4. **Configuration Extension:**
|
|
- Extend `Config` struct with `AuthConfig` and `DatabaseConfig`
|
|
- Add environment variable bindings with `DLC_` prefix
|
|
- Update `LoadConfig()` function
|
|
|
|
### Phase 11: Authentication System
|
|
|
|
**Objective:** Implement secure authentication with JWT
|
|
|
|
1. **Auth Service:**
|
|
- `pkg/auth/service.go` - JWT generation/validation
|
|
- `pkg/auth/middleware.go` - Chi authentication middleware
|
|
- `pkg/auth/context.go` - Context utilities for user data
|
|
|
|
2. **Authentication Endpoints:**
|
|
- `POST /api/v1/auth/register` - User registration
|
|
- `POST /api/v1/auth/login` - User login
|
|
- `POST /api/v1/auth/refresh` - Token refresh
|
|
|
|
3. **Password Security:**
|
|
- Implement bcrypt password hashing (work factor 12)
|
|
- Add password validation rules
|
|
- Implement secure password comparison
|
|
|
|
4. **Admin Authentication:**
|
|
- Master password configuration
|
|
- Non-persisted admin user
|
|
- Admin middleware for privileged endpoints
|
|
|
|
### Phase 12: Integration & Personalization
|
|
|
|
**Objective:** Integrate authentication with existing services
|
|
|
|
1. **Greet Service Enhancement:**
|
|
- Update `pkg/greet/greet.go` to check authenticated username
|
|
- Maintain backward compatibility
|
|
- Add context-based username extraction
|
|
|
|
2. **User Profile Endpoints:**
|
|
- `GET /api/v1/users/me` - Get current user profile
|
|
- `PUT /api/v1/users/me` - Update profile (description, goal)
|
|
- `PUT /api/v1/users/me/password` - Change password
|
|
|
|
3. **Admin Endpoints:**
|
|
- `GET /api/v1/admin/users` - List all users
|
|
- `POST /api/v1/admin/users/{username}/allow-reset` - Allow password reset
|
|
- `DELETE /api/v1/admin/users/{username}` - Delete user
|
|
|
|
### Phase 13: Password Reset & Testing
|
|
|
|
**Objective:** Implement password reset workflow and comprehensive testing
|
|
|
|
1. **Password Reset Workflow:**
|
|
- `POST /api/v1/auth/reset-password` - Unauthenticated reset for flagged users
|
|
- Admin flag management
|
|
- Rate limiting for reset endpoints
|
|
|
|
2. **BDD Test Scenarios:**
|
|
- User registration and login
|
|
- Personalized greetings for authenticated users
|
|
- Admin password reset workflow
|
|
- Error handling and validation
|
|
|
|
3. **Unit & Integration Tests:**
|
|
- Password hashing/verification
|
|
- JWT token generation/validation
|
|
- Repository methods
|
|
- Authentication middleware
|
|
|
|
### Phase 14: CI/CD & Documentation
|
|
|
|
**Objective:** Update pipeline and create comprehensive documentation
|
|
|
|
1. **CI/CD Updates:**
|
|
- Add PostgreSQL service to CI environment
|
|
- Update dependency management
|
|
- Add authentication test suite
|
|
- Implement security scanning
|
|
|
|
2. **Documentation:**
|
|
- Update `AGENTS.md` with new architecture
|
|
- Create user management wiki page
|
|
- Update API documentation with Swagger
|
|
- Add configuration examples
|
|
|
|
3. **Deployment Preparation:**
|
|
- Create database migration guide
|
|
- Update Docker configuration
|
|
- Add environment variable documentation
|
|
- Create rollback plan
|
|
|
|
## Alignment with Existing Phases
|
|
|
|
This implementation builds upon the completed phases:
|
|
|
|
- **Phase 1-3:** Uses existing Go 1.26.1, Chi router, Zerolog, and interface-based design
|
|
- **Phase 5:** Extends Viper configuration management
|
|
- **Phase 6:** Integrates with graceful shutdown patterns
|
|
- **Phase 7:** Maintains OpenTelemetry compatibility
|
|
- **Phase 8:** Follows existing build system patterns
|
|
- **Phase 9:** Preserves trace-level logging approach
|
|
|
|
## Backward Compatibility
|
|
|
|
The implementation maintains full backward compatibility:
|
|
|
|
1. **Greet Service:** Falls back to original behavior when no authentication
|
|
2. **API Endpoints:** Existing `/api/v1/greet/*` endpoints unchanged
|
|
3. **Configuration:** All existing config options preserved
|
|
4. **Logging:** Maintains existing Zerolog integration
|
|
5. **Telemetry:** OpenTelemetry continues to work unchanged
|
|
|
|
## Success Metrics
|
|
|
|
1. **Security:** No authentication bypass vulnerabilities
|
|
2. **Performance:** <50ms auth middleware overhead
|
|
3. **Reliability:** 99.9% uptime for auth endpoints
|
|
4. **Adoption:** 80% of API calls authenticated within 3 months
|
|
5. **Satisfaction:** User feedback on personalization features
|
|
|
|
## Open Questions
|
|
|
|
1. Should we implement refresh tokens for longer sessions?
|
|
2. What should be the maximum session duration?
|
|
3. Should we add IP-based rate limiting for auth endpoints?
|
|
4. What username characters should be allowed beyond alphanumeric?
|
|
5. Should we implement account lockout after failed attempts?
|
|
|
|
## Future Considerations
|
|
|
|
1. **Multi-factor Authentication:** For enhanced security
|
|
2. **OAuth Integration:** For third-party identity providers
|
|
3. **User Activity Logging:** For audit trails
|
|
4. **Password Strength Meter:** For better user experience
|
|
5. **Account Recovery:** Email/phone-based recovery options
|
|
6. **JWT Secret Rotation:** Implement secret persistence and rotation mechanism (Issue #8)
|
|
|
|
## References
|
|
|
|
- [GORM Documentation](https://gorm.io/)
|
|
- [JWT RFC 7519](https://tools.ietf.org/html/rfc7519)
|
|
- [OWASP Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html)
|
|
- [bcrypt Password Hashing](https://en.wikipedia.org/wiki/Bcrypt)
|
|
|
|
**Approved by:** [Product Owner]
|
|
**Approval Date:** [To be determined]
|
|
**Implementation Target:** Q2 2024 |