|
LibJWT 3.5.0
The C JSON Web Token Library +JWK +JWKS
|
Many real-world specifications are not new cryptography — they are application profiles: an ordinary signed JWT with a particular media type ("typ"), a required set of claims, and a key-binding convention. LibJWT's job is to expose the primitives; this page shows how to compose them into each profile. Every recipe below builds and verifies a token with the public API only, and is mirrored by a test in tests/jwt_profiles.c.
The reusable pieces are:
| Primitive | Function(s) | Used by |
|---|---|---|
| Media-type pinning | jwt_checker_expect_typ, jwt_builder_settyp | all typ-bearing profiles |
| Algorithm allowlist | jwt_checker_setalgs | all (blocks alg confusion) |
| Required claims | jwt_checker_require | at+jwt, VAPID, PASSporT |
| Confirmation (cnf) | jwt_builder_setcnf_jkt, jwt_builder_setcnf, jwt_get_cnf | DPoP, mTLS |
| Embedded-key verify | jwt_checker_enable_embedded_jwk | DPoP, OpenID4VCI |
| Token hash | jwt_token_hash | DPoP ath |
| JWK Thumbprint | jwks_item_thumbprint | DPoP, OpenID4VCI |
| X.509 (x5c/x5t#S256) | jwks_item_x5c, jwks_item_x5t_s256 | PASSporT, JAdES, mTLS |
| Detached payload | jwt_builder_set_detached, jwt_checker_verify_detached | JAdES |
📄 RFC-9068 profiles a JWT access token: the header "typ" is "at+jwt" and a fixed set of claims (iss, exp, aud, sub, client_id, iat, jti) is mandatory. Pin the type and algorithm, and use jwt_checker_require to assert the mandatory claims are present (LibJWT otherwise validates only the claims you ask it to compare).
📄 RFC-8292 (VAPID) is the most widely deployed plain JWS-over-P-256 profile on the web: an ES256 token whose aud is the push service origin, sub a contact URI, and exp at most 24 hours out. There is no special "typ"; the discipline is the fixed algorithm and the required claims.
📄 RFC-8225 PASSporT (the token behind STIR/SHAKEN) signs caller-identity claims (orig, dest, iat, attest) with "typ":"passport", typically ES256, and carries the signing certificate via "x5u" or "x5c". Validate the type, algorithm, and required claims here; read the certificate chain with jwks_item_x5c (chain/trust validation against the SHAKEN CA is the caller's PKI policy — see 🖊 Detached signatures — JAdES (ETSI 119 182-1) for reading x5c).
An OpenID4VCI key proof ("typ":"openid4vci-proof+jwt") is self-contained: the signing key travels in the protected-header "jwk" (RFC-7515 Sec 4.1.3) and the issuer binds the credential to that key. Because the header key is supplied by the presenter, it must be confirmed — here against the holder-key thumbprint the issuer recorded for the request — with jwt_checker_enable_embedded_jwk, which refuses to trust an embedded key without a pin.
📄 RFC-9449 DPoP binds an access token to a client key. The access token carries a cnf.jkt (set with jwt_builder_setcnf_jkt); each request is accompanied by a "dpop+jwt" proof that carries the client's public key in its header "jwk" and an "ath" claim hashing the access token. To verify a proof: pin the embedded key to the access token's cnf.jkt, then check that ath matches jwt_token_hash of the presented access token (and that htm/ the request).htu match
📄 RFC-8705 binds an access token to a client TLS certificate via a cnf "x5t#S256" member (the certificate's SHA-256 thumbprint). Set it with jwt_builder_setcnf; at the resource server, read it with jwt_get_cnf and compare against the thumbprint of the certificate presented in the TLS handshake (which your TLS terminator provides).
JAdES (the eIDAS JWS profile) commonly signs a detached document — the payload is conveyed out of band, not inside the token — with the signing certificate chain in the "x5c" header. Sign opaque bytes unencoded (📄 RFC-7797) and detached, then verify with jwt_checker_verify_detached, supplying the document. Read the chain with jwks_item_x5c (parsed from a JWK's x5c); certificate-path validation is the caller's PKI policy.