The sessionToToken method was incorrectly returning the session cookie token instead of the actual refreshToken from the database. This caused "No refresh token available" errors when users logged in via SSO (cross-domain cookie) because the /api/v1/auth/refresh endpoint expects the refreshToken field from the sessions table, not the cookie token. Now the method: - Fetches the session from database by cookie token - Uses existing refreshToken if available - Generates and stores a new refreshToken if missing - Returns the actual refreshToken that works with token refresh Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| docs | ||
| postgres/init | ||
| scripts | ||
| src | ||
| test | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| auth.ts | ||
| CLAUDE.md | ||
| docker-entrypoint.sh | ||
| Dockerfile | ||
| drizzle.config.ts | ||
| eslint.config.mjs | ||
| jest.config.js | ||
| MIGRATIONS.md | ||
| nest-cli.json | ||
| package.json | ||
| pnpm-lock.yaml | ||
| QUICKSTART.md | ||
| README.md | ||
| tsconfig.json | ||
Mana Core Auth
Central authentication and credit management system for the Mana Universe ecosystem.
Features
-
JWT-based Authentication (RS256 algorithm)
- User registration and login
- Refresh token rotation
- Multi-session management
- Device tracking
-
Credit System
- User balance management
- Transaction ledger with double-entry bookkeeping
- Optimistic locking for concurrency
- Daily free credits
- Signup bonus (150 credits)
- Idempotency for credit operations
-
Security
- Row-Level Security (RLS) on PostgreSQL
- Rate limiting
- CORS protection
- Helmet security headers
- SCRAM-SHA-256 password authentication
-
Infrastructure
- Docker-based deployment
- Traefik reverse proxy with automatic SSL
- PgBouncer connection pooling
- Redis caching
- Prometheus + Grafana monitoring
Quick Start
Development Setup
-
Install dependencies
pnpm install -
Generate JWT keys
cd mana-core-auth ./scripts/generate-keys.sh -
Set up environment variables
cp .env.example .env # Edit .env and add your JWT keys and other configuration -
Start PostgreSQL and Redis (using Docker)
docker-compose up postgres redis -d -
Run migrations
pnpm migration:generate pnpm migration:run -
Start development server
pnpm start:devThe server will be available at
http://localhost:3001/api/v1
Production Deployment (Docker)
-
Set up environment variables
cp .env.example .env # Edit .env with production values -
Generate JWT keys
./mana-core-auth/scripts/generate-keys.sh # Add the generated keys to .env -
Start all services
docker-compose up -d -
Check service health
docker-compose ps docker-compose logs -f mana-core-auth
API Endpoints
Authentication
POST /api/v1/auth/register
- Register a new user
- Body:
{ email, password, name? } - Returns: User object
POST /api/v1/auth/login
- Login with email and password
- Body:
{ email, password, deviceId?, deviceName? } - Returns:
{ user, accessToken, refreshToken, expiresIn, tokenType }
POST /api/v1/auth/refresh
- Refresh access token
- Body:
{ refreshToken } - Returns: New token pair
POST /api/v1/auth/logout
- Logout and revoke session
- Requires: Bearer token
- Returns: Success message
POST /api/v1/auth/validate
- Validate a JWT token
- Body:
{ token } - Returns:
{ valid, payload }
Credits
GET /api/v1/credits/balance
- Get current credit balance
- Requires: Bearer token
- Returns:
{ balance, freeCreditsRemaining, totalEarned, totalSpent }
POST /api/v1/credits/use
- Deduct credits from balance
- Requires: Bearer token
- Body:
{ amount, appId, description, idempotencyKey?, metadata? } - Returns: Transaction details
GET /api/v1/credits/transactions?limit=50&offset=0
- Get transaction history
- Requires: Bearer token
- Returns: Array of transactions
GET /api/v1/credits/purchases
- Get purchase history
- Requires: Bearer token
- Returns: Array of purchases
GET /api/v1/credits/packages
- Get available credit packages
- Requires: Bearer token
- Returns: Array of packages
Database Schema
Auth Schema
auth.users- User accountsauth.sessions- Active sessionsauth.passwords- Hashed passwordsauth.accounts- OAuth provider accountsauth.verification_tokens- Email verification & password resetauth.two_factor_auth- 2FA configurationauth.security_events- Security audit log
Credits Schema
credits.balances- User credit balancescredits.transactions- Transaction ledgercredits.packages- Available credit packagescredits.purchases- Purchase historycredits.usage_stats- Usage analytics
Environment Variables
See .env.example for all available configuration options.
Key variables:
DATABASE_URL- PostgreSQL connection stringJWT_PUBLIC_KEY- RS256 public key (PEM format)JWT_PRIVATE_KEY- RS256 private key (PEM format)REDIS_HOST,REDIS_PORT,REDIS_PASSWORD- Redis configurationSTRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET- Stripe integrationCORS_ORIGINS- Allowed origins for CORSCREDITS_SIGNUP_BONUS- Free credits on signup (default: 150)CREDITS_DAILY_FREE- Daily free credits (default: 5)
Development
Available Scripts
# Start development server with hot-reload
pnpm start:dev
# Build for production
pnpm build
# Start production server
pnpm start:prod
# Run tests
pnpm test
# Generate database migration
pnpm migration:generate
# Run migrations
pnpm migration:run
# Open Drizzle Studio (database GUI)
pnpm db:studio
# Lint and format
pnpm lint
pnpm format
Architecture
Token Flow
- User registers/logs in → Receives
accessToken(15min) +refreshToken(7 days) - Client stores tokens securely (httpOnly cookies on web, SecureStore on mobile)
- Client includes
Authorization: Bearer <accessToken>in requests - When access token expires, client uses refresh token to get new pair
- Refresh tokens are single-use (rotation for security)
Credit System
- Signup Bonus: 150 free credits on registration
- Daily Free Credits: 5 credits added every 24 hours
- Paid Credits: Purchased via Stripe (100 mana = €1)
- Usage Priority: Free credits used first, then paid credits
- Idempotency: Duplicate requests with same key are detected and ignored
- Concurrency: Optimistic locking prevents race conditions
Security Considerations
- JWT Keys: Generate strong RS256 keys and keep private key secure
- Database: Use strong passwords and enable SSL in production
- Redis: Always set a password for Redis
- CORS: Only allow trusted origins
- Rate Limiting: Configured via Traefik and NestJS throttler
- RLS Policies: Enforce data isolation at database level
- HTTPS: Always use SSL/TLS in production (via Traefik)
Monitoring
- Prometheus: Available at
http://localhost:9090 - Grafana: Available at
http://localhost:3000 - Logs:
docker-compose logs -f mana-core-auth
License
Private - Mana Universe
Support
For issues and questions, contact the development team.