first: commit
commit
50fbb2224e
@ -0,0 +1,122 @@
|
|||||||
|
db_backups/
|
||||||
|
|
||||||
|
# build
|
||||||
|
build/
|
||||||
|
build-test/
|
||||||
|
# keys
|
||||||
|
.keys/
|
||||||
|
# vscode
|
||||||
|
.vscode/
|
||||||
|
# JWT
|
||||||
|
*RS256.key*
|
||||||
|
# nyc
|
||||||
|
.nyc_output
|
||||||
|
converage
|
||||||
|
*.lcov
|
||||||
|
# vim
|
||||||
|
*.swp
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
AuthKey_XSVS859WJA.p8
|
||||||
|
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
.env.test
|
||||||
|
.env.prod
|
||||||
|
.env.auth
|
||||||
|
.env.vault
|
||||||
|
|
||||||
|
# .pem files
|
||||||
|
pk*.pem
|
||||||
|
rsa*.pem
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# next.js build output
|
||||||
|
.next
|
||||||
|
|
||||||
|
# nuxt.js build output
|
||||||
|
.nuxt
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# Elastic Beanstalk Files
|
||||||
|
.elasticbeanstalk/*
|
||||||
|
!.elasticbeanstalk/*.cfg.yml
|
||||||
|
!.elasticbeanstalk/*.global.yml
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci --only=production
|
||||||
|
|
||||||
|
# Copy source and build
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build:prod
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 3700
|
||||||
|
|
||||||
|
# Start the application
|
||||||
|
CMD ["node", "build/src/index.js"]
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Copy source
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 3700
|
||||||
|
|
||||||
|
# Development mode with hot reload
|
||||||
|
CMD ["npm", "run", "dev"]
|
||||||
@ -0,0 +1,180 @@
|
|||||||
|
# Quick Start Guide - playchoo-auth
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. **Redis** running locally or accessible
|
||||||
|
2. **SwissOID client credentials** (client ID + secret)
|
||||||
|
3. **Node.js 20+** installed
|
||||||
|
|
||||||
|
## Local Development Setup
|
||||||
|
|
||||||
|
### 1. Install Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Configure Environment
|
||||||
|
|
||||||
|
Copy `.env` and update with your values:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env .env.local
|
||||||
|
# Edit .env.local with your SwissOID credentials
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Prepare the shared Redis instance
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Ensure the shared network exists (no-op if it already does)
|
||||||
|
docker network create playchoo_redis_network || true
|
||||||
|
|
||||||
|
# Start the Redis service from py-playchoo-api (or attach your own instance to the same network)
|
||||||
|
(cd ../py-playchoo-api && docker compose -f docker-compose.dev.yml up redis)
|
||||||
|
```
|
||||||
|
|
||||||
|
> If you run the Node service directly on your machine, set `REDIS_URL` to
|
||||||
|
> `redis://localhost:6379`. Inside Docker the compose file rewrites it to
|
||||||
|
> `redis://redis:6379` automatically.
|
||||||
|
|
||||||
|
### 4. Start the Auth Service
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
The service will start on `http://localhost:3700`.
|
||||||
|
|
||||||
|
### 5. Test the Endpoints
|
||||||
|
|
||||||
|
**Health Check**:
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3700/healthz
|
||||||
|
```
|
||||||
|
|
||||||
|
**Auth Status** (should return unauthenticated):
|
||||||
|
```bash
|
||||||
|
curl http://localhost:3700/auth/status
|
||||||
|
```
|
||||||
|
|
||||||
|
**Login** (open in browser):
|
||||||
|
```
|
||||||
|
http://localhost:3700/login
|
||||||
|
```
|
||||||
|
|
||||||
|
This will redirect to SwissOID, and after login, redirect back to your `RP_FRONTEND_URL`.
|
||||||
|
|
||||||
|
## Production Deployment
|
||||||
|
|
||||||
|
### 1. Build the Application
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build:prod
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Update Production Environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.prod .env.prod.local
|
||||||
|
# Edit .env.prod.local with production values
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Deploy with Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verify Integration
|
||||||
|
|
||||||
|
### Check Session Storage
|
||||||
|
|
||||||
|
After logging in, check Redis for your session:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Connect to Redis
|
||||||
|
redis-cli
|
||||||
|
|
||||||
|
# List all session keys
|
||||||
|
KEYS session:*
|
||||||
|
|
||||||
|
# View a specific session
|
||||||
|
GET session:<your-session-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
You should see JSON like:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sub": "user-uuid-from-swissoid",
|
||||||
|
"email": "user@example.com",
|
||||||
|
"iat": 1234567890,
|
||||||
|
"exp": 1234575090
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Cookie Setting
|
||||||
|
|
||||||
|
Use browser DevTools:
|
||||||
|
1. Open Network tab
|
||||||
|
2. Visit `http://localhost:3700/login`
|
||||||
|
3. Complete SwissOID flow
|
||||||
|
4. Check Application → Cookies
|
||||||
|
5. Verify `playchoo_session` cookie is set with:
|
||||||
|
- Domain: `.playchoo.com` (or `localhost` in dev)
|
||||||
|
- Secure: `true` (in production)
|
||||||
|
- HttpOnly: `true`
|
||||||
|
- SameSite: `None` (or `Lax`)
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "Session not found" in API
|
||||||
|
|
||||||
|
- Verify Redis is running: `redis-cli ping`
|
||||||
|
- Check cookie name matches in both services: `SESSION_COOKIE_NAME`
|
||||||
|
- Ensure `REDIS_URL` is the same in auth service and API
|
||||||
|
|
||||||
|
### SwissOID callback fails
|
||||||
|
|
||||||
|
- Verify `OIDC_REDIRECT_BASE_URL` matches your registered redirect URI
|
||||||
|
- Check SwissOID client is configured for `authorization_code` flow
|
||||||
|
- Ensure `SWISSOID_CLIENT_SECRET` is correct
|
||||||
|
|
||||||
|
### Cookie not set
|
||||||
|
|
||||||
|
- Check `RP_COOKIE_DOMAIN` matches your domain structure
|
||||||
|
- For localhost, use `localhost` (no leading dot)
|
||||||
|
- For production, use `.playchoo.com` (with leading dot)
|
||||||
|
- Verify `CORS_ALLOWED_ORIGIN` includes your frontend URL
|
||||||
|
|
||||||
|
### CORS errors
|
||||||
|
|
||||||
|
- Add frontend URL to `CORS_ALLOWED_ORIGIN`
|
||||||
|
- Ensure frontend uses `credentials: 'include'` in fetch
|
||||||
|
- Check browser console for specific CORS error
|
||||||
|
|
||||||
|
## Environment Variables Reference
|
||||||
|
|
||||||
|
| Variable | Description | Example |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `SWISSOID_CLIENT_ID` | SwissOID client identifier | `playchoo` |
|
||||||
|
| `SWISSOID_CLIENT_SECRET` | SwissOID client secret | `<secret>` |
|
||||||
|
| `SESSION_COOKIE_NAME` | Name of session cookie | `playchoo_session` |
|
||||||
|
| `SESSION_TTL` | Session lifetime (seconds) | `7200` (2 hours) |
|
||||||
|
| `REDIS_URL` | Redis connection string | `redis://redis:6379` |
|
||||||
|
| `RP_FRONTEND_URL` | Frontend redirect after login | `https://app.playchoo.com` |
|
||||||
|
| `RP_COOKIE_DOMAIN` | Cookie domain | `.playchoo.com` |
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. **Integrate with py-playchoo-api**: See `/py-playchoo-api/README.md`
|
||||||
|
2. **Update Frontend**: Install `swissoid-front` and configure provider
|
||||||
|
3. **Configure Production Secrets**: Use a secrets manager for sensitive values
|
||||||
|
4. **Set up Monitoring**: Add alerts for Redis health, auth failures
|
||||||
|
5. **Test End-to-End**: Complete login flow from frontend → auth → API
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues or questions, check:
|
||||||
|
- [swissoid-back README](../swissoid-back/README.md)
|
||||||
|
- [Integration Summary](../SWISSOID_INTEGRATION_SUMMARY.md)
|
||||||
|
- SwissOID documentation
|
||||||
@ -0,0 +1,122 @@
|
|||||||
|
# playchoo-auth
|
||||||
|
|
||||||
|
SwissOID authentication service for Playchoo. Manages OIDC login flow, session storage in Redis, and provides authentication endpoints for the Playchoo stack.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- **SwissOID Integration**: Uses `swissoid-back` for OIDC authorization code flow
|
||||||
|
- **Session Storage**: Redis-backed sessions with HttpOnly cookies
|
||||||
|
- **Shared Sessions**: `api.playchoo.com` and `app.playchoo.com` share session state via Redis
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
- `GET /login` - Initiates SwissOID OIDC flow
|
||||||
|
- `POST /oidc/callback` - Handles SwissOID callback
|
||||||
|
- `GET /auth/status` - Returns current authentication status
|
||||||
|
- `POST /auth/logout` - Destroys session
|
||||||
|
- `GET /healthz` - Health check
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
```env
|
||||||
|
# SwissOID Configuration
|
||||||
|
SWISSOID_CLIENT_ID=playchoo
|
||||||
|
SWISSOID_CLIENT_SECRET=<your-secret>
|
||||||
|
SWISSOID_ISSUER=https://api.swissoid.com
|
||||||
|
SWISSOID_JWKS_URI=https://api.swissoid.com/.well-known/jwks.json
|
||||||
|
SWISSOID_TOKEN_ENDPOINT=https://api.swissoid.com/token
|
||||||
|
SWISSOID_AUTHORIZE_ENDPOINT=https://api.swissoid.com/authorize
|
||||||
|
|
||||||
|
# Session Configuration
|
||||||
|
SESSION_COOKIE_NAME=playchoo_session
|
||||||
|
REFRESH_COOKIE_NAME=playchoo_refresh
|
||||||
|
SESSION_SECRET=<generate-random-secret>
|
||||||
|
STATE_SIGNING_SECRET=<generate-random-secret>
|
||||||
|
SESSION_TTL=7200
|
||||||
|
REFRESH_TTL=604800
|
||||||
|
|
||||||
|
# Redis (shared with py-playchoo-api)
|
||||||
|
REDIS_URL=redis://redis:6379
|
||||||
|
|
||||||
|
# RP Configuration
|
||||||
|
OIDC_REDIRECT_BASE_URL=https://auth.playchoo.com
|
||||||
|
RP_FRONTEND_URL=https://app.playchoo.com
|
||||||
|
RP_COOKIE_DOMAIN=.playchoo.com
|
||||||
|
POST_LOGIN_PATH=/dashboard
|
||||||
|
```
|
||||||
|
|
||||||
|
> When running the service directly on your host (outside Docker), override
|
||||||
|
> `REDIS_URL` to `redis://localhost:6379`. The Docker Compose files remap it to
|
||||||
|
> `redis://redis:6379` so the container can reach the shared Redis service.
|
||||||
|
|
||||||
|
## Local Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Ensure the shared Redis network exists (run once)
|
||||||
|
docker network create playchoo_redis_network || true
|
||||||
|
|
||||||
|
# Start the Redis service from py-playchoo-api (or attach your own instance to the same network)
|
||||||
|
(cd ../py-playchoo-api && docker compose -f docker-compose.dev.yml up redis)
|
||||||
|
|
||||||
|
# In a new terminal, start the auth service
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
The service will start on `http://localhost:3700` and will reuse the Redis
|
||||||
|
container from `py-playchoo-api` through the `playchoo_redis_network` network.
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Development
|
||||||
|
docker-compose -f docker-compose.dev.yml up
|
||||||
|
|
||||||
|
# Production
|
||||||
|
docker-compose up
|
||||||
|
```
|
||||||
|
|
||||||
|
## Session Format
|
||||||
|
|
||||||
|
Sessions stored in Redis under key `session:<sessionId>`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sub": "user-uuid-from-swissoid",
|
||||||
|
"email": "user@example.com",
|
||||||
|
"iat": 1234567890,
|
||||||
|
"exp": 1234575090
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration
|
||||||
|
|
||||||
|
### Python API (py-playchoo-api)
|
||||||
|
|
||||||
|
The Python API reads sessions from the same Redis instance:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Retrieve session from cookie
|
||||||
|
session_id = request.cookies.get('playchoo_session')
|
||||||
|
session_data = redis_client.get(f'session:{session_id}')
|
||||||
|
user_uuid = json.loads(session_data)['sub']
|
||||||
|
```
|
||||||
|
|
||||||
|
### Frontend (playchoo-nextjs)
|
||||||
|
|
||||||
|
Uses `swissoid-front` React provider:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { SwissOIDAuthProvider } from 'swissoid-front';
|
||||||
|
|
||||||
|
<SwissOIDAuthProvider baseUrl="https://auth.playchoo.com">
|
||||||
|
<App />
|
||||||
|
</SwissOIDAuthProvider>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- [`swissoid-back` README](../swissoid-back/README.md) - OIDC backend integration
|
||||||
|
- [`swissoid-front` README](../swissoid-front/README.md) - React frontend helpers
|
||||||
|
- [Playchoo API README](../py-playchoo-api/README.md) - Session lookup implementation
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
playchoo-auth:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
ports:
|
||||||
|
- "3700:3700"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
- APP_PORT=3700
|
||||||
|
- REDIS_URL=${REDIS_URL:-redis://redis:6379}
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
- /app/node_modules
|
||||||
|
networks:
|
||||||
|
- playchoo_redis_network
|
||||||
|
command: npm run dev
|
||||||
|
|
||||||
|
networks:
|
||||||
|
playchoo_redis_network:
|
||||||
|
name: playchoo_redis_network
|
||||||
|
external: true
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
playchoo-auth:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "3700:3700"
|
||||||
|
env_file:
|
||||||
|
- .env.prod
|
||||||
|
environment:
|
||||||
|
NODE_ENV: ${NODE_ENV:-production}
|
||||||
|
APP_PORT: ${APP_PORT:-3700}
|
||||||
|
APPLICATION_NAME: ${APPLICATION_NAME:-Playchoo Auth}
|
||||||
|
CORS_ALLOWED_ORIGIN: ${CORS_ALLOWED_ORIGIN}
|
||||||
|
SWISSOID_CLIENT_ID: ${SWISSOID_CLIENT_ID}
|
||||||
|
SWISSOID_CLIENT_SECRET: ${SWISSOID_CLIENT_SECRET}
|
||||||
|
SWISSOID_ISSUER: ${SWISSOID_ISSUER}
|
||||||
|
SWISSOID_JWKS_URI: ${SWISSOID_JWKS_URI}
|
||||||
|
SWISSOID_TOKEN_ENDPOINT: ${SWISSOID_TOKEN_ENDPOINT}
|
||||||
|
SWISSOID_AUTHORIZE_ENDPOINT: ${SWISSOID_AUTHORIZE_ENDPOINT}
|
||||||
|
REDIS_URL: ${REDIS_URL}
|
||||||
|
SESSION_COOKIE_NAME: ${SESSION_COOKIE_NAME:-playchoo_session}
|
||||||
|
REFRESH_COOKIE_NAME: ${REFRESH_COOKIE_NAME:-playchoo_refresh}
|
||||||
|
SESSION_SECRET: ${SESSION_SECRET}
|
||||||
|
STATE_SIGNING_SECRET: ${STATE_SIGNING_SECRET}
|
||||||
|
SESSION_TTL: ${SESSION_TTL:-7200}
|
||||||
|
REFRESH_TTL: ${REFRESH_TTL:-604800}
|
||||||
|
OIDC_REDIRECT_BASE_URL: ${OIDC_REDIRECT_BASE_URL}
|
||||||
|
RP_FRONTEND_URL: ${RP_FRONTEND_URL}
|
||||||
|
RP_COOKIE_DOMAIN: ${RP_COOKIE_DOMAIN}
|
||||||
|
POST_LOGIN_PATH: ${POST_LOGIN_PATH:-/dashboard}
|
||||||
|
ALLOW_CONTINUE_PARAM: ${ALLOW_CONTINUE_PARAM:-true}
|
||||||
|
LOGGER_LOG: ${LOGGER_LOG:-1}
|
||||||
|
LOGGER_DEBUG: ${LOGGER_DEBUG:-0}
|
||||||
|
networks:
|
||||||
|
- playchoo_redis_network
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
networks:
|
||||||
|
playchoo_redis_network:
|
||||||
|
name: playchoo_redis_network
|
||||||
|
external: true
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "playchoo-auth",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "SwissOID authentication service for Playchoo",
|
||||||
|
"main": "build/src/index.js",
|
||||||
|
"type": "commonjs",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"build:prod": "tsc",
|
||||||
|
"start": "node build/src/index.js",
|
||||||
|
"dev": "ts-node src/index.ts",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": ["swissoid", "auth", "oidc"],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"di-why": "^0.20.1",
|
||||||
|
"express": "^5.1.0",
|
||||||
|
"express-knifey": "^1.1.3",
|
||||||
|
"ioredis": "^5.8.1",
|
||||||
|
"swissoid-back": "^2.2.5",
|
||||||
|
"swiss-army-knifey": "^1.36.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/express": "^4.17.21",
|
||||||
|
"@types/node": "^20.11.0",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "^5.3.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
import { isMeantToBeTrue, UnknownEnv } from 'swiss-army-knifey';
|
||||||
|
|
||||||
|
type Env = UnknownEnv & {
|
||||||
|
APPLICATION_NAME?: string;
|
||||||
|
APP_PORT?: string;
|
||||||
|
NODE_ENV?: string;
|
||||||
|
CORS_ALLOWED_ORIGIN?: string;
|
||||||
|
CORS_CREDENTIALS?: string;
|
||||||
|
COOKIE_DOMAIN?: string;
|
||||||
|
SECURE_COOKIES?: string;
|
||||||
|
TRUST_PROXY?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const appConfigMap = (env: Env) => ({
|
||||||
|
applicationName: env.APPLICATION_NAME || 'Playchoo Auth',
|
||||||
|
serverPort: (env.APP_PORT !== undefined && parseInt(env.APP_PORT, 10)) || 3700,
|
||||||
|
nodeEnv: env.NODE_ENV || 'development',
|
||||||
|
|
||||||
|
corsAllowedOrigin: env.CORS_ALLOWED_ORIGIN || 'http://localhost:3000',
|
||||||
|
corsCredentials:
|
||||||
|
env.CORS_CREDENTIALS !== undefined
|
||||||
|
? isMeantToBeTrue(env.CORS_CREDENTIALS)
|
||||||
|
: true,
|
||||||
|
|
||||||
|
cookieDomain: env.COOKIE_DOMAIN,
|
||||||
|
secureCookies:
|
||||||
|
env.SECURE_COOKIES !== undefined
|
||||||
|
? isMeantToBeTrue(env.SECURE_COOKIES)
|
||||||
|
: env.NODE_ENV === 'production',
|
||||||
|
|
||||||
|
trustProxy: env.TRUST_PROXY || '1',
|
||||||
|
healthCheckPath: '/healthz',
|
||||||
|
healthCheckResponse: 'ok',
|
||||||
|
});
|
||||||
|
|
||||||
|
export default appConfigMap;
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
import 'dotenv/config';
|
||||||
|
import DiContainer from 'di-why/build/src/DiContainer';
|
||||||
|
import appConfigMap from './config/appConfigMap';
|
||||||
|
import { loadDict } from './loaders';
|
||||||
|
|
||||||
|
async function bootstrap() {
|
||||||
|
console.log('[Bootstrap] Starting Playchoo Auth Service...');
|
||||||
|
|
||||||
|
// Create DI container with all loaders
|
||||||
|
const diContainer = new DiContainer({
|
||||||
|
load: {
|
||||||
|
...loadDict,
|
||||||
|
// Override appConfig with our custom config
|
||||||
|
appConfig: {
|
||||||
|
factory: () => appConfigMap(process.env),
|
||||||
|
locateDeps: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start the Express server (includes all middleware, OIDC routes, health checks)
|
||||||
|
await diContainer.load('expressLauncher');
|
||||||
|
|
||||||
|
console.log('[Bootstrap] Playchoo Auth Service started successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrap().catch((error) => {
|
||||||
|
console.error('[Bootstrap] Failed to start Playchoo Auth Service:', error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
import { mergeLDs } from 'di-why';
|
||||||
|
import expressLoadDict, {
|
||||||
|
EXPRESS_MIDDLEWARE,
|
||||||
|
buildMiddlewareConfig,
|
||||||
|
} from 'express-knifey';
|
||||||
|
import type { MiddlewareConfig, MiddlewarePathConfig } from 'express-knifey';
|
||||||
|
import { swissoidAuthLoadDict } from 'swissoid-back';
|
||||||
|
|
||||||
|
const middlewareConfig: MiddlewarePathConfig = buildMiddlewareConfig([
|
||||||
|
{
|
||||||
|
path: '*',
|
||||||
|
middleware: [
|
||||||
|
EXPRESS_MIDDLEWARE.trustProxy,
|
||||||
|
EXPRESS_MIDDLEWARE.cors,
|
||||||
|
EXPRESS_MIDDLEWARE.cookieParser,
|
||||||
|
EXPRESS_MIDDLEWARE.bodyParser,
|
||||||
|
EXPRESS_MIDDLEWARE.urlencoded,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: EXPRESS_MIDDLEWARE.healthCheck.defaultPath ?? '/healthz',
|
||||||
|
middleware: [EXPRESS_MIDDLEWARE.healthCheck],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const globalPath = '*';
|
||||||
|
const enhancedGlobal: MiddlewareConfig[] = [
|
||||||
|
...(middlewareConfig[globalPath] ?? []),
|
||||||
|
{ name: 'oidcStandardRoutesMiddleware', priority: 60 },
|
||||||
|
];
|
||||||
|
|
||||||
|
middlewareConfig[globalPath] = enhancedGlobal;
|
||||||
|
|
||||||
|
export const loadDict = mergeLDs(
|
||||||
|
expressLoadDict,
|
||||||
|
swissoidAuthLoadDict,
|
||||||
|
{
|
||||||
|
middlewareConfig: {
|
||||||
|
factory: () => middlewareConfig,
|
||||||
|
locateDeps: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export default loadDict;
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"module": "commonjs",
|
||||||
|
"lib": ["ES2020"],
|
||||||
|
"outDir": "./build",
|
||||||
|
"rootDir": "./",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"moduleResolution": "node"
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "build"]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue