Hello!
Can you show the configuration of the strategy on the relevant resource and the relevant output of mix phx.routes
? See below which routes are relevant.
I had an issue of mapping up the name of the resource and strategy properly, so it would fail to resolve it as the resource would be called MyApp.Accounts.Account
rather than MyApp.Accounts.User
, and there were some places I had missed to update.
It was a while though, but if you inspect the JWT token I think there should be a reference to the name of the resource, which should correspond to a piece of the route(s):
GET /auth/account/password/sign_in_with_token MyApp.Accounts.Account.password :sign_in_with_token
POST /auth/account/password/register MyApp.Accounts.Account.password :register
POST /auth/account/password/sign_in MyApp.Accounts.Account.password :sign_in
GET /auth/account/google MyApp.Accounts.Account.google :request
GET /auth/account/google/callback MyApp.Accounts.Account.google :callback
Here you can see that for the MyApp.Accounts.Account
resource the routes start with "/auth/account"
, and this needs to be reflected in various places, I learned the hard way. For example, the @current_user
attribute in LiveView was not set as a result and I had to update that to be @current_account
, I think… (need to confirm this, so no Trust me, bro on this one)
The symptom was that my actor was not set when I expected it to be, and it was caused by my refactoring of MyApp.Accounts.User
→ MyApp.Accounts.Account
. I had to hunt down the places where it was resolved in the imported plugs and so on. My issue was however primarily in a LiveView context, not an API with JWT tokens.
This part in your pipeline could be relevant given what I said above:
plug :set_actor, :user
The :set_actor
plug argument subject_name – :user
here – is the relevant part here. See AshAuthentication.Plug.Helpers.set_actor/2 @ GitHub
And looking at AshAuthentication.Plug.Helpers.retrieve_bearer/3 – which is called by the macro-defined function :load_from_bearer
added by use AshAuthentication.Phoenix.Router
at the top of your router – we can see this logic:
with {:ok, %{"sub" => subject, "jti" => jti} = claims, resource}
when not is_map_key(claims, "act") <- Jwt.verify(token, otp_app, opts),
{:ok, token_record} <-
validate_token(resource, jti),
{:ok, user} <-
AshAuthentication.subject_to_user(
subject,
resource,
opts
),
{:ok, subject_name} <- Info.authentication_subject_name(resource),
current_subject_name <- current_subject_name(subject_name) do
conn
|> Conn.assign(current_subject_name, user)
|> maybe_assign_token_record(token_record, subject_name)
else
_ -> conn
end
It tries to identify the correct resource to load based on the JWT, and if it fails along the way, the conn
will be untouched.
So, if AshAuthentication.Plug.Helpers.retrieve_from_bearer/3
fails, there will be no assign corresponding to current_subject_name
, which also needs to match the argument passed to :set_actor
after, as that plug in essence just takes the previous assign and adds it as the actor.
If there’s a mismatch there, such as in my case when I refactored the name of my resource, it would just get nil
when attempting to access the subject_name
because I had not updated the subject_name in some places.
So if you have a different name for your resource, this could be a reason. If you do not though, try to turn on `AshAuthenticationDebug to see if you can get some more information that way and we can see what else we can discover.