Add Basic Auth to Phoenix with Environment Variables

There are some situations where you want to block access to an environment such as when you're just staging a project. For this particular case, using a custom Basic Auth Plug that's conditional on environment variables may be all you need.
Add Basic Auth to Phoenix with Environment Variables

There are some situations where you want to block access to an environment such as when you’re just staging a project.

For this particular case, using a custom Basic Auth Plug that’s conditional on environment variables may be all you need.

Let’s get started by create a custom plug and then “plug” it into our system.

It’s assumed that you want to restrict access to the entire application in a staging environment.

Basic Auth Plug

First create WEB/controllers/basic_auth.ex with this content:

(Remember to update MyAppWeb)

defmodule MyAppWeb.BasicAuth do
  import Plug.Conn
  @realm "Basic realm=\"Staging\""

  def init(opts), do: opts

  def call(conn, correct_auth) do
    case get_req_header(conn, "authorization") do
      ["Basic " <> attempted_auth] -> verify(conn, attempted_auth, correct_auth)
      _ -> unauthorized(conn)
    end
  end

  defp verify(conn, attempted_auth, username: username, password: password) do
    case encode(username, password) do
      ^attempted_auth -> conn
      _ -> unauthorized(conn)
    end
  end

  defp encode(username, password), do: Base.encode64(username <> ":" <> password)

  defp unauthorized(conn) do
    conn
    |> put_resp_header("www-authenticate", @realm)
    |> send_resp(401, "unauthorized")
    |> halt()
  end
end

Configuration

Next, let’s add some simple configuration to config/config.ex:

config :my_app, MyAppWeb.BasicAuth, username: "admin", password: "secret"

You can also use environment variables to keep these values out of your repo, but for this simple set up, let’s just keep it as is.

Router Conditional

Open WEB/router.ex and add the plug to a pipeline:

pipeline :browser do
  ...
  if System.get_env("APP_DOMAIN") == "staging.myapp.com" do
    plug BasicAuth, Application.fetch_env!(:my_app, BasicAuth)
  end
end

This will check for the value of APP_DOMAIN and conditionally pipe the connection through the custom plug.

NOTE: Don’t forget to actually set APP_DOMAIN in your staging environment.

Test Locally

You can optionally test the new Plug out by passing the environment variable’s expected value when you start up the Phoenix server:

$ APP_DOMAIN=staging.myapp.com mix -S phx.server

Then you should see the basic auth prompt to enter the credentials.

Wrapping Up

This was a very simple strategy for restricting access to a staging environment without adding any dependencies.

This can be expanding and improved upon in many ways but should serve as a basic starting point.

Troy Martin
Senior Engineer working with Elixir and JS.
Keep in the Loop

Subscribe for Updates