The applyPolicy function runs on protected fields within the GraphQL schema. In order to pass the check, the policy check Promise must return true. If the policy check fails for any reason, errors will be returned in the GraphQL response. For example, for the schema:
directive @auth(
requires: Role = ADMIN,
) on OBJECT | FIELD_DEFINITION
enum Role {
ADMIN
REVIEWER
USER
UNKNOWN
}
type Query {
add(x: Int, y: Int): Int @auth(requires: USER)
}A failed auth response would look like:
{
"data": {
"add": null
},
"errors": [
{
"message": "Failed auth policy check on add",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"add"
]
}
]
}You can return errors in the GraphQL response in two ways.
'use strict'
const Fastify = require('fastify')
const mercurius = require('mercurius')
const mercuriusAuth = require('mercurius-auth')
const app = Fastify()
const schema = `
directive @auth(
requires: Role = ADMIN,
) on OBJECT | FIELD_DEFINITION
enum Role {
ADMIN
REVIEWER
USER
UNKNOWN
}
type Query {
add(x: Int, y: Int): Int @auth(requires: USER)
}
`
const resolvers = {
Query: {
add: async (_, { x, y }) => x + y
}
}
app.register(mercurius, {
schema,
resolvers
})
app.register(mercuriusAuth, {
authContext (context) {
return {
identity: context.reply.request.headers['x-user']
}
},
async applyPolicy (authDirectiveAST, parent, args, context, info) {
if (context.auth.identity !== 'admin') {
throw new Error(`custom auth error on ${info.fieldName}`)
}
return true
},
authDirective: 'auth'
})
app.listen({ port: 3000 })'use strict'
const Fastify = require('fastify')
const mercurius = require('mercurius')
const mercuriusAuth = require('mercurius-auth')
const app = Fastify()
const schema = `
directive @auth(
requires: Role = ADMIN,
) on OBJECT | FIELD_DEFINITION
enum Role {
ADMIN
REVIEWER
USER
UNKNOWN
}
type Query {
add(x: Int, y: Int): Int @auth(requires: USER)
}
`
const resolvers = {
Query: {
add: async (_, { x, y }) => x + y
}
}
app.register(mercurius, {
schema,
resolvers
})
app.register(mercuriusAuth, {
authContext (context) {
return {
identity: context.reply.request.headers['x-user']
}
},
async applyPolicy (authDirectiveAST, parent, args, context, info) {
if (context.auth.identity !== 'admin') {
return new Error(`custom auth error on ${info.fieldName}`)
}
return true
},
authDirective: 'auth'
})
app.listen({ port: 3000 })Mercurius defaults all errors with the HTTP 500 status code. You can customize this property by using the built-in ErrorWithProps custom error provided by the underlining Mercurius plug-in
...
async applyPolicy (authDirectiveAST, parent, args, context, info) {
if (context.auth.identity !== 'admin') {
const err = new mercurius.ErrorWithProps(`custom auth error on ${info.fieldName}`);
err.statusCode = 200;
return err // or throw err
}
return true
}
...