Authenticating an SPA via graphql
Anyone have any tips for authenticating an SPA via graphql? I've got basic ash_authentication boilerplate user/token resources setup. I'm wondering if the best way to do this is to wire up my own query/mutation that can set the token as a cookie... kinda trying to keep the elixir side more purely graphql, so my SPA is the main UI interface and I'm not using the ash_authentication_phoenix routes.
28 Replies
https://hexdocs.pm/ash_graphql/authorize-with-graphql.html some info on that here
That seems more like how to set the actor assuming the token exists on the request (if I understand correctly) but I'm looking more for how to perform the sign in via gql
oh right, you're asking about the mutations/queries
I thought we had something for that
Do you have the book?
I do!
There is a section in the book that describes it
Solution
"Authenticating via GraphQL"
Oh awesome. This looks basically like what I was trying but I appear to have gotten the semantics slightly wrong haha. I was doing
using
read_one
instead of get
with identity false
. Technically the way I was doing it works but it winds up with a filter
input which makes sense in terms of ash semantics but in terms of an actual sign in endpoint is bizarre so I was wondering if I was totally missing something. Seems like not, just a slight semantic difference. Thanks!Supposing I wanted the token to wind up in a cookie set by the server... is the only way to make my own resolver that sets the cookie on the connection?
You can use
modify_resolution
IIRC which lets you modify the connHmm. The
Absinthe.Resolution
doesn't seem to have the conn in it at all 🤔
Based on my limited understanding of absinthe, it seems like modifying the conn and modifying the resolution are 2 separate things (see here).
I'm wondering if this should be a separate piece of the ash_graphql dsl, like before_send
that can mess with the conn
I'd be happy to try my hand at a PR that does this (assuming I'm correct in my understanding that the current DSL doesn't actually support it)
Actually I'm realizing it's not so simple ha, since modifying the conn happens at the plug level (which is detached from the ash dsl).I could have sworn there was a way to do it with the dsl
Based on the docs it seems like that was the intention. but as far as I can see there's no way to modify the conn except in the absinthe plug, which the ash dsl doesn't configure at all as of now. I think it might work to use
modify_resolution
to set some auth_token param somewhere in the resolution and then have code in my application that uses the absinthe plug's before_send
option to grab that and set a cookie. It's possible that's what the docs were trying to communicate, they do link out to the section of the absinte plug docs about before_send after all.
It'll be a bit before I can get back to experimenting with this but when I do I'll probably submit a PR with some more in-depth docs for how to accomplish this for future folks that may be trying to use cookies for this.Okay
So, I see where the disconnect is
You have to couple it with something
https://hexdocs.pm/absinthe_plug/Absinthe.Plug.html#module-before-send
You use the
before_send
option on the absinthe plug
Which gets the context that is setyeah, that's what I was thinking
So:
1.
modify_resolution
to set context in resolver
2. before_send
to extract and modify conn
would be a great addition to the docs.yup, cool. I'll submit a docs PR (might be a couple days ha)
😄
BTW: we're finding this is a great task for claude 4 FWIW
Running into this on a personal project, gotta go do real work now 😂
open up the ash_graphql repo, paste in this thread and say "fix the docs" to avoid this issue
Updating docs?
Ah right
probably a good idea, I'm notoriously bad at writing docs 😂
I've considered even automating it from these help threads 😆
How about logging out? Should
Token.actions.revoke_token
be exposed as a gql mutation with an appropriate policy? I don't recall seeing logout mentioned in the book.I think that would make sense. No need for a special policy though, since it would just log out whoever the current actor is
how does AshAuth come into play over graphql?
^ I was adding my own policies there. e.g.
(and removed the forbid_if always() policy)
Definitely seems that the default policies are kinda optimizing for the use case of ash_authentication_phoenix
I can see why though, policies for interacting with users are one of those things that could depend a lot on your application use case
Yeah, its just there as a safety measure
or to make it clear that nothings allowed
I tried exposing
revoke_token
to gql but didn't have much luck. I kept running into forbidden. It looks like it wanted authorized for other token related actions. I gave up but will circle back at some point.
Something else to note; I was also signing in with oauth against Entra ID (Azure) and then in the callback after Entra posts back to Phoenix I was manually generating a token.
I noticed that two tokens were being created. Turns out App.Accounts.user_register_with_microsoft
was creating a token via change AshAuthentication.GenerateTokenChange
in the register_with_microsoft
action so my manual token creation was duplicative.
The original token gets stuffed into metadata so I was able to just grab that and remove my manual token creation.
If you're getting forbidden it is likely from policies on the user
You'll have to set them up to allow any given user to call that action