Attesto.Config (Attesto v0.5.0)

Copy Markdown View Source

Immutable configuration a token operation runs against.

A Config binds together everything Attesto.Token needs that is policy rather than protocol: who the issuer and audience are, where keys come from, what principal kinds exist, and the default token lifetime. Build one once (typically memoised by the host application) and pass it to Attesto.Token.mint/3 and Attesto.Token.verify/3.

Fields

  • :issuer - the iss claim value minted into every token and required to match on verify. A non-empty string (an https:// URL in any real deployment).
  • :audience - the aud claim value. A non-empty string.
  • :keystore - a module implementing Attesto.Keystore.
  • :principal_kinds - the non-empty list of Attesto.PrincipalKind structs this issuer serves. Their claim_values must be distinct, and their sub_prefixes must be distinct, so the kind a token claims and the subject it carries map unambiguously.
  • :principal_kind_claim - the JWT claim name that carries the principal kind's claim_value. Defaults to "principal_kind". A host may set its own (e.g. a namespaced private claim) without changing any other behaviour.
  • :default_lifetime_seconds - access-token lifetime when a caller does not request a shorter one. Defaults to 900 (15 minutes).
  • :token_endpoint_path - the request path the token endpoint is mounted at, used to derive token_endpoint_url/1 (the URL a DPoP proof's htu must sign, and the URL OAuth metadata would publish). Defaults to "/oauth/token".

Reserved claims

The claim names Attesto assembles itself - iss, aud, exp, iat, jti, sub, scope, typ, cnf, and the configured principal_kind_claim - are reserved. Attesto.Token.mint/3 refuses a principal whose extra claims would collide with one of them, so a caller can never shadow a protocol claim.

Summary

Functions

Build and validate a Config.

Return the Attesto.PrincipalKind whose claim_value equals claim_value, or nil if no configured kind matches.

The canonical external URL of the token endpoint: the configured issuer merged with token_endpoint_path. This is the URL a client's DPoP proof must sign in its htu claim (RFC 9449 §4.3) and the URL OAuth Authorization Server Metadata (RFC 8414) would publish. Derived from issuer rather than a live request so it is stable behind any TLS terminator or reverse proxy.

Types

t()

@type t() :: %Attesto.Config{
  access_token_header_typ: String.t() | nil,
  audience: String.t(),
  default_lifetime_seconds: pos_integer(),
  issuer: String.t(),
  keystore: module(),
  principal_kind_claim: String.t(),
  principal_kinds: [Attesto.PrincipalKind.t(), ...],
  token_endpoint_path: String.t()
}

Functions

new(opts)

@spec new(keyword()) :: t()

Build and validate a Config.

Attesto.Config.new(
  issuer: "https://api.example/",
  audience: "https://api.example/",
  keystore: MyApp.Keystore,
  principal_kinds: [
    Attesto.PrincipalKind.new("client", "oc_",
      required_claims: [{"client_id", :non_empty_string}]),
    Attesto.PrincipalKind.new("user", "usr_",
      required_claims: [
        {"act", :non_empty_string},
        {"sid", :non_empty_string},
        {"token_version", :non_neg_integer}
      ])
  ]
)

Raises ArgumentError on a malformed configuration (blank issuer or audience, a keystore that is not a module, an empty or non-list principal-kind set, duplicate claim_values or sub_prefixes, or a principal_kind_claim that collides with a reserved claim). This is evaluated once at boot, so it fails loudly rather than at the first token operation.

principal_kind(config, claim_value)

@spec principal_kind(t(), term()) :: Attesto.PrincipalKind.t() | nil

Return the Attesto.PrincipalKind whose claim_value equals claim_value, or nil if no configured kind matches.

token_endpoint_url(config)

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

The canonical external URL of the token endpoint: the configured issuer merged with token_endpoint_path. This is the URL a client's DPoP proof must sign in its htu claim (RFC 9449 §4.3) and the URL OAuth Authorization Server Metadata (RFC 8414) would publish. Derived from issuer rather than a live request so it is stable behind any TLS terminator or reverse proxy.