{"id":16648,"library":"mercurius-auth","title":"Mercurius Auth Plugin","description":"Mercurius Auth is a Fastify plugin designed to add configurable authentication and authorization support to GraphQL APIs built with Mercurius. It is currently at stable version 6.0.0, with major updates often aligning with new Fastify or Mercurius versions. The plugin allows defining auth directives directly within the GraphQL schema to apply custom policies against protected fields, supporting both normal and gateway modes. Alternatively, it can operate in an 'External Policy' mode, offering programmatic control over authorization. Key differentiators include its tight integration with the Fastify and Mercurius ecosystems, its ability to build an auth context, and its GraphQL spec compliance, including features like schema filtering and replacement. Development appears active, with regular updates and dependency bumps.","status":"active","version":"6.0.0","language":"javascript","source_language":"en","source_url":"https://github.com/mercurius-js/auth","tags":["javascript","typescript"],"install":[{"cmd":"npm install mercurius-auth","lang":"bash","label":"npm"},{"cmd":"yarn add mercurius-auth","lang":"bash","label":"yarn"},{"cmd":"pnpm add mercurius-auth","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"mercurius-auth is a Fastify plugin and registers with a Fastify instance.","package":"fastify","optional":false},{"reason":"mercurius-auth extends Mercurius to provide GraphQL authentication and authorization.","package":"mercurius","optional":false}],"imports":[{"note":"While CommonJS `require` works for older Node.js versions or specific configurations, modern Fastify/Mercurius setups often prefer ESM `import`.","wrong":"const mercuriusAuth = require('mercurius-auth')","symbol":"mercuriusAuth","correct":"import mercuriusAuth from 'mercurius-auth'"},{"note":"Fastify itself supports both CJS and ESM; consistency with your project's module system is recommended.","wrong":"const Fastify = require('fastify')","symbol":"Fastify","correct":"import Fastify from 'fastify'"},{"note":"Mercurius, like Fastify, supports both CJS and ESM. Use `import` for modern setups.","wrong":"const mercurius = require('mercurius')","symbol":"mercurius","correct":"import mercurius from 'mercurius'"}],"quickstart":{"code":"import Fastify from 'fastify';\nimport mercurius from 'mercurius';\nimport mercuriusAuth from 'mercurius-auth';\n\nconst app = Fastify();\n\nconst schema = `\n  directive @auth(\n    requires: Role = ADMIN,\n  ) on OBJECT | FIELD_DEFINITION\n\n  enum Role {\n    ADMIN\n    REVIEWER\n    USER\n    UNKNOWN\n  }\n\n  type Query {\n    add(x: Int, y: Int): Int @auth(requires: USER)\n    adminData: String @auth(requires: ADMIN)\n  }\n`;\n\nconst resolvers = {\n  Query: {\n    add: async (_, { x, y }) => x + y,\n    adminData: async () => 'Secret admin information'\n  }\n};\n\napp.register(mercurius, {\n  schema,\n  resolvers\n});\n\napp.register(mercuriusAuth, {\n  authContext (context) {\n    // Simulate loading user identity from request headers\n    const identity = context.reply.request.headers['x-user'] || 'UNKNOWN';\n    return {\n      identity: identity.toUpperCase() // Ensure consistency\n    };\n  },\n  async applyPolicy (authDirectiveAST, parent, args, context, info) {\n    const requiredRole = authDirectiveAST.requires;\n    const userRole = context.auth.identity; // Assuming identity is the role for simplicity\n\n    if (requiredRole === 'ADMIN' && userRole !== 'ADMIN') {\n      return false;\n    }\n    if (requiredRole === 'USER' && (userRole !== 'ADMIN' && userRole !== 'USER')) {\n        return false;\n    }\n    return true; // Policy passes\n  },\n  authDirective: 'auth'\n});\n\napp.listen({ port: 3000 }, (err) => {\n  if (err) {\n    app.log.error(err);\n    process.exit(1);\n  }\n  app.log.info(`Server listening on port 3000`);\n});\n\n// Example usage (e.g., with curl):\n// curl -H \"x-user: user\" http://localhost:3000/graphql -X POST -H \"Content-Type: application/json\" -d '{\"query\":\"query { add(x: 5, y: 3) }\"}'\n// curl -H \"x-user: admin\" http://localhost:3000/graphql -X POST -H \"Content-Type: application/json\" -d '{\"query\":\"query { adminData }\"}'\n// curl -H \"x-user: user\" http://localhost:3000/graphql -X POST -H \"Content-Type: application/json\" -d '{\"query\":\"query { adminData }\"}' // Should fail","lang":"typescript","description":"This quickstart demonstrates `mercurius-auth` in 'Directive mode' using Fastify and Mercurius. It defines a custom `@auth` directive with role-based authorization, extracting the user role from request headers in `authContext` and enforcing policies in `applyPolicy`."},"warnings":[{"fix":"Ensure your project is using Fastify v4 or greater, and ideally Fastify v5 compatible versions when using mercurius-auth v6.0.0. Update your `fastify` and `mercurius` packages accordingly.","message":"Version 6.0.0 of mercurius-auth introduces compatibility changes to prepare for Fastify v5. While it might still work with Fastify v4, it is highly recommended to upgrade Fastify to its latest major version alongside mercurius-auth v6.0.0 to ensure full compatibility and avoid potential issues. This aligns with Fastify's plugin API evolution.","severity":"breaking","affected_versions":">=6.0.0"},{"fix":"Upgrade your Fastify dependency to v4 or newer. Review your Fastify application code for any breaking changes introduced in Fastify v4 and update accordingly. Ensure Mercurius is also compatible with Fastify v4.","message":"Version 3.0.0 of mercurius-auth upgraded its core dependency to Fastify v4. This is a significant breaking change as Fastify v4 introduced several API changes, particularly around plugin registration and decorators. Directly incompatible Fastify v3 usage will result in runtime errors.","severity":"breaking","affected_versions":">=3.0.0 <6.0.0"},{"fix":"No direct code changes are typically required unless you were directly interacting with or extending internal components that relied on `@graphql-tools/wrap` within mercurius-auth. Ensure thorough testing after upgrading.","message":"Mercurius Auth v2.0.2 removed the `@graphql-tools/wrap` dependency and replaced its functionality internally. While this primarily impacted internal implementation, it might have subtle effects if your application relied on specific behaviors or types exposed by that dependency through earlier mercurius-auth versions.","severity":"breaking","affected_versions":">=2.0.2"},{"fix":"Adopt ESM `import` statements consistently across your Fastify and Mercurius application, especially if your `package.json` specifies `\"type\": \"module\"`.","message":"When using `mercurius-auth` in ESM modules, ensure you use `import mercuriusAuth from 'mercurius-auth'` instead of `require`. While Fastify and Mercurius generally handle both, mixing module systems can lead to unexpected errors or require specific build configurations.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Always register `mercurius-auth` using `app.register(mercuriusAuth, options)` where `app` is your Fastify instance.","cause":"Attempting to initialize `mercurius-auth` directly without using `fastify.register()` or passing incorrect options to `register`.","error":"Error: mercuriusAuth must be used as a Fastify plugin, i.e. `fastify.register(mercuriusAuth)`"},{"fix":"Ensure your Fastify and Mercurius versions are compatible with `mercurius-auth`. Specifically, `mercurius-auth` v3+ requires Fastify v4+. Also, check your Mercurius registration for proper context propagation.","cause":"This error often occurs when `context.reply.request` is `undefined` within `authContext`, usually due to an incompatible Fastify version or a misconfigured Mercurius instance not properly passing the Fastify context.","error":"TypeError: Cannot read properties of undefined (reading 'request') in authContext"},{"fix":"Make sure your GraphQL schema includes the directive definition (e.g., `directive @auth(...)`) and that the `authDirective` option in `app.register(mercuriusAuth, { authDirective: 'auth' })` matches your directive name.","cause":"The `@auth` directive (or your custom directive name) has been used in the schema but was not properly defined in the `mercurius-auth` options or included in the `authDirective` option.","error":"Error: Unknown directive \"@auth\"."}],"ecosystem":"npm"}