Joken.Config behaviour (Joken v2.4.0) View Source

Main entry point for configuring Joken. This module has two approaches:

Creating a map of Joken.Claim s

If you prefer to avoid using macros, you can create your configuration manually. Joken's configuration is just a map with keys being binaries (the claim name) and the value an instance of Joken.Claim.

Example

%{"exp" => %Joken.Claim{
  generate: fn -> Joken.Config.current_time() + (2 * 60 * 60) end,
  validate: fn val, _claims, _context -> val < Joken.Config.current_time() end
}}

Since this is cumbersome and error prone, you can use this module with a more fluent API, see:

Another approach is to just use Joken.Config in a module. This will load a signer configuration (from config.exs) and a map of Joken.Claim s.

Example

defmodule MyAuth do
  use Joken.Config
end

This way, Joken.Config will implement some functions for you:

  • generate_claims/1: generates dynamic claims and adds them to the passed map.
  • encode_and_sign/2: takes a map of claims, encodes it to JSON and signs it.
  • verify/2: check for token tampering using a signer.
  • validate/2: takes a claim map and a configuration to run validations.
  • generate_and_sign/2: combines generation and signing.
  • verify_and_validate/2: combines verification and validation.
  • token_config/0: where you customize token generation and validation.

It will also add use Joken.Hooks so you can easily hook into Joken's lifecycle.

Overriding functions

All callbacks in Joken.Config and Joken.Hooks are overridable. This can be used for customizing the token configuration. All that is needed is to override the token_config/0 function returning your map of binary keys to Joken.Claim structs. Example from the benchmark suite:

defmodule MyCustomClaimsAuth do
  use Joken.Config

  @impl true
  def token_config do
    %{} # empty claim map
    |> add_claim("name", fn -> "John Doe" end, &(&1 == "John Doe"))
    |> add_claim("test", fn -> true end, &(&1 == true))
    |> add_claim("age", fn -> 666 end, &(&1 > 18))
    |> add_claim("simple time test", fn -> 1 end, &(Joken.current_time() > &1))
  end
end

Customizing default generated claims

The default claims generation is just a bypass call to default_claims/1. If one would like to customize it, then we need only to override the token_config function:

defmodule MyCustomDefaults do
  use Joken.Config

  def token_config, do: default_claims(default_exp: 60 * 60) # 1 hour
end

Options

You can pass some options to use Joken.Config to ease on your configuration:

  • :default_signer: a signer configuration key in config.exs (see Joken.Signer)

Link to this section Summary

Callbacks

Encodes the given map of claims to JSON and signs it.

Generates a JWT claim set.

Defines the Joken.token_config/0 used for all the operations in this module.

Runs validations on the already verified token.

Verifies token's signature using a Joken.Signer.

Functions

Adds the given hook to the list of hooks passed to all operations in this module.

Initializes a map of Joken.Claims with "exp", "iat", "nbf", "iss", "aud" and "jti".

Link to this section Callbacks

Link to this callback

encode_and_sign(claims, arg2)

View Source

Specs

encode_and_sign(Joken.claims(), Joken.signer_arg() | nil) ::
  {:ok, Joken.bearer_token(), Joken.claims()} | {:error, Joken.error_reason()}

Encodes the given map of claims to JSON and signs it.

The signer used will be (in order of preference):

  1. The one represented by the key passed as second argument. The signer will be parsed from the configuration.
  2. If no argument was passed then we will use the one from the configuration :default_signer passed as argument for the use Joken.Config macro.
  3. If no key was passed for the use macro then we will use the one configured as :default_signer in the configuration.

Specs

generate_claims(extra :: Joken.claims()) ::
  {:ok, Joken.claims()} | {:error, Joken.error_reason()}

Generates a JWT claim set.

Extra claims must be a map with keys as binaries. Ex: %{"sub" => "some@one.com"}

Specs

token_config() :: Joken.token_config()

Defines the Joken.token_config/0 used for all the operations in this module.

The default implementation is just a bypass call to default_claims/1.

Specs

validate(Joken.claims(), term()) ::
  {:ok, Joken.claims()} | {:error, Joken.error_reason()}

Runs validations on the already verified token.

Link to this callback

verify(bearer_token, arg2)

View Source

Specs

verify(Joken.bearer_token(), Joken.signer_arg() | nil) ::
  {:ok, Joken.claims()} | {:error, Joken.error_reason()}

Verifies token's signature using a Joken.Signer.

The signer used is (in order of precedence):

  1. The signer in the configuration with the given key.
  2. The Joken.Signer instance passed to the method.
  3. The signer passed in the use Joken.Config through the default_signer key.
  4. The default signer in configuration (the one with the key default_signer).

It returns either:

  • {:ok, claims_map} where claims_map is the token's claims.
  • {:error, [message: message, claim: key, claim_val: claim_value]} where message can be used on the frontend (it does not contain which claim nor which value failed).

Link to this section Functions

Link to this function

add_claim(config, claim_key, generate_fun \\ nil, validate_fun \\ nil, options \\ [])

View Source

Specs

add_claim(
  Joken.token_config(),
  binary(),
  (... -> any()) | nil,
  (... -> any()) | nil,
  Keyword.t()
) :: Joken.token_config()

Adds a Joken.Claim with the given claim key to a map.

This is a convenience builder function. It does exactly what this example does:

iex> config = %{}
iex> generate_fun = fn -> "Hi" end
iex> validate_fun = &(&1 =~ "Hi")
iex> claim = %Joken.Claims{generate: generate_fun, validate: validate_fun}
iex> config = Map.put(config, "claim key", claim)
Link to this macro

add_hook(hook_module, options \\ [])

View Source (macro)

Adds the given hook to the list of hooks passed to all operations in this module.

When using use Joken.Config in a module, this already adds the module as a hook. So, if you want to only override one lifecycle callback, you can simply override it on the module that uses Joken.Config.

Link to this function

default_claims(options \\ [])

View Source

Specs

default_claims(Keyword.t()) :: Joken.token_config()

Initializes a map of Joken.Claims with "exp", "iat", "nbf", "iss", "aud" and "jti".

Default parameters can be customized with options:

  • :skip: do not include claims in this list. Ex: [:iss, :aud]
  • :default_exp: changes the default expiration of the token. Default is 2 hours
  • :iss: changes the issuer claim. Default is "Joken"
  • :aud: changes the audience claim. Default is "Joken"