Current section
Files
Jump to
Current section
Files
lib/access_token.ex
defmodule AccessToken do
@moduledoc """
A plug for extracting the access token from the request.
The token may be sent by the request either via the params with key `access_token` or a
header with name `Authorization` and content `Bearer <access token>`.
To use it, just plug it into the desired module:
plug AccessToken
If present, the access token will be accessible through the `assigns` map of the connection.
conn.assigns[:access_token]
## Options
* `:param` - The name of the HTTP *request* parameter to check for
the access token. Default value is `access_token`.
plug AccessToken, param: "token"
* `:http_header` - The name of the HTTP *request* header to check for
the access token. Default value is `authorization`.
plug AccessToken, http_header: "custom-authorization"
* `:http_header_prefix` - The prefix of the HTTP *request* authorization header.
Default value is `Bearer`.
plug AccessToken, http_header_prefix: "Token"
* `:assign_to` - The name of the key to assign the access token.
Defaults to `:access_token`
plug AccessToken, assign_to: :token
* `:error_status` - The status code to be returned in case the access token is not
present. The status can be `nil`, an integer or an atom. The list of allowed atoms
is available in `Plug.Conn.Status`. Defaults to `:unauthorized`
plug AccessToken, error_status: :bad_request
* `:error_handler` - The function to be called in case the access token is not
present. The `:error_handler` is set using a `{module, function, args}` triple.
The function will receive the `conn` followed by the list of `args` provided.
plug AccessToken,
error_handler: {Phoenix.Controller, :render, [MyAppWeb.ErrorView, "401.json"]}
"""
@behaviour Plug
def init(opts \\ []) do
%{
param: Keyword.get(opts, :param, "access_token"),
http_header: Keyword.get(opts, :http_header, "authorization"),
http_header_prefix: Keyword.get(opts, :http_header_prefix, "Bearer"),
assign_key: Keyword.get(opts, :assign_to, :access_token),
error_status: Keyword.get(opts, :error_status, :unauthorized),
error_handler: Keyword.get(opts, :error_handler)
}
end
def call(%Plug.Conn{} = conn, config) do
case conn.params[config.param] || get_access_token_from_headers(conn, config) do
nil ->
conn
|> Plug.Conn.put_status(config.error_status)
|> apply_error_handler(config)
|> Plug.Conn.halt()
access_token ->
Plug.Conn.assign(conn, config.assign_key, String.trim(access_token))
end
end
defp apply_error_handler(conn, %{error_handler: nil}), do: conn
defp apply_error_handler(conn, %{error_handler: {mod, fun, args}}) do
apply(mod, fun, [conn] ++ args)
end
defp get_access_token_from_headers(conn, config) do
with [header] <- Plug.Conn.get_req_header(conn, config.http_header),
true <- String.starts_with?(header, config.http_header_prefix) do
String.replace_leading(header, config.http_header_prefix, "")
else
_ -> nil
end
end
end