@sphereon/jarm
Version:
Sphereon JARM
496 lines (482 loc) • 19.6 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// lib/index.ts
var index_exports = {};
__export(index_exports, {
jarmAuthResponseDirectPostJwtValidate: () => jarmAuthResponseDirectPostJwtValidate,
jarmAuthResponseDirectPostValidateParams: () => jarmAuthResponseDirectPostValidateParams,
jarmAuthResponseSend: () => jarmAuthResponseSend,
jarmMetadataValidate: () => jarmMetadataValidate,
vAuthRequestParams: () => vAuthRequestParams,
vJarmAuthResponseErrorParams: () => vJarmAuthResponseErrorParams,
vJarmAuthResponseParams: () => vJarmAuthResponseParams,
vJarmAuthResponseValidateMetadataInput: () => vJarmAuthResponseValidateMetadataInput,
vJarmClientMetadata: () => vJarmClientMetadata,
vJarmClientMetadataEncrypt: () => vJarmClientMetadataEncrypt,
vJarmClientMetadataSign: () => vJarmClientMetadataSign,
vJarmClientMetadataSignEncrypt: () => vJarmClientMetadataSignEncrypt,
vJarmDirectPostJwtParams: () => vJarmDirectPostJwtParams,
vJarmMetadataValidateOut: () => vJarmMetadataValidateOut,
vJarmServerMetadata: () => vJarmServerMetadata,
vOAuthAuthRequestGetParamsOut: () => vOAuthAuthRequestGetParamsOut,
validateJarmAuthResponseParams: () => validateJarmAuthResponseParams
});
module.exports = __toCommonJS(index_exports);
// lib/utils.ts
function appendQueryParams(input) {
const { url: url2, params } = input;
for (const [key, value] of Object.entries(params)) {
url2.searchParams.append(key, encodeURIComponent(value));
}
return url2;
}
__name(appendQueryParams, "appendQueryParams");
function appendFragmentParams(input) {
const { url: url2, fragments } = input;
const fragmentParams = new URLSearchParams(url2.hash.slice(1));
for (const [key, value] of Object.entries(fragments)) {
fragmentParams.append(key, encodeURIComponent(value));
}
url2.hash = fragmentParams.toString();
return url2;
}
__name(appendFragmentParams, "appendFragmentParams");
function assertValueSupported(input) {
const { required, error, supported, actual } = input;
const intersection = supported.find((value) => value === actual);
if (required && !intersection) throw error;
return intersection;
}
__name(assertValueSupported, "assertValueSupported");
// lib/v-response-mode-registry.ts
var v = __toESM(require("valibot"), 1);
var vJarmResponseMode = v.picklist([
"jwt",
"query.jwt",
"fragment.jwt",
"form_post.jwt"
]);
var vOpenid4vpResponseMode = v.picklist([
"direct_post"
]);
var vOpenid4vpJarmResponseMode = v.picklist([
"direct_post.jwt"
]);
var vResponseMode = v.pipe(v.picklist([
"query",
"fragment",
...vOpenid4vpResponseMode.options,
...vJarmResponseMode.options,
...vOpenid4vpJarmResponseMode.options
]), v.description("Informs the Authorization Server of the mechanism to be used for returning parameters from the Authorization Endpoint."));
var getDisAllowedResponseModes = /* @__PURE__ */ __name((input) => {
const { response_type } = input;
switch (response_type) {
case "code token":
return [
"query"
];
case "code id_token":
return [
"query"
];
case "id_token token":
return [
"query"
];
case "code id_token token":
return [
"query"
];
}
return void 0;
}, "getDisAllowedResponseModes");
var getDefaultResponseMode = /* @__PURE__ */ __name((input) => {
const { response_type } = input;
switch (response_type) {
case "code":
case "none":
return "query";
case "token":
case "id_token":
case "code token":
case "code id_token":
case "id_token token":
case "code id_token token":
case "vp_token":
case "id_token vp_token":
return "fragment";
}
}, "getDefaultResponseMode");
var getJarmDefaultResponseMode = /* @__PURE__ */ __name((input) => {
const responseMode = getDefaultResponseMode(input);
switch (responseMode) {
case "query":
return "query.jwt";
case "fragment":
return "fragment.jwt";
}
}, "getJarmDefaultResponseMode");
var validateResponseMode = /* @__PURE__ */ __name((input) => {
const disallowedResponseModes = getDisAllowedResponseModes(input);
if (disallowedResponseModes?.includes(input.response_mode)) {
throw new Error(`Response_type '${input.response_type}' is not compatible with response_mode '${input.response_mode}'.`);
}
}, "validateResponseMode");
// lib/jarm-auth-response-send/jarm-auth-response-send.ts
var jarmAuthResponseSend = /* @__PURE__ */ __name(async (input) => {
const { authRequestParams, authResponse, state } = input;
const responseEndpoint = "response_uri" in authRequestParams ? new URL(authRequestParams.response_uri) : new URL(authRequestParams.redirect_uri);
const responseMode = authRequestParams.response_mode && authRequestParams.response_mode !== "jwt" ? authRequestParams.response_mode : getJarmDefaultResponseMode(authRequestParams);
validateResponseMode({
response_type: authRequestParams.response_type,
response_mode: responseMode
});
switch (responseMode) {
case "direct_post.jwt":
return handleDirectPostJwt(responseEndpoint, authResponse, state);
case "query.jwt":
return handleQueryJwt(responseEndpoint, authResponse, state);
case "fragment.jwt":
return handleFragmentJwt(responseEndpoint, authResponse, state);
case "form_post.jwt":
throw new Error("Not implemented. form_post.jwt is not yet supported.");
}
}, "jarmAuthResponseSend");
async function handleDirectPostJwt(responseEndpoint, responseJwt, state) {
const response = await fetch(responseEndpoint, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: `response=${responseJwt}&state=${state}`
});
return response;
}
__name(handleDirectPostJwt, "handleDirectPostJwt");
async function handleQueryJwt(responseEndpoint, responseJwt, state) {
const responseUrl = appendQueryParams({
url: responseEndpoint,
params: {
response: responseJwt,
state
}
});
const response = await fetch(responseUrl, {
method: "POST"
});
return response;
}
__name(handleQueryJwt, "handleQueryJwt");
async function handleFragmentJwt(responseEndpoint, responseJwt, state) {
const responseUrl = appendFragmentParams({
url: responseEndpoint,
fragments: {
response: responseJwt,
state
}
});
const response = await fetch(responseUrl, {
method: "POST"
});
return response;
}
__name(handleFragmentJwt, "handleFragmentJwt");
// lib/jarm-auth-response/c-jarm-auth-response.ts
var v3 = __toESM(require("valibot"), 1);
// lib/v-response-type-registry.ts
var v2 = __toESM(require("valibot"), 1);
var oAuthResponseTypes = v2.picklist([
"code",
"token"
]);
var oAuthMRTEPResponseTypes = v2.picklist([
"none",
"id_token",
"code token",
"code id_token",
"id_token token",
"code id_token token"
]);
var openid4vpResponseTypes = v2.picklist([
"vp_token",
"id_token vp_token"
]);
var vTransformedResponseTypes = v2.picklist([
...openid4vpResponseTypes.options,
...oAuthResponseTypes.options,
...oAuthMRTEPResponseTypes.options
]);
var vResponseType = v2.pipe(v2.string(), v2.transform((val) => val.split(" ").sort().join(" ")), vTransformedResponseTypes);
// lib/jarm-auth-response/c-jarm-auth-response.ts
var vAuthRequestParams = v3.looseObject({
state: v3.optional(v3.string()),
response_mode: v3.optional(v3.union([
vJarmResponseMode,
vOpenid4vpJarmResponseMode
])),
client_id: v3.string(),
response_type: vResponseType,
client_metadata: v3.looseObject({
jwks: v3.optional(v3.object({
keys: v3.array(v3.looseObject({
kid: v3.optional(v3.string()),
kty: v3.string()
}))
})),
jwks_uri: v3.optional(v3.string())
})
});
var vOAuthAuthRequestGetParamsOut = v3.object({
authRequestParams: vAuthRequestParams
});
// lib/jarm-auth-response/jarm-auth-response.ts
var import_oid4vc_common2 = require("@sphereon/oid4vc-common");
var v6 = __toESM(require("valibot"), 1);
// lib/jarm-auth-response/v-jarm-auth-response-params.ts
var import_oid4vc_common = require("@sphereon/oid4vc-common");
var v4 = __toESM(require("valibot"), 1);
var vJarmAuthResponseErrorParams = v4.looseObject({
error: v4.string(),
state: v4.optional(v4.string()),
error_description: v4.pipe(v4.optional(v4.string()), v4.description("Text providing additional information, used to assist the client developer in understanding the error that occurred.")),
error_uri: v4.pipe(v4.optional(v4.pipe(v4.string(), v4.url())), v4.description("A URI identifying a human-readable web page with information about the error, used to provide the client developer with additional information about the error"))
});
var vJarmAuthResponseParams = v4.looseObject({
state: v4.optional(v4.string()),
/**
* The issuer URL of the authorization server that created the response
*/
iss: v4.string(),
/**
* Expiration of the JWT
*/
exp: v4.number(),
/**
* The client_id of the client the response is intended for
*/
aud: v4.string()
});
var validateJarmAuthResponseParams = /* @__PURE__ */ __name((input) => {
const { authRequestParams, authResponseParams } = input;
if (authRequestParams.state !== authResponseParams.state) {
throw new Error(`State missmatch in jarm-auth-response. Expected '${authRequestParams.state}' received '${authRequestParams.state}'.`);
}
if (authRequestParams.client_id !== authResponseParams.aud) {
throw new Error(`Invalid audience in jarm-auth-response. Expected '${authRequestParams.client_id}' received '${authResponseParams.aud}'.`);
}
if ((0, import_oid4vc_common.checkExp)({
exp: authResponseParams.exp
})) {
throw new Error(`The '${authRequestParams.state}' and the jarm-auth-response.`);
}
}, "validateJarmAuthResponseParams");
// lib/jarm-auth-response/v-jarm-direct-post-jwt-auth-response-params.ts
var v5 = __toESM(require("valibot"), 1);
var vJarmDirectPostJwtParams = v5.looseObject({
...v5.omit(vJarmAuthResponseParams, [
"iss",
"aud",
"exp"
]).entries,
...v5.partial(v5.pick(vJarmAuthResponseParams, [
"iss",
"aud",
"exp"
])).entries,
vp_token: v5.union([
v5.string(),
v5.array(v5.pipe(v5.string(), v5.nonEmpty()))
]),
dcql_query: v5.unknown(),
nonce: v5.optional(v5.string())
});
var jarmAuthResponseDirectPostValidateParams = /* @__PURE__ */ __name((input) => {
const { authRequestParams, authResponseParams } = input;
if (authRequestParams.state !== authResponseParams.state) {
throw new Error(`State missmatch between auth request '${authRequestParams.state}' and the jarm-auth-response.`);
}
}, "jarmAuthResponseDirectPostValidateParams");
// lib/jarm-auth-response/jarm-auth-response.ts
var parseJarmAuthResponseParams = /* @__PURE__ */ __name((schema, responseParams) => {
if (v6.is(vJarmAuthResponseErrorParams, responseParams)) {
const errorResponseJson = JSON.stringify(responseParams, void 0, 2);
throw new Error(`Received error response from authorization server. '${errorResponseJson}'`);
}
return v6.parse(schema, responseParams);
}, "parseJarmAuthResponseParams");
var decryptJarmAuthResponse = /* @__PURE__ */ __name(async (input, ctx) => {
const { response } = input;
const responseProtectedHeader = (0, import_oid4vc_common2.decodeProtectedHeader)(response);
if (!responseProtectedHeader.kid) {
throw new Error(`Jarm JWE is missing the protected header field 'kid'.`);
}
const { plaintext } = await ctx.jwe.decryptCompact({
jwe: response,
jwk: {
kid: responseProtectedHeader.kid
}
});
return plaintext;
}, "decryptJarmAuthResponse");
var jarmAuthResponseDirectPostJwtValidate = /* @__PURE__ */ __name(async (input, ctx) => {
const { response } = input;
const responseIsEncrypted = (0, import_oid4vc_common2.isJwe)(response);
const decryptedResponse = responseIsEncrypted ? await decryptJarmAuthResponse(input, ctx) : response;
const responseIsSigned = (0, import_oid4vc_common2.isJws)(decryptedResponse);
if (!responseIsEncrypted && !responseIsSigned) {
throw new Error("Jarm Auth Response must be either encrypted, signed, or signed and encrypted.");
}
let authResponseParams;
let authRequestParams;
if (responseIsSigned) {
throw new Error("Signed JARM responses are not supported.");
} else {
const jsonResponse = JSON.parse(decryptedResponse);
authResponseParams = parseJarmAuthResponseParams(vJarmDirectPostJwtParams, jsonResponse);
({ authRequestParams } = await ctx.openid4vp.authRequest.getParams(authResponseParams));
}
jarmAuthResponseDirectPostValidateParams({
authRequestParams,
authResponseParams
});
let type;
if (responseIsSigned && responseIsEncrypted) type = "signed encrypted";
else if (responseIsEncrypted) type = "encrypted";
else type = "signed";
return {
authRequestParams,
authResponseParams,
type
};
}, "jarmAuthResponseDirectPostJwtValidate");
// lib/metadata/v-jarm-client-metadata.ts
var v7 = __toESM(require("valibot"), 1);
var vJarmClientMetadataSign = v7.object({
authorization_signed_response_alg: v7.pipe(v7.optional(v7.string()), v7.description("JWA. If this is specified, the response will be signed using JWS and the configured algorithm. The algorithm none is not allowed.")),
authorization_encrypted_response_alg: v7.optional(v7.never()),
authorization_encrypted_response_enc: v7.optional(v7.never())
});
var vJarmClientMetadataEncrypt = v7.object({
authorization_signed_response_alg: v7.optional(v7.never()),
authorization_encrypted_response_alg: v7.pipe(v7.string(), v7.description("JWE alg algorithm JWA. If both signing and encryption are requested, the response will be signed then encrypted with the provided algorithm.")),
authorization_encrypted_response_enc: v7.pipe(v7.optional(v7.string(), "A128CBC-HS256"), v7.description("JWE enc algorithm JWA. If both signing and encryption are requested, the response will be signed then encrypted with the provided algorithm."))
});
var vJarmClientMetadataSignEncrypt = v7.object({
...v7.pick(vJarmClientMetadataSign, [
"authorization_signed_response_alg"
]).entries,
...v7.pick(vJarmClientMetadataEncrypt, [
"authorization_encrypted_response_alg",
"authorization_encrypted_response_enc"
]).entries
});
var vJarmClientMetadata = v7.union([
vJarmClientMetadataSign,
vJarmClientMetadataEncrypt,
vJarmClientMetadataSignEncrypt
]);
// lib/metadata/v-jarm-server-metadata.ts
var v8 = __toESM(require("valibot"), 1);
var vJarmServerMetadata = v8.object({
authorization_signing_alg_values_supported: v8.pipe(v8.array(v8.string()), v8.description("JSON array containing a list of the JWS [RFC7515] signing algorithms (alg values) JWA [RFC7518] supported by the authorization endpoint to sign the response.")),
authorization_encryption_alg_values_supported: v8.pipe(v8.array(v8.string()), v8.description("JSON array containing a list of the JWE [RFC7516] encryption algorithms (alg values) JWA [RFC7518] supported by the authorization endpoint to encrypt the response.")),
authorization_encryption_enc_values_supported: v8.pipe(v8.array(v8.string()), v8.description("JSON array containing a list of the JWE [RFC7516] encryption algorithms (enc values) JWA [RFC7518] supported by the authorization endpoint to encrypt the response."))
});
// lib/metadata/jarm-validate-metadata.ts
var v9 = __toESM(require("valibot"), 1);
var vJarmAuthResponseValidateMetadataInput = v9.object({
client_metadata: vJarmClientMetadata,
server_metadata: v9.partial(vJarmServerMetadata)
});
var vJarmMetadataValidateOut = v9.variant("type", [
v9.object({
type: v9.literal("signed"),
client_metadata: vJarmClientMetadataSign
}),
v9.object({
type: v9.literal("encrypted"),
client_metadata: vJarmClientMetadataEncrypt
}),
v9.object({
type: v9.literal("signed encrypted"),
client_metadata: vJarmClientMetadataSignEncrypt
})
]);
var jarmMetadataValidate = /* @__PURE__ */ __name((vJarmMetadataValidate) => {
const { client_metadata, server_metadata } = vJarmMetadataValidate;
const { authorization_encrypted_response_alg, authorization_encrypted_response_enc, authorization_signed_response_alg } = client_metadata;
assertValueSupported({
supported: server_metadata.authorization_signing_alg_values_supported ?? [],
actual: authorization_signed_response_alg,
required: !!authorization_signed_response_alg,
error: new Error("Invalid authorization_signed_response_alg")
});
assertValueSupported({
supported: server_metadata.authorization_encryption_alg_values_supported ?? [],
actual: authorization_encrypted_response_alg,
required: !!authorization_encrypted_response_alg,
error: new Error("Invalid authorization_encrypted_response_alg")
});
assertValueSupported({
supported: server_metadata.authorization_encryption_enc_values_supported ?? [],
actual: authorization_encrypted_response_enc,
required: !!authorization_encrypted_response_enc,
error: new Error("Invalid authorization_encrypted_response_enc")
});
if (authorization_signed_response_alg && authorization_encrypted_response_alg && authorization_encrypted_response_enc) {
return {
type: "signed encrypted",
client_metadata: {
authorization_signed_response_alg,
authorization_encrypted_response_alg,
authorization_encrypted_response_enc
}
};
} else if (authorization_signed_response_alg && !authorization_encrypted_response_alg && !authorization_encrypted_response_enc) {
return {
type: "signed",
client_metadata: {
authorization_signed_response_alg
}
};
} else if (!authorization_signed_response_alg && authorization_encrypted_response_alg && authorization_encrypted_response_enc) {
return {
type: "encrypted",
client_metadata: {
authorization_encrypted_response_alg,
authorization_encrypted_response_enc
}
};
} else {
throw new Error(`Invalid jarm client_metadata combination`);
}
}, "jarmMetadataValidate");
//# sourceMappingURL=index.cjs.map