defmodule Oidcc.Plug.ExtractAuthorization do @moduledoc """ Extract `authorization` request header This module should be used together with `Oidcc.Plug.IntrospectToken`, `Oidcc.Plug.LoadUserinfo` or `Oidcc.Plug.ValidateJwtToken`. ```elixir defmodule SampleAppWeb.Endpoint do use Phoenix.Endpoint, otp_app: :sample_app # ... plug Oidcc.Plug.ExtractAuthorization plug Oidcc.Plug.RequireAuthorization, [...] # Ensure Authorization Token provided plug Oidcc.Plug.IntrospectToken, [...] # Check Token via Introspection plug Oidcc.Plug.LoadUserinfo, [...] # Check Token via Userinfo plug Oidcc.Plug.ValidateJwtToken, [...] # Check Token via JWT validation plug SampleAppWeb.Router end ``` """ @moduledoc since: "0.1.0" @behaviour Plug import Plug.Conn, only: [get_req_header: 2, put_private: 3, halt: 1, send_resp: 3] @typedoc """ Plug Configuration Options ## Options * `send_invalid_header_response` - Customize Error Response for invalid header """ @typedoc since: "0.1.0" @type opts :: [ {:send_invalid_header_response, (conn :: Plug.Conn.t(), given_header :: [String.t()] -> Plug.Conn.t())} ] @impl Plug def init(opts), do: Keyword.validate!(opts, send_invalid_header_response: &__MODULE__.send_invalid_header_response/2 ) @impl Plug def call(%Plug.Conn{} = conn, opts) do send_invalid_header_response = Keyword.fetch!(opts, :send_invalid_header_response) case get_req_header(conn, "authorization") do ["Bearer " <> token | _rest] -> put_private(conn, __MODULE__, token) [] -> put_private(conn, __MODULE__, nil) header -> send_invalid_header_response.(conn, header) end end @doc false @spec send_invalid_header_response(conn :: Plug.Conn.t(), given_header :: [String.t()]) :: Plug.Conn.t() def send_invalid_header_response(conn, [header | _rest]) do conn |> halt() |> send_resp(:bad_request, """ Invalid authorization Header Expected: Authorization: Bearer Given: #{inspect(header)} """) end end