diff --git a/package-lock.json b/package-lock.json index 70e2d3cf1..02e353dd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "ejs": "^3.1.8", "express": "^4.18.2", "ipaddr.js": "^2.0.1", + "jose": "^4.13.1", "jsdom": "^21.1.0", "jsonwebtoken": "^9.0.0", "ldapjs": "^2.3.3", @@ -3111,7 +3112,8 @@ }, "node_modules/jose": { "version": "4.13.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.13.1.tgz", + "integrity": "sha512-MSJQC5vXco5Br38mzaQKiq9mwt7lwj2eXpgpRyQYNHYt2lq1PjkWa7DLXX0WVcQLE9HhMh3jPiufS7fhJf+CLQ==", "funding": { "url": "https://github.com/sponsors/panva" } diff --git a/package.json b/package.json index b53a92eb5..fd24df78e 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "ejs": "^3.1.8", "express": "^4.18.2", "ipaddr.js": "^2.0.1", + "jose": "^4.13.1", "jsdom": "^21.1.0", "jsonwebtoken": "^9.0.0", "ldapjs": "^2.3.3", diff --git a/src/blobs.js b/src/blobs.js index 2e1550dba..71c242336 100644 --- a/src/blobs.js +++ b/src/blobs.js @@ -22,6 +22,8 @@ exports = module.exports = { PROXY_AUTH_TOKEN_SECRET: 'proxy_auth_token_secret', + OIDC_KEY: 'oidc_key', // this is only JWT private key, the public key will be derived + CERT_PREFIX: 'cert', CERT_SUFFIX: 'cert', diff --git a/src/oidc.js b/src/oidc.js index 95d86fe23..4f0f8b1ca 100644 --- a/src/oidc.js +++ b/src/oidc.js @@ -14,6 +14,7 @@ exports = module.exports = { const assert = require('assert'), BoxError = require('./boxerror.js'), + blobs = require('./blobs.js'), constants = require('./constants.js'), database = require('./database.js'), debug = require('debug')('box:oidc'), @@ -25,6 +26,7 @@ const assert = require('assert'), paths = require('./paths.js'), http = require('http'), HttpError = require('connect-lastmile').HttpError, + jose = require('jose'), safe = require('safetydance'), settings = require('./settings.js'), users = require('./users.js'), @@ -547,6 +549,18 @@ async function start() { const { Provider } = await import('oidc-provider'); + // TODO we may want to rotate those in the future + let key = await blobs.getString(blobs.OIDC_KEY); + if (!key) { + debug('Generating new OIDC EdDSA key'); + const { privateKey } = await jose.generateKeyPair('EdDSA'); + key = await jose.exportJWK(privateKey); + await blobs.setString(blobs.OIDC_KEY, JSON.stringify(key)); + } else { + debug('Using existing OIDC EdDSA key'); + key = JSON.parse(key); + } + const configuration = { findAccount, renderError, @@ -556,6 +570,9 @@ async function start() { return `${ROUTE_PREFIX}/interaction/${interaction.uid}`; } }, + jwks: { + keys: [ key ] + }, claims: { email: ['email', 'email_verified'], profile: [ 'family_name', 'given_name', 'locale', 'name', 'preferred_username' ]