@sphereon/oid4vci-common
Version:
OpenID 4 Verifiable Credential Issuance Common Types
142 lines • 9.17 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.validateJWT = exports.extractBearerToken = exports.isJWS = exports.createProofOfPossession = void 0;
const debug_1 = __importDefault(require("debug"));
const jwt_decode_1 = require("jwt-decode");
const __1 = require("..");
const types_1 = require("../types");
const debug = (0, debug_1.default)('sphereon:openid4vci:common');
/**
*
* - proofOfPossessionCallback: JWTSignerCallback
* Mandatory if you want to create (sign) ProofOfPossession
* - proofOfPossessionVerifierCallback?: JWTVerifyCallback
* If exists, verifies the ProofOfPossession
* - proofOfPossessionCallbackArgs: ProofOfPossessionCallbackArgs
* arguments needed for signing ProofOfPossession
* - proofOfPossessionCallback: JWTSignerCallback
* Mandatory to create (sign) ProofOfPossession
* - proofOfPossessionVerifierCallback?: JWTVerifyCallback
* If exists, verifies the ProofOfPossession
* @param popMode
* @param callbacks
* @param jwtProps
* @param existingJwt
* - Optional, clientId of the party requesting the credential
*/
const createProofOfPossession = (popMode, callbacks, jwtProps, existingJwt) => __awaiter(void 0, void 0, void 0, function* () {
if (!callbacks.signCallback) {
debug(`no jwt signer callback or arguments supplied!`);
throw new Error(types_1.BAD_PARAMS);
}
const jwtPayload = createJWT(popMode, jwtProps, existingJwt);
const jwt = yield callbacks.signCallback(jwtPayload, jwtPayload.header.kid);
const proof = {
proof_type: 'jwt',
jwt,
};
try {
partiallyValidateJWS(jwt);
if (callbacks.verifyCallback) {
debug(`Calling supplied verify callback....`);
yield callbacks.verifyCallback({ jwt, kid: jwtPayload.header.kid });
debug(`Supplied verify callback return success result`);
}
}
catch (_a) {
debug(`JWS was not valid`);
throw new Error(types_1.JWS_NOT_VALID);
}
debug(`Proof of Possession JWT:\r\n${jwt}`);
return proof;
});
exports.createProofOfPossession = createProofOfPossession;
const partiallyValidateJWS = (jws) => {
if (jws.split('.').length !== 3 || !jws.startsWith('ey')) {
throw new Error(types_1.JWS_NOT_VALID);
}
};
const isJWS = (token) => {
try {
partiallyValidateJWS(token);
return true;
}
catch (e) {
return false;
}
};
exports.isJWS = isJWS;
const extractBearerToken = (authorizationHeader) => {
var _a;
return authorizationHeader ? (_a = /Bearer (.*)/i.exec(authorizationHeader)) === null || _a === void 0 ? void 0 : _a[1] : undefined;
};
exports.extractBearerToken = extractBearerToken;
const validateJWT = (jwt, opts) => __awaiter(void 0, void 0, void 0, function* () {
if (!jwt) {
throw Error('No JWT was supplied');
}
if (!(opts === null || opts === void 0 ? void 0 : opts.accessTokenVerificationCallback)) {
__1.VCI_LOG_COMMON.warning(`No access token verification callback supplied. Access tokens will not be verified, except for a very basic check`);
partiallyValidateJWS(jwt);
const header = (0, jwt_decode_1.jwtDecode)(jwt, { header: true });
const payload = (0, jwt_decode_1.jwtDecode)(jwt, { header: false });
return Object.assign(Object.assign({ jwt: { header, payload } }, header), payload);
}
else {
return yield opts.accessTokenVerificationCallback({ jwt, kid: opts.kid });
}
});
exports.validateJWT = validateJWT;
const createJWT = (mode, jwtProps, existingJwt) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
const aud = mode === 'pop'
? getJwtProperty('aud', true, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.issuer, (_a = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.payload) === null || _a === void 0 ? void 0 : _a.aud)
: getJwtProperty('aud', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.aud, (_b = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.payload) === null || _b === void 0 ? void 0 : _b.aud);
const iss = mode === 'pop'
? getJwtProperty('iss', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.clientId, (_c = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.payload) === null || _c === void 0 ? void 0 : _c.iss)
: getJwtProperty('iss', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.issuer, (_d = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.payload) === null || _d === void 0 ? void 0 : _d.iss);
const client_id = mode === 'JWT' ? getJwtProperty('client_id', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.clientId, (_e = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.payload) === null || _e === void 0 ? void 0 : _e.client_id) : undefined;
const jti = getJwtProperty('jti', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.jti, (_f = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.payload) === null || _f === void 0 ? void 0 : _f.jti);
const typ = getJwtProperty('typ', true, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.typ, (_g = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.header) === null || _g === void 0 ? void 0 : _g.typ, 'openid4vci-proof+jwt');
const nonce = getJwtProperty('nonce', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.nonce, (_h = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.payload) === null || _h === void 0 ? void 0 : _h.nonce); // Officially this is required, but some implementations don't have it
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const alg = getJwtProperty('alg', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.alg, (_j = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.header) === null || _j === void 0 ? void 0 : _j.alg, 'ES256');
const kid = getJwtProperty('kid', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.kid, (_k = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.header) === null || _k === void 0 ? void 0 : _k.kid);
const jwk = getJwtProperty('jwk', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.jwk, (_l = existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.header) === null || _l === void 0 ? void 0 : _l.jwk);
const x5c = getJwtProperty('x5c', false, jwtProps === null || jwtProps === void 0 ? void 0 : jwtProps.x5c, existingJwt === null || existingJwt === void 0 ? void 0 : existingJwt.header.x5c);
const jwt = Object.assign({}, existingJwt);
const now = +new Date();
const jwtPayload = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (aud && { aud })), { iat: (_o = (_m = jwt.payload) === null || _m === void 0 ? void 0 : _m.iat) !== null && _o !== void 0 ? _o : Math.floor(now / 1000) - 60, exp: (_q = (_p = jwt.payload) === null || _p === void 0 ? void 0 : _p.exp) !== null && _q !== void 0 ? _q : Math.floor(now / 1000) + 10 * 60, nonce }), (client_id && { client_id })), (iss && { iss })), (jti && { jti }));
const jwtHeader = Object.assign(Object.assign(Object.assign({ typ,
alg }, (kid && { kid })), (jwk && { jwk })), (x5c && { x5c }));
return {
payload: Object.assign(Object.assign({}, jwt.payload), jwtPayload),
header: Object.assign(Object.assign({}, jwt.header), jwtHeader),
};
};
const getJwtProperty = (propertyName, required, option, jwtProperty, defaultValue) => {
if ((typeof option === 'string' || Array.isArray(option)) && option && jwtProperty && option !== jwtProperty) {
throw Error(`Cannot have a property '${propertyName}' with value '${option}' and different JWT value '${jwtProperty}' at the same time`);
}
let result = (jwtProperty ? jwtProperty : option);
if (!result) {
if (required) {
throw Error(`No ${propertyName} property provided either in a JWT or as option`);
}
result = defaultValue;
}
return result;
};
//# sourceMappingURL=ProofUtil.js.map