@bitblit/epsilon
Version:
Tiny adapter to simplify building API gateway Lambda APIS
95 lines • 4.55 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GoogleWebTokenManipulator = void 0;
const logger_1 = require("@bitblit/ratchet/common/logger");
const string_ratchet_1 = require("@bitblit/ratchet/common/string-ratchet");
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
const jwks_rsa_1 = __importDefault(require("jwks-rsa"));
const cross_fetch_1 = __importDefault(require("cross-fetch"));
class GoogleWebTokenManipulator {
constructor(clientId) {
this.clientId = clientId;
}
extractTokenFromAuthorizationHeader(authHeader) {
return __awaiter(this, void 0, void 0, function* () {
let tokenString = string_ratchet_1.StringRatchet.trimToEmpty(authHeader);
if (tokenString.toLowerCase().startsWith('bearer ')) {
tokenString = tokenString.substring(7);
}
const validated = !!tokenString ? yield this.parseAndValidateGoogleToken(tokenString, false) : null;
return validated;
});
}
parseAndValidateGoogleToken(googleToken, allowExpired = false) {
return __awaiter(this, void 0, void 0, function* () {
logger_1.Logger.debug('Auth : %s', string_ratchet_1.StringRatchet.obscure(googleToken, 4));
// First decode so we can get the keys
const fullToken = jsonwebtoken_1.default.decode(googleToken, { complete: true });
const kid = fullToken.header.kid;
const nowEpochSeconds = Math.floor(new Date().getTime() / 1000);
const pubKey = yield this.fetchSigningKey(kid);
const validated = jsonwebtoken_1.default.verify(googleToken, pubKey, {
audience: this.clientId,
issuer: ['https://accounts.google.com', 'accounts.google.com'],
ignoreExpiration: allowExpired,
clockTimestamp: nowEpochSeconds,
});
return validated;
});
}
fetchSigningKey(kid) {
return __awaiter(this, void 0, void 0, function* () {
const jClient = yield this.fetchJwksClient();
return new Promise((res, rej) => {
jClient.getSigningKey(kid, (err, key) => {
if (err) {
rej(err);
}
else {
res(key.publicKey || key.rsaPublicKey);
}
});
});
});
}
fetchJwksClient() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.jwksClient) {
const discDoc = yield this.fetchGoogleDiscoveryDocument();
const client = (0, jwks_rsa_1.default)({
cache: true,
cacheMaxEntries: 5,
cacheMaxAge: 1000 * 60 * 60 * 10,
jwksUri: discDoc.jwks_uri,
});
this.jwksClient = client;
}
return this.jwksClient;
});
}
fetchGoogleDiscoveryDocument() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.cacheGoogleDiscoveryDocument) {
const resp = yield (0, cross_fetch_1.default)(GoogleWebTokenManipulator.GOOGLE_DISCOVERY_DOCUMENT);
const doc = yield resp.json();
this.cacheGoogleDiscoveryDocument = doc;
}
return this.cacheGoogleDiscoveryDocument;
});
}
}
exports.GoogleWebTokenManipulator = GoogleWebTokenManipulator;
GoogleWebTokenManipulator.GOOGLE_DISCOVERY_DOCUMENT = 'https://accounts.google.com/.well-known/openid-configuration';
//# sourceMappingURL=google-web-token-manipulator.js.map