DEV Community

Cover image for Implement token Authentication with Phoenix.Token
Dung Nguyen for OnPoint Vietnam

Posted on • Updated on

Implement token Authentication with Phoenix.Token

In this post, you'll learn how to implement token 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 alternative token authentication with few lines of code.

Let's do it.

1. Implement Token module

Here is the document of Phoenix.Token.

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

defmodule MyApp.Token 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)

  @doc """
  Verify given token by:
  - 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}
Enter fullscreen mode Exit fullscreen mode

Here we wrap in Token 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 token

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

Enter fullscreen mode Exit fullscreen mode

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

3. Build Plug to verify token

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

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

  def init(opts) do

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

4. Add plug to router

defmodule MyAppWeb.Router do
  use MyAppWeb, :router

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

  pipeline :authenticated do
    plug MyAppWeb.Plug.Authenticate

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

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

Enter fullscreen mode Exit fullscreen mode

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


Implement token authentication with Phoenix is so easy and you may not need Guardian for your application.
In this post I only implement simple version of token authentication. In real application, you should store 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.

If you want to known what is the different between JWT token and Phoenix.Token. Here is the answer from elixir forum

So, to answer the question: Phoenix.Token (with Plug Tokens) vs. JWT, several points I noticed:

  • Phoenix.Token doesn’t let you specify signing algorithms. JWT (for example using Joken 18) does.

  • Both encodes some form of payload into Base64, and the encoding can be read by clients (so you shouldn’t include sensitive information).

  • JWT allows you to encode arbitrary JSON objects as payload, Phoenix.Token uses Erlang terms serialization.

Top comments (2)

darnahsan profile image
Ahsan Nabi Dar

Good writup but JWT and Phoenix token similarity ends at them being kind of token. What you are doing is authentication with phoenix token not JWT authentication with phoenix token as both might be token but are not the same. A title update would make it clearer

bluzky profile image
Dung Nguyen

Thank you very much for correcting me. I have updated the title and content to make it clear.