mercurius-auth supports the following options:
- applyPolicy
(policy: any, parent: object, args: Record<string, any>, context: MercuriusContext, info: GraphQLResolveInfo) => Promise<boolean | Error>- the policy promise to run when an auth protected field is selected by the query. This must returntruein order to pass the check and allow access to the protected field. - authContext
(context: MercuriusContext) => object | Promise<object>(optional) - assigns the returned data toMercuriusContext.authfor use in theapplyPolicyfunction. This runs within apreExecutionMercurius GraphQL request hook. - mode
'directive' | 'external'(optional, default:'directive') - the mode of operation for the plugin. Depending on the mode of operation selected, this has the following options:
-
authDirective
string- the name of the directive that the Mercurius auth plugin will look for within the GraphQL schema in order to identify protected fields. For example, for directive definitiondirective @auth on OBJECT | FIELD_DEFINITION, the corresponding name would beauth. -
filterSchema
boolean- whentrue, introspection queries will only return the parts of the schema which are accessible based on the applied policies.
- policy
MercuriusAuthPolicy(optional) - the auth policy definition. The field definition is passed as the first argument whenapplyPolicyis called for the associated field.
Extends: Record<string, MercuriusAuthTypePolicy>
Each key within the MercuriusAuthPolicy type corresponds with the GraphQL type name. For example, if we wanted to protect an object type:
type Message {
...
}We would use the key: Message:
{
Message: { ... }
}Extends: Record<string, any>
- __typePolicy
any(optional) - The policy definition for the type.
Each key within the MercuriusAuthTypePolicy type corresponds with the GraphQL field name on a type. For example, if we wanted to protect type field message:
type Message {
title: String
message: String
}We would use the key: message:
{
Message: {
message: { requires: 'user' }
}
}If we want to protect the entire type, we would use __typePolicy:
{
Message: {
__typePolicy: { requires: 'user' }
}
}This also works alongside specific field policies on the type:
{
Message: {
__typePolicy: { requires: 'user', }
message: { requires: 'admin' }
}
}The plugin must be registered after Mercurius is registered.
'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) {
return context.auth.identity === 'admin'
},
authDirective: 'auth'
})
app.listen({ port: 3000 })'use strict'
const Fastify = require('fastify')
const mercurius = require('mercurius')
const mercuriusAuth = require('..')
const app = Fastify()
const schema = `
type Message {
title: String
message: String
adminMessage: String
}
type Query {
messages: [Message]
message(title: String): Message
}
`
const messages = [
{
title: 'one',
message: 'one',
adminMessage: 'admin message one'
},
{
title: 'two',
message: 'two',
adminMessage: 'admin message two'
}
]
const resolvers = {
Query: {
messages: async (parent, args, context, info) => {
return messages
},
message: async (parent, args, context, info) => {
return messages.find(message => message.title === args.title)
}
}
}
app.register(mercurius, {
schema,
resolvers
})
app.register(mercuriusAuth, {
authContext (context) {
const permissions = context.reply.request.headers['x-user'] || ''
return { permissions }
},
async applyPolicy (policy, parent, args, context, info) {
return context.auth.permissions.includes(policy.requires)
},
mode: 'external',
policy: {
Message: {
__typePolicy: { requires: 'user' },
adminMessage: { requires: 'admin' }
},
Query: {
messages: { requires: 'user' }
}
}
})
app.listen({ port: 3000 })