ElixirPhoenix FrameworkJWTRestAPI
Last updated at 2023-10-22

Elixir REST API with JWT Authentication

ClickUp
Note
AI Status
Full
Last Edit By
Last edited time
Oct 22, 2023 08:48 AM
Metatag
Slug
rest-api-elixir-jwt-auth
Writer
Published
Published
Date
Oct 22, 2023
Category
Elixir
Phoenix Framework
JWT
RestAPI
In this article, we will explore how to build a REST API with authentication using Elixir and JWT (JSON Web Tokens).
Elixir is a functional programming language built on the Erlang VM, known for its scalability and fault-tolerance.
JWT provides a secure way to authenticate and authorize requests in a stateless manner.

Prerequisites

Before diving into building the REST API, make sure you have the following prerequisites installed:
  • Elixir: Install the latest version of Elixir from the official Elixir website.
  • Phoenix Framework: Phoenix is a web framework for Elixir. Install Phoenix by running the following command:
mix archive.install hex phx_new
  • PostgreSQL: We will be using PostgreSQL as our database.

Setting up the Project

Let's start by creating a new Phoenix project.
Open your terminal and run the following command:
mix phx.new my_api --no-webpack --no-html
This command creates a new Phoenix project called "my_api" without the default JavaScript and HTML setups.
We will only focus on building the REST API with authentication.
Next, navigate to the project directory:
cd my_api

Configuring the Database

Before we can start building our API, we need to configure the database connection. Open the config/dev.exs file and update the database configuration with your PostgreSQL credentials:
config :my_api, MyApi.Repo, username: "your_username", password: "your_password", database: "my_api_dev", hostname: "localhost", pool_size: 10
Make sure to update the username, password, and database fields with your own PostgreSQL credentials.

Creating the User Model

To handle user authentication, we need to create a User model.
Run the following command in your terminal to generate the User model:
mix phx.gen.schema Accounts.User users name:string email:string password_hash:string
This command generates a User model with the necessary fields for authentication - name, email, and password hash.
Next, apply the database migration to create the users table:
mix ecto.migrate

Implementing JWT Authentication

To implement JWT authentication, we will be using the Guardian library.
Add Guardian as a dependency in your mix.exs file:
defp deps do [ # Other dependencies {:guardian, "~> 2.0"} ] end
Run the following command to fetch the new dependency:
mix deps.get
Next, let's generate a Guardian configuration file:
mix guardian.init
This command creates a config/guardian.exs file with default configuration options.
Update the config/config.exs file to include the Guardian configuration:
config :my_api, MyApiWeb.Guardian, issuer: "my_api", secret_key: "your_secret_key"
Make sure to replace "your_secret_key" with your own secret key.

Creating the Authentication Controller

Now, let's create a controller responsible for handling authentication.
Run the following command in your terminal:
mix phx.gen.html Accounts Auth auths email:string password:string
This command generates an Auth controller with email and password fields for authentication.
Next, open the lib/my_api_web/router.ex file and add the following route:
scope "/api", MyApiWeb do pipe_through :api resources "/auth", AuthController, only: [:create] end

Implementing Authentication Logic

Open the lib/my_api_web/controllers/auth_controller.ex file and update the create action as follows:
def create(conn, %{"auth" => %{"email" => email, "password" => password}}) do case Accounts.authenticate(email, password) do {:ok, user} -> token = Guardian.encode_and_sign(user, :token) conn |> put_status(:created) |> render("token.json", token: token) {:error, _reason} -> conn |> put_status(:unauthorized) |> render("error.json", message: "Invalid email or password") end end
This code authenticates the user with the provided email and password.
If the authentication is successful, it generates a JWT token using Guardian and returns it in the response.
Otherwise, it returns an unauthorized error message.

Protecting Routes with JWT

To protect certain routes with JWT authentication, we can create a plug.
Run the following command to generate a lib/my_api_web/plugs/authenticate.ex file:
mix phx.gen.plug Accounts Authenticate authenticate
Open the lib/my_api_web/plugs/authenticate.ex file and update it as follows:
defmodule MyApiWeb.Plugs.Authenticate do @behaviour Plug def init(_options), do: [] def call(conn, _options) do case Guardian.Plug.current_resource(conn) do {:ok, _user} -> conn _ -> conn |> put_status(:unauthorized) |> render("error.json", message: "Unauthorized") end end end
This plug checks if the current request is authenticated using Guardian.
If the request is authenticated, it proceeds to the next plug or controller.
Otherwise, it returns an unauthorized error message.

Protecting Routes with JWT

To protect certain routes with JWT authentication, we can create a plug.
Run the following command to generate a lib/my_api_web/plugs/authenticate.ex file:
mix phx.gen.plug Accounts Authenticate authenticate
Open the lib/my_api_web/plugs/authenticate.ex file and update it as follows:
defmodule MyApiWeb.Plugs.Authenticate do @behaviour Plug def init(_options), do: [] def call(conn, _options) do case Guardian.Plug.current_resource(conn) do {:ok, _user} -> conn _ -> conn |> put_status(:unauthorized) |> render("error.json", message: "Unauthorized") end end end
This plug checks if the current request is authenticated using Guardian.
If the request is authenticated, it proceeds to the next plug or controller.
Otherwise, it returns an unauthorized error message.

Conclusion

In this article, we have learned how to build a REST API with authentication using Elixir and JWT.
We covered the necessary steps to configure the project, create a user model, implement JWT authentication, and protect routes using plugs.
Using these techniques, you can build secure and scalable REST APIs with Elixir.

References

Discussion (0)

Related Posts