UNPKG

httplease-asap

Version:

ASAP authentication filter for httplease

71 lines (56 loc) 2.22 kB
'use strict'; const crypto = require('crypto'); const jsonWebToken = require('jsonwebtoken'); function assertDefined(value, message) { if (value === undefined || value === null || value === '') { throw new Error(message); } } function createAuthHeaderGenerator(jwtConfig) { assertDefined(jwtConfig.privateKey, 'jwtConfig.privateKey must be set'); assertDefined(jwtConfig.keyId, 'jwtConfig.keyId must be set'); assertDefined(jwtConfig.issuer, 'jwtConfig.issuer must be set'); assertDefined(jwtConfig.audience, 'jwtConfig.audience must be set'); const privateKey = jwtConfig.privateKey.replace(/\\n/g, '\n').replace(/"/g, ''); // The max age is less than the expiry so that we don't ever reuse a nearly expired token const tokenExpiryMs = jwtConfig.tokenExpiryMs || 10 * 60 * 1000; const tokenMaxAgeMs = jwtConfig.tokenMaxAgeMs || 9 * 60 * 1000; const additionalClaims = jwtConfig.additionalClaims || {}; let lastUpdated = 0; let authHeader; function isExpired(now) { const tokenAge = now - lastUpdated; return tokenAge > tokenMaxAgeMs; } function generateStandardClaims(now) { return { aud: jwtConfig.audience, iss: jwtConfig.issuer, sub: jwtConfig.subject || jwtConfig.issuer, iat: Math.floor(now / 1000), nbf: Math.floor(now / 1000), exp: Math.floor((now + tokenExpiryMs) / 1000), jti: crypto.randomBytes(20).toString('hex') }; } function getOrGenerateAuthHeader() { const now = Date.now(); if (!isExpired(now)) { return authHeader; } const claims = Object.assign({}, generateStandardClaims(now), additionalClaims); const options = { algorithm: 'RS256', header: { kid: jwtConfig.keyId } }; authHeader = 'Bearer ' + jsonWebToken.sign(claims, privateKey, options); lastUpdated = now; return authHeader; } // Fail if we cannot generate an auth header getOrGenerateAuthHeader(); return getOrGenerateAuthHeader; } module.exports = createAuthHeaderGenerator;