Plug.BasicAuth
Functionality for providing Basic HTTP authentication.
It is recommended to only use this module in production if SSL is enabled and enforced. See Plug.SSL
for more information.
Compile-time usage
If you have a single username and password, you can use the basic_auth/2
plug:
import Plug.BasicAuth plug :basic_auth, username: "hello", password: "secret"
Or if you would rather put those in a config file:
# lib/your_app.ex import Plug.BasicAuth plug :basic_auth, Application.compile_env(:my_app, :basic_auth) # config/config.exs config :my_app, :basic_auth, username: "hello", password: "secret"
Once the user first accesses the page, the request will be denied with reason 401 and the request is halted. The browser will then prompt the user for username and password. If they match, then the request succeeds.
Both approaches shown above rely on static configuration. Let's see alternatives.
Runtime-time usage
As any other Plug, we can use the basic_auth
at runtime by simply wrapping it in a function:
plug :auth defp auth(conn, opts) do username = System.fetch_env!("AUTH_USERNAME") password = System.fetch_env!("AUTH_PASSWORD") Plug.BasicAuth.basic_auth(conn, username: username, password: password) end
This approach is useful when both username and password are specified upfront and available at runtime. However, you may also want to compute a different password for each different user. In those cases, we can use the low-level API.
Low-level usage
If you want to provide your own authentication logic on top of Basic HTTP auth, you can use the low-level functions. As an example, we define :auth
plug that extracts username and password from the request headers, compares them against the database, and either assigns a :current_user
on success or responds with an error on failure.
plug :auth defp auth(conn, _opts) do with {user, pass} <- Plug.BasicAuth.parse_basic_auth(conn), %User{} = user <- MyApp.Accounts.find_by_username_and_password(user, pass) do assign(conn, :current_user, user) else _ -> conn |> Plug.BasicAuth.request_basic_auth() |> halt() end end
Keep in mind that:
The supplied
user
andpass
may be empty strings;If you are comparing the username and password with existing strings, do not use
==/2
. UsePlug.Crypto.secure_compare/2
instead.
Summary
Functions
- basic_auth(conn, options \\ [])
Higher level usage of Basic HTTP auth.
- encode_basic_auth(user, pass)
Encodes a basic authentication header.
- parse_basic_auth(conn)
Parses the request username and password from Basic HTTP auth.
- request_basic_auth(conn, options \\ [])
Requests basic authentication from the client.
Functions
basic_auth(conn, options \\ [])
Higher level usage of Basic HTTP auth.
See the module docs for examples.
Options
-
:username
- the expected username -
:password
- the expected password -
:realm
- the authentication realm. The value is not fully sanitized, so do not accept user input as the realm and use strings with only alphanumeric characters and space
encode_basic_auth(user, pass)
Encodes a basic authentication header.
This can be used during tests:
put_req_header(conn, "authorization", encode_basic_auth("hello", "world"))
parse_basic_auth(conn)
Parses the request username and password from Basic HTTP auth.
It returns either {user, pass}
or :error
. Note the username and password may be empty strings. When comparing the username and password with the expected values, be sure to use Plug.Crypto.secure_compare/2
.
See the module docs for examples.
request_basic_auth(conn, options \\ [])
Requests basic authentication from the client.
It sets the response to status 401 with "Unauthorized" as body. The response is not sent though (nor the connection is halted), allowing developers to further customize it.
Options
-
:realm
- the authentication realm. The value is not fully sanitized, so do not accept user input as the realm and use strings with only alphanumeric characters and space
© 2013 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/plug/Plug.BasicAuth.html