• Stars
    star
    164
  • Rank 230,032 (Top 5 %)
  • Language
    Elixir
  • License
    MIT License
  • Created over 9 years ago
  • Updated over 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Elixir Plug to easily add HTTP basic authentication to an app

DEPRECATED

Plug.BasicAuth is now part of Plug.

BasicAuth

This is an Elixir Plug for adding basic authentication into an application.

The plug can be configured to use:

  1. Static username and password in application configuration

-OR-

  1. Your own custom authentication function

Note that if using option (1), prior to 2.2.1 the library was vulnerable to timing attacks; we suggest updating ~> 2.2.2.

If you are using your own custom authentication function, then you are are on your own. (Plug.Crypto.secure_compare/2 is something that may help you compare binaries in constant time.)

How to use

Add the package as a dependency in your Elixir project using something along the lines of:

  defp deps do
    [{:basic_auth, "~> 2.2.2"}]
  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"
]

All configuration is read at runtime to support using REPLACE_OS_VARS as part of a release.

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.

The function must have an arity of 3, and be of the form

@spec myfunction(Plug.Conn.t, String.t, String.t) :: Plug.Conn.t

It will receive a connection, username, and password.

Easy as that!

Authenticating with custom response body

If you want a custom unauthorised response body you can configure a custom_response:

plug BasicAuth,
    use_config: {:your_app, :your_config},
    custom_response: &YouApp.Helpers.unauthorized_response/1

or

plug BasicAuth,
    callback: &User.find_by_username_and_password/3,
    realm: "Area 51",
    custom_response: &YouApp.Helpers.unauthorized_response/1

Where :custom_response is a custom response function that takes a conn. For example:

def unauthorized_response(conn) do
    conn
    |> Plug.Conn.put_resp_content_type("application/json")
    |> Plug.Conn.send_resp(401, ~s[{"message": "Unauthorized"}])
  end

Authenticating only for specific actions

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]

Testing controllers with Basic Auth

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].

Update Tests to insert a basic authentication header

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", %{conn: conn} 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", %{conn: conn} do
  conn = conn
    |> get("/admin/users")

  assert response(conn, 401) =~ "401 Unauthorized"
end

More Repositories

1

fedecks_client

Client side of elixir device to phoenix comms over binary websockets
Elixir
14
star
2

binary-websockets-example

Simple example of using binary websocket messages within Phoenix
Elixir
10
star
3

fedecks_server

fedecks_server
Elixir
8
star
4

vintage_heart

For Nerves projects with networking. Gives VintageNet a kick if there's no internet connectivity, falling back on a reboot after 3 kicks.
Elixir
7
star
5

saxophone

Elixir
7
star
6

erlang_and_otp_in_action_in_elixir

Translating Erlang & OTP in Action example code into Elixir. For kicks.
Elixir
6
star
7

correct-horse-elixir

Correct horse battery staple in Elixir
Elixir
6
star
8

portynif

Elixir
4
star
9

yaapt-2

JavaScript
4
star
10

furlough

SCSS
4
star
11

stripe2qif

Elixir command line application for converting stripe balance changing applications to qif
Elixir
4
star
12

correcthorsebatterystaple

Generates passwords consisting of four words, inspired by http://xkcd.com/936/
HTML
4
star
13

otp-multicast-example

Using multicast with Elixir
Elixir
3
star
14

MapKitDragAndDrop

MapKit sample for custom AnnotationView drag-and-drop with dynamic callout info update
Objective-C
3
star
15

fit-bookstore

Java example bookstore for example application
Java
3
star
16

osx_watchfolder

Gem for watching folders in Ruby on OSX 10.5 +
Ruby
2
star
17

dotfiles

Shell
2
star
18

rbiphonetest_iphonetutorial

Objective-C
2
star
19

airtrafficcontrol

2
star
20

vintage_net_wizard_launcher

For Nerves projects, launches the VintageNetWizard if unconfigured and monitors a GPIO button for wizard launching
Elixir
2
star
21

shopping

Elixir
2
star
22

dummy-proxy

Java stunted framework for stubbing with partial implementations
Java
2
star
23

elixir-mix-format-pre-commit-hook

Pre-commit hook to check formatting
Shell
2
star
24

scip_classy

Anglo-Celt SICP Study Group - Group Classy solutions
2
star
25

fedecks

Client and Server pair of hexicles (Elixir hex packages) for communicating between a Nerves device and a Phoenix app
Elixir
1
star
26

deploy_example

Ruby
1
star
27

gproc_select_examples

Translation of https://gist.github.com/rustyio/188032 to Elixir
Elixir
1
star
28

forecast

Messing around with Elixir
Elixir
1
star
29

morsey

Use a physical telegraph key, and a Pi Zero, to send messages to Slack with morse code.
Elixir
1
star
30

ScratchCpps

C++
1
star
31

forecastwebapp

Elixir
1
star
32

mlx90640_c_lib

"Fork" of https://github.com/melexis/mlx90640-library for at least comparing with Elixir version
C++
1
star
33

programmingerlanginelixir

Elixir
1
star
34

hacky_memory_tracker

Ruby
1
star
35

pragmatic-elixir-exercises

Elixir
1
star
36

nerves_system

Nerves Elixir System Compiler
Elixir
1
star
37

connectivity_led_status

connectivity_led_status
Elixir
1
star
38

simplest_pub_sub

Arguably pointessly thin wrapper over Elixir's Registry for a simple Pub Sub
Elixir
1
star
39

ruby_irb_demonstration

Rough script for an introduction to Ruby demonstration using IRB
Ruby
1
star
40

hc_sr_501_occupation

Nerves, or similar, Elixir library for interfacing with a HC-SR501 passive infra-red motion sensor.
Elixir
1
star
41

asinatraapp

Ruby
1
star