Overview
Add a new auth FastAPI microservice providing user registration, login, and JWT-based authentication. This is the foundation for all user-specific features (Discogs OAuth connection, collection/wantlist sync).
Reference Implementations
- apollonia (
api/endpoints/auth.py, shared/models.py) — JWT auth pattern (register/login/me, bcrypt passwords, OAuth2PasswordBearer)
- vinyldigger (
backend/src/models/user.py, backend/src/api/v1/endpoints/auth.py) — Production auth implementation with the same stack
Technical Approach
New Service: auth/
FastAPI microservice following existing discogsography patterns (structlog, Prometheus metrics, health checks, non-root Docker, uv).
Ports: 8004 (API), 8005 (health)
Endpoints:
POST /api/v1/auth/register — Create account (email, password)
POST /api/v1/auth/token — Login, returns JWT access token
GET /api/v1/auth/me — Get current user (requires Bearer token)
GET /health — Health check
PostgreSQL Schema
users table (from vinyldigger backend/src/models/user.py):
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
hashed_password VARCHAR(255) NOT NULL,
is_active BOOLEAN DEFAULT TRUE NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);
CREATE INDEX ON users(email);
oauth_tokens table (from vinyldigger backend/src/models/oauth_token.py) — stores Discogs OAuth tokens per user:
CREATE TYPE oauth_provider AS ENUM ('discogs');
CREATE TABLE oauth_tokens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
provider oauth_provider NOT NULL,
access_token VARCHAR(5000) NOT NULL,
access_token_secret VARCHAR(5000), -- OAuth 1.0a only
provider_user_id VARCHAR(255), -- Discogs user ID
provider_username VARCHAR(255), -- Discogs username (cached for API calls)
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
UNIQUE(user_id, provider)
);
app_config table — stores Discogs app credentials (admin-configured, not env vars per vinyldigger pattern):
CREATE TABLE app_config (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
key VARCHAR(255) UNIQUE NOT NULL,
value TEXT NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);
-- Keys: discogs_consumer_key, discogs_consumer_secret
Dependencies
# adapt from vinyldigger backend/pyproject.toml
python-jose = {extras = ["cryptography"]} # JWT signing/verification
passlib = {extras = ["bcrypt"]} # Password hashing
python-multipart = "*" # OAuth2PasswordRequestForm
JWT Configuration
class AuthConfig(BaseSettings):
secret_key: str # JWT_SECRET_KEY env var (required)
algorithm: str = "HS256"
access_token_expire_minutes: int = 30
Validation Rules
- Email: unique, valid format (vinyldigger uses email, not username)
- Password: minimum 8 chars
Admin Interface
Expose a simple admin endpoint for setting Discogs app credentials (consumer key/secret) that stores them in app_config rather than environment variables. This matches vinyldigger's pattern of per-instance credential management.
Docker Compose
Add auth service to docker-compose.yml:
auth:
build: ./auth
ports: ["8004:8004", "8005:8005"]
environment:
- POSTGRES_ADDRESS=postgres:5432
- REDIS_URL=redis://redis:6379 # needed for OAuth request token storage
- JWT_SECRET_KEY=${JWT_SECRET_KEY}
depends_on: [postgres, redis]
Note: Redis is already in docker-compose.yml for existing services.
Acceptance Criteria
Part of
Parent: #60 — feat: Discogs user integration — authenticate, sync collection & wantlist
Next step: #57 — Discogs OAuth 1.0a connection
Overview
Add a new
authFastAPI microservice providing user registration, login, and JWT-based authentication. This is the foundation for all user-specific features (Discogs OAuth connection, collection/wantlist sync).Reference Implementations
api/endpoints/auth.py,shared/models.py) — JWT auth pattern (register/login/me, bcrypt passwords, OAuth2PasswordBearer)backend/src/models/user.py,backend/src/api/v1/endpoints/auth.py) — Production auth implementation with the same stackTechnical Approach
New Service:
auth/FastAPI microservice following existing discogsography patterns (structlog, Prometheus metrics, health checks, non-root Docker, uv).
Ports: 8004 (API), 8005 (health)
Endpoints:
POST /api/v1/auth/register— Create account (email, password)POST /api/v1/auth/token— Login, returns JWT access tokenGET /api/v1/auth/me— Get current user (requires Bearer token)GET /health— Health checkPostgreSQL Schema
userstable (from vinyldiggerbackend/src/models/user.py):oauth_tokenstable (from vinyldiggerbackend/src/models/oauth_token.py) — stores Discogs OAuth tokens per user:app_configtable — stores Discogs app credentials (admin-configured, not env vars per vinyldigger pattern):Dependencies
JWT Configuration
Validation Rules
Admin Interface
Expose a simple admin endpoint for setting Discogs app credentials (consumer key/secret) that stores them in
app_configrather than environment variables. This matches vinyldigger's pattern of per-instance credential management.Docker Compose
Add
authservice todocker-compose.yml:Note: Redis is already in docker-compose.yml for existing services.
Acceptance Criteria
authmicroservice starts and passes health checks/mereturns 401 for missing/invalid tokensusersandoauth_tokenstables created in PostgreSQL with indexesapp_configtable allows admin to configure Discogs credentials via APIdocker-compose upincludes auth service.env.examplePart of
Parent: #60 — feat: Discogs user integration — authenticate, sync collection & wantlist
Next step: #57 — Discogs OAuth 1.0a connection