Files
suaveplan/packages/security-stack/security/jws/src/header/header.ts
2026-05-27 23:47:53 +01:00

45 lines
1.5 KiB
TypeScript

import {
base64urlDecodeJson,
base64urlEncodeString,
} from "../base64url/base64url.js";
import { JWS_CODES, JwsError } from "../errors/error-codes.js";
import { recordError } from "../observability/metrics.js";
import { JoseHeaderSchema } from "../schemas/schemas.js";
import type { JoseHeader } from "./header.types.js";
/**
* Parse a base64url-encoded JOSE protected header (or a raw object) and
* validate the registered-parameter shape per RFC 7515 §4.1. Unknown
* parameters survive round-trip.
*
* @throws JwsError(JWS.HEADER_MALFORMED) when the input does not decode
* to a JSON object whose `alg` is a string.
*/
export function parseHeader(
input: string | Record<string, unknown>
): JoseHeader {
const raw = typeof input === "string" ? base64urlDecodeJson(input) : input;
const parsed = JoseHeaderSchema.safeParse(raw);
if (!parsed.success) {
const err = new JwsError(
JWS_CODES.HEADER_MALFORMED,
"error.jws.header-shape-invalid",
{ context: { issues: parsed.error.issues } }
);
recordError(err.code);
throw err;
}
return parsed.data as JoseHeader;
}
/**
* Serialize a JOSE header to a base64url-encoded UTF-8 JSON string.
* Keys preserve insertion order; callers that need a canonical order
* should sort before passing in.
*/
export function serializeHeader(
header: JoseHeader | Record<string, unknown>
): string {
return base64urlEncodeString(JSON.stringify(header));
}