The error type of the OAuth 2.1 client (ConduitMcp.Client.OAuth.*).
Every OAuth helper that can fail returns {:error, %ConduitMcp.Client.OAuth.Error{}}.
Match on :reason, which is one of the closed set in reasons/0.
Fields
:reason- an atom fromreasons/0.:data- optional, non-secret context: the metadata field that failed (%{field: "token_endpoint", scheme: "javascript"}), a parser detail atom, or, for authorization-response errors, the server'serror,error_descriptionanderror_uristrings exactly as received. It may hold server-supplied text, somessage/1never renders it.
Secrets
No OAuth helper ever puts a token, refresh token, authorization code,
state or PKCE verifier into an error, and message/1 renders only the
reason and a fixed description. The message is safe to log.
Reasons
Parsing and URL rules (Challenge, Resource, Discovery, Pending):
:invalid_challenge- aWWW-Authenticatevalue is malformed or over a limit;:datais the detail atom (seeConduitMcp.Client.OAuth.Challenge).:invalid_url- a URL does not parse, has no host, carries user info, or (for an issuer) has a query or fragment;:datanames the problem.:insecure_url- a URL that must behttpsis not (plainhttpis only admitted for loopback hosts, and for anything but a redirect URI only behindallow_insecure: true).
Discovery and metadata validation (Discovery, PKCE):
:resource_mismatch- Protected Resource Metadataresourceis not exactly the canonical server URI (RFC 9728 §3.3).:no_authorization_server- the PRM lists no authorization server.:issuer_not_allowed- the chosen authorization server is not in the configuredexpected_issuersallowlist.:invalid_metadata- PRM or authorization-server metadata is not an object or a field has the wrong type;:datanames the field.:issuer_mismatch- authorization-server metadataissueris not exactly the issuer the metadata URL was built from (RFC 8414 §3.3).:pkce_unsupported-code_challenge_methods_supportedis absent or lacks"S256".:insecure_endpoint- an endpoint in the authorization-server metadata is nothttps(this is also howjavascript:,file:,data:and every other scheme is refused);:datanames the field and scheme.
Authorization response (Callback):
:invalid_state-stateis missing or does not match.:principal_mismatch- the callback is completed under a different principal than the one that started the flow.:state_expired- the pending authorization outlived its TTL.:iss_mismatch- the responseissis not exactly the recorded issuer (RFC 9207 §2.4). Nothing else from the response is surfaced.:iss_missing- the authorization server advertisesauthorization_response_iss_parameter_supportedbut sent noiss.:missing_code- neithercodenorerroris present.:invalid_pending- a stored pending authorization could not be restored byConduitMcp.Client.OAuth.Pending.from_map/1;:datanames the field.:access_denied,:invalid_request,:unauthorized_client,:unsupported_response_type,:invalid_scope,:server_error,:temporarily_unavailable- the authorization server returned that RFC 6749 §4.1.2.1errorcode.:authorization_error- the authorization server returned any othererrorcode; it is in:dataas a string, never as an atom.
Runtime (produced by the HTTP-layer OAuth flow, defined here so the set is closed in one place):
:authorization_required- interactive authorization is needed.:no_protected_resource_metadata- every PRM candidate URL failed.:no_authorization_server_metadata- every AS-metadata candidate failed.:authorization_server_changed- pre-registered credentials are bound to a different issuer than the one the server now names.:no_registration_method- no pre-registered client, CIMD or DCR applies.:registration_failed- dynamic client registration was refused.:invalid_grant- the token endpoint rejected the code or refresh token.:token_request_failed- the token endpoint failed otherwise (data: %{reason: :invalid_token_response}for a malformed answer, an access token holding anything but visible ASCII included).:step_up_limit- the step-up attempt limit for a resource and scope set was reached (seeConduitMcp.Client.OAuth.Scopes.step_up_allowed?/4).:url_blocked-ConduitMcp.Client.URLPolicyrefused a server-supplied URL before any connection was made (a private, loopback or otherwise internal address, or an unresolvable host);:datais the policy's reason.:client_secret_unavailable- a client secret configured as{:system, "VAR"}names an unset environment variable;:datais the variable name.
Summary
Functions
{:error, new(reason, data)}.
Builds an error, raising ArgumentError when reason is not in reasons/0.
Every valid :reason, in documentation order.
Types
@type reason() ::
:invalid_challenge
| :invalid_url
| :insecure_url
| :resource_mismatch
| :no_authorization_server
| :issuer_not_allowed
| :invalid_metadata
| :issuer_mismatch
| :pkce_unsupported
| :insecure_endpoint
| :invalid_state
| :principal_mismatch
| :state_expired
| :iss_mismatch
| :iss_missing
| :missing_code
| :invalid_pending
| :access_denied
| :invalid_request
| :unauthorized_client
| :unsupported_response_type
| :invalid_scope
| :server_error
| :temporarily_unavailable
| :authorization_error
| :authorization_required
| :no_protected_resource_metadata
| :no_authorization_server_metadata
| :authorization_server_changed
| :no_registration_method
| :registration_failed
| :invalid_grant
| :token_request_failed
| :step_up_limit
| :url_blocked
| :client_secret_unavailable
Functions
{:error, new(reason, data)}.
Builds an error, raising ArgumentError when reason is not in reasons/0.
iex> ConduitMcp.Client.OAuth.Error.new(:pkce_unsupported).reason
:pkce_unsupported
@spec reasons() :: [reason(), ...]
Every valid :reason, in documentation order.