Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

express-openid-connect

Package Overview
Dependencies
Maintainers
47
Versions
44
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

express-openid-connect - npm Package Compare versions

Comparing version 2.10.0 to 2.11.0

lib/crypto.js

41

index.d.ts

@@ -249,5 +249,8 @@ // Type definitions for express-openid-connect

/**
* REQUIRED. The secret(s) used to derive an encryption key for the user identity in a session cookie and
* to sign the transient cookies used by the login callback.
* Use a single string key or array of keys for an encrypted session cookie.
* REQUIRED. The secret(s) used to derive an encryption key for the user identity in a stateless session cookie,
* to sign the transient cookies used by the login callback and to sign the custom session store cookies if
* {@Link signSessionStoreCookie} is `true`. Use a single string key or array of keys.
* If an array of secrets is provided, only the first element will be used to sign or encrypt the values, while all
* the elements will be considered when decrypting or verifying the values.
*
* Can use env key SECRET instead.

@@ -641,5 +644,7 @@ */

*
* **IMPORTANT** If you override this method you must use a suitable
* cryptographically strong random value of sufficient size to prevent collisions
* and reduce the ability to hijack a session by guessing the session ID.
* **IMPORTANT** If you override this method you should be careful to generate
* unique IDs so your sessions do not conflict. Also, to reduce the ability
* to hijack a session by guessing the session ID, you must use a suitable
* cryptographically strong random value of sufficient size or sign the cookie
* by setting {@Link signSessionStoreCookie} to `true`.
*/

@@ -649,2 +654,26 @@ genid?: (req: OpenidRequest) => string;

