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

redfloyd
Greetings fellow alchemists ! I have started to write an open-source interpreter in Elixir (GitHub - nicolasdilley/dwarf-interpreter: Th...
New
bluegene
Hi guys, I’ve been on a personal journey to learn Elixir for the past two years. During this journey I’ve been using the spaced repetiti...
New
stryrckt
I’m excited about the new LiveComponents feature in LiveView, but I haven’t seen much written on it, so I decided to write a couple of ar...
New
AstonJ
..or as and when you can think of one :icon_cool: This thread my also be of interest: What took you way too long to figure out? :003:
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
nelsonic
Complete beginners Todo List Tutorial in Phoenix 1.5.3 (latest and greatest): https://github.com/dwyl/phoenix-todo-list-tutorial It’s a...
New
9mm
So I’m really loving elixir. BY FAR the most excruciating piece of learning a functional language for me is having to “transform” all my ...
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
pinksynth
Whenever tests have to interact with an Ecto.Repo, sometimes it’s necessary to test a few different branches or paths that data can take....
New
dogweather
I just finished a long process of configuring and debugging a Docker Compose-based dev environment. Several late-night hours! I think I’v...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39467 209
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

We're in Beta

About us Mission Statement