AttestoPhoenix.ClientAuthentication (AttestoPhoenix v0.7.1)

Copy Markdown View Source

OAuth 2.0 client authentication (RFC 6749 §2.3), as conn-free core.

This is the single place that turns the request's Authorization header and body parameters into either an authenticated client or an AttestoPhoenix.OAuthError. It is shared by the token endpoint (RFC 6749 §3.2) and the Pushed Authorization Request endpoint (RFC 9126): both authenticate the client identically; only the policy around the secretless/public path and the event/wire rendering differ, and those are the caller's concern.

Methods

Accepts HTTP Basic credentials (RFC 6749 §2.3.1, RFC 7617), request-body credentials (RFC 6749 §2.3.1), and private_key_jwt assertions (RFC 7523 / OIDC Core §9). Presenting more than one client-authentication method is rejected (RFC 6749 §2.3).

Policy

The one decision that differs between callers is carried as data on AttestoPhoenix.ClientAuthentication.Policy:

  • :allow_public - whether a client identified without a secret/assertion may authenticate as a public client (RFC 6749 §2.1), relying on PKCE (RFC 7636) downstream. The token endpoint allows this; the PAR endpoint does not, because a request reference established without proof of possession of the client secret would let anyone who knows a confidential client's client_id push requests in its name. When false, a body client_id without a secret is rejected with invalid_client "client authentication required".
  • :assertion_audiences - the acceptable aud values for a private_key_jwt assertion (RFC 7523 §3 / FAPI 2: the issuer identifier, not the endpoint URL).
  • :assertion_max_lifetime - the maximum assertion lifetime, in seconds, and the replay-record TTL (RFC 7523 §3).

Return value

authenticate/4 returns {:ok, %Result{client, client_id, method}} or {:error, %AttestoPhoenix.OAuthError{}}. It reads only data: the Authorization header values and the parsed body params. It never touches a conn and never emits an event - the caller renders the result/error and emits whatever audit event it owns.

Security details preserved

  • On an unknown/revoked client, a dummy verify_client_secret/2 call against :unknown_client runs so the lookup-failure path matches the wrong-secret path in observable timing (RFC 6749 §2.3 / OWASP).
  • Every client-authentication failure returns the single generic invalid_client "client authentication failed" message, so an attacker cannot tell an unknown client from a wrong secret.
  • Presenting more than one authentication method is rejected with invalid_request (RFC 6749 §2.3).

Summary

Functions

Authenticate the client from the request's Authorization header values and body params (RFC 6749 §2.3).

Functions

authenticate(authorization_headers, params, config, policy)

Authenticate the client from the request's Authorization header values and body params (RFC 6749 §2.3).

authorization_headers is the list of Authorization header values (as returned by Plug.Conn.get_req_header(conn, "authorization")). params is the parsed request body. Returns {:ok, %Result{}} or {:error, %AttestoPhoenix.OAuthError{}}.