/**
* Sign the session store cookies to reduce the chance of collisions
* and reduce the ability to hijack a session by guessing the session ID.
*
* This is required if you override {@Link genid} and don't use a suitable
* cryptographically strong random value of sufficient size.
*/
signSessionStoreCookie: boolean;
/**
* If you enable {@Link signSessionStoreCookie} your existing sessions will
* be invalidated. You can use this flag to temporarily allow unsigned cookies
* while you sign your user's session cookies. For example:
*
* Set {@Link signSessionStoreCookie} to `true` and {@Link requireSignedSessionStoreCookie} to `false`.
* Wait for your {@Link rollingDuration} (default 1 day) or {@Link absoluteDuration} (default 1 week)
* to pass (which ever comes first). By this time all your sessions cookies will either be signed or
* have expired, then you can remove the {@Link requireSignedSessionStoreCookie} config option which
* will set it to `true`.
*
* Signed session store cookies will be mandatory in the next major release.
*/
requireSignedSessionStoreCookie: boolean;
/**
* If you want your session duration to be rolling, eg reset everytime the

@@ -651,0 +680,0 @@ * user is active on your site, set this to a `true`. If you want the session

56

lib/appSession.js
const { strict: assert, AssertionError } = require('assert');
const {
JWK,
JWKS,
JWE,

@@ -12,3 +10,3 @@ errors: { JOSEError },

const COOKIES = require('./cookies');
const { encryption: deriveKey } = require('./hkdf');
const { getKeyStore, verifyCookie, signCookie } = require('./crypto');
const debug = require('./debug')('appSession');

@@ -51,9 +49,4 @@

module.exports = (config) => {
let current;
const alg = 'dir';
const enc = 'A256GCM';
const secrets = Array.isArray(config.secret)
? config.secret
: [config.secret];
const sessionName = config.session.name;

@@ -66,2 +59,4 @@ const cookieConfig = config.session.cookie;

rollingDuration,
signSessionStoreCookie,
requireSignedSessionStoreCookie,
} = config.session;

@@ -80,12 +75,3 @@

let keystore = new JWKS.KeyStore();
secrets.forEach((secretString, i) => {
const key = JWK.asKey(deriveKey(secretString));
if (i === 0) {
current = key;
}
keystore.add(key);
});
let [current, keystore] = getKeyStore(config.secret, true);
if (keystore.size === 1) {

@@ -197,2 +183,6 @@ keystore = current;

getCookie(req) {
return req[COOKIES][sessionName];
}
setCookie(req, res, iat) {

@@ -208,2 +198,9 @@ setCookie(req, res, iat);

this._destroy = promisify(store.destroy).bind(store);
let [current, keystore] = getKeyStore(config.secret);
if (keystore.size === 1) {
keystore = current;
}
this._keyStore = keystore;
this._current = current;
}

@@ -240,2 +237,17 @@

getCookie(req) {
if (signSessionStoreCookie) {
const verified = verifyCookie(
sessionName,
req[COOKIES][sessionName],
this._keyStore
);
if (requireSignedSessionStoreCookie) {
return verified;
}
return verified || req[COOKIES][sessionName];
}
return req[COOKIES][sessionName];
}
setCookie(

@@ -257,3 +269,7 @@ id,

delete cookieOptions.transient;
res.cookie(sessionName, id, cookieOptions);
let value = id;
if (signSessionStoreCookie) {
value = signCookie(sessionName, id, this._current);
}
res.cookie(sessionName, value, cookieOptions);
}

@@ -292,3 +308,3 @@ }

debug('reading session from %s cookie', sessionName);
existingSessionValue = req[COOKIES][sessionName];
existingSessionValue = store.getCookie(req);
} else if (req[COOKIES].hasOwnProperty(`${sessionName}.0`)) {

@@ -295,0 +311,0 @@ // get JWE from chunked session cookie

@@ -51,2 +51,6 @@ const Joi = require('joi');

.default(() => defaultSessionIdGenerator),
signSessionStoreCookie: Joi.boolean().optional().default(false),
requireSignedSessionStoreCookie: Joi.boolean()
.optional()
.default(Joi.ref('signSessionStoreCookie')),
cookie: Joi.object({

@@ -53,0 +57,0 @@ domain: Joi.string().optional(),

@@ -1,2 +0,1 @@

const cb = require('cb');
const url = require('url');

@@ -9,2 +8,3 @@ const urlJoin = require('url-join');

const debug = require('./debug')('context');
const { once } = require('./once');
const { get: getClient } = require('./client');

@@ -177,3 +177,3 @@ const { encodeState } = require('../lib/hooks/getLoginState');

let { config, req, res, next, transient } = weakRef(this);
next = cb(next).once();
next = once(next);
try {

@@ -275,3 +275,3 @@ const client = await getClient(config);

let { config, req, res, next } = weakRef(this);
next = cb(next).once();
next = once(next);
let returnURL = params.returnTo || config.routes.postLogoutRedirect;

@@ -278,0 +278,0 @@ debug('req.oidc.logout() with return url: %s', returnURL);

const { generators } = require('openid-client');
const { JWKS, JWS, JWK } = require('jose');
const { signing: deriveKey } = require('./hkdf');
const header = { alg: 'HS256', b64: false, crit: ['b64'] };
const getPayload = (cookie, value) => Buffer.from(`${cookie}=${value}`);
const flattenedJWSFromCookie = (cookie, value, signature) => ({
protected: Buffer.from(JSON.stringify(header))
.toString('base64')
.replace(/=/g, '')
.replace(/\+/g, '-')
.replace(/\//g, '_'),
payload: getPayload(cookie, value),
signature,
});
const generateSignature = (cookie, value, key) => {
const payload = getPayload(cookie, value);
return JWS.sign.flattened(payload, key, header).signature;
};
const verifySignature = (cookie, value, signature, keystore) => {
try {
return !!JWS.verify(
flattenedJWSFromCookie(cookie, value, signature),
keystore,
{ algorithm: 'HS256', crit: ['b64'] }
);
} catch (err) {
return false;
}
};
const getCookieValue = (cookie, value, keystore) => {
if (!value) {
return undefined;
}
let signature;
[value, signature] = value.split('.');
if (verifySignature(cookie, value, signature, keystore)) {
return value;
}
return undefined;
};
const generateCookieValue = (cookie, value, key) => {
const signature = generateSignature(cookie, value, key);
return `${value}.${signature}`;
};
const {
signCookie: generateCookieValue,
verifyCookie: getCookieValue,
getKeyStore,
} = require('./crypto');
const COOKIES = require('./cookies');

@@ -53,14 +11,4 @@

constructor({ secret, session, legacySameSiteCookie }) {
let current;
let [current, keystore] = getKeyStore(secret);
const secrets = Array.isArray(secret) ? secret : [secret];
let keystore = new JWKS.KeyStore();
secrets.forEach((secretString, i) => {
const key = JWK.asKey(deriveKey(secretString));
if (i === 0) {
current = key;
}
keystore.add(key);
});
if (keystore.size === 1) {

@@ -67,0 +15,0 @@ keystore = current;

const express = require('express');
const cb = require('cb');
const createError = require('http-errors');
const debug = require('../lib/debug')('auth');
const { once } = require('../lib/once');
const { get: getConfig } = require('../lib/config');

@@ -72,3 +72,3 @@ const { get: getClient } = require('../lib/client');

async (req, res, next) => {
next = cb(next).once();
next = once(next);

@@ -75,0 +75,0 @@ client =

{
"name": "express-openid-connect",
"version": "2.10.0",
"version": "2.11.0",
"description": "Express middleware to protect web applications using OpenID Connect.",

@@ -29,3 +29,2 @@ "homepage": "https://github.com/auth0/express-openid-connect",

"base64url": "^3.0.1",
"cb": "^0.1.0",
"clone": "^2.1.2",

@@ -36,3 +35,3 @@ "cookie": "^0.5.0",

"http-errors": "^1.8.1",
"joi": "^17.6.3",
"joi": "^17.7.0",
"jose": "^2.0.6",

@@ -39,0 +38,0 @@ "on-headers": "^1.0.2",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc