Current section
Files
Jump to
Current section
Files
lib/jwt_armor.ex
defmodule JwtArmor do
@moduledoc """
Documentation for `JwtArmor`.
JwtArmor wraps the Joken package to make it simpler to use with the security best practices.
"""
@doc """
Generate the token for a given config and any extra info you need.
```
config = %JwtArmor.Config{
signer: %JwtArmor.Config.Signer{
algorithm: "HS256",
secret: "my secret key"
},
claims: %JwtArmor.Config.Claims{
exp: 60 * 60, # 1 hour
aud: "the-audience",
iss: "the-issuser"
}
}
{ok, token, claims} = JwtArmor.generate(config, %{"extra_id" => "any id"})
```
"""
def generate(%JwtArmor.Config{} = config, %{} = extras \\ %{}) do
Joken.generate_and_sign(token_config(config.claims), extras, signer(config.signer), [])
end
defp token_config(%JwtArmor.Config.Claims{} = claims_config) do
Joken.Config.default_claims()
|> Map.merge(%{
"exp" => handle_claim_exp(claims_config.exp),
"aud" => handle_claim_aud(claims_config.aud),
"iss" => handle_claim_iss(claims_config.iss)
})
end
defp signer(%JwtArmor.Config.Signer{} = signer_config) do
Joken.Signer.create(signer_config.algorithm, signer_config.secret)
end
defp handle_claim_exp(expiry_in_seconds) do
extra_seconds =
case expiry_in_seconds do
nil ->
0
_ ->
expiry_in_seconds
end
%Joken.Claim{
generate: fn -> Joken.current_time() + extra_seconds end,
validate: fn val, _claims, _context -> val > Joken.current_time() end
}
end
defp handle_claim_aud(audience) do
%Joken.Claim{
generate: fn -> audience end,
validate: fn val, _claims, _context -> val == audience end
}
end
defp handle_claim_iss(issuer) do
%Joken.Claim{
generate: fn -> issuer end,
validate: fn val, _claims, _context -> val == issuer end
}
end
@doc """
Verify the token by a given signer.
```
token = "a token example"
signer = %JwtArmor.Config.Signer{
algorithm: "HS256",
secret: "my secret key"
}
{ok, claims} = JwtArmor.verify(token, signer)
# if "ok" is an :error the "claims" contains the error message
```
"""
def verify(token, %JwtArmor.Config.Signer{} = signer_config) do
Joken.verify(token, signer(signer_config))
end
@doc """
Validate the token by a given signer.
```
token = "a token example"
claims = %JwtArmor.Config.Claims{
exp: 60 * 60, # 1 hour
aud: "the-audience",
iss: "the-issuser"
}
{ok, claim_maps} = JwtArmor.validate(token, claims)
# if "ok" is an :error the "claim_maps" contains the error message
```
"""
def validate(%JwtArmor.Config.Claims{} = claims_config, verified_claims) do
token_config(claims_config)
|> Joken.validate(verified_claims)
end
@doc """
Verify and validate the token by a given config.
```
token = "a token example"
config = %JwtArmor.Config{
signer: %JwtArmor.Config.Signer{
algorithm: "HS256",
secret: "my secret key"
},
claims: %JwtArmor.Config.Claims{
exp: 60 * 60, # 1 hour
aud: "the-audience",
iss: "the-issuser"
}
}
{ok, claims} = JwtArmor.verify_and_validate(token, config)
# if "ok" is an :error the "claims" contains the error message
```
"""
def verify_and_validate(token, %JwtArmor.Config{} = config) do
token_config(config.claims)
|> Joken.verify_and_validate(token, signer(config.signer))
end
end