Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Placing Guardian tokens inside cookies and reading them from there

I have an application that uses JWT authentication with Guardian. When a user signs in, the response contains the jwt in the body. The front-end (which is an SPA) then stores that jwt in localStorage, and attaches it to the Authorization header of every request sent from there on. The server then verifies this using Guardian's built-in verification plug:

pipeline :api do
  plug :accepts, ["json"]
  plug Guardian.Plug.VerifyHeader, realm: "Bearer"
end

I would like to change this so that, instead of storing the JWTs in localStorage (which isn't secure), the server sends them to the front-end as secure cookies (with Secure and HttpOnly settings). I then want Guardian to read the jwt from the cookie, rather than from the Authorization header.

Does Guardian support this functionality?

Here is my SessionController create function:

def create(conn, params) do
  case authenticate(params) do
    {:ok, user} ->
      new_conn = Guardian.Plug.api_sign_in(conn, user, :access)
      jwt = Guardian.Plug.current_token(new_conn)

      new_conn
      |> put_status(:created)
      |> render("show.json", user: user, jwt: jwt)
    :error ->
      conn
      |> put_status(:unauthorized)
      |> render("error.json")
  end
end
like image 1000
Ege Ersoz Avatar asked Mar 14 '17 21:03

Ege Ersoz


1 Answers

UPDATE: This is with Guardian 1.0 (which you should use if you can!).

I think you can just do something like this:

defmodule MyApp.SessionController do
  def login(conn, params) do
    # your code to find the user based on auth strategy here
    {:ok, jwt, _} = MyApp.Guardian.encode_and_sign(user)
    conn = put_session(conn, :auth_token, jwt)
    # send your response...
  end
end

Would use HttpOnly and Secure flags on the cookie. Should be fine to store client side this way.

To fetch the user, you may need to write your own little plug, but your MyApp.Guardian module could look something like this:

defmodule MyApp.Guardian do
  use Guardian, otp_app: :my_app
  alias MyApp.Accounts

  def subject_for_token(%Accounts.Human{} = human, _claims) do
    {:ok, to_string(human.id)}
  end
  def subject_for_token(_, _) do
    {:error, :resource_not_found}
  end

  def resource_from_claims(%{"sub" => sub}) do
    case Accounts.find_human(sub) do
      nil -> {:error, :resource_not_found}
      human -> {:ok, human}
    end
  end
  def resource_from_claims(_) do
    {:error, :resource_not_found}
  end
end
like image 177
cnnrjcbsn Avatar answered Nov 03 '22 01:11

cnnrjcbsn