Implement JWT Authentication with Phoenix.Token

In this post, you’ll learn how to implement JWT based authentication using Phoenix.Token.

This is originally posted on The Orange+

In our previous projects, we use guardian library to implement JWT authentication. Guardian is a great library which …


This content originally appeared on DEV Community and was authored by Dung Nguyen

In this post, you'll learn how to implement JWT based authentication using Phoenix.Token.

This is originally posted on The Orange+

In our previous projects, we use guardian library to implement JWT authentication. Guardian is a great library which provides lots of method and tool to work with authentication. But sometime we don't need them all. And recently, I found Phoenix.Token module shipped with phoenix framework that helps me to implement JWT authentication with few lines of code.

Let's do it.

1. Implement JwtToken module

Here is the document of Phoenix.Token.

We just wrap sign and verify function from Phoenix.Token to create and check for valid JWT token.

defmodule MyApp.JwtToken do
  @signing_salt "octosell_api"
  # token for 2 week
  @token_age_secs 14 * 86_400

  @doc """
  Create token for given data
  """
  @spec sign(map()) :: binary()
  def sign(data) do
    Phoenix.Token.sign(MyAppWeb.Endpoint, @signing_salt, data)
  end


  @doc """
  Verify given token by:
  - Check if this token is issued and stored in Redis
  - Verify token signature
  - Verify expiration time
  """
  @spec verify(String.t()) :: {:ok, any()} | {:error, :unauthenticated}
  def verify(token) do
    case Phoenix.Token.verify(MyAppWeb.Endpoint, @signing_salt, token,
             max_age: @token_age_secs
           ) do
      {:ok, data} -> {:ok, data}
      _error -> {:error, :unauthenticated}
    end
  end
end

Here we wrap in JwtToken module to simplify API. We pass MyAppWeb.Endpoint here to use secret key that config for endpoint. You can pass secret key from config as firt argument.

2. Generate JWT token

defmodule MyAppWeb.SessionController do
  ...
  def new(conn, %{"email" => email, "password" => password}) do
    with {:ok, user} <- Account.authenticate_user(email, password),
         {:ok, token} <- MyApp.JwtToken.sign(%{user_id: user.id}) do
      ...
      # return token to client
    else
      _ ->
        {:error, gettext("email or password is in correct")}
    end
  end
end

Here we create JWT token with a map %{user_id: user.id} and return to client.

3. Build Plug to verify token

Client sent jwt token to server via header Authorization. We extract token and call JwtToken.verify to check if jwt token is valid and not expired.

defmodule MyApp.Plug.Authenticate do
  import Plug.Conn
  require Logger

  def init(opts) do
    opts
  end

  def call(conn, _opts) do
    with ["Bearer " <> token] <- get_req_header(conn, "authorization"),
         {:ok, data} <- MyApp.JwtToken.verify(token) do
      conn
      |> assign(:current_user, MyApp.Account.get_user(data.user_id))
    else
      error ->
        conn
        |> put_status(:unauthorized)
        |> Phoenix.Controller.put_view(MyAppWeb.ErrorView)
        |> Phoenix.Controller.render(:"401")
        |> halt()
    end
  end
end

4. Add plug to router

defmodule MyAppWeb.Router do
  use MyAppWeb, :router

  pipeline :api do
    plug :accepts, ["json"]
  end

  pipeline :authenticated do
    plug MyAppWeb.Plug.Authenticate
  end

  scope "/api", MyAppWeb do
    pipe_through :api
    post "/auth/login", SessionController, :new
  end

  scope "/api", MyAppWeb do
    pipe_through [:api, :authenticated]
    delete "/auth/logout", SessionController, :delete
    ...
  end
end

We have done with it. Just a few line of code

Conclusion

Implement JWT authentication with Phoenix is so easy and you may not need Guardian for your application.
In this post I only implement simple version of JWT authentication. In real application, you should store jwt token signature in database or redis and

  • In Authenticate plug check if the token exists in database.
  • When user logout, clear it from database/redis to make sure that token cannot be used to make request anymore.

Thanks for reading.


This content originally appeared on DEV Community and was authored by Dung Nguyen


Print Share Comment Cite Upload Translate Updates
APA

Dung Nguyen | Sciencx (2021-08-26T13:42:44+00:00) Implement JWT Authentication with Phoenix.Token. Retrieved from https://www.scien.cx/2021/08/26/implement-jwt-authentication-with-phoenix-token/

MLA
" » Implement JWT Authentication with Phoenix.Token." Dung Nguyen | Sciencx - Thursday August 26, 2021, https://www.scien.cx/2021/08/26/implement-jwt-authentication-with-phoenix-token/
HARVARD
Dung Nguyen | Sciencx Thursday August 26, 2021 » Implement JWT Authentication with Phoenix.Token., viewed ,<https://www.scien.cx/2021/08/26/implement-jwt-authentication-with-phoenix-token/>
VANCOUVER
Dung Nguyen | Sciencx - » Implement JWT Authentication with Phoenix.Token. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/08/26/implement-jwt-authentication-with-phoenix-token/
CHICAGO
" » Implement JWT Authentication with Phoenix.Token." Dung Nguyen | Sciencx - Accessed . https://www.scien.cx/2021/08/26/implement-jwt-authentication-with-phoenix-token/
IEEE
" » Implement JWT Authentication with Phoenix.Token." Dung Nguyen | Sciencx [Online]. Available: https://www.scien.cx/2021/08/26/implement-jwt-authentication-with-phoenix-token/. [Accessed: ]
rf:citation
» Implement JWT Authentication with Phoenix.Token | Dung Nguyen | Sciencx | https://www.scien.cx/2021/08/26/implement-jwt-authentication-with-phoenix-token/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.