fireproofsocks

fireproofsocks

Signing a JWT?

Does anyone have a full working example of signing JWTs? I guess this is partly a question about the process too… this is related to earlier work I did (and this other post).

When you complete a sign-in with Google, you are given a JWT. You can can look up the PEM that was used to sign the key at https://www.googleapis.com/oauth2/v1/certs

And that can be used to verify that the JWT has not been tampered with.

From
https://github.com/danharper/hmac-examples#elixir

There’s this Elixir example:

key = 'the shared secret key here'
message = 'the message to hash here'

signature = :crypto.hmac(:sha256, key, message)

# to lowercase hexits
Base.encode16(signature, case: :lower)

When you’re dealing with a JWT, the message is a Base64 encoding of the JSON header + the JSON claims. But what’s the key in this scenario? When Google lets us query its PEM, what is in that PEM? Is it a private key? A public key? Or a combination? And what gets used to sign the JWT?

I’m writing tests around this stuff, so I need to be able to generate a public + private key, convert them (or one of them?) to PEM format, and then properly sign the key so that the JWT can be properly checked.

Most Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Hey @fireproofsocks it’s a private key. Here is code I wrote to validate JWT keys against google firebase pem. You can probably refactor it to grab pems from somewhere else.

First, I had a genserver which, on boot, would fetch the keys from Google and put them in ets:

def request_keys(_) do
    url = keys_url()

    {:ok, 200, headers, body} = :hackney.request(:get, url, [], "", [:with_body])

    {_, cache_control} =
      Enum.find(headers, fn {k, _} ->
        String.downcase(k) == "cache-control"
      end)

    [_, expire_in] = Regex.run(~r/max\-age\=([0-9]*),/, cache_control)
    expire_in = String.to_integer(expire_in)

    body
    |> Jason.decode!()
    |> Map.values()
    |> Enum.map(&JOSE.JWK.from_pem/1)
    |> Enum.map(fn key ->
      %{type: :firebase, key: key, expire_in: expire_in * 1000}
    end)
  end

  defp keys_url() do
    "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com"
  end

That’s the fetching and parsing code, the ets and refresh based on expires in is left as an exercise to the reader.

In any case once that’s in place, when a request comes in with a JWT key you can verify it via:

def verify(token) do
    [{:keys, keys}] = :ets.lookup(Maven.Accounts.Auth, :keys)

    Enum.find_value(keys, &do_verify(&1, token))
  end

  defp do_verify(key_data, token) do
    case JOSE.JWT.verify(key_data.key, token) do
      {true, %{fields: fields}, _} ->
        {:ok, key_data.type, fields}

      _ ->
        nil
    end
  end
fireproofsocks

fireproofsocks

Thanks @benwilson512 – this is a clean example of how to verify keys, cleaner than what I had worked out. However, I was looking for how to sign the key. @danschultzer – I think AssentJWT.sign/3 does exactly what I want. Thank you!

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Hi @enkr1, please provide samples of the code you are running, and the resources you’ve tried to follow. We can’t help if you don’t show us what you’ve tried so far.

Where Next?

Popular in Questions Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
vac
Hi, I’m quite new in Elixir and I’m trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and I...
New
nobody
How to bind a phoenix app to a specific ip address? could not find anything about that, nowhere, unfortunately, but for me this is quite...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I’m a nov...
New

Other popular topics Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29377 241
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47930 226
New

We're in Beta

About us Mission Statement