Elixir's web framework Phoenix makes use of Plugs which are composable module layers through which the HTTP request passes through allowing the incoming request to be manipulated as it is processed. As per Phoenix docs
Plug lives at the heart of Phoenix's HTTP layer, and Phoenix puts Plug front and center. We interact with plugs at every step of the request life-cycle, and the core Phoenix components like endpoints, routers, and controllers are all just plugs internally
Recently building an API (yes Phoenix is now my go to choice for web dev :) ) I decided to use simple_token_authentication hex package instead of hand-rolling out an API Token checker. It has some nice features where it adds service name to the log metadata for the matching token and uses erlang's persistent_term
to make some performance gains. Also you should never hand-roll out Auth(n/z) by yourself to avoid missing out on edge cases or introducing loopholes.
The only shortcoming I faced with simple_token_authentication
was that it requires that the API token should be sent in Authorization
header for e.g Authorization: <API TOKEN>
. Now this doesn't seem to be a problem when you are integrating your API with other services that you own (having API keys in mobile and web app are just useless for protection by exposing them publicly). This can be done as intended other than in case the Authorization
header is not available or restricted for use and you would need to use a custom header to pass the value. Another case and more prominent one is when integrating your API with 3rd party service or webhook where you can't pass a value in a HTTP header and have to append it to your URL.
So in order to pick your API token from HTTP header X-API-TOKEN
or param x_api_token
. You can add a plug that sits before SimpleTokenAuthentication
Plug in the pipeline and it would transfer the value over to Authorization header.
defmodule MaverickWeb.Plugs.TransferApiTokenToAuthorization do
@moduledoc """
The TransferApiTokenToAuthorization Plug.
"""
import Plug.Conn
@api_key_header "x-api-key"
@api_key_param "x_api_key"
def init(opts), do: opts
def call(conn, _opts) do
token = get_token_from_header(conn) || get_token_from_params(conn) || ""
conn = put_req_header(conn, "authorization", token)
conn
end
defp get_token_from_header(conn) do
case get_req_header(conn, @api_key_header) do
[val | _] -> val
_ -> nil
end
end
defp get_token_from_params(conn), do: Map.get(conn.query_params, @api_key_param)
end
You can use this to transfer values from any intended header or param to any header in your request.
Banner Image : https://blog.logrocket.com/wp-content/uploads/2022/10/phoenix-plugs-web-app-functions.png
Top comments (0)