Hey,
How could I do that i send a GET request to api/events and I get public events only but if i send an auth token then i get the user’s events?
Basically using the same route but returning something different if there is a user logged in.
I believe it has to do something with the router, if I send just to /api scope it won’t have a user ever, but if I send to [:api, :jwt_authenticated] without a token then it obviously says that I am not logged in.
I tried to make a separate definition for returning if not logged in, but same result
scope "/api", DotooAppWeb do
pipe_through(:api)
get("/users", UserController, :index_not_logged)
post("/users", UserController, :create)
get("/events", EventController, :index_not_logged)
scope "/auth" do
post("/identity/callback", AuthenticationController, :identity_callback)
end
pipe_through(:jwt_authenticated)
resources("/users", UserController, only: [:index, :create, :show, :update, :delete])
resources("/events", EventController, only: [:index, :create, :show, :update, :delete])
end
Is there a way around this?
I followed this article mainly for setting up my authentication: http://blog.nathansplace.co.uk/2018/ueberauth-and-guardian
So the way that I would normally do it, is to have a Plug that sets conn.assigns.current_user
based on token. If there is a valid token, the current_user
is set to something, otherwise it’s set to nil
.
Then, you write a function that has two heads: load_events_for_user(nil)
and load_events_for_user(user)
and call it from the controller with:
def index(conn, params) do
events = load_events_for_user(conn.assigns.current_user)
render "index.html", events: events
end
The version of function with nil
as argument does return public events. The other one loads events for user.
Could you share maybe an example, or more about the plug?
Also then I would have this in the router outside of the authenticated scope right?
ok I think I am getting there but for conn.assigns.current_user i am getting an error, that it is invalid
EDIT
ok getting argument error now
defmodule DotooAppWeb.Plug.SetUser do
def init(default), do: default
def call(conn, _default) do
user = Guardian.Plug.current_resource(conn)
conn.assigns.current_user(user)
end
end
ok so seems like guardian doesnt figure out the user, but in conn the token is there, why is that?
Alright, so you are using Guardian with I think already does all you need to be done on the Plug level. I missed that part, I am sorry. So you may not need another plug!
Instead just write in your controller:
def index(conn, _params) do
user = Guardian.Plug.current_resource(conn)
render "index.json", events: find_events_for_user(user)
end
defp find events_for_user(nil) do
# fetch public events here
end
defp find_events_for_user(user) do
# fetch events for user
end
(please adjust accordingly the index function, you may render stuff in different way)
yeah this should work, but now I am basically back to where i started, if no token then it doesnt get authenticated, since it doesnt pass the authenticated scope
so if i keep the scope and send token then there is user but if i remove it and send the token then it still acts like if there wouldn’t be a token hence no user
here is my router part:
pipe_through(:jwt_authenticated)
resources("/users", UserController, only: [:index, :show, :update, :delete])
and the plug that this pipeline uses:
plug(Guardian.Plug.VerifySession, claims: %{"typ" => "access"})
plug(Guardian.Plug.VerifyHeader, claims: %{"typ" => "access"})
plug(Guardian.Plug.EnsureAuthenticated)
plug(Guardian.Plug.LoadResource, ensure: true)