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

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

srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
pgiesin
This should be a simple problem but I just can’t seem to figure it out. I have a standalone Elixir app that won’t find the database. Dep...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
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
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
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 45766 226
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New

We're in Beta

About us Mission Statement