Skip to content

Instantly share code, notes, and snippets.

@UA3MQJ
Last active May 16, 2021 21:54
Show Gist options
  • Save UA3MQJ/d4aad1cda62a43364f53ffad08b865d9 to your computer and use it in GitHub Desktop.
Save UA3MQJ/d4aad1cda62a43364f53ffad08b865d9 to your computer and use it in GitHub Desktop.
Elixir Joken JWT Examples v1.x

https://github.com/bryanjos/joken - A JSON Web Token (JWT) Library

1. Закодировать JWT - подпись секретным текстовым ключем "my_secret_key"

  token = %{user_id: 123}
  |> Joken.token()
  |> Joken.with_signer(Joken.hs256("my_secret_key"))
  |> Joken.sign()
  |> Joken.get_compact()

Результат - токен

"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjN9.czVgXnZv56oliGbbFV3HZMwrJsZEWgpoZO13yxgjPuA"

2. Расшифровать токен без проверки

  token
  |> Joken.token()
  |> Joken.peek()

Результат - данные

%{"user_id" => 123}

3. Проверить подпись, зная текстовый секретный ключ

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"}

3. Ассиметричное шифрование

Цель - сделать так, чтобы Сервер А создал токен, а Сервер Б мог проверить подпись токена, при этом не разглашая "секретный ключ" из Сервера А в Сервер Б, т.к. он нам может не принадлежать. Для этого можно применять пару закрытый/публичный ключ.

Формируем пары ключей (вторая пара для теста проверки подписи не тем открытым ключем):

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

3.1 Создаем токен, подписанный приватным ключем1

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()

3.2 Проверяем подпись, имея только публичный ключ1

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"}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment