Authentication actions as graphQL queries/mutations?
Is it possible to use AshGraphQL with AshAuthentication to sign_in and sign_up?
I've tried adding the
sign_in_with_password
action as a graphql query:
But this will ask for the user id as input, also it will not return the token, only the user.
What I wanted was to be able to do something like this:
95 Replies
Yep! You can do that π The basic way is this:
That should change the response type to include the token metadata
You can also use the
modify_resolution
which takes an MFA (if I recall correctly) and you should be able to leverage that to modify the conn. @barnabasj are you doing authentication over graphql? I don't have a setup that does it currently, so I don't recall exactly what it looks like to do that.Not sure if I'm doing something wrong, but after making the above changes, I get this error in playground:

π€
do you need the mutation name?
mutation MutationName {
like just a made up name
Does your new mutation show up in the schema?Ah, I think I found a bug
I need to have at least one mutation implemented in the
mutations
part of graphql
to make my sign_in_with_password
query shows up as a mutation.So, if I do this:
It will not show up in playground (see image)

But, if I do this:
Now it will show up fine

It is still requiring the
id
field though
Not right now, we are just using rest endpoints for auth. Still doing it with POW, unfortunately I did not have time to change it to ash_auth as of yet
@Blibs can I see your schema?
the absinthe schema, I mean
Wondering if you have an empty
mutations
block or notSure, but I'm not sure how to get it, isn't that automatically generated by AshGraphQL during compilation time? Or do you mean the
graphql
code block inside my resource?Just the contents of the absinthe schema that you have currently
like you should have a
schema.ex
that calls use AshGraphql
It will be mostly empty, just want to see if there are issues thereAhh, got it
okay that does look right. Weird that you have to have at least one mutation...
Oh
For the id issue, set
identity false
Not identity nil
sorryAh, yeah, now there is not more an id as input π
But, also the API only returns the user resource, not a token
Are you on the latest version of ash_authentication?
oh, you will also need to be on the latest version of
ash_graphql
as well
returning metadata on read actions was added recentlylet me check that
You are correct, I was in an outdated version of ash_authentication
I had to add this to my query
type_name :user_with_token
and after that now I'm getting the token ππ₯³
But I'm seeing something else that is a little bit odd.
Not sure why, but the query will onyl work if I add the hashedPassword field to be returned, if I don't add it, the query will crash in the backend
This is the error that I get

okay that looks like a bug in
ash_graphql
well...that looks like two bugs
but lets fix the first one, one secThis is the query that will trigger this:
This one will work just fine:
This only happens with the
hashedPassword
field, all other fields works just finethis is strange, we already fixed the issue around it not selecting
hashed_password
...
Okay, so ash_graphql
main has a fix for the first errorLet me try with it here and see how it goes
π€ I think something may have been lost in a merge or something here? I could swear I fixed this
The error changed a little bit

Yeah, that looks like what I expected
I will push the fix up for you
not sure what happened there
gimme a few
thanks man π
GitHub
improvement: add select_for_senders by zachdaniel Β· Pull Request #1...
fix: select hashed_password on sign in preparation
You could try that branch out and see how it works for you
query-select-fixes
in ash_authentication
Seems like that branch fixed the issue for me π
π₯³
Sorry to bombard you with more questions, but is there a way for me to make the register_with_password also return a token? From the documentation, it doesn't seem like I can use the same approach I did with the query as mutation
π€ I thought that one should do it on its own
maybe I'm doing something wrong, I will post more information here
This is my mutation code block:
As can be seem from the schema, there is no token field being returned:

Have you defined the
register_with_password
action yourself?
actually, looks like that is also missing from the action definitionNo, I'm using the default one from AshAuthentication
can you update your branch?
I just pushed another commit to the branch
mix deps.update ash_authentication
Seems like something broke with the new commit

oh
sorry one sec
okay try again π

Seems like it is working now π
π₯³
Hopefully, this is my last question regarding this, at least for a while π
, but I showed the API to my frontend team and they complained that it is not using GraphQL standards...
Instead of having this:
they want this:
Basically having the token outside of the user, and having the inputs ins a input object the same way the registerWithPassword is.
π€ potentially π
It would take some time to make those work
maybe just converting the action itself to a create would do the trick?
Yeah, potentially.
Try this:
This is a bit of a hack but would get you the api you want I believe
Then you could do
Once you get it working, could you make an issue on
ash_hq
documenting what you couldn't do with a read action and what you had to do to work around it? We can add options in the future to make this better (like input_object? true
for queries, and metadata_placement :new_type | :alongside
Yes, I will do that for sure
Hmm, I'm getting some absinthe schema error because the
email
field identifier is not unique π€Ah, yeah
add
accept []
to the create actionThanks a lot Zach, that worked!
π₯³
You also have the option of defining a regular old mutation in graphql
that kind of thing
So that can be an escape hatch when you want to do something
ash_graphql
doesn't support.
You can read more about it in the absinthe docs: https://hexdocs.pm/absinthe/mutations.html#next-step
If you do it that way you won't need the unnecessary create actionActually I think that was what I was about to ask, they seem to not be happy yet with it because of something related to the function being global or whatever, I'm not sure since I just started using GraphQL.
π€
I'm starting to get pissed off with them tbh π
π
In case of that escape hatch, It seems that I would return a map and ash_graphql woudl create the graphql schemas correct?
Yeah, if you use our types, you just need to return the appropriate map
What do they mean in terms of
global
?
Do they want your mutations split up by category or something?They basically sent me this:
That is what they expected, I mean, I think they are talking about that signIn inside a signIn I guess, I will need to read more about graphQL to get this..
π€ thats really just one mutation, its not nested
its just how you name an operation
What they said is that they expected that I would send the input inside the query. Not sure why
That mutation should basically for you I imagine
But, going back to this, can I manually create my own Absinthe schema by and use it there? I guess that way I would be able to do exactly what they want.
Yep π
I'm still curious whats wrong with the other mutation
And to do that it would be using that resolve function or another one? Is there a way that I can also manually define the Absinthe inputs too? I mean, basically make the whole query by hand I guess
Yeah, once you start writing absinthe stuff you're basically in full control
I will look into that, and after I find out what exactly they are talking about I will update here so we can see if it is just meaningless complains or something that would add value to ash_graphql and possibly create a ticket in the ash_graphql repo
And thanks a lot for the patience Zach, I really appreciate that
no problem π best of luck!
@Zach Daniel quick question about this. what do I need to import to make the object and field available?
Not sure really, Iβd suggest reading the absinthe documentation
It is what they use as far as I can tell, I think it just breaks because I'm using it directly inside the
mutations
blockI think the object part goes outside of the mutations block
the part it complains is actually this one:
field :sign_in, type: :sign_in_result do
That part goes in mutations
From their documentation this should be inside a
mutation do
block
If I add it to the mutations do
block, I get this error:
Invalid schema notation: field
must only be used within input_object
, interface
, object
, schema_declaration
. Was used in schema
.Ohβ¦can i see the whole file?
oohhhhh
all that stuff goes in your
schema.ex
file
not in the resourceYep, that was it hahah, now it works
Ok, the last question of today, I promise.
Do we have some documentation or can you tell me where in the ash code you handle
Ash.Error.Forbidden
errors for mutations? I would like to add that to my custom mutation so it handles errors the same wayI'll add a helper for you
Okay
In the
main
branch of ash_graphql
there is AshGraphql.Error.to_errors(errors)
So you can do something like this:
Haven't tried it myself but I think something like that should workHmm, I don't think that will work since that protocol doesn't seem to be implemented for Ash.Error.Forbidden which is the error that the sign_in_with_password will return
You can implement the protocol yourself for:
AshAuthentication.Errors.AuthenticationFailed
and make it return an error like "invalid username or password"Ah, got it, I will that. I just though that was already implemented somewhere in AshGraphql
Since it already handles the error correctly when using it
π€ what do you mean?
I mean the MutationError which are added and handled automatically by AshGraphql when creating mutations with it

I'm pretty sure that error won't actually show up though
because it doesn't have the protocol implemented for it
AshGraphql won't show errors it doesn't know how to display.
Yeah, it will show up as a generic error
gotcha, okay
like "something went wrong"?
Yeah, just noticed that π
You should have what you need by either implementing the protocol for that error or doing some custom poking at the errors and returning whatever error you want π
Yep, working great now!

So eventually we should add options for read actions to return result types like mutations, and to accept input objects like mutations.
I was about to create another post, but I think this is kinda on topic...
Since I can now get the token from my sign-in query, I went ahead and added it to the HTTP header as a bearer authentication header and I can see that when I run another query in GraphQL, the route pipeline will fetch the token, find the user, and run the AshGraphQL plug which adds the user as an actor to the Absinthe context.
Looking at the documentation, this seems like it is all that is needed to make the actor available in my resource.
But this doesn't seem to be working, I added some log to
AshGraphql.Graphql.Resolver
resolve
function and I can see that when the code tries to fetch the actor, it returns nil
.
I can elaborate more on what changes I made, but I basically followed the https://ash-hq.org/docs/guides/ash_graphql/latest/how_to/authorize-with-graphql guide
Ah, I think I found the issueFor reference.
The problema is that I was using
:load_from_bearer
in my pipeline which will add the user in the connection assigns with the :current_user
key.
Since I wanted to still use that plug, I just created a small plug that will set that assign as the actor (see image)
So, in case someone needs to do something similar in the future, this is how I did my customs mutations with graphql plus Ash:
First, in my
Marketplace.Accounts.User
resource, I added the graphql code block:
Then, I created a module to store my custom queries/mutations/types:
As you can see, right now this has 2 mutations, sign_in_with_password
and register_with_password
.
Now inside my graphql schema, I added:
And that is pretty much it. I'm happy with this solution, but any suggestions are welcome.