nexus-plugin-prisma
nexus-plugin-prisma copied to clipboard
Authorization
Hi!
I’m really excited to use this package for my latest project but I’m not really sure how to manage authorization with this.
How can I protect the t.crud and t.model fields from unauthorized users?
Is graphql-shield the only option? The type unsafety there feels really cumbersome.
How do you guys authorize users to access certain mutations and queries?
Indeed I wish there was an authorization pattern integrated within this plugin, because I'm not a big fan of having the declaration rules inside a single centralized shield
object...
I would prefer defining my permissions logic right inside the t.crud
and t.model
and have just a generic logic in the plugin options to express generic rules like default: IsAdmin
or read-only: everyone
.
Otherwise you can implement kind of an authorization middleware by overriding the resolve
function: https://nexusjs.org/pluginss/prisma/runtime#resolve
I am using this:
async function resolveIfAdmin(root: any, args: any, ctx: any, info: any, originalResolve: any) {
const isAdmin = await ctx.isAdmin() // you need to implement isAdmin yourself
if (isAdmin) {
return originalResolve(root, args, ctx, info)
} else {
throw Error("You need to be admin to perform this action")
}
}
export const mutateYear = extendType({
type: 'Mutation',
definition(t) {
t.crud.createOneYear({
resolve: resolveIfAdmin, // action will fail if you are not admin
})
t.crud.updateOneYear({
resolve: resolveIfAdmin, // action will fail if you are not admin
})
},
})
It's probably not perfect, but it works for me.
I'm using https://github.com/Sytten/nexus-shield which is very nice.
import { hasRole } from "../rules";
import { Role } from "../generated/types";
export const UserQuery = extendType({
type: "Query",
definition(t) {
t.crud.user({ shield: hasRole(Role.Editor)() });
t.crud.users({ shield: hasRole(Role.Editor)() });
},
});
Maybe https://nexusjs.org/docs/plugins/field-authorize is of interest:
t.field('postById', {
type: Post,
args: { id: idArg() },
authorize: (root, args, ctx) => ctx.auth.canViewPost(args.id),
resolve(root, args, ctx) {
return ctx.post.byId(args.id)
},
})
Catching up on this old thread as I'm trying to figure out the best option here as well. @mikkelsl the fieldAuthorize
seems to be a good simple option, but it's unclear if that has the automatic caching built in like the shield options do?