https://github.com/bryanjos/joken - A JSON Web Token (JWT) Library
token = %{user_id: 123}
|> Joken.token()
|> Joken.with_signer(Joken.hs256("my_secret_key"))
|> Joken.sign()
|> Joken.get_compact()
Результат - токен
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjN9.czVgXnZv56oliGbbFV3HZMwrJsZEWgpoZO13yxgjPuA"
token
|> Joken.token()
|> Joken.peek()
Результат - данные
%{"user_id" => 123}
token \
|> Joken.token() \
|> Joken.with_signer(Joken.hs256("my_secret_key")) \
|> Joken.verify!()
Результат - {:ok, данные}
{:ok, %{"user_id" => 123}}
Поддельный токен
fake_data = token
|> String.split(".")
|> (fn([_, y, _]) -> y end).()
|> Base.url_decode64!(padding: false)
|> Poison.decode!()
|> Map.merge(%{"user_id" => 666})
|> Poison.encode!()
|> Base.url_encode64(padding: false)
"eyJ1c2VyX2lkIjo2NjZ9"
[head, _, sign] = token
|> String.split(".")
fake_token = head <> "." <> fake_data <> "." <> sign
iex(xx)> fake_token = head <> "." <> fake_data <> "." <> sign
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo2NjZ9.czVgXnZv56oliGbbFV3HZMwrJsZEWgpoZO13yxgjPuA"
iex(xx)> token
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjN9.czVgXnZv56oliGbbFV3HZMwrJsZEWgpoZO13yxgjPuA"
проверяем
fake_token
|> Joken.token()
|> Joken.with_signer(Joken.hs256("my_secret_key"))
|> Joken.verify!()
{:error, "Invalid signature"}
проверяем не верным секретным текстовым ключем
token
|> Joken.token()
|> Joken.with_signer(Joken.hs256("my_fake_secret_key"))
|> Joken.verify!()
{:error, "Invalid signature"}
Цель - сделать так, чтобы Сервер А создал токен, а Сервер Б мог проверить подпись токена, при этом не разглашая "секретный ключ" из Сервера А в Сервер Б, т.к. он нам может не принадлежать. Для этого можно применять пару закрытый/публичный ключ.
Формируем пары ключей (вторая пара для теста проверки подписи не тем открытым ключем):
openssl genrsa -out mykey1.pri 1024
openssl rsa -in mykey1.pri -pubout > mykey1.pub
openssl genrsa -out mykey2.pri 1024
openssl rsa -in mykey2.pri -pubout > mykey2.pub
key_pri = JOSE.JWK.from_pem_file("./mykey1.pri") # загружаем ключ
signed_token = %{user_id: 123}
|> Joken.token()
|> Joken.sign(Joken.rs256(key_pri))
|> Joken.get_compact()
key_pub = JOSE.JWK.from_pem_file("./mykey1.pub") # загружаем публичный ключ
signed_token \
|> Joken.token() \
|> Joken.with_signer(Joken.rs256(key_pub)) \
|> Joken.verify!()
Результат - {:ok, данные}
{:ok, %{"user_id" => 123}}
С другим публичным ключем будет, естественно, ошибка:
key_pub2 = JOSE.JWK.from_pem_file("./mykey2.pub")
signed_token \
|> Joken.token() \
|> Joken.with_signer(Joken.rs256(key_pub2)) \
|> Joken.verify!()
{:error, "Invalid signature"}