@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
JavaScript
;
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