Next.js Utils

@devcraft-ts/abac-admin-nextjs

Server-side utilities and API route helpers for Next.js applications. Built on @devcraft-ts/abac-admin-core which leverages abac-engine for policy evaluation.

Built on abac-engine

This package provides Next.js-specific utilities for building ABAC admin interfaces powered by abac-engine. It includes pre-built API route handlers, authentication middleware, and server utilities. Learn more →

Server-Side

Built for Next.js App Router and API routes

Auth Middleware

Built-in authentication and authorization

Type-Safe

Full TypeScript support with abac-engine types

Zero Config

Works out of the box with sensible defaults

Automatic Validation

Built-in Zod validation for all endpoints

Installation

npm install @devcraft-ts/abac-admin-nextjs

# Includes dependencies
# - @devcraft-ts/abac-admin-core
# - @devcraft-ts/abac-admin-react

# Peer dependencies
npm install next react react-dom zod

Quick Start

1. Create API Routes

Set up API routes for policy and attribute management.

// app/api/abac/policies/route.ts
import { createPolicyRoutes } from '@devcraft-ts/abac-admin-nextjs/server';
import { ABACAdminClient } from '@devcraft-ts/abac-admin-core';

const getClient = () => new ABACAdminClient({
  baseURL: process.env.ABAC_API_URL!,
  headers: {
    'Authorization': `Bearer ${process.env.ABAC_API_TOKEN}`
  }
});

export const { GET, POST } = createPolicyRoutes(getClient);
</parameter>

export { GET, POST };

// app/api/abac/policies/[id]/route.ts
import { createPolicyRoutes } from '@devcraft-ts/abac-admin-nextjs';
import { getABACClient } from '@/lib/abac-client';

const { GET, PUT, DELETE } = createPolicyRoutes({
  getClient: () => getABACClient()
});

export { GET, PUT, DELETE };

2. Use Hooks in Your Components

"use client";

import { ABACProvider, usePolicies } from '@devcraft-ts/abac-admin-react';

function PolicyList() {
  const { policies, isLoading } = usePolicies();

  if (isLoading) return <div>Loading...</div>;

  return (
    <div>
      {policies.map(policy => (
        <div key={policy.id}>{policy.description}</div>
      ))}
    </div>
  );
}

export default function PoliciesPage() {
  return (
    <ABACProvider config={{ baseURL: '/api/abac' }}>
      <PolicyList />
    </ABACProvider>
  );
}

API Route Helpers

createPolicyRoutes

Creates API route handlers for policy management.

import { createPolicyRoutes } from '@devcraft-ts/abac-admin-nextjs';

const { GET, POST, PUT, DELETE, PATCH } = createPolicyRoutes({
  getClient: () => getABACClient(),
  middleware?: authMiddleware // Optional authentication
});

// Returns handlers for:
// GET    /api/policies       - List policies
// POST   /api/policies       - Create policy
// GET    /api/policies/[id]  - Get policy
// PUT    /api/policies/[id]  - Update policy
// DELETE /api/policies/[id]  - Delete policy
// PATCH  /api/policies/[id]  - Activate/deactivate

createAttributeRoutes

Creates API route handlers for attribute management.

// app/api/abac/attributes/[type]/[id]/route.ts
import { createAttributeRoutes } from '@devcraft-ts/abac-admin-nextjs';

const { GET, POST, DELETE } = createAttributeRoutes({
  getClient: () => getABACClient()
});

export { GET, POST, DELETE };

// Handles:
// GET    /api/attributes/user/user-123     - Get attributes
// POST   /api/attributes/user/user-123     - Set attributes
// DELETE /api/attributes/user/user-123     - Delete attributes

createAuditRoutes

Creates API route handlers for audit logs.

// app/api/abac/audit/route.ts
import { createAuditRoutes } from '@devcraft-ts/abac-admin-nextjs';

const { GET } = createAuditRoutes({
  getClient: () => getABACClient()
});

export { GET };

// Handles:
// GET /api/audit?entityType=policy&limit=50

Authentication Middleware

createAuthMiddleware

Create authentication middleware for protecting API routes.

import { createAuthMiddleware } from '@devcraft-ts/abac-admin-nextjs';
import { getSession } from '@/lib/auth';

const authMiddleware = createAuthMiddleware({
  getUser: async (request) => {
    const session = await getSession(request);
    return session?.user;
  },
  isAuthorized: (user, context) => {
    // Check if user is authorized
    return user?.role === 'admin';
  },
  onUnauthorized: () => {
    return new Response('Unauthorized', { status: 401 });
  }
});

// Use with route creators
const { GET, POST } = createPolicyRoutes({
  getClient: () => getABACClient(),
  middleware: authMiddleware
});

Built-in Authorization Helpers

import {
  requireRole,
  requirePermission,
  requireAny,
  requireAll
} from '@devcraft-ts/abac-admin-nextjs';

// Require specific role
const authMiddleware = requireRole('admin');

// Require specific permission
const authMiddleware = requirePermission('policies:write');

// Require any of the roles
const authMiddleware = requireAny(['admin', 'manager']);

// Require all permissions
const authMiddleware = requireAll([
  'policies:read',
  'policies:write'
]);

// Combine with custom logic
const authMiddleware = createAuthMiddleware({
  getUser: async (request) => getSession(request),
  isAuthorized: (user) => {
    return user?.roles?.includes('admin') ||
           user?.permissions?.includes('policies:write');
  }
});

Complete Example

Project Structure

app/
├── api/
│   └── abac/
│       ├── policies/
│       │   ├── route.ts          # List/Create policies
│       │   └── [id]/
│       │       └── route.ts      # Get/Update/Delete policy
│       ├── attributes/
│       │   └── [type]/
│       │       └── [id]/
│       │           └── route.ts  # Manage attributes
│       └── audit/
│           └── route.ts          # Audit logs
├── admin/
│   ├── layout.tsx               # Admin layout with auth
│   └── policies/
│       └── page.tsx             # Policies management page
└── lib/
    ├── abac-client.ts           # ABAC client setup
    └── auth-middleware.ts       # Auth middleware

lib/abac-client.ts

import { ABACAdminClient } from '@devcraft-ts/abac-admin-core';

export function getABACClient() {
  return new ABACAdminClient({
    baseURL: process.env.ABAC_API_URL!,
    headers: {
      'Authorization': `Bearer ${process.env.ABAC_API_TOKEN}`,
      'X-API-Key': process.env.ABAC_API_KEY!
    }
  });
}

lib/auth-middleware.ts

import { createAuthMiddleware } from '@devcraft-ts/abac-admin-nextjs';
import { getServerSession } from 'next-auth';

export const authMiddleware = createAuthMiddleware({
  getUser: async (request) => {
    const session = await getServerSession();
    return session?.user;
  },
  isAuthorized: (user) => {
    return user?.roles?.includes('admin');
  },
  onUnauthorized: () => {
    return new Response(
      JSON.stringify({ error: 'Unauthorized' }),
      { status: 401 }
    );
  }
});

app/api/abac/policies/route.ts

import { createPolicyRoutes } from '@devcraft-ts/abac-admin-nextjs';
import { getABACClient } from '@/lib/abac-client';
import { authMiddleware } from '@/lib/auth-middleware';

const { GET, POST } = createPolicyRoutes({
  getClient: () => getABACClient(),
  middleware: authMiddleware
});

export { GET, POST };

app/admin/policies/page.tsx

"use client";

import { ABACProvider, usePolicies } from '@devcraft-ts/abac-admin-react';
import { PolicyList } from '@devcraft-ts/abac-admin-react-ui';

export default function PoliciesPage() {
  return (
    <ABACProvider config={{ baseURL: '/api/abac' }}>
      <div className="container mx-auto py-8">
        <h1 className="text-3xl font-bold mb-6">Policies</h1>
        <PolicyList
          onCreate={() => console.log('Create')}
          onEdit={(id) => console.log('Edit', id)}
          onDelete={(id) => console.log('Delete', id)}
        />
      </div>
    </ABACProvider>
  );
}

Advanced Usage

Dynamic Authentication

const { GET, POST } = createPolicyRoutes({
  getClient: async (request) => {
    // Get user token from request
    const token = request.headers.get('Authorization');

    return new ABACAdminClient({
      baseURL: process.env.ABAC_API_URL!,
      headers: {
        'Authorization': token || ''
      }
    });
  }
});

Custom Error Responses

const authMiddleware = createAuthMiddleware({
  getUser: async (request) => getSession(request),
  isAuthorized: (user) => user?.role === 'admin',
  onUnauthorized: (context) => {
    return new Response(
      JSON.stringify({
        error: 'Access Denied',
        message: 'Admin role required',
        path: context.pathname
      }),
      {
        status: 403,
        headers: { 'Content-Type': 'application/json' }
      }
    );
  }
});

Best Practices

Use Environment Variables

Store API URLs and tokens in environment variables, never hardcode them.

Protect All Admin Routes

Always use authentication middleware on API routes that manage policies and attributes.

Use Proper RBAC

Implement role-based access control to restrict who can create, update, or delete policies.

Handle Errors Gracefully

Provide meaningful error messages and proper HTTP status codes in API responses.

Next Steps