ExMCP.Authorization.JWT (ex_mcp v0.9.0)

View Source

General-purpose JWT module wrapping JOSE for MCP authorization.

Provides key loading, JWT signing, verification, and claims validation used by OAuth client assertions, ID-JAG tokens, and JWT bearer grants.

Summary

Functions

Fetches a JWKS (JSON Web Key Set) from a URL.

Generates an EC key pair for development/testing.

Generates a unique JWT ID (jti).

Generates an RSA key pair for development/testing.

Loads a JWK from a PEM string, JWK map, or file path.

Reads the unverified header from a JWS token (for typ checking).

Signs a claims map into a compact JWS string.

Converts a JWK to a map representation (for JWKS publishing).

Extracts the public key from a JWK.

Validates standard JWT claims against expected values.

Verifies a JWS string and returns decoded claims.

Verifies a JWS string and validates claims against expected values.

Functions

fetch_jwks(url)

@spec fetch_jwks(String.t()) :: {:ok, [JOSE.JWK.t()]} | {:error, term()}

Fetches a JWKS (JSON Web Key Set) from a URL.

generate_ec_key(opts \\ [])

@spec generate_ec_key(keyword()) :: JOSE.JWK.t()

Generates an EC key pair for development/testing.

Options

  • :curve - EC curve name (default: "P-256")

generate_jti()

@spec generate_jti() :: String.t()

Generates a unique JWT ID (jti).

generate_rsa_key(opts \\ [])

@spec generate_rsa_key(keyword()) :: JOSE.JWK.t()

Generates an RSA key pair for development/testing.

Options

  • :size - Key size in bits (default: 2048)

load_key(jwk_map)

@spec load_key(map() | String.t() | {:pem_file, String.t()}) ::
  {:ok, JOSE.JWK.t()} | {:error, term()}

Loads a JWK from a PEM string, JWK map, or file path.

Examples

{:ok, jwk} = JWT.load_key(%{"kty" => "RSA", ...})
{:ok, jwk} = JWT.load_key("-----BEGIN RSA PRIVATE KEY-----\n...")
{:ok, jwk} = JWT.load_key({:pem_file, "/path/to/key.pem"})

peek_header(token)

@spec peek_header(String.t()) :: {:ok, map()} | {:error, term()}

Reads the unverified header from a JWS token (for typ checking).

sign(claims, jwk, opts \\ [])

@spec sign(map(), JOSE.JWK.t(), keyword()) :: {:ok, String.t()} | {:error, term()}

Signs a claims map into a compact JWS string.

Options

  • :alg - Signing algorithm (default: "RS256")
  • :kid - Key ID to include in header
  • :typ - Token type header (default: "JWT")

to_map(jwk)

@spec to_map(JOSE.JWK.t()) :: map()

Converts a JWK to a map representation (for JWKS publishing).

to_public_key(jwk)

@spec to_public_key(JOSE.JWK.t()) :: JOSE.JWK.t()

Extracts the public key from a JWK.

validate_claims(claims, expected \\ [])

@spec validate_claims(
  map(),
  keyword()
) :: {:ok, map()} | {:error, term()}

Validates standard JWT claims against expected values.

Options

  • :iss - Expected issuer
  • :aud - Expected audience (string or list)
  • :sub - Expected subject
  • :max_age - Maximum token age in seconds
  • :required - List of required claim keys (as strings)

verify(token, jwk_or_jwks)

@spec verify(String.t(), JOSE.JWK.t() | [JOSE.JWK.t()]) ::
  {:ok, map()} | {:error, term()}

Verifies a JWS string and returns decoded claims.

Accepts a single JWK or a list of JWKs (JWKS).

verify_and_validate(token, jwk_or_jwks, expected \\ [])

@spec verify_and_validate(String.t(), JOSE.JWK.t() | [JOSE.JWK.t()], keyword()) ::
  {:ok, map()} | {:error, term()}

Verifies a JWS string and validates claims against expected values.

Expected Claims Options

  • :iss - Expected issuer
  • :aud - Expected audience (string or list)
  • :sub - Expected subject
  • :max_age - Maximum token age in seconds
  • :required - List of required claim keys