Issuer, resource, and redirect URL correctness behind a proxy

Copy Markdown View Source

Behind Fly, NGINX, a CDN, or any reverse proxy, the request the application sees is not the request the client sent: the scheme is often plain HTTP after TLS termination, and the Host header may be an internal name. OAuth and OIDC URL correctness depends on the canonical, client-visible host and scheme, not on whatever reached the application socket.

Why this matters

  • The issuer (iss) is minted into every token and published in the discovery documents (RFC 8414 §2). It MUST be the canonical https URL clients use. Deriving it from a live request behind a proxy can leak an internal host or an http scheme.

  • The DPoP htu (RFC 9449 §4.3) is the URL the client signed. If the server computes htu from a proxied request it may not match what the client signed, and valid proofs are rejected.

  • Redirect URIs are exact-matched (RFC 6749 §3.1.2.3). A host/scheme mismatch breaks the match.

Configure the canonical identity, not the request

AttestoPhoenix.Config:

  • :issuer - set this to the fixed canonical https issuer URL. The library derives the discovery issuer and the advertised endpoint URLs from it (via the :oauth_path_prefix / per-endpoint path resolvers), so it never needs to reconstruct the host from a request. This is stable behind any TLS terminator.

  • :trusted_proxies - the list of trusted proxy CIDRs/IPs that controls whether X-Forwarded-* headers are honored. Default [] (no forwarded trust): nothing is taken from a Forwarded / X-Forwarded-* header unless the immediate peer is in this list. Set it to your proxy's address range so forwarded scheme/host are trusted only from your proxy and never from an arbitrary client.

  • :require_https - keep this true (the default) in production so the endpoints enforce HTTPS.

  • :htu - (conn -> canonical_url_string). When the default derivation from :trusted_proxies is not enough (an unusual proxy chain, a host rewrite), override exactly how the DPoP htu is computed. Return the canonical URL the client would have signed.

Checklist

  • [ ] :issuer is the fixed canonical https URL (no internal host).
  • [ ] :trusted_proxies lists your proxy's address range, nothing wider.
  • [ ] :require_https is true.
  • [ ] Advertised endpoint paths match the mount via :oauth_path_prefix (see
    the consumer migration guide).
  • [ ] If proofs are rejected behind the proxy, set :htu to return the
    canonical signed URL.