Authorization as a Service — now in production

Stop building auth.
Start shipping features.

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.

React Vue.js Go Java Multi-tenant Fine-grained RBAC
Authorization as a Service dashboard — manage roles, permissions and users shape shape
The Problem

Managing permissions in SaaS is harder than it looks

Every SaaS app needs authorization. Most teams underestimate it — and pay the price in lost weeks, security bugs, and frustrated customers.

Weeks of boilerplate

Building roles, permissions, and access checks from scratch takes weeks of effort that could be spent on your actual product.

Multi-tenant complexity

Each customer organisation needs isolated roles, resources, and permissions. Getting the data model right for multi-tenancy is notoriously tricky.

Security risks

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.

UI your customers need too

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.

The Solution

Implement authorization in Go, Java, React, or Vue

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.

App.jsx — @a11n-io/cerberus-reactjs
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;
}
App.vue — @a11n-io/cerberus-vuejs
<!-- 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>
auth.go — github.com/a11n-io/go-cerberus
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)
}
AuthService.java — io.a11n:java-cerberus
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();
    }
}
React
cerberus-reactjs
View on GitHub
Vue.js
cerberus-vuejs
View on GitHub
Go
go-cerberus
View on GitHub
Java
java-cerberus
View on GitHub
Features

Everything you need, nothing you don't

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.

Fine-grained RBAC

Define roles and policies at any granularity — from account level down to individual resources. Your customers control their own permissions.

Learn More

4 Open-source libraries

Native libraries for React, Vue.js, Go, and Java. All open-source, all idiomatic to their ecosystems — no vendor lock-in.

Browse GitHub

Built-in admin UI

Drop-in React and Vue components let your customers manage their own users, roles, and permissions — no extra work for your team.

Learn More

Migrations & SDLC

Version and migrate your permission schemas alongside your application code. Ship authorization changes with confidence.

Learn More
About Cerberus

A dedicated authorization service, built for SaaS

Cerberus 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 Docs
Cerberus authorization microservice architecture diagram
Pricing

Start free, scale as you grow

Try the full service for free. Upgrade when you're ready to go to production.

shape
FAQ

Common questions

Everything you want to know before getting started.

Most developers have access checks running within an hour. The backend client (Go or Java) takes ~20 lines to initialise and start checking permissions. The frontend components (React or Vue) are drop-in wrappers. Check the documentation and the example app to see how it all fits together.
Multi-tenancy is a first-class concept in Cerberus. Each customer account is completely isolated — roles, permissions, and resources are all scoped to the account. When a new customer signs up, you bootstrap their account with a single atomic Execute call that creates the account, users, roles, and default permissions in one transaction.
Cerberus only stores resource identifiers and user references — no sensitive business data ever leaves your system. All communication is encrypted in transit.
Use the go-cerberus or java-cerberus client libraries. Both expose the same simple pattern: initialise a client with your API key, call 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.
Yes — this is the primary use case. Cerberus is itself an authorization microservice. Each of your backend services (Go, Java, or any HTTP client) queries Cerberus to verify access. Because authorization is centralised, you avoid duplicating permission logic across services and get a single source of truth for all your access policies.
The React and Vue libraries ship with ready-made <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.
CONTACT US

Questions? We'd love
to hear from you.

Get in Touch

info@a11n.io