Topics Authentication & Authorization Role-Based Access Control
advanced 17 min read

Role-Based Access Control

Implement RBAC with Fastify hooks and decorators for fine-grained permissions.

Role-Based Access Control

// Role checking middleware\napp.decorate('requireRole', function(...roles) {\n  return async (request, reply) => {\n    await request.jwtVerify();\n\n    if (!roles.includes(request.user.role)) {\n      return reply.code(403).send({\n        error: 'Insufficient permissions',\n        required: roles,\n        yourRole: request.user.role,\n      });\n    }\n  };\n});\n\n// Usage\napp.get('/admin/users', {\n  preHandler: [app.requireRole('admin')],\n}, async (request) => {\n  return db.users.findAll();\n});\n\napp.get('/manager/reports', {\n  preHandler: [app.requireRole('admin', 'manager')],\n}, async (request) => {\n  return db.reports.findAll();\n});\n\n// Permission-based access\napp.decorate('requirePermission', function(permission) {\n  return async (request, reply) => {\n    await request.jwtVerify();\n\n    const permissions = {\n      admin: ['*'],\n      manager: ['read:users', 'write:reports', 'read:reports'],\n      editor: ['write:posts', 'read:posts'],\n      user: ['read:posts'],\n    };\n\n    const userPermissions = permissions[request.user.role] || [];\n\n    if (!userPermissions.includes('*') && !userPermissions.includes(permission)) {\n      return reply.code(403).send({ error: 'Missing permission: ' + permission });\n    }\n  };\n});\n\napp.delete('/posts/:id', {\n  preHandler: [app.requirePermission('write:posts')],\n}, async (request) => {\n  return db.posts.delete(request.params.id);\n});

Examples

const Fastify = require('fastify');

const app = Fastify({ logger: true });

// RBAC setup
async function build() {
  await app.register(require('@fastify/jwt'), {
    secret: 'change-me',
  });

  // Role-based access
  app.decorate('canAccess', function(...roles) {
    return async (request, reply) => {
      try {
        await request.jwtVerify();
      } catch {
        return reply.code(401).send({ error: 'Unauthorized' });
      }

      if (!roles.includes(request.user.role)) {
        reply.code(403);
        return { error: 'Forbidden', required: roles, yourRole: request.user.role };
      }
    };
  });

  // Routes with different access levels
  app.get('/public', async () => ({
    message: 'This is public',
  }));

  app.get('/user/data', {
    preHandler: [app.canAccess('user', 'admin', 'manager')],
  }, async (request) => ({
    message: 'User data',
    user: request.user,
  }));

  app.get('/admin', {
    preHandler: [app.canAccess('admin')],
  }, async () => ({
    message: 'Admin panel',
    users: [{ id: 1, name: 'Alice' }],
  }));

  // Login endpoint
  app.post('/login', async (request) => {
    const { username, role = 'user' } = request.body;
    const token = app.jwt.sign({ username, role }, { expiresIn: '1h' });
    return { token, user: { username, role } };
  });

  await app.listen({ port: 3000 });
}

build();

Your Notes

Sign in to take notes for this lesson.

Discussion

Sign in to join the discussion.

Flashcards

Sign in to create flashcards.