oidcc_http_adapter behaviour (Oidcc v3.8.0)

Copy Markdown View Source

HTTP transport adapter.

Adapters perform the transport operation for oidcc_http_util and return the raw response representation used by httpc:request/5. OIDCC remains responsible for telemetry, response decoding, content-type validation, DPoP nonce handling, and error normalization.

Configure an adapter through the request_opts for each outbound operation:

Adapter = {my_http_adapter, #{}},

{ok, ProviderPid} =
  oidcc_provider_configuration_worker:start_link(#{
    issuer => <<"https://my.provider">>,
    provider_configuration_opts => #{
      request_opts => #{
        http_adapter => Adapter
      }
    }
  }),

{ok, ClientContext} =
  oidcc_client_context:from_configuration_worker(
    ProviderPid,
    <<"client_id">>,
    <<"client_secret">>
  ),

oidcc_token:retrieve(
  AuthCode,
  ClientContext,
  #{
    request_opts => #{
      http_adapter => Adapter
    }
  }
).

Elixir modules can implement the same behavior:

defmodule MyHttpAdapter do
  @behaviour :oidcc_http_adapter

  @impl true
  def request(method, request, http_options, request_options, config) do
    # Return {:ok, {{http_version, status, reason}, headers, binary_body}}
    # or {:error, reason}.
  end
end

adapter = {MyHttpAdapter, %{}}

{:ok, provider_pid} =
  Oidcc.ProviderConfiguration.Worker.start_link(%{
    issuer: "https://my.provider",
    provider_configuration_opts: %{
      request_opts: %{
        http_adapter: adapter
      }
    }
  })

{:ok, client_context} =
  Oidcc.ClientContext.from_configuration_worker(
    provider_pid,
    "client_id",
    "client_secret"
  )

Oidcc.Token.retrieve(auth_code, client_context, %{
  request_opts: %{
    http_adapter: adapter
  }
})

The provider worker's provider_configuration_opts.request_opts apply only to provider discovery and JWKS requests. They are not copied into token, userinfo, introspection, registration, or authorization options. Configure request_opts.http_adapter for both paths when both need the adapter.

The complete request tuple, including its original URL, is passed to the adapter unchanged. An adapter must return:

  • the raw status-line tuple {HttpVersion, Status, Reason};
  • headers in the representation expected by oidcc_http_util;
  • a binary response body; or
  • {error, Reason} for a transport failure.

Response header names must be lower-case byte strings as returned by httpc. Header values may be any iodata accepted by httpc.

Adapters control redirect handling and response-body collection. Security-aware adapters must not follow redirects implicitly. They must resolve and validate each redirect destination before connecting, and enforce response-size limits while receiving the body.

Adapters may emit their own telemetry. The telemetry span owned by oidcc_http_util remains authoritative for OIDCC HTTP operations.

Summary

Types

Adapter module and adapter-specific configuration.

HTTP header representation accepted and returned by httpc:request/5.

HTTP options constructed by oidcc_http_util.

HTTP method accepted by httpc:request/5.

HTTP request tuple accepted by httpc:request/5.

HTTP request body accepted by httpc:request/5.

Request options passed to adapters.

Raw httpc-compatible response.

Types

config()

-type config() :: {module(), map()}.

Adapter module and adapter-specific configuration.

header()

-type header() :: {Field :: [byte()], Value :: binary() | iolist()}.

HTTP header representation accepted and returned by httpc:request/5.

http_options()

-type http_options() :: [{timeout, timeout()} | {ssl, [ssl:tls_option()]}].

HTTP options constructed by oidcc_http_util.

The list includes the request timeout and, when configured, TLS options.

method()

-type method() :: head | get | put | patch | post | trace | options | delete.

HTTP method accepted by httpc:request/5.

request()

-type request() ::
          {uri_string:uri_string(), [header()]} |
          {uri_string:uri_string(), [header()], ContentType :: string(), request_body()}.

HTTP request tuple accepted by httpc:request/5.

request_body()

-type request_body() ::
          iolist() |
          binary() |
          {fun((Accumulator :: term()) -> eof | {ok, iolist(), Accumulator :: term()}),
           Accumulator :: term()} |
          {chunkify,
           fun((Accumulator :: term()) -> eof | {ok, iolist(), Accumulator :: term()}),
           Accumulator :: term()}.

HTTP request body accepted by httpc:request/5.

request_options()

-type request_options() :: [{body_format, binary}].

Request options passed to adapters.

response()

-type response() ::
          {ok,
           {{HttpVersion :: string(), Status :: non_neg_integer(), Reason :: string()},
            [header()],
            binary()}} |
          {error, term()}.

Raw httpc-compatible response.

Callbacks

request(Method, Request, HttpOptions, RequestOptions, AdapterConfig)

-callback request(Method :: method(),
                  Request :: request(),
                  HttpOptions :: http_options(),
                  RequestOptions :: request_options(),
                  AdapterConfig :: map()) ->
                     response().

Perform an HTTP request.

Request contains the original URL and is passed without transformation. HttpOptions and RequestOptions are the values constructed by oidcc_http_util. AdapterConfig is the map paired with the adapter module in request_opts.http_adapter.