You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
5.1 KiB
Markdown
190 lines
5.1 KiB
Markdown
# swissoid-back
|
|
|
|
SwissOID authentication backend for Node.js applications. Provides reusable OIDC authentication components for integrating with SwissOID (Swiss eID).
|
|
|
|
## Features
|
|
|
|
- 🔐 Full OIDC Authorization Code Flow implementation
|
|
- 🍪 Session management with Redis
|
|
- 🔑 JWT verification with JWKS (for validating SwissOID ID tokens and optional DATs)
|
|
- 🎯 Built for di-why dependency injection
|
|
- 📦 Reusable authentication components
|
|
- 🔄 Configurable via environment variables or appConfig
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
npm install swissoid-back
|
|
```
|
|
|
|
## Requirements
|
|
|
|
- Node.js >= 18
|
|
- Redis server for session storage
|
|
- SwissOID client credentials
|
|
|
|
## Usage
|
|
|
|
### With express-knifey / graphql-knifey (Recommended)
|
|
|
|
`swissoid-back` integrates with `express-knifey` middleware handles so gateways/standalone services can share the same DI wiring used across Cronide:
|
|
|
|
```typescript
|
|
import DiContainer, { mergeLDs } from 'di-why';
|
|
import { apolloSubgraphServerModularLDGen } from 'graphql-knifey';
|
|
import { swissoidAuthLoadDict } from 'swissoid-back';
|
|
|
|
// Define middleware configuration including OIDC routes
|
|
const middlewareConfig = {
|
|
global: [
|
|
{ name: 'expressCorsMiddleware', priority: 90 },
|
|
{ name: 'expressCookieParserMiddleware', priority: 80 },
|
|
{ name: 'expressBodyParserMiddleware', priority: 70 },
|
|
{ name: 'oidcStandardRoutesMiddleware', priority: 60 },
|
|
],
|
|
'/graphql': [
|
|
{ name: 'expressGraphqlMiddleware', required: true, priority: -100 },
|
|
],
|
|
};
|
|
|
|
const diContainer = new DiContainer({
|
|
load: mergeLDs(
|
|
// GraphQL server with middleware config
|
|
apolloSubgraphServerModularLDGen({
|
|
resolvers,
|
|
typeDefs,
|
|
middlewareConfig
|
|
}),
|
|
|
|
// SwissOID authentication components
|
|
swissoidAuthLoadDict,
|
|
|
|
// Your other loaders...
|
|
)
|
|
});
|
|
```
|
|
|
|
### Direct Express Usage
|
|
|
|
```typescript
|
|
import { swissoidAuthLoadDict } from 'swissoid-back';
|
|
|
|
// Load OIDC routes directly (this will mount them on the express app)
|
|
await diContainer.load('oidcStandardRoutes');
|
|
```
|
|
|
|
### AppConfig Integration
|
|
|
|
swissoid-back provides an appConfigMap that can be merged with your application's configuration:
|
|
|
|
```typescript
|
|
import { swissoidMergeAppConfigMap } from 'swissoid-back';
|
|
|
|
const merged = swissoidMergeAppConfigMap(yourAppConfigMap);
|
|
export type AppConfig = ReturnType<typeof merged>;
|
|
```
|
|
|
|
### Configuration
|
|
|
|
Create a `.env` file with the required configuration (see `.env.example` for all options):
|
|
|
|
```env
|
|
# SwissOID Configuration
|
|
SWISSOID_ISSUER=https://api.swissoid.com
|
|
SWISSOID_CLIENT_ID=your-client-id
|
|
SWISSOID_CLIENT_SECRET=your-client-secret
|
|
SWISSOID_TOKEN_ENDPOINT=https://api.swissoid.com/token
|
|
SWISSOID_JWKS_URI=https://api.swissoid.com/.well-known/jwks.json
|
|
|
|
# Redis Configuration
|
|
REDIS_HOST=localhost
|
|
REDIS_PORT=6379
|
|
|
|
# Session Configuration
|
|
SESSION_COOKIE_NAME=connect.sid
|
|
SESSION_SECRET=your-session-secret
|
|
# Optional: override derived state signing secret
|
|
# STATE_SIGNING_SECRET=your-state-secret
|
|
|
|
# RP Configuration
|
|
RP_FRONTEND_URL=http://localhost:3000
|
|
COOKIE_DOMAIN=localhost
|
|
OIDC_REDIRECT_BASE_URL=http://localhost:3668
|
|
```
|
|
|
|
### Generating strong secrets
|
|
|
|
Use the helper script to produce high-entropy values for
|
|
`SESSION_SECRET` and `STATE_SIGNING_SECRET`:
|
|
|
|
```bash
|
|
npm run generate:secrets
|
|
```
|
|
|
|
You can also invoke the packaged CLI from your own project:
|
|
|
|
```bash
|
|
npx swissoid-back-generate-secrets
|
|
```
|
|
|
|
Example output:
|
|
|
|
```
|
|
SESSION_SECRET=8Qd8d...snipped
|
|
STATE_SIGNING_SECRET=Ob7v3...snipped
|
|
|
|
# Copy the values above into your deployment secret store (.env, Vault, etc.).
|
|
# Keep them private and rotate on a regular schedule.
|
|
```
|
|
|
|
- Pass `--derive-state` to derive the state secret from the session secret
|
|
(mirrors the default behaviour when `STATE_SIGNING_SECRET` is omitted).
|
|
- Adjust entropy with `--session-bytes=<n>` or `--state-bytes=<n>` if you need
|
|
different lengths (defaults: 48 bytes for the session secret and 32 for the
|
|
state secret).
|
|
|
|
## Routes
|
|
|
|
The package provides the following OIDC routes when loaded:
|
|
|
|
- `GET /login` - Initiates OIDC authorization flow
|
|
- `POST /oidc/callback` - Handles OIDC callback from SwissOID
|
|
- `GET /oidc/finalize` - Completes authentication and sets session (gateway subsequently mints a DAT for subgraphs)
|
|
- `GET /auth/status` - Returns current authentication status
|
|
- `POST /auth/logout` - Logs out the user
|
|
- `GET /auth/debug` - Debug endpoint to check session and cookie status
|
|
- `GET /auth/ping` - Connectivity test endpoint
|
|
|
|
## Components
|
|
|
|
The `swissoidAuthLoadDict` includes:
|
|
|
|
- **redisClient**: Redis connection for session storage
|
|
- **sessionService**: Session management service
|
|
- **cookieManager**: Cookie handling utilities
|
|
- **oidcStandardRoutes**: Express router with OIDC endpoints
|
|
- **oidcStandardRoutesMiddleware**: Middleware-compatible version for express-knifey integration
|
|
- **swissoidAppConfigMap**: AppConfig map with priority 60
|
|
|
|
## Exports
|
|
|
|
```typescript
|
|
// Main LoadDict for di-why
|
|
import { swissoidAuthLoadDict } from 'swissoid-back';
|
|
|
|
// AppConfig utilities
|
|
import { swissoidMergeAppConfigMap } from 'swissoid-back';
|
|
|
|
// Individual loaders if needed
|
|
import {
|
|
sessionService,
|
|
cookieManager,
|
|
oidcStandardRoutes,
|
|
oidcStandardRoutesMiddleware
|
|
} from 'swissoid-back';
|
|
```
|
|
|
|
## License
|
|
|
|
MIT
|