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
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 ![]()
Most Liked
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
.
-
Ecto creates databases with
mix ecto.createnotmix ecto.migrate. -
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
-
Personally I prefer file names as
lib/myApi/accounts/user.exinstead ofuser.exinlib/myApi/accounts/. I think it is easier to follow. -
The first listing of
put_pasword_hash(changeset)...and later import Comeonin.Bcrypt… trim our put_change function:.. The second listing ofput_password_hashhas no difference from the first listing -
Mention that we need to
alias myApi.Guardianinside ouruser_controller.ex, before altering thecreate/2function, otherwise it tries to use the Guardian module from the guardian library -
Inside the create controller why do we need a
withinside awith? 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?
-
You create the
sign_in/2inside theUserController. Shouldn’t the session be handled by a separateSessionController? -
show/2inUserControllerwhy does it need theif? Theconnpasses throughLoadResourceandEnsureAuthenticatedso theuseris already authenticated and loaded inside theconn. Also theEnsureAuthenticatedalready 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
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! ![]()
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.
Popular in Guides/Tuts
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









