feat: generate secrets

master
Guillermo Pages 2 months ago
parent b3554c1310
commit 76ac7fe403

@ -103,6 +103,8 @@ 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
@ -110,6 +112,37 @@ 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:

@ -8,7 +8,11 @@
"build": "tsc",
"dev": "tsc --watch",
"test": "jest",
"prepublishOnly": "npm run build"
"prepublishOnly": "npm run build",
"generate:secrets": "node scripts/generate-session-secrets.js"
},
"bin": {
"swissoid-back-generate-secrets": "./scripts/generate-session-secrets.js"
},
"keywords": [
"swissoid",
@ -41,6 +45,7 @@
"typescript": "^5.9.2"
},
"files": [
"dist"
"dist",
"scripts/generate-session-secrets.js"
]
}

@ -0,0 +1,56 @@
#!/usr/bin/env node
/**
* Helper CLI to generate SESSION_SECRET and STATE_SIGNING_SECRET values.
*
* Usage:
* node scripts/generate-session-secrets.js
*
* Optional flags:
* --session-bytes=<number> (default: 48)
* --state-bytes=<number> (default: 32)
* --derive-state (derive STATE_SIGNING_SECRET from SESSION_SECRET)
*/
const { randomBytes } = require('node:crypto');
const defaults = {
sessionBytes: 48,
stateBytes: 32,
deriveState: false,
};
const options = process.argv.slice(2).reduce((acc, arg) => {
if (arg.startsWith('--session-bytes=')) {
acc.sessionBytes = parseInt(arg.split('=')[1], 10);
} else if (arg.startsWith('--state-bytes=')) {
acc.stateBytes = parseInt(arg.split('=')[1], 10);
} else if (arg === '--derive-state') {
acc.deriveState = true;
}
return acc;
}, { ...defaults });
const validateBytes = (value, flagName) => {
if (!Number.isInteger(value) || value <= 0) {
console.error(`Invalid value for ${flagName}. Expected a positive integer, received: ${value}`);
process.exit(1);
}
};
validateBytes(options.sessionBytes, '--session-bytes');
if (!options.deriveState) {
validateBytes(options.stateBytes, '--state-bytes');
}
const generateSecret = (bytes) => randomBytes(bytes).toString('base64');
const sessionSecret = generateSecret(options.sessionBytes);
const stateSecret = options.deriveState
? `${sessionSecret}-state-signing`
: generateSecret(options.stateBytes);
console.log(`SESSION_SECRET=${sessionSecret}`);
console.log(`STATE_SIGNING_SECRET=${stateSecret}`);
console.log('\n# Copy the values above into your deployment secret store (.env, Vault, etc.).');
console.log('# Keep them private and rotate on a regular schedule.');
Loading…
Cancel
Save