View Source Charon.TokenFactory.SymmetricJwt (Charon v1.0.1-beta)
The default and most simple form of self-signed tokens, JWTs with symmetric-key signatures. These are suited for everything but OpenID Connect implementations, because these require third parties to verify the token signature, which requires assymetric keys.
config
Config
Additional config is required for this module (see Charon.TokenFactory.SymmetricJwt.Config
):
Charon.Config.from_enum(
...,
optional_modules: %{
Charon.TokenFactory.SymmetricJwt => %{
get_secret: fn -> :crypto.strong_rand_bytes(32) end,
algorithm: :poly1305,
json_module: Jason
}
}
)
The following options are supported:
:get_secret
(required). A getter/0 for secret for the JWT's signature algorithm. Must be exactly 256 bits in case of Poly1305 alg.:algorithm
(optional). The token signature algorithm, may be:sha256
(default),:sha384
,:sha512
or:poly1305
.:json_module
(optional, default Jason). The JSON encoding lib.
examples-doctests
Examples / doctests
# verify ignores the config's algorithm, grabbing it from the JWT header instead
# this allows changing algorithms without invalidating existing JWTs
iex> get_secret = fn -> "symmetric key" end
iex> config = %{optional_modules: %{SymmetricJwt => SymmetricJwt.Config.from_enum(get_secret: get_secret)}}
iex> payload = %{"iss" => "joe", "exp" => 1_300_819_380, "http://example.com/is_root" => true}
iex> {:ok, token} = sign(payload, config)
{:ok, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlLCJpc3MiOiJqb2UifQ.shLcxOl_HBBsOTvPnskfIlxHUibPN7Y9T4LhPB-iBwM"}
iex> config = %{optional_modules: %{SymmetricJwt => SymmetricJwt.Config.from_enum(get_secret: get_secret, algorithm: :sha512)}}
iex> {:ok, ^payload} = verify(token, config)
iex> get_secret = fn -> "symmetric key" end
iex> config = %{optional_modules: %{SymmetricJwt => SymmetricJwt.Config.from_enum(get_secret: get_secret)}}
iex> verify("a", config)
{:error, "malformed token"}
iex> verify("a.b.c", config)
{:error, "encoding invalid"}
iex> header = %{"alg" => "boom"} |> Jason.encode!() |> Base.url_encode64(padding: false)
iex> verify(header <> ".YQ.YQ", config)
{:error, "unsupported signature algorithm"}
iex> header = %{"alg" => "HS256"} |> Jason.encode!() |> Base.url_encode64(padding: false)
iex> verify(header <> ".YQ.YQ", config)
{:error, "signature invalid"}
# poly1305 is also supported, and requires a 256-bits key
iex> secret = :crypto.strong_rand_bytes(32)
iex> get_secret = fn -> secret end
iex> config = %{optional_modules: %{SymmetricJwt => SymmetricJwt.Config.from_enum(get_secret: get_secret, algorithm: :poly1305)}}
iex> payload = %{"iss" => "joe", "exp" => 1_300_819_380, "http://example.com/is_root" => true}
iex> {:ok, token} = sign(payload, config)
iex> {:ok, ^payload} = verify(token, config)
iex> header = token |> String.split(".") |> List.first() |> Base.url_decode64!() |> Jason.decode!()
iex> %{"alg" => "Poly1305", "nonce" => <<_::binary>>, "typ" => "JWT"} = header
iex> config = %{optional_modules: %{SymmetricJwt => SymmetricJwt.Config.from_enum(get_secret: fn -> :crypto.strong_rand_bytes(32) end)}}
iex> {:error, "signature invalid"} = verify(token, config)