UNPKG

@sphereon/did-auth-siop-adapter

Version:

Self Issued OpenID V2 (SIOPv2) and OpenID 4 Verifiable Presentations (OID4VP) did adapter

521 lines (512 loc) 21.4 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // lib/index.ts var index_exports = {}; __export(index_exports, { CheckLinkedDomain: () => CheckLinkedDomain, VerificationMode: () => VerificationMode, createDidJWT: () => createDidJWT, createDidJwtAdapter: () => createDidJwtAdapter, getAudience: () => getAudience, getMethodFromDid: () => getMethodFromDid, getResolver: () => getResolver, getResolverUnion: () => getResolverUnion, getSubDidFromPayload: () => getSubDidFromPayload, isExternalSignature: () => isExternalSignature, isInternalSignature: () => isInternalSignature, isIssSelfIssued: () => isIssSelfIssued, isSuppliedSignature: () => isSuppliedSignature, mergeAllDidMethods: () => mergeAllDidMethods, resolveDidDocument: () => resolveDidDocument, signDidJwtInternal: () => signDidJwtInternal, signIDTokenPayload: () => signIDTokenPayload, signRequestObjectPayload: () => signRequestObjectPayload, toSIOPRegistrationDidMethod: () => toSIOPRegistrationDidMethod, validateLinkedDomainWithDid: () => validateLinkedDomainWithDid, verfiyDidJwtAdapter: () => verfiyDidJwtAdapter, verifyDidJWT: () => verifyDidJWT }); module.exports = __toCommonJS(index_exports); // lib/did/DidJWT.ts var import_did_auth_siop = require("@sphereon/did-auth-siop"); var import_oid4vc_common = require("@sphereon/oid4vc-common"); var import_did_jwt = require("did-jwt"); // lib/helpers.ts var isInternalSignature = /* @__PURE__ */ __name((object) => "hexPrivateKey" in object && "did" in object, "isInternalSignature"); var isExternalSignature = /* @__PURE__ */ __name((object) => "signatureUri" in object && "did" in object, "isExternalSignature"); var isSuppliedSignature = /* @__PURE__ */ __name((object) => "signature" in object, "isSuppliedSignature"); // lib/did/DidJWT.ts async function verifyDidJWT(jwt, resolver, options) { return (0, import_did_jwt.verifyJWT)(jwt, { ...options, resolver }); } __name(verifyDidJWT, "verifyDidJWT"); async function createDidJWT(payload, { issuer, signer, expiresIn, canonicalize }, header) { return (0, import_did_jwt.createJWT)(payload, { issuer, signer, expiresIn, canonicalize }, header); } __name(createDidJWT, "createDidJWT"); async function signIDTokenPayload(payload, signature) { if (isInternalSignature(signature)) { if (!signature.kid) { return Promise.reject(Error("missing kid from signature")); } return signDidJwtInternal(payload, payload.issuer, signature.hexPrivateKey, signature.alg, signature.kid, signature.customJwtSigner); } else if (isExternalSignature(signature)) { return signDidJwtExternal(payload, signature.signatureUri, signature.authZToken, signature.alg, signature.kid); } else if (isSuppliedSignature(signature)) { if (!signature.kid) { return Promise.reject(Error("missing kid from signature")); } return signDidJwtSupplied(payload, payload.issuer, signature.signature, signature.alg, signature.kid); } else { throw new Error("Signature parameters should be internal signature with hexPrivateKey, did, and an optional kid, or external signature parameters with signatureUri, did, and optionals parameters authZToken, hexPublicKey, and kid"); } } __name(signIDTokenPayload, "signIDTokenPayload"); async function signRequestObjectPayload(payload, signature) { let issuer = payload.iss; if (!issuer) { issuer = signature.did; } if (!issuer) { throw Error("No issuer supplied to sign the JWT"); } if (!payload.iss) { payload.iss = issuer; } if (!payload.sub) { payload.sub = signature.did; } if (isInternalSignature(signature)) { if (!signature.kid) { return Promise.reject(Error("missing kid from signature")); } return signDidJwtInternal(payload, issuer, signature.hexPrivateKey, signature.alg, signature.kid, signature.customJwtSigner); } else if (isExternalSignature(signature)) { return signDidJwtExternal(payload, signature.signatureUri, signature.authZToken, signature.alg, signature.kid); } else if (isSuppliedSignature(signature)) { if (!signature.kid) { return Promise.reject(Error("missing kid from signature")); } return signDidJwtSupplied(payload, issuer, signature.signature, signature.alg, signature.kid); } else { throw new Error("Signature parameters should be internal signature with hexPrivateKey, did, and an optional kid, or external signature parameters with signatureUri, did, and optionals parameters authZToken, hexPublicKey, and kid"); } } __name(signRequestObjectPayload, "signRequestObjectPayload"); async function signDidJwtInternal(payload, issuer, hexPrivateKey, alg, kid, customJwtSigner) { const signer = determineSigner(alg, hexPrivateKey, customJwtSigner); const header = { alg, kid }; const options = { issuer, signer, expiresIn: import_did_auth_siop.DEFAULT_EXPIRATION_TIME }; return await createDidJWT({ ...payload }, options, header); } __name(signDidJwtInternal, "signDidJwtInternal"); async function signDidJwtExternal(payload, signatureUri, authZToken, alg, kid) { const body = { issuer: payload.iss && payload.iss.includes("did:") ? payload.iss : payload.sub, payload, expiresIn: import_did_auth_siop.DEFAULT_EXPIRATION_TIME, alg, selfIssued: payload.iss && payload.iss.includes(import_did_auth_siop.ResponseIss.SELF_ISSUED_V2) ? payload.iss : void 0, kid }; const response = await (0, import_did_auth_siop.post)(signatureUri, JSON.stringify(body), { bearerToken: authZToken }); if (!response.successBody) { return Promise.reject(Error("the siop SignatureResponse does not have a successBody")); } return response.successBody.jws; } __name(signDidJwtExternal, "signDidJwtExternal"); async function signDidJwtSupplied(payload, issuer, signer, alg, kid) { const header = { alg, kid }; const options = { issuer, signer, expiresIn: import_did_auth_siop.DEFAULT_EXPIRATION_TIME }; return await createDidJWT({ ...payload }, options, header); } __name(signDidJwtSupplied, "signDidJwtSupplied"); var determineSigner = /* @__PURE__ */ __name((alg, hexPrivateKey, customSigner) => { if (customSigner) { return customSigner; } else if (!hexPrivateKey) { throw new Error("no private key provided"); } const privateKey = (0, import_did_jwt.hexToBytes)(hexPrivateKey.replace("0x", "")); switch (alg) { case import_oid4vc_common.SigningAlgo.EDDSA: return (0, import_did_jwt.EdDSASigner)(privateKey); case import_oid4vc_common.SigningAlgo.ES256: return (0, import_did_jwt.ES256Signer)(privateKey); case import_oid4vc_common.SigningAlgo.ES256K: return (0, import_did_jwt.ES256KSigner)(privateKey); case import_oid4vc_common.SigningAlgo.PS256: throw Error("PS256 is not supported yet. Please provide a custom signer"); case import_oid4vc_common.SigningAlgo.RS256: throw Error("RS256 is not supported yet. Please provide a custom signer"); } }, "determineSigner"); function getAudience(jwt) { const { payload } = (0, import_did_jwt.decodeJWT)(jwt); if (!payload) { throw new Error(import_did_auth_siop.SIOPErrors.NO_AUDIENCE); } else if (!payload.aud) { return void 0; } else if (Array.isArray(payload.aud)) { throw new Error(import_did_auth_siop.SIOPErrors.INVALID_AUDIENCE); } return payload.aud; } __name(getAudience, "getAudience"); function assertIssSelfIssuedOrDid(payload) { if (!payload.sub || !payload.sub.startsWith("did:") || !payload.iss || !isIssSelfIssued(payload)) { throw new Error("Token does not have a iss DID"); } } __name(assertIssSelfIssuedOrDid, "assertIssSelfIssuedOrDid"); function getSubDidFromPayload(payload, header) { assertIssSelfIssuedOrDid(payload); if (isIssSelfIssued(payload)) { let did; if (payload.sub && payload.sub.startsWith("did:")) { did = payload.sub; } if (!did && header && header.kid && header.kid.startsWith("did:")) { did = header.kid.split("#")[0]; } if (did) { return did; } } return payload.sub; } __name(getSubDidFromPayload, "getSubDidFromPayload"); function isIssSelfIssued(payload) { return payload.iss && payload.iss.includes(import_did_auth_siop.ResponseIss.SELF_ISSUED_V1) || payload.iss && payload.iss.includes(import_did_auth_siop.ResponseIss.SELF_ISSUED_V2) || payload.iss === payload.sub; } __name(isIssSelfIssued, "isIssSelfIssued"); function getMethodFromDid(did) { if (!did) { throw new Error(import_did_auth_siop.SIOPErrors.BAD_PARAMS); } const split = did.split(":"); if (split.length == 1 && did.length > 0) { return did; } else if (!did.startsWith("did:") || split.length < 2) { throw new Error(import_did_auth_siop.SIOPErrors.BAD_PARAMS); } return split[1]; } __name(getMethodFromDid, "getMethodFromDid"); function toSIOPRegistrationDidMethod(didOrMethod) { let prefix = didOrMethod; if (!didOrMethod.startsWith("did:")) { prefix = "did:" + didOrMethod; } const split = prefix.split(":"); return `${split[0]}:${split[1]}`; } __name(toSIOPRegistrationDidMethod, "toSIOPRegistrationDidMethod"); // lib/did/DIDResolution.ts var import_did_auth_siop2 = require("@sphereon/did-auth-siop"); var import_did_uni_client = require("@sphereon/did-uni-client"); var import_did_resolver = require("did-resolver"); function getResolver(opts) { if (opts && typeof opts.resolver === "object") { return opts.resolver; } if (!opts || !opts.subjectSyntaxTypesSupported) { if (opts?.noUniversalResolverFallback) { throw Error(`No subject syntax types nor did methods configured for DID resolution, but fallback to universal resolver has been disabled`); } console.log(`Falling back to universal resolver as no resolve opts have been provided, or no subject syntax types supported are provided. It is wise to fix this`); return new import_did_uni_client.UniResolver(); } const uniResolvers = []; if (opts.subjectSyntaxTypesSupported.indexOf(import_did_auth_siop2.SubjectIdentifierType.DID) === -1) { const specificDidMethods = opts.subjectSyntaxTypesSupported.filter((sst) => sst.includes("did:")); if (!specificDidMethods.length) { throw new Error("No did method found."); } for (const didMethod of specificDidMethods) { const uniResolver = (0, import_did_uni_client.getUniResolver)(getMethodFromDid(didMethod), { resolveUrl: opts.resolveUrl }); uniResolvers.push(uniResolver); } return new import_did_resolver.Resolver(...uniResolvers); } else { if (opts?.noUniversalResolverFallback) { throw Error(`No subject syntax types nor did methods configured for DID resolution, but fallback to universal resolver has been disabled`); } console.log(`Falling back to universal resolver as no resolve opts have been provided, or no subject syntax types supported are provided. It is wise to fix this`); return new import_did_uni_client.UniResolver(); } } __name(getResolver, "getResolver"); function getResolverUnion(customResolver, subjectSyntaxTypesSupported, resolverMap) { if (customResolver) { return customResolver; } const fallbackResolver = customResolver ? customResolver : new import_did_uni_client.UniResolver(); const uniResolvers = []; const subjectTypes = []; if (subjectSyntaxTypesSupported) { typeof subjectSyntaxTypesSupported === "string" ? subjectTypes.push(subjectSyntaxTypesSupported) : subjectTypes.push(...subjectSyntaxTypesSupported); } if (subjectTypes.indexOf(import_did_auth_siop2.SubjectSyntaxTypesSupportedValues.DID.valueOf()) !== -1) { return customResolver ? customResolver : new import_did_uni_client.UniResolver(); } const specificDidMethods = subjectTypes.filter((sst) => !!sst && sst.startsWith("did:")); specificDidMethods.forEach((dm) => { let methodResolver; if (!resolverMap.has(dm) || resolverMap.get(dm) === null) { methodResolver = (0, import_did_uni_client.getUniResolver)(getMethodFromDid(dm)); if (methodResolver) { uniResolvers.push(methodResolver); } } else { methodResolver = resolverMap.get(dm); if (methodResolver) { uniResolvers.push({ [dm]: methodResolver.resolve }); } } }); return subjectTypes.indexOf(import_did_auth_siop2.SubjectSyntaxTypesSupportedValues.DID.valueOf()) !== -1 ? new import_did_resolver.Resolver(...{ fallbackResolver, ...uniResolvers }) : new import_did_resolver.Resolver(...uniResolvers); } __name(getResolverUnion, "getResolverUnion"); function mergeAllDidMethods(subjectSyntaxTypesSupported, resolvers) { if (!Array.isArray(subjectSyntaxTypesSupported)) { subjectSyntaxTypesSupported = [ subjectSyntaxTypesSupported ]; } const unionSubjectSyntaxTypes = /* @__PURE__ */ new Set(); subjectSyntaxTypesSupported.forEach((sst) => unionSubjectSyntaxTypes.add(sst)); resolvers.forEach((_, didMethod) => unionSubjectSyntaxTypes.add(toSIOPRegistrationDidMethod(didMethod))); return Array.from(unionSubjectSyntaxTypes); } __name(mergeAllDidMethods, "mergeAllDidMethods"); async function resolveDidDocument(did, opts) { const result = await getResolver({ ...opts }).resolve(did, { accept: "application/did+ld+json" }); if (result?.didResolutionMetadata?.error) { throw Error(result.didResolutionMetadata.error); } if (!result.didDocument && result.id) { return result; } return result.didDocument; } __name(resolveDidDocument, "resolveDidDocument"); // lib/did/LinkedDomainValidations.ts var import_wellknown_dids_client = require("@sphereon/wellknown-dids-client"); // lib/types/SIOP.types.ts var CheckLinkedDomain = /* @__PURE__ */ function(CheckLinkedDomain2) { CheckLinkedDomain2["NEVER"] = "never"; CheckLinkedDomain2["IF_PRESENT"] = "if_present"; CheckLinkedDomain2["ALWAYS"] = "always"; return CheckLinkedDomain2; }({}); var VerificationMode = /* @__PURE__ */ function(VerificationMode2) { VerificationMode2[VerificationMode2["INTERNAL"] = 0] = "INTERNAL"; VerificationMode2[VerificationMode2["EXTERNAL"] = 1] = "EXTERNAL"; return VerificationMode2; }({}); // lib/did/LinkedDomainValidations.ts function getValidationErrorMessages(validationResult) { const messages = []; if (validationResult.message) { messages.push(validationResult.message); } if (validationResult?.endpointDescriptors?.length) { for (const endpointDescriptor of validationResult.endpointDescriptors) { if (endpointDescriptor.message) { messages.push(endpointDescriptor.message); } if (endpointDescriptor.resources) { for (const resource of endpointDescriptor.resources) { if (resource.message) { messages.push(resource.message); } } } } } return messages; } __name(getValidationErrorMessages, "getValidationErrorMessages"); function checkInvalidMessages(validationErrorMessages) { if (!validationErrorMessages || !validationErrorMessages.length) { return { status: false, message: "linked domain is invalid." }; } const validMessages = [ import_wellknown_dids_client.WDCErrors.PROPERTY_LINKED_DIDS_DOES_NOT_CONTAIN_ANY_DOMAIN_LINK_CREDENTIALS.valueOf(), import_wellknown_dids_client.WDCErrors.PROPERTY_LINKED_DIDS_NOT_PRESENT.valueOf(), import_wellknown_dids_client.WDCErrors.PROPERTY_TYPE_NOT_CONTAIN_VALID_LINKED_DOMAIN.valueOf(), import_wellknown_dids_client.WDCErrors.PROPERTY_SERVICE_NOT_PRESENT.valueOf() ]; for (const validationErrorMessage of validationErrorMessages) { if (!validMessages.filter((vm) => validationErrorMessage.includes(vm)).pop()) { return { status: false, message: validationErrorMessage }; } } return { status: true }; } __name(checkInvalidMessages, "checkInvalidMessages"); async function validateLinkedDomainWithDid(did, verification) { const { checkLinkedDomain, resolveOpts, wellknownDIDVerifyCallback } = verification; if (checkLinkedDomain === CheckLinkedDomain.NEVER) { return; } const didDocument = await resolveDidDocument(did, { ...resolveOpts, subjectSyntaxTypesSupported: [ toSIOPRegistrationDidMethod(getMethodFromDid(did)) ] }); if (!didDocument) { throw Error(`Could not resolve DID: ${did}`); } if ((!didDocument.service || !didDocument.service.find((s) => s.type === "LinkedDomains")) && checkLinkedDomain === CheckLinkedDomain.IF_PRESENT) { return; } try { if (!wellknownDIDVerifyCallback) { return Promise.reject(Error("wellknownDIDVerifyCallback is required for checkWellKnownDid")); } const validationResult = await checkWellKnownDid({ didDocument, verifyCallback: wellknownDIDVerifyCallback }); if (validationResult.status === import_wellknown_dids_client.ValidationStatusEnum.INVALID) { const validationErrorMessages = getValidationErrorMessages(validationResult); const messageCondition = checkInvalidMessages(validationErrorMessages); if (checkLinkedDomain === CheckLinkedDomain.ALWAYS || checkLinkedDomain === CheckLinkedDomain.IF_PRESENT && !messageCondition.status) { throw new Error(messageCondition.message ? messageCondition.message : validationErrorMessages[0]); } } } catch (err) { const messageCondition = checkInvalidMessages([ err.message ]); if (checkLinkedDomain === CheckLinkedDomain.ALWAYS || checkLinkedDomain === CheckLinkedDomain.IF_PRESENT && !messageCondition.status) { throw new Error(err.message); } } } __name(validateLinkedDomainWithDid, "validateLinkedDomainWithDid"); async function checkWellKnownDid(args) { const verifier = new import_wellknown_dids_client.WellKnownDidVerifier({ verifySignatureCallback: args.verifyCallback, onlyVerifyServiceDid: false }); return await verifier.verifyDomainLinkage({ didDocument: args.didDocument }); } __name(checkWellKnownDid, "checkWellKnownDid"); // lib/DidJwtAdapter.ts var verfiyDidJwtAdapter = /* @__PURE__ */ __name(async (jwtVerifier, jwt, options) => { if (jwtVerifier.method === "did") { const audience = options?.verification?.resolveOpts?.jwtVerifyOpts?.audience ?? getAudience(jwt.raw); await verifyDidJWT(jwt.raw, options.resolver, { ...options.verification?.resolveOpts?.jwtVerifyOpts, audience }); if (jwtVerifier.type === "request-object" && jwt.payload.client_id?.startsWith("did:")) { const authorizationRequestPayload = jwt.payload; if (options.verification?.checkLinkedDomain && options.verification.checkLinkedDomain != CheckLinkedDomain.NEVER) { if (!authorizationRequestPayload.client_id) { return Promise.reject(Error("missing client_id from AuthorizationRequestPayload")); } await validateLinkedDomainWithDid(authorizationRequestPayload.client_id, options.verification); } else if (!options.verification?.checkLinkedDomain && options.verification.wellknownDIDVerifyCallback) { if (!authorizationRequestPayload.client_id) { return Promise.reject(Error("missing client_id from AuthorizationRequestPayload")); } await validateLinkedDomainWithDid(authorizationRequestPayload.client_id, options.verification); } } if (jwtVerifier.type === "id-token") { const issuerDid = getSubDidFromPayload(jwt.payload); if (options.verification?.checkLinkedDomain && options.verification.checkLinkedDomain != CheckLinkedDomain.NEVER) { await validateLinkedDomainWithDid(issuerDid, options.verification); } else if (!options.verification?.checkLinkedDomain && options.verification.wellknownDIDVerifyCallback) { await validateLinkedDomainWithDid(issuerDid, options.verification); } } return true; } throw new Error("Invalid use of the did-auth-siop create jwt adapter"); }, "verfiyDidJwtAdapter"); var createDidJwtAdapter = /* @__PURE__ */ __name(async (signature, jwtIssuer, jwt) => { if (jwtIssuer.method === "did") { const issuer = jwtIssuer.didUrl.split("#")[0]; jwt.payload.issuer = issuer; if (jwtIssuer.type === "request-object") { return await signRequestObjectPayload(jwt.payload, signature); } else if (jwtIssuer.type === "id-token") { return await signIDTokenPayload(jwt.payload, signature); } } throw new Error("Invalid use of the did-auth-siop create jwt adapter"); }, "createDidJwtAdapter"); //# sourceMappingURL=index.cjs.map