71 lines
2.1 KiB
Elixir
71 lines
2.1 KiB
Elixir
defmodule BallsPDS.JWT do
|
|
alias BallsPDS.WAC
|
|
require Logger
|
|
|
|
def generate_my_jwk() do
|
|
raw_private_key = Base.decode16!(Application.get_env(:balls_pds, :owner_private_key))
|
|
generate_jwk(raw_private_key)
|
|
end
|
|
|
|
def generate_jwk(raw_private_key) when is_binary(raw_private_key) do
|
|
private_key = raw_private_key |> Base.encode64()
|
|
{:ok, public_key} = :crypto.generate_key(:eddsa, :ed25519, private_key)
|
|
JOSE.JWK.from_key({:okp, :Ed25519, public_key, private_key})
|
|
end
|
|
|
|
def query_public_jwk(ap_id, key_id) do
|
|
case WAC.cached_query_public_key(ap_id, key_id) do
|
|
{:ok, raw_public_key} ->
|
|
encoded_key = Base.url_encode64(raw_public_key, padding: false)
|
|
|
|
{:ok,
|
|
%{
|
|
# Key Type: Octet Key Pair
|
|
"kty" => "OKP",
|
|
# Curve: Ed25519
|
|
"crv" => "Ed25519",
|
|
# Public Key (Base64Url-encoded)
|
|
"x" => encoded_key
|
|
}}
|
|
end
|
|
end
|
|
|
|
def extract_key_info(jwt) when is_binary(jwt) do
|
|
with {:subject, {:ok, %{"sub" => subject}}} <- {:subject, JOSE.JWT.peek_payload(jwt)},
|
|
{:kid, {:ok, %{"kid" => kid}}} <- {:kid, JOSE.JWT.peek_protected(jwt)} do
|
|
{:ok, %{subject: subject, id: kid}}
|
|
else
|
|
{err, {:error, error}} ->
|
|
Logger.error("extracting key info from JWT: #{err}: #{inspect(error)}")
|
|
{:error, error}
|
|
end
|
|
end
|
|
|
|
def generate_jwt(days \\ 30) when is_integer(days) and days > 0 do
|
|
jwk = generate_my_jwk()
|
|
signer = Joken.Signer.create("EdDSA", jwk)
|
|
|
|
id = Application.get_env(:balls_pds, :owner_ap_id)
|
|
|
|
claims = %{
|
|
"iss" => id,
|
|
"sub" => id,
|
|
"aud" => Application.get_env(:balls_pds, :owner_ap_id),
|
|
"iat" => DateTime.utc_now() |> DateTime.to_unix(),
|
|
"exp" => DateTime.utc_now() |> DateTime.add(30, :day) |> DateTime.to_unix()
|
|
}
|
|
|
|
Joken.generate_and_sign!(claims, signer)
|
|
end
|
|
|
|
def verify_jwt(jwt, jwk) do
|
|
public_jwk = Map.drop(jwk, ["d"])
|
|
signer = Joken.Signer.create("EdDSA", public_jwk)
|
|
|
|
case Joken.verify_and_validate(signer, jwt) do
|
|
{:ok, claims} -> {:ok, claims}
|
|
{:error, reason} -> {:error, reason}
|
|
end
|
|
end
|
|
end
|