react-access-engine
v1.0.0
Published
Unified access control for React & Node.js — RBAC, ABAC, feature flags, A/B experiments, plan gating, policy engine, remote config. Works with Next.js, Express, Fastify. SSR-safe, tree-shakeable, zero dependencies. One hook, one component.
Downloads
481
Maintainers
Keywords
Readme
react-access-engine
Unified access control for React.js/Next.js — RBAC, ABAC, feature flags, experiments, plan gating, and policy engine.
One hook. One component. Everything you need.
Also works on Node.js/Express — same config, same logic, no extra package.
React.js, Next.js, Node.js, Express, RBAC, ABAC, authorization, permissions, feature flags, A/B testing, plan gating, remote config, SSR-safe, TypeScript
Documentation · Playground · GitHub
Why?
React apps cobble together homegrown RBAC, a feature flag service, ad-hoc plan gating, and manual A/B test wiring each with its own provider, API, and blind spots.
react-access-engine replaces all of them with one system:
const { can, is, has, tier } = useAccess();
can('edit'); // check permission
is('admin'); // check role
has('dark-mode'); // check feature flag
tier('pro'); // check planFeatures
- RBAC — Multi-role users, role → permission mapping, wildcard permissions
- ABAC — Attribute-based policies with allow/deny rules and custom condition operators
- Feature Flags — Boolean toggles, percentage rollouts, role/plan/environment targeting
- A/B Experiments — Deterministic variant assignment, SSR-safe hashing
- Plan Gating — Hierarchical subscription tiers with automatic comparison
- Remote Config — Fetch config from API with stale-while-revalidate, polling, signature verification
- Condition Engine — Declarative ABAC with built-in operators (equals, in, greaterThan, etc.)
- Plugin System — Lifecycle hooks for audit logging, analytics, custom operators
- DevTools — Optional overlay for inspecting access decisions in real time
- Type Safety — Full TypeScript inference —
InferRoles,InferPermissions,InferFeatures - SSR-Ready — Deterministic evaluation, works with Next.js App Router
- Tree-Shakeable — Import only what you use — unused engines are eliminated at build time
- Backend Support — Same engine functions work in Node.js/Express — no separate package needed
- Zero Dependencies — No runtime dependencies beyond React
Installation
npm install react-access-engineRequires
react >= 18as a peer dependency.
Quick Start
1. Define your config
import { defineAccess } from 'react-access-engine';
const config = defineAccess({
roles: ['viewer', 'editor', 'admin'],
permissions: {
viewer: ['articles:read'],
editor: ['articles:read', 'articles:write'],
admin: ['*'],
},
plans: ['free', 'pro', 'enterprise'],
features: {
'dark-mode': true,
'ai-assist': { enabled: true, allowedPlans: ['pro', 'enterprise'] },
'beta-editor': { rolloutPercentage: 25 },
},
});2. Wrap your app
import { AccessProvider } from 'react-access-engine';
function App() {
return (
<AccessProvider config={config} user={{ id: 'u1', roles: ['editor'], plan: 'pro' }}>
<YourApp />
</AccessProvider>
);
}3. Use it
One hook — useAccess() — does everything:
import { useAccess } from 'react-access-engine';
function Dashboard() {
const { can, is, has, tier } = useAccess();
return (
<div>
{can('articles:write') && <button>New Article</button>}
{is('admin') && <AdminPanel />}
{has('dark-mode') && <DarkTheme />}
{tier('pro') && <AIAssistant />}
</div>
);
}Or use <Allow> — one component for all access control:
import { Allow } from 'react-access-engine';
function StorePage() {
return (
<>
{/* Permission gate */}
<Allow permission="articles:write" fallback={<ReadOnlyView />}>
<Editor />
</Allow>
{/* Role gate */}
<Allow role="admin">
<AdminTools />
</Allow>
{/* Feature flag gate */}
<Allow feature="dark-mode">
<DarkTheme />
</Allow>
{/* Plan gate with upgrade prompt */}
<Allow plan="pro" fallback={<UpgradePrompt />}>
<ProFeatures />
</Allow>
{/* Combine conditions */}
<Allow permission="analytics:view" plan="pro" match="all">
<AnalyticsDashboard />
</Allow>
</>
);
}More React Examples
ABAC — resource-level access:
import { Can } from 'react-access-engine';
// Seller can only edit their own products
<Can perform="products:edit" on={{ sellerId: product.sellerId }}>
<button>Edit Product</button>
</Can>
// Support can only refund recent orders
<Can perform="orders:refund" on={{ orderedAt: order.createdAt }}>
<button>Process Refund</button>
</Can>Feature flags:
import { Feature } from 'react-access-engine';
<Feature name="live-chat" fallback={<EmailSupport />}>
<LiveChat />
</Feature>;A/B experiments:
import { Experiment, useExperiment } from 'react-access-engine';
// Declarative
<Experiment
id="checkout-redesign"
variants={{ control: <CheckoutA />, redesign: <CheckoutB /> }}
fallback={<CheckoutA />}
/>;
// Hook-based
function Checkout() {
const { variant } = useExperiment('checkout-layout');
return variant === 'single-page' ? <OnePageCheckout /> : <MultiStepCheckout />;
}Plan gating with upgrade prompt:
import { usePlan } from 'react-access-engine';
function AIRecommendations() {
const { hasPlanAccess } = usePlan();
if (!hasPlanAccess('pro')) {
return <UpgradeBanner plan="pro" />;
}
return <AIPanel />;
}API Reference
Config
defineAccess— Create a fully typed access configurationmergeConfigs— Merge base config with overrides (remote patches)
Components
AccessProvider— Context provider — wraps your appAllow— Universal gate — permission, role, feature, planCan— Permission gate with ABAC resource supportFeature— Feature flag gateExperiment— A/B test variant rendererAccessGate— Multi-condition gate with mode (all/any)PermissionGuard— Route-level guard requiring all permissionsFeatureToggle— Render-prop variant of Feature
Hooks
useAccess()— All-in-one access checking (can,is,has,tier)usePermission(perm, resource?)— Check a single permissionuseRole()— Role checking utilitiesuseFeature(name)— Check a feature flag with reasonusePolicy(perm, resource?)— Evaluate policy rulesuseExperiment(id)— Get experiment assignmentusePlan()— Subscription plan checksuseAccessDebug()— Debug metadata (whendebug: true)useRemoteConfig(base, loader)— Remote config with SWR pattern
Engines & Utilities
RemoteConfigEngine— Programmatic remote config with polling & SWRDebugEngine— Event recording for devtools integrationevaluateCondition/evaluateConditions— Evaluate ABAC conditionsbuildConditionContext— Build context from user/resource/envAccessContext— React Context for advanced integrations
Backend / Node.js
All engine functions are pure logic — no React dependency. Use the same config on your server:
import {
hasPermission,
hasRole,
evaluateFeature,
evaluatePolicy,
assignExperiment,
hasPlanAccess,
} from 'react-access-engine';
// Works in Express, Fastify, Deno, or any JS runtime
if (hasPermission(user, 'articles:read', config)) {
/* allow */
}
if (evaluateFeature('ai-assist', user, config).enabled) {
/* feature on */
}
if (hasPlanAccess(user, 'pro', config)) {
/* plan ok */
}Express middleware example:
function requirePermission(...perms: string[]) {
return (req, res, next) => {
for (const perm of perms) {
if (!hasPermission(req.user, perm, config)) {
return res.status(403).json({ error: `Permission denied: ${perm}` });
}
}
next();
};
}
app.get('/api/articles', requirePermission('articles:read'), (req, res) => {
res.json({ articles: getAllArticles() });
});
app.delete('/api/articles/:id', requirePermission('articles:delete'), (req, res) => {
const article = getArticleById(req.params.id);
const policy = evaluatePolicy('articles:delete', req.user, config, { resource: article });
if (policy.effect === 'deny') {
return res.status(403).json({ error: 'Policy denied', reason: policy.reason });
}
deleteArticle(req.params.id);
res.json({ message: 'Deleted' });
});All backend exports:
- Roles —
hasRole,hasAnyRole,hasAllRoles - Permissions —
hasPermission,hasAnyPermission,hasAllPermissions,getPermissionsForUser - Features —
evaluateFeature,evaluateAllFeatures - Policies —
evaluatePolicy - Experiments —
assignExperiment - Plans —
hasPlanAccess,getPlanTier - Conditions —
evaluateCondition,evaluateConditions,buildConditionContext - Classes —
PluginEngine,DebugEngine
See the full backend docs for shared config patterns, feature-gated endpoints, plan guards, ABAC policy evaluation, A/B experiments, and plugin usage on Node.js.
Plugin Factories
createAuditLoggerPlugin— Drop-in audit logging plugincreateAnalyticsPlugin— Analytics event tracking plugincreateOperatorPlugin— Register custom condition operators
Type Inference Helpers
import type {
InferRoles,
InferPermissions,
InferFeatures,
InferPlans,
InferExperiments,
} from 'react-access-engine';
type Roles = InferRoles<typeof config>; // 'viewer' | 'editor' | 'admin'
type Perms = InferPermissions<typeof config>; // 'articles:read' | 'articles:write' | '*'Advanced Usage
See the full documentation for details on:
- ABAC Policies — Composable allow/deny rules with resource conditions
- Percentage Rollouts — Deterministic feature rollouts based on user ID hashing
- Feature Dependencies — Features that require other features to be enabled
- Remote Config — Fetch & merge config from API with polling and signature verification
- Condition Engine — Declarative ABAC with built-in operators (equals, in, greaterThan, etc.)
- Plugin System — Audit logging, analytics, custom operators
- Experiments — A/B testing with deterministic variant assignment
- SSR / Next.js — Works with App Router, no client-only APIs in core
DevTools
Install the companion devtools package for a development overlay:
npm install -D react-access-engine-devtoolsimport { AccessDevtools } from 'react-access-engine-devtools';
<AccessProvider config={config} user={user}>
<YourApp />
<AccessDevtools />
</AccessProvider>;