express-openid-connect
Advanced tools
Comparing version 2.4.0 to 2.5.0
@@ -464,2 +464,7 @@ // Type definitions for express-openid-connect | ||
tokenEndpointParams?: TokenParameters; | ||
/** | ||
* Http timeout for oidc client requests in milliseconds. Default is 5000. Minimum is 500. | ||
*/ | ||
httpTimeout?: number; | ||
} | ||
@@ -536,2 +541,12 @@ | ||
/** | ||
* A Function for generating a session id when using a custom session store. | ||
* For full details see the documentation for express-session | ||
* at [genid](https://github.com/expressjs/session/blob/master/README.md#genid). | ||
* If encrypted cookie storage is used or no value is provided, a default implementation is used. | ||
* Be aware the default implmentation is slightly different in this library as compared to the | ||
* default session id generation used express-session. | ||
*/ | ||
genid?: (req: OpenidRequest) => string; | ||
/** | ||
* If you want your session duration to be rolling, eg reset everytime the | ||
@@ -538,0 +553,0 @@ * user is active on your site, set this to a `true`. If you want the session |
@@ -8,3 +8,2 @@ const { strict: assert, AssertionError } = require('assert'); | ||
} = require('jose'); | ||
const crypto = require('crypto'); | ||
const { promisify } = require('util'); | ||
@@ -18,3 +17,3 @@ const cookie = require('cookie'); | ||
const epoch = () => (Date.now() / 1000) | 0; | ||
const CHUNK_BYTE_SIZE = 4000; | ||
const MAX_COOKIE_SIZE = 4096; | ||
@@ -49,2 +48,3 @@ function attachSessionObject(req, sessionName, value) { | ||
const { | ||
genid: generateId, | ||
absoluteDuration, | ||
@@ -55,2 +55,12 @@ rolling: rollingEnabled, | ||
const { transient: emptyTransient, ...emptyCookieOptions } = cookieConfig; | ||
emptyCookieOptions.expires = emptyTransient ? 0 : new Date(); | ||
const emptyCookie = cookie.serialize( | ||
`${sessionName}.0`, | ||
'', | ||
emptyCookieOptions | ||
); | ||
const cookieChunkSize = MAX_COOKIE_SIZE - emptyCookie.length; | ||
let keystore = new JWKS.KeyStore(); | ||
@@ -97,7 +107,5 @@ | ||
) { | ||
const cookieOptions = { | ||
...cookieConfig, | ||
expires: cookieConfig.transient ? 0 : new Date(exp * 1000), | ||
}; | ||
delete cookieOptions.transient; | ||
const cookies = req[COOKIES]; | ||
const { transient: cookieTransient, ...cookieOptions } = cookieConfig; | ||
cookieOptions.expires = cookieTransient ? 0 : new Date(exp * 1000); | ||
@@ -110,3 +118,3 @@ // session was deleted or is empty, this matches all session cookies (chunked or unchunked) | ||
); | ||
for (const cookieName of Object.keys(req[COOKIES])) { | ||
for (const cookieName of Object.keys(cookies)) { | ||
if (cookieName.match(`^${sessionName}(?:\\.\\d)?$`)) { | ||
@@ -124,2 +132,3 @@ res.clearCookie(cookieName, { | ||
); | ||
const value = encrypt(JSON.stringify(req[sessionName]), { | ||
@@ -131,15 +140,33 @@ iat, | ||
const chunkCount = Math.ceil(value.length / CHUNK_BYTE_SIZE); | ||
const chunkCount = Math.ceil(value.length / cookieChunkSize); | ||
if (chunkCount > 1) { | ||
debug('cookie size greater than %d, chunking', CHUNK_BYTE_SIZE); | ||
debug('cookie size greater than %d, chunking', cookieChunkSize); | ||
for (let i = 0; i < chunkCount; i++) { | ||
const chunkValue = value.slice( | ||
i * CHUNK_BYTE_SIZE, | ||
(i + 1) * CHUNK_BYTE_SIZE | ||
i * cookieChunkSize, | ||
(i + 1) * cookieChunkSize | ||
); | ||
const chunkCookieName = `${sessionName}.${i}`; | ||
res.cookie(chunkCookieName, chunkValue, cookieOptions); | ||
} | ||
if (sessionName in cookies) { | ||
debug('replacing non chunked cookie with chunked cookies'); | ||
res.clearCookie(sessionName, { | ||
domain: cookieConfig.domain, | ||
path: cookieConfig.path, | ||
}); | ||
} | ||
} else { | ||
res.cookie(sessionName, value, cookieOptions); | ||
for (const cookieName of Object.keys(cookies)) { | ||
debug('replacing chunked cookies with non chunked cookies'); | ||
if (cookieName.match(`^${sessionName}\\.\\d$`)) { | ||
res.clearCookie(cookieName, { | ||
domain: cookieConfig.domain, | ||
path: cookieConfig.path, | ||
}); | ||
} | ||
} | ||
} | ||
@@ -313,3 +340,3 @@ } | ||
const id = existingSessionValue || crypto.randomBytes(16).toString('hex'); | ||
const id = existingSessionValue || generateId(req); | ||
@@ -316,0 +343,0 @@ onHeaders(res, () => store.setCookie(id, req, res, { iat })); |
@@ -35,5 +35,6 @@ const { Issuer, custom } = require('openid-client'); | ||
}; | ||
options.timeout = 5000; | ||
options.timeout = config.httpTimeout; | ||
return options; | ||
}; | ||
const applyHttpOptionsCustom = (entity) => | ||
@@ -40,0 +41,0 @@ (entity[custom.http_options] = defaultHttpOptions); |
const Joi = require('joi'); | ||
const crypto = require('crypto'); | ||
const { defaultState: getLoginState } = require('./hooks/getLoginState'); | ||
const isHttps = /^https:/i; | ||
const defaultSessionIdGenerator = () => crypto.randomBytes(16).toString('hex'); | ||
const paramsSchema = Joi.object({ | ||
@@ -41,2 +44,6 @@ secret: Joi.alternatives([ | ||
store: Joi.object().optional(), | ||
genid: Joi.function() | ||
.maxArity(1) | ||
.optional() | ||
.default(() => defaultSessionIdGenerator), | ||
cookie: Joi.object({ | ||
@@ -188,2 +195,3 @@ domain: Joi.string().optional(), | ||
}), | ||
httpTimeout: Joi.number().optional().min(500).default(5000), | ||
}); | ||
@@ -190,0 +198,0 @@ |
{ | ||
"name": "express-openid-connect", | ||
"version": "2.4.0", | ||
"version": "2.5.0", | ||
"description": "Express middleware to protect web applications using OpenID Connect.", | ||
@@ -17,3 +17,3 @@ "homepage": "https://github.com/auth0/express-openid-connect", | ||
"start:example": "node ./examples/run_example.js", | ||
"test": "mocha", | ||
"test": "mocha --max-http-header-size=16384", | ||
"test:ci": "nyc --reporter=lcov npm test", | ||
@@ -33,10 +33,10 @@ "docs": "typedoc --options typedoc.js index.d.ts", | ||
"cookie": "^0.4.1", | ||
"debug": "^4.1.1", | ||
"futoin-hkdf": "^1.3.2", | ||
"http-errors": "^1.7.3", | ||
"debug": "^4.3.2", | ||
"futoin-hkdf": "^1.3.3", | ||
"http-errors": "^1.8.0", | ||
"joi": "^17.4.0", | ||
"jose": "^2.0.5", | ||
"on-headers": "^1.0.2", | ||
"openid-client": "^4.0.0", | ||
"p-memoize": "^4.0.0", | ||
"openid-client": "^4.7.4", | ||
"p-memoize": "^4.0.1", | ||
"url-join": "^4.0.1" | ||
@@ -43,0 +43,0 @@ }, |
@@ -77,5 +77,5 @@ # Express OpenID Connect | ||
Errors raised by this library are handled by the [default Express error handler](https://expressjs.com/en/guide/error-handling.html#the-default-error-handler) which, in the interests of security, does not include the stack trace in the production environment. | ||
Errors raised by this library are handled by the [default Express error handler](https://expressjs.com/en/guide/error-handling.html#the-default-error-handler) which, in the interests of security, does not include the stack trace or error message in the production environment. If you write your own error handler, you should not render the error message without using a templating engine that will properly escape it first. | ||
But you may want to go one step further and hide additional error details from client, like the error message. To do this see the Express documentation on writing [Custom error handlers](https://expressjs.com/en/guide/error-handling.html#writing-error-handlers) | ||
To write your own error handler, see the Express documentation on writing [Custom error handlers](https://expressjs.com/en/guide/error-handling.html#writing-error-handlers). | ||
@@ -82,0 +82,0 @@ ## Contributing |
2248
79529
19
Updateddebug@^4.3.2
Updatedfutoin-hkdf@^1.3.3
Updatedhttp-errors@^1.8.0
Updatedopenid-client@^4.7.4
Updatedp-memoize@^4.0.1