Implementing authorization in Go, Java, React, or Vue from scratch takes weeks and
is easy to get wrong.
a11n gives your SaaS app production-ready RBAC and permission management
in minutes — not weeks.
Every SaaS app needs authorization. Most teams underestimate it — and pay the price in lost weeks, security bugs, and frustrated customers.
Building roles, permissions, and access checks from scratch takes weeks of effort that could be spent on your actual product.
Each customer organisation needs isolated roles, resources, and permissions. Getting the data model right for multi-tenancy is notoriously tricky.
A missed permission check or a broken role hierarchy is a security incident waiting to happen. Home-grown auth is hard to audit and easy to misconfigure.
Your users want to manage their own team permissions. Building admin UIs for roles, users, and policies doubles the effort on top of the backend work.
Drop in a library for your stack and start guarding resources immediately. No custom schemas, no bespoke databases — just clear, expressive APIs built for multi-tenant SaaS.
import { CerberusProvider, AccessGuard, useAccess } from '@a11n-io/cerberus-reactjs';
// 1. Wrap your app — one-time setup
function App() {
return (
<CerberusProvider
apiHost="https://cerberus-api.a11n.io"
socketHost="wss://cerberus-ws.a11n.io"
>
<ProjectDashboard />
</CerberusProvider>
);
}
// 2. Guard any UI element — real-time permission checks via WebSocket
function ProjectDashboard({ projectId }) {
return (
<div>
<h1>Project Overview</h1>
{/* Only users with 'edit' access see the edit button */}
<AccessGuard resourceId={projectId} action="edit">
<EditProjectButton />
<template slot="otherwise">
<span className="badge">View only</span>
</template>
</AccessGuard>
{/* Delete is restricted to admins */}
<AccessGuard resourceId={projectId} action="delete">
<DeleteProjectButton />
</AccessGuard>
</div>
);
}
// 3. Or use the hook for imperative logic
function ExportButton({ reportId }) {
const [canExport, setCanExport] = React.useState(false);
useAccess(reportId, 'export', setCanExport);
return canExport ? <button>Export CSV</button> : null;
}
<!-- main.js: register the plugin -->
import { createApp } from 'vue'
import CerberusPlugin from '@a11n-io/cerberus-vuejs'
import App from './App.vue'
createApp(App)
.use(CerberusPlugin)
.mount('#app')
<!-- App.vue: wrap with provider -->
<template>
<CerberusProvider
api-host="https://cerberus-api.a11n.io"
socket-host="wss://cerberus-ws.a11n.io"
>
<ProjectDashboard />
</CerberusProvider>
</template>
<!-- ProjectDashboard.vue: guard UI elements -->
<template>
<div>
<h1>Project Overview</h1>
<!-- Only users with 'edit' permission see this -->
<AccessGuard :resource-id="projectId" action="edit">
<EditProjectButton />
<template #otherwise>
<span class="badge">View only</span>
</template>
</AccessGuard>
<!-- Restrict destructive actions to admins -->
<AccessGuard :resource-id="projectId" action="delete">
<DeleteProjectButton />
</AccessGuard>
</div>
</template>
<script setup>
import { AccessGuard } from '@a11n-io/cerberus-vuejs'
import { useAccess } from '@a11n-io/cerberus-vuejs'
const props = defineProps({ projectId: String })
// Use the composable for programmatic checks
const canExport = ref(false)
useAccess(props.projectId, 'export', (granted) => {
canExport.value = granted
})
</script>
package main
import (
"context"
"net/http"
"os"
cerberus "github.com/a11n-io/go-cerberus"
)
// 1. Initialise the client once at startup
var client = cerberus.NewClient(
"https://cerberus-api.a11n.io",
os.Getenv("CERBERUS_API_KEY"),
os.Getenv("CERBERUS_API_SECRET"),
)
// 2. Guard any HTTP handler with a middleware
func RequireAction(action string, next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
resourceId := r.PathValue("id")
ctx := r.Context()
ok, err := client.HasAccess(ctx, resourceId, action)
if err != nil || !ok {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
next(w, r)
}
}
// 3. Bootstrap a new customer account atomically
func onUserSignup(ctx context.Context, accountId, userId, email, name string) error {
return client.Execute(accountId, userId,
cerberus.CreateResourceCmd(accountId, "", "Account"),
cerberus.CreateUserCmd(userId, email, name),
cerberus.CreateRoleCmd("Admin"),
cerberus.CreateRoleCmd("Member"),
cerberus.AssignRoleCmd("Admin", userId),
cerberus.CreateRolePermissionCmd("Admin", accountId, []string{"CanManage", "CanInvite", "CanDelete"}),
cerberus.CreateRolePermissionCmd("Member", accountId, []string{"CanView"}),
)
}
// Routes
func main() {
http.HandleFunc("GET /projects/{id}", RequireAction("view", getProject))
http.HandleFunc("PUT /projects/{id}", RequireAction("edit", updateProject))
http.HandleFunc("DELETE /projects/{id}", RequireAction("delete", deleteProject))
http.ListenAndServe(":8080", nil)
}
import io.a11n.cerberus.CerberusClient;
import io.a11n.cerberus.command.Command;
import io.a11n.cerberus.model.TokenPair;
// 1. Initialise the client (inject as a Spring bean, for example)
@Bean
public CerberusClient cerberusClient() {
return CerberusClient.newClient(
"https://cerberus-api.a11n.io",
System.getenv("CERBERUS_API_KEY"),
System.getenv("CERBERUS_API_SECRET")
);
}
// 2. Check access in your service or filter layer
@Service
public class AuthService {
private final CerberusClient cerberus;
public void requireAccess(String userId, String accountId,
String resourceId, String action) {
TokenPair token = cerberus.getUserToken(accountId, userId);
boolean allowed = cerberus.hasAccess(token, resourceId, action);
if (!allowed) {
throw new AccessDeniedException("Action '" + action + "' not permitted");
}
}
// 3. Bootstrap a new customer account atomically
public void onUserSignup(String accountId, String userId,
String email, String name) throws CerberusException {
cerberus.execute(accountId, userId,
Command.createResource(accountId, null, "Account"),
Command.createUser(userId, email, name),
Command.createRole("Admin"),
Command.createRole("Member"),
Command.assignRole("Admin", userId),
Command.createRolePermission("Admin", accountId, List.of("CanManage", "CanInvite", "CanDelete")),
Command.createRolePermission("Member", accountId, List.of("CanView"))
);
}
}
// 4. Protect a Spring MVC controller
@RestController
@RequestMapping("/projects")
public class ProjectController {
@PutMapping("/{id}")
public ResponseEntity<?> update(@PathVariable String id,
@AuthUser User user) {
authService.requireAccess(user.getId(), user.getAccountId(), id, "edit");
// ... your business logic
return ResponseEntity.ok().build();
}
}
Cerberus is a dedicated authorization microservice built for multi-tenant SaaS. It centralises your permission logic so every backend service calls one source of truth, running alongside your existing stack as a hosted cloud service.
Define roles and policies at any granularity — from account level down to individual resources. Your customers control their own permissions.
Learn MoreNative libraries for React, Vue.js, Go, and Java. All open-source, all idiomatic to their ecosystems — no vendor lock-in.
Browse GitHubDrop-in React and Vue components let your customers manage their own users, roles, and permissions — no extra work for your team.
Learn MoreVersion and migrate your permission schemas alongside your application code. Ship authorization changes with confidence.
Learn MoreCerberus is our flagship authorization engine — a purpose-built microservice that centralises all permission logic for your SaaS application. It stores only resource identifiers, never your sensitive business data, making it inherently safe to integrate.
Real-time access decisions are delivered over WebSocket, so your UI reacts instantly to permission changes. Backend services in Go or Java query the same engine, giving you a single source of truth for authorization across your entire architecture.
Read the DocsTry the full service for free. Upgrade when you're ready to go to production.
Everything you want to know before getting started.
Execute call that creates the account, users, roles, and default
permissions in one transaction.
HasAccess(ctx, resourceId, action)
(Go) or hasAccess(token, resourceId, action) (Java) in your
middleware or service layer, and use Execute() to bootstrap
roles and permissions when onboarding new customers. All libraries are
open-source on GitHub.
<Users>, <Roles>, and
<Permissions> management components. Embed them in your app's
settings page and your customers immediately have a full authorization UI to
manage their team — without you writing a single extra line.