dwyl / learn-json-web-tokens

:closed_lock_with_key: Learn how to use JSON Web Token (JWT) to secure your next Web App! (Tutorial/Example with Tests!!)
MIT License
4.18k stars 254 forks source link

Translate Example to Elixir #104

Open nelsonic opened 5 years ago

nelsonic commented 5 years ago

This tutorial is great for JavaScript but it would be amaze to have it in Elixir from first principals to understand how to authenticate a request using JWT.

Todo

@RobStallion we briefly discussed this on the call today. Please add any other acceptance criteria you feel are relevant.

RobStallion commented 5 years ago

@nelsonic I have been reviewing the code in /example to get a better understanding of how it works in order for me to recreate it in elixir.

I think I have understood the gist of what is happening for the most part. You create a few routes in the server.js file and all the logic for these routes come from helper.js.

This is all straightforward enough to recreate in elixir (even without a phx server).

I have found a few packages/modules that are capable of creating JWTs in elixir. They are:

So far I have only used joken but it was fairly straightforward to create a JWT with it...

    {:ok, token, _} = LearnJwt.Token.generate_and_sign(%{user_id: 1})
    IO.inspect(token)

    LearnJwt.Token.verify_and_validate!(token)
    |> IO.inspect(label: "===> ")

logs....

"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJhdWQiOiJKb2tlbiIsImV4cCI6MTU1MzYzODYyMCwiaWF0IjoxNTUzNjMxNDIwLCJpc3MiOiJKb2tlbiIsImp0aSI6IjJtN3BuMnQ2MDBmMWN1Z3ZlazAwMDA1MyIsIm5iZiI6MTU1MzYzMTQyMH0.HQ-AQjvnIO7tIJF2joB45BJj7oLEznYSKUHZdMf9qe0"
===> : %{
  "aud" => "Joken",
  "exp" => 1553638620,
  "iat" => 1553631420,
  "iss" => "Joken",
  "jti" => "2m7pn2t600f1cugvek000053",
  "nbf" => 1553631420,
  "user_id" => 1
}

The verify_and_validate function also makes sure that the JWT has not been tampered with. If we create a JWT with the default secret and then try to decrypt it with a different secret we get an error... config/dev.exs

config :joken,
  default_signer: "secret",
  testing: "test"

some_controller

    {:ok, token2, _} = LearnJwt.Token.generate_and_sign(%{user_id: 1}, :testing)
    LearnJwt.Token.verify_and_validate!(token2)

we get the following error...

image

This means that we can use these functions to create and verify our JWTs.

The part I am not entirely sure how to replicate is this, sending the JWT to the client.

I can send it to the client in the assigns argument of the render function like so...

render(conn, "index.html", jwt: token)

at which point we could store it in localStorage.

I haven't yet touched on how we will send the JWT back to the server but I assume that we can do this with js on the front end if there is not a "clean" way to do it using phoenix forms. (I have not seen one example of a phoenix application using phoenix templating to send jwt back to the server which leads me to think it is not "clean")

nelsonic commented 5 years ago

@RobStallion please consider using https://hexdocs.pm/plug/Plug.Conn.html put_private/3 to save the JTW as auth_token. For an implementation example see: /lib/expected/plugs.ex#L88 LMK if you have want to walk+talk through it at any point this morning. 🤙

nelsonic commented 5 years ago

Have you had a read of: https://hexdocs.pm/plug/Plug.Session.COOKIE.html ? 💭

RobStallion commented 5 years ago

Taking a short break from this for now. Will come back to in a couple of days