UNPKG

@sphereon/did-auth-siop-adapter

Version:

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

500 lines (492 loc) 19.2 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // lib/did/DidJWT.ts import { DEFAULT_EXPIRATION_TIME, post, ResponseIss, SIOPErrors } from "@sphereon/did-auth-siop"; import { SigningAlgo } from "@sphereon/oid4vc-common"; import { createJWT, decodeJWT, EdDSASigner, ES256KSigner, ES256Signer, hexToBytes, verifyJWT } from "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 verifyJWT(jwt, { ...options, resolver }); } __name(verifyDidJWT, "verifyDidJWT"); async function createDidJWT(payload, { issuer, signer, expiresIn, canonicalize }, header) { return 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: 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: DEFAULT_EXPIRATION_TIME, alg, selfIssued: payload.iss && payload.iss.includes(ResponseIss.SELF_ISSUED_V2) ? payload.iss : void 0, kid }; const response = await 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: 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 = hexToBytes(hexPrivateKey.replace("0x", "")); switch (alg) { case SigningAlgo.EDDSA: return EdDSASigner(privateKey); case SigningAlgo.ES256: return ES256Signer(privateKey); case SigningAlgo.ES256K: return ES256KSigner(privateKey); case SigningAlgo.PS256: throw Error("PS256 is not supported yet. Please provide a custom signer"); case SigningAlgo.RS256: throw Error("RS256 is not supported yet. Please provide a custom signer"); } }, "determineSigner"); function getAudience(jwt) { const { payload } = decodeJWT(jwt); if (!payload) { throw new Error(SIOPErrors.NO_AUDIENCE); } else if (!payload.aud) { return void 0; } else if (Array.isArray(payload.aud)) { throw new Error(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(ResponseIss.SELF_ISSUED_V1) || payload.iss && payload.iss.includes(ResponseIss.SELF_ISSUED_V2) || payload.iss === payload.sub; } __name(isIssSelfIssued, "isIssSelfIssued"); function getMethodFromDid(did) { if (!did) { throw new Error(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(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 import { SubjectIdentifierType, SubjectSyntaxTypesSupportedValues } from "@sphereon/did-auth-siop"; import { getUniResolver, UniResolver } from "@sphereon/did-uni-client"; import { Resolver } from "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 UniResolver(); } const uniResolvers = []; if (opts.subjectSyntaxTypesSupported.indexOf(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 = getUniResolver(getMethodFromDid(didMethod), { resolveUrl: opts.resolveUrl }); uniResolvers.push(uniResolver); } return new 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 UniResolver(); } } __name(getResolver, "getResolver"); function getResolverUnion(customResolver, subjectSyntaxTypesSupported, resolverMap) { if (customResolver) { return customResolver; } const fallbackResolver = customResolver ? customResolver : new UniResolver(); const uniResolvers = []; const subjectTypes = []; if (subjectSyntaxTypesSupported) { typeof subjectSyntaxTypesSupported === "string" ? subjectTypes.push(subjectSyntaxTypesSupported) : subjectTypes.push(...subjectSyntaxTypesSupported); } if (subjectTypes.indexOf(SubjectSyntaxTypesSupportedValues.DID.valueOf()) !== -1) { return customResolver ? customResolver : new UniResolver(); } const specificDidMethods = subjectTypes.filter((sst) => !!sst && sst.startsWith("did:")); specificDidMethods.forEach((dm) => { let methodResolver; if (!resolverMap.has(dm) || resolverMap.get(dm) === null) { methodResolver = getUniResolver(getMethodFromDid(dm)); if (methodResolver) { uniResolvers.push(methodResolver); } } else { methodResolver = resolverMap.get(dm); if (methodResolver) { uniResolvers.push({ [dm]: methodResolver.resolve }); } } }); return subjectTypes.indexOf(SubjectSyntaxTypesSupportedValues.DID.valueOf()) !== -1 ? new Resolver(...{ fallbackResolver, ...uniResolvers }) : new 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 import { ValidationStatusEnum, WDCErrors, WellKnownDidVerifier } from "@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 = [ WDCErrors.PROPERTY_LINKED_DIDS_DOES_NOT_CONTAIN_ANY_DOMAIN_LINK_CREDENTIALS.valueOf(), WDCErrors.PROPERTY_LINKED_DIDS_NOT_PRESENT.valueOf(), WDCErrors.PROPERTY_TYPE_NOT_CONTAIN_VALID_LINKED_DOMAIN.valueOf(), 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 === 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 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"); export { CheckLinkedDomain, VerificationMode, createDidJWT, createDidJwtAdapter, getAudience, getMethodFromDid, getResolver, getResolverUnion, getSubDidFromPayload, isExternalSignature, isInternalSignature, isIssSelfIssued, isSuppliedSignature, mergeAllDidMethods, resolveDidDocument, signDidJwtInternal, signIDTokenPayload, signRequestObjectPayload, toSIOPRegistrationDidMethod, validateLinkedDomainWithDid, verfiyDidJwtAdapter, verifyDidJWT }; //# sourceMappingURL=index.js.map