Packages
joken
1.2.1
2.6.2
2.6.1
2.6.0
2.5.0
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.1
2.0.0
2.0.0-rc3
2.0.0-rc2
2.0.0-rc1
2.0.0-rc0
1.5.0
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.2
1.2.1
1.2.0
1.1.1
1.1.0
1.0.1
1.0.0
0.16.1
0.16.0
0.15.0
0.14.1
0.14.0
0.13.1
0.13.0
0.12.0
0.11.0
0.10.1
0.10.0
0.8.1
0.8.0
0.7.0
0.6.2
0.6.1
0.6.0
0.5.0
0.1.0
JWT (JSON Web Token) library for Elixir.
Current section
Files
Jump to
Current section
Files
lib/joken/plug.ex
if Code.ensure_loaded?(Plug.Conn) do
defmodule Joken.Plug do
import Joken
alias Joken.Token
require Logger
@moduledoc """
A Plug for signing and verifying authentication tokens.
## Usage
There are two possible scenarios:
1. Same configuration for all routes
2. Per route configuration
In the first scenario just add this plug before the dispatch plug.
defmodule MyRouter do
use Plug.Router
plug Joken.Plug, verify: &MyRouter.verify_function/0
plug :match
plug :dispatch
post "/user" do
# will only execute here if token is present and valid
end
match _ do
# will only execute here if token is present and valid
end
def verify_function() do
%Joken.Token{}
|> Joken.with_signer(hs256("secret"))
|> Joken.with_sub(1234567890)
end
end
In the second scenario, you will need at least plug ~> 0.14 in your deps.
Then you must plug this AFTER :match and BEFORE :dispatch.
defmodule MyRouter do
use Plug.Router
# route options
@skip_token_verification %{joken_skip: true}
plug :match
plug Joken.Plug, verify: &MyRouter.verify_function/0
plug :dispatch
post "/user" do
# will only execute here if token is present and valid
end
# see options section below
match _, private: @skip_token_verification do
# will NOT try to validate a token
end
def verify_function() do
%Joken.Token{}
|> Joken.with_signer(hs256("secret"))
|> Joken.with_sub(1234567890)
end
end
## Options
This plug accepts the following options in its initialization:
- `verify` (required): a function used to verify the token. The function must at least specify algorithm used and your secret using the `with_signer` function (see above). Must return a Token.
- `on_error` (optional): a function that will be called with `conn` and
`message`. Must return a tuple containing the conn and a binary representing
the 401 response. If it's a map, it will be turned into json, otherwise, it
will be returned as is.
When using this with per route options you must pass a private map of
options to the route. The keys that Joken will look for in that map are:
- `joken_skip`: skips token validation
- `joken_verify`: Same as `verify` above. Overrides
`verify` if it was defined on the Plug
- `joken_on_error`: Same as `on_error` above. Overrides
`on_error` if it was defined on the Plug
"""
import Plug.Conn
@lint {Credo.Check.Design.AliasUsage, false}
@doc false
def init(opts) do
verify = get_verify(opts)
on_error = Keyword.get(opts, :on_error, &Joken.Plug.default_on_error/2)
{verify, on_error}
end
@doc false
def call(conn, {verify, on_error}) do
unless Map.has_key?(conn.private, :joken_verify) do
conn = set_joken_verify(conn, verify)
end
unless Map.has_key?(conn.private, :joken_on_error) do
conn = put_private(conn, :joken_on_error, on_error)
end
if Map.get(conn.private, :joken_skip, false) do
conn
else
parse_auth(conn, get_req_header(conn, "authorization"))
end
end
defp get_verify(options) do
case Keyword.take(options, [:verify, :on_verifying]) do
[verify: verify] -> verify
[verify: verify, on_verifying: _] ->
warn_on_verifying
verify
[on_verifying: verify] ->
warn_on_verifying
verify
[] ->
warn_supply_verify_function
nil
end
end
defp warn_on_verifying do
Logger.warn "on_verifying is deprecated for the Joken plug and will be removed in a future version. Please use verify instead."
end
defp warn_supply_verify_function do
Logger.warn "You need to supply a verify function to the Joken token."
end
defp set_joken_verify(conn, verify) do
case conn.private do
%{joken_on_verifying: deprecated_verify} ->
warn_on_verifying
put_private(conn, :joken_verify, deprecated_verify)
_ ->
put_private(conn, :joken_verify, verify)
end
end
defp parse_auth(conn, ["Bearer " <> incoming_token]) do
payload_fun = Map.get(conn.private, :joken_verify)
verified_token = payload_fun.()
|> with_compact_token(incoming_token)
|> verify
evaluate(conn, verified_token)
end
defp parse_auth(conn, _header) do
send_401(conn, "Unauthorized")
end
defp evaluate(conn, %Token{error: nil} = token) do
assign(conn, :joken_claims, get_claims(token))
end
defp evaluate(conn, %Token{error: message}) do
send_401(conn, message)
end
defp send_401(conn, message) do
on_error = conn.private[:joken_on_error]
{conn, message} = case on_error.(conn, message) do
{conn, map} when is_map(map) ->
create_json_response(conn, map)
response ->
response
end
conn
|> send_resp(401, message)
|> halt
end
defp create_json_response(conn, map) do
conn = put_resp_content_type(conn, "application/json")
json = Poison.encode!(map)
{conn, json}
end
@doc false
def default_on_error(conn, message) do
{conn, message}
end
end
end