This is an Elixir Plug for adding basic authentication into an application.
The plug can be configured to use:
- Static username and password in application configuration
-OR-
- Your own custom authentication function
Note that putting values directly into the plug is no longer supported.
## NO LONGER SUPPORTED
plug BasicAuth, realm: "realm", password: "password", username: "username"
Add the package as a dependency in your Elixir project using something along the lines of:
defp deps do
[{:basic_auth, "~> 2.1.4"}]
end
Add into the top of a controller, or into a router pipeline a plug declaration like:
plug BasicAuth, use_config: {:your_app, :your_config}
Where :your_app and :your_config should refer to values in your application config.
In your configuration you can set values directly, eg
config :your_app, your_config: [
username: "admin",
password: "simple_password",
realm: "Admin Area"
]
or choose to get one (or all) from environment variables, eg
config :basic_auth, my_auth_with_system: [
username: {:system, "BASIC_AUTH_USERNAME"},
password: {:system, "BASIC_AUTH_PASSWORD"},
realm: {:system, "BASIC_AUTH_REALM"}
]
Alternatively you can provide a custom function to the plug to authenticate the user any way you want, such as finding the user from a database.
plug BasicAuth, callback: &User.find_by_username_and_password/3
(or optionally provide a realm)
plug BasicAuth, callback: &User.find_by_username_and_password/3, realm: "Area 51"
Where :callback is your custom authentication function that takes a conn, username and a
password and returns a conn. Your function must return Plug.Conn.halt(conn)
if authentication
fails, otherwise you can use Plug.Conn.assign(conn, :current_user, ...)
to enhance
the conn with variables or session for your controller.
Easy as that!
If you're looking to authenticate only for a subset of actions in a controller you can use plug's when action in
syntax as shown below
plug BasicAuth, [use_config: {: your_app, : your_config}] when action in [:edit, :delete]
additionally you can exclude specific actions using not
plug BasicAuth, [use_config: {: your_app, : your_config}] when not action in [:index, :show]
If you're storing credentials within configuration files, we can reuse them within our test files
directly using snippets like Application.get_env(:basic_auth)[:username]
.
Any controller that makes use of basic authentication, will need an additional header injected into the connection in order for your tests to continue to work. The following is a brief snippet of how to get started. There is a more detailed blog post that explains a bit more about what needs to be done.
At the top of my controller test I have something that looks like:
@username Application.get_env(:the_app, :basic_auth)[:username]
@password Application.get_env(:the_app, :basic_auth)[:password]
defp using_basic_auth(conn, username, password) do
header_content = "Basic " <> Base.encode64("#{username}:#{password}")
conn |> put_req_header("authorization", header_content)
end
Then for any tests, I can simply pipe in this helper method to the connection process:
test "GET / successfully renders when basic auth credentials supplied" do
conn = conn
|> using_basic_auth(@username, @password)
|> get("/admin/users")
assert html_response(conn, 200) =~ "Users"
end
And a test case without basic auth for completeness:
test "GET / without basic auth credentials prevents access" do
conn = conn
|> get("/admin/users")
assert response(conn, 401) =~ "401 Unauthorized"
end