Packages
auth_plug
0.3.1
1.5.2
1.5.1
1.5.0
1.4.21
1.4.20
1.4.19
1.4.18
1.4.17
1.4.16
1.4.15
1.4.14
1.4.13
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.7
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.3
1.2.2
1.2.1
1.2.0
1.1.1
1.1.0
1.0.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.5.0
0.4.0
0.3.1
0.3.0
0.2.1
0.2.0
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Turnkey Auth Plug lets you protect any route in an Elixir/Phoenix App.
Current section
Files
Jump to
Current section
Files
lib/auth_plug.ex
defmodule AuthPlug do
import Plug.Conn # https://hexdocs.pm/plug/readme.html#the-plug-conn-struct
require Logger # https://hexdocs.pm/logger/Logger.html
@secret System.get_env("SECRET_KEY_BASE")
@signer Joken.Signer.create("HS256", @secret)
def init(options) do
options # return options unmodified
end
def call(conn, options) do
# Setup Plug.Session
conn = setup_session(conn)
# Locate JWT so we can attempt to verify it:
jwt = cond do
# Check for Person in Plug.Conn.assigns
Map.has_key?(conn.assigns, :person) && not is_nil(conn.assigns.person) ->
conn.assigns.person
# Check for Session in Plug.Session:
not is_nil(get_session(conn, :person)) ->
get_session(conn, :person)
# Check for JWT in URL Query String:
conn.query_string =~ "jwt" ->
query = URI.decode_query(conn.query_string)
Map.get(query, "jwt")
# Check for JWT in Headers:
Enum.count(get_req_header(conn, "authorization")) > 0 ->
conn.req_headers
|> List.keyfind("authorization", 0)
|> get_token_from_header()
# By default return nil so auth check fails
true ->
nil
end
validate_token(conn, jwt, options)
end
def setup_session(conn) do
conn = put_in(conn.secret_key_base, @secret)
opts =
Plug.Session.init(
store: :cookie,
key: "_auth_key",
secret_key_base: @secret,
signing_salt: @secret
)
conn
|> Plug.Session.call(opts)
|> fetch_session()
|> configure_session(renew: true)
end
# fail fast if no JWT in auth header:
defp get_token_from_header(nil), do: nil
defp get_token_from_header({"authorization", value}) do
value = String.replace(value, "Bearer", "") |> String.trim()
# fast check for JWT format validity before slower verify:
if is_nil(value) do
nil
else
case Enum.count(String.split(value, ".")) == 3 do
false ->
nil
# appears to be valid JWT proceed to verifying it
true ->
value
end
end
end
defp validate_token(conn, nil, opts), do: unauthorized(conn, opts)
defp validate_token(conn, jwt, opts) do
case AuthPlug.Token.verify_and_validate(jwt, @signer) do
{:ok, values} ->
# convert map of string to atom: stackoverflow.com/questions/31990134
claims = for {k, v} <- values, into: %{}, do: {String.to_atom(k), v}
conn
|> assign(:decoded, claims)
|> assign(:person, jwt)
|> put_session(:person, jwt)
{:error, reason} ->
Logger.error(Kernel.inspect(reason))
unauthorized(conn, opts)
end
end
defp unauthorized(conn, opts) do
baseurl = AuthPlug.Helpers.get_baseurl_from_conn(conn)
to = opts.auth_url <> "?redirect=" <> baseurl <> conn.request_path
status = 301 # gotta tell the browser to redirect to the auth_url with 301
conn
|> put_resp_header("location", to) # redirect to auth_url
|> resp(status, "unauthorized") # only our tests see this.
|> halt() # halt the conn so no further processing is done.
end
end