Auth question, has anyone been able to implement a...
# orm-help
p
Auth question, has anyone been able to implement a Schema directive for something like @auth(isOwner: true) with prisma bindings. For example this would handle if a user is the owner of a particular resource for say publishing a post. Basically need a way to pass in the type of the resource to ctx.db.exists[typeFromResource](...etc). In this case typeFromResource would need to be Post but I’m not sure where to get that value. Is this even possible or should this use case be delegated to being done in the resolver like in the example. Schema directives are potentially very powerful and can keep your resolvers thin.
m
Hi, @lawjolla, has an excellent blog post about this topic: https://blog.graph.cool/graphql-directive-permissions-authorization-made-easy-54c076b5368e
l
Thanks @medelman! Schema directives are a newer, more advanced version of directive resolvers. But the same idea still holds. You don’t want to deal with authorization on the Prisma cluster. Do that on your Application server.
m
Whoops. Looks like I misread the original question. My bad.
GraphQL tech just evolving at light-speed right now.
l
It’s not a problem! It’s basically just an expanded API from directive resolvers.
p
@lawjolla I’ve read the article and found a few threads relating but I think there’s something that I’m missing entirely. Code snippet to come..
say if you had a query like this
Copy code
directive @auth(
  requires: Role = SUBSCRIBER
  isOwner: Boolean = false
) on FIELD_DEFINITION | QUERY

type Query {
  me: User @auth
  users: [User!]! @auth(requires: ADMIN)
}
and if your schema directive you have
Copy code
export class IsAuthenticated extends SchemaDirectiveVisitor {
  public visitFieldDefinition(field: GraphQLField<any, any>, details) {
    console.log('DETAILS', details.objectType);
    // console.log('SchemaVisitorArgs', this.args);
    const requiredRole = this.args.requires;

    const { resolve = defaultFieldResolver } = field;

    field.resolve = async function(...resolveArgs) {
      const [source, args, ctx, info] = resolveArgs;
      console.log('SOURCE INSIDE FIELD RESOLVE', source);
      console.log('ARGS INSIDE FIELD RESOLVE', args);
      console.log('INFO INSIDE FIELD RESOLVE', info.fieldNodes);

      const { userId, role } = validateJwt(ctx);

      const isOwner = await ctx.db.exists[Type]({
        where: {
          author: id,
        },
      });

      console.log('USER ID + ROLE FROM JWT', userId, role);

      if (role !== requiredRole) {
        throw new Error(`You must be a ${requiredRole}`);
      }

      ctx.id = userId;

      const result = await resolve.apply(this, resolveArgs);
      return result;
    };
  }
}
as your schema directive, where would you get the Type from
l
@philch I haven't dug into the Schema Resolver API, so there may be an elegant solution. For directive resolvers, I used the inelegant but still effective:
Copy code
users: [User!]! @auth(type: "User", requires: ADMIN)
p
hmm, I was looking through your example repo and I think I’ve found a way to make it work, the jwt-middleware was actually what I was missing
I don’t think there is a way without passing the type
but with multiple directives it’s not too bad just passing it in