so, we have functions and permissions. I'd expect ...
# prisma-whats-new
q
so, we have functions and permissions. I'd expect that these permissions are for these functions. Something like User.read looks like a function to me, and we can add authorization there by doing something like:
Copy code
- operation: Users.read
    authenticated: true
    query: hasRoleAdmin.graphql
When having a function of type
operationBefore
, how can I add authentication/authorization before that function? So:
Copy code
makeUser:
    type: operationBefore
    operation: User.create
    handler:
      code:
        src: ./src/befores/createUser.ts
        environment:
          ...
Inside the
src/befores/createUser.ts
function, I call an external service, and if that one succeeds, another user can be created. However, this logic may only be executed when the user has proper rights. For now, it seems that adding:
Copy code
- operation: Users.read
    authenticated: true
    query: hasCreateUserPermission.graphql
the query logic is executed 'after' the operationBefore query, which leads to weird results (on the external service, some stuff is added, but not on graphcool, since the user is not authorized to do so. I'd prefer to have the authentication logic be executed before the request pipeline. What is the intended behaviour? And if it is intended that the authentication is executed as the last one in the request pipeline, how to move it to the front of the pipeline?
m
@qsys You need to incorporate auth/permissions into
operationBefore
you can also override
createUser
and do the permission checking in there
in every FaaS you can check if the user is authenticated with the following code:
Copy code
if (!event.context.auth || !event.context.auth.nodeId) {
    return { error: 'No user logged in.' }
  }
Once inside your FaaS, you can call the api using the user's token:
Copy code
// create graphcool api using the user's token
    const graphcool = new Graphcool(
      event.context.graphcool.serviceId || event.context.graphcool.projectId!,
      {
        token: event.context.auth.token,
        endpoints: event.context.graphcool.endpoints,
      },
    ) 
    const api = graphcool.api('simple/v1')
this way when you call the api, it will apply the permission logic 🙂
q
ok... too bad. Need scatter auth logic in config files and in permission queries. Don't like it. Will do it anyway... I don't get that last example you give. The first one, well, that one only checks authentication, not authorization (I have quite a lot of these, since I need to make a different one for every combination of roles/groups/permissions). Now, I need to copy that logic inside functions, right?
m
the last example sits inside a function. It takes the token from the user who made the request and uses it to initiate the Graphcool object. You can then call the gc api as if you were that user and the permissions kick in.
q
ok, but how do I call one of the permission queries there? They are not an endpoint. I just need to invoke the permission queries without duplicating code - preferably the same way permissions are set, but I know now that this will not be possible.
m
when you make a call to the api. It will check if there are applicable permission queries and if it finds any it will run them automatically.
so you only need to set the permissions once
q
right, but when I have a
operationBefore
, the permission queries will only be called after that operation, and before the
User.create
, right? That's not the aim: the aim is to check first if a user has rights to do something, and than do everything as one atomic operation (
operationBefore
+
User.create
). There is no api to call, just a mutation query with an operationBefore. authorization must be checked before.
m
You're probably best off creating a function like
signup
then only allow admins to
createUser
. That's what I did
That way
createUser
is limited to super users and everyone else uses a different function. It means you can split out the permissions and business logic keeping it simple
q
This is not the use case. I have a sign up. That part is ok. The point is: when creating a new user, another external function is called as well. Both the external call as the graphcool create user should be atomic. Authentication must be done before this atomic operation.
sign up is rather unrelated.
I know createUser is limited to superusers. That's the part that is ok. The part that is not ok, is that the
operationBefore
, the external call, is executed before authorization.
the flow should be
authorize
->
operationBefore
(external call) ->
createUser
the flow using graphcool PQ now is
operationBefore
(external call) ->
authorize
->
createUser
this means, graphcool does intervenes in the business logic instead of splitting PQ and business logic
m
okay got it. Why don't you create another function say
createUser2
or a better name. You can do the permission checking in there manually then call
createUser
?
q
well, that's what I want t avoid: the manual checks.
I have the permission queries already (for other operations).
So I need to duplicate the logic.
No fun, but it seems there's no other way.
m
yeah - I know it's frustrating. Graphcool was great to build something quickly but as my app grew in complexitity, I ended up pushing business logic onto my React app and working around Graphcool. I moved to Prisma (self-hosted + AWS RDS db) and couldn't be happier ....
q
right, thx... I've seem more design flaws in GC, but well, I'll just have to live with it, I suppose 😛
the moment I'd move to Prisma, I'd just implement a graphQL endpoint myself, I guess.
m
it not too hard to make the move and I use Apex Up to deploy my server and it makes the devOps easy 🙂
Good luck
q
thx