njwest

njwest

Phoenix 1.3 JWT Auth API with Guardian JWTs, password hashing

Greetings: I just wrote a step-by-step guide on building a Phoenix 1.3 JWT Auth API with Guardian JWTs and Comeonin password hashing.

I would love some feedback, as I’m sure there are some things I missed/things I can improve!

Medium Article: Phoenix JWT Auth API with Guardian

Github Repo

Also: this is Part I of a two-part series; for my next trick, I’ll show how to build a React Native client for this API :slight_smile:

Most Liked

voger

voger

I went through the tutorial. Good timing. I am trying to learn how to use Guardian and this article is very comprehensive. I like how you explain things along the way. I also picked a couple of tricks. Thanks.

I do have some feedback. I hope I am not being that guy hung in every minor detail :lol: .

  1. Ecto creates databases with mix ecto.create not mix ecto.migrate.

  2. When creating Accounts.Users add in routers

  scope "/api", MyApiWeb do
    pipe_through :api
    resources "/users", UserController, except: [:new, :edit]
  end

before running mix ecto.migrate otherwise it throws CompileError about undefined
user_path/3

  1. Personally I prefer file names as lib/myApi/accounts/user.ex instead of user.ex in lib/myApi/accounts/. I think it is easier to follow.

  2. The first listing of put_pasword_hash(changeset)... and later import Comeonin.Bcrypt… trim our put_change function:.. The second listing of put_password_hash has no difference from the first listing

  3. Mention that we need to alias myApi.Guardian inside our user_controller.ex, before altering the create/2 function, otherwise it tries to use the Guardian module from the guardian library

  4. Inside the create controller why do we need a with inside a with? It works with

    with {:ok, %User{} = user} <- Accounts.create_user(user_params),
         {:ok, token, _claims} <- Guardian.encode_and_sign(user) do
    # magic ...
    end

or I am missing something in the flow of the code?

  1. You create the sign_in/2 inside the UserController. Shouldn’t the session be handled by a separate SessionController?

  2. show/2 in UserController why does it need the if? The conn passes through LoadResource and EnsureAuthenticated so the user is already authenticated and loaded inside the conn. Also the EnsureAuthenticated already returns an {:error, :unauthenticated}

Also, if it doesn’t get out of article’s scope, can you please add how to use guardian_db?

Thanks again for the nice tutorial.

njwest

njwest

@voger

Many thanks for the thoughtful feedback and improvements, Voger! Will be implementing your improvements shortly

Re: 7. I don’t use a SessionController because this app doesn’t use sessions – it only uses JWT token exchange.

The sign_in function only calls Accounts.insert_or_update_user(changeset), which leads to Guardian.encode_and_sign(user) on success – this returns a JWT, which can be used by a client to act on the server, but it does not create a session on the server.

This is one of the great advantages of JWTs in appropriate contexts: your server doesn’t have to create and manage sessions for logged in users; your server only has to act when a client makes a request, and rather than checking the client’s session on the server to see if it should proceed, it just has to validate the token sent by the client.

You can use Guardian for sessions, using Guardian.Plug.sign_in(user) in a session login function and Guardian.Plug.VerifySession in your auth pipeline, but in the case of this API-only app, I did not find it necessary

Thanks again for the feedback! :slight_smile:

script

script

Hi I just followed your guide. This was my first experience with the jwt . The side details you provided in the post are very well written and organised. I really enjoyed it . I think the code for guardian pipeline should be inside the router. But overall its really simple what you described. And I am waiting for its second part.

Where Next?

Popular in Guides/Tuts Top

benwilson512
Correct if me I’m wrong, as best I can tell there aren’t any reasons to use mix run --no-halt in production vs releases. The marginal val...
New
redfloyd
Greetings fellow alchemists ! I have started to write an open-source interpreter in Elixir (GitHub - nicolasdilley/dwarf-interpreter: Th...
New
hlx
Typed my very first blog post ever, hope it will help some people https://henricus.xyz/roll-your-own-email-password-authentication-with-...
New
kuon
I have a page with a large state that is loaded from DB, let’s call that “data”. I have a root live view that load “data” on mount and r...
New
niku
I write an article Parameterized testing with ExUnit.The key concept is using ExUnit.Case.register_test/4 such as ExUnit.start() defmod...
New
magnetic
Hey :waving_hand:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and ...
New
dkuku
I Created a blog post about setting up svelte with phoenix. I found it a bit tricky and the only blog post I found was written using som...
New
sergio
I couldn’t find any guides that worked well with Phoenix 1.6.0 and esbuild. I hope this helps people test the waters and eases you into t...
New
Zurga
In a quest to optimize the amount of data sent between the server and client I recently decided to try to use MessagePack instead of JSON...
New
caspg
Hi everyone, I recently implemented a real-time search feature in a Phoenix application using LiveView and Tailwind, and I wanted to sha...
New

Other popular topics Top

malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement