March 30, 2025

ikayaniaamirshahzad@gmail.com

Visualizing Role Field Access in GraphQL: Generating and Auditing RBAC Matrix


When debugging or auditing GraphQL APIs — especially in Hasura —

the key question is often:

“Which roles can access which fields on which types?”

Answering this by hand is slow, error-prone, and unscalable.

This guide shows how to auto-generate a Role × Field access matrix, export it as CSV/HTML, and visualize it interactively.




1. Objective: Matrix Output

Example table:

Role Table Field SELECT INSERT UPDATE DELETE
user users id
user users email
public posts title
admin users password_hash



2. Data Source: Hasura Metadata

Permissions live in:

metadata/
├── tables/
│   ├── users.yaml
│   ├── posts.yaml
Enter fullscreen mode

Exit fullscreen mode

Each file contains permissions by role:

select_permissions:
  - role: user
    permission:
      columns: [id, email]
      filter: { id: { _eq: X-Hasura-User-Id } }
insert_permissions:
  - role: public
    permission:
      columns: [title, content]
Enter fullscreen mode

Exit fullscreen mode




3. CLI Generator Script (Node.js)

Install dependencies:

npm install yaml glob chalk fs
Enter fullscreen mode

Exit fullscreen mode

Script outline:

// rbac-matrix.js
import fs from 'fs';
import yaml from 'yaml';
import glob from 'glob';

const matrix = [];

const files = glob.sync('./metadata/tables/*.yaml');
for (const file of files) {
  const table = file.split('/').pop().replace('.yaml', '');
  const doc = yaml.parse(fs.readFileSync(file, 'utf8'));

  ['select', 'insert', 'update', 'delete'].forEach(action => {
    const perms = doc[`${action}_permissions`] || [];
    perms.forEach(p => {
      const role = p.role;
      const cols = p.permission?.columns || [];
      cols.forEach(col => {
        const row = matrix.find(r => r.role === role && r.table === table && r.field === col);
        if (row) {
          row[action.toUpperCase()] = '';
        } else {
          matrix.push({
            role,
            table,
            field: col,
            SELECT: '',
            INSERT: '',
            UPDATE: '',
            DELETE: '',
            [action.toUpperCase()]: ''
          });
        }
      });
    });
  });
}

const csv = [
  ['Role', 'Table', 'Field', 'SELECT', 'INSERT', 'UPDATE', 'DELETE'],
  ...matrix.map(r => [r.role, r.table, r.field, r.SELECT, r.INSERT, r.UPDATE, r.DELETE])
].map(row => row.join(',')).join('\n');

fs.writeFileSync('rbac-matrix.csv', csv);
console.log('✅ RBAC matrix written to rbac-matrix.csv');
Enter fullscreen mode

Exit fullscreen mode




4. Optional: HTML Table Renderer

Convert CSV → HTML table with filters (use DataTables.js or React):