DEV Community

Cover image for Stop Building Authz, Start Building Value: A Deep Dive into Authorization, REBAC, and SpiceDB
Alex Patterson for CodingCatDev

Posted on • Originally published at codingcat.dev

Stop Building Authz, Start Building Value: A Deep Dive into Authorization, REBAC, and SpiceDB

Original: https://codingcat.dev/podcast/scaling-permissions-with-spicedb-rebac-explained

Welcome back, fellow cats and coders! Whether you've landed here from the CodingCat.dev podcast or you're looking for the freshest snacks in dev land, you're in for a treat. Today, we're getting hands-on with modern authorization models, putting REBAC under the microscope, and spotlighting SpiceDB—the open source project that's changing how folks scale permissions for their apps. Plus, we’ll sprinkle in code, diagrams, and best practices from the field.

So, let’s paw at the mouse and dig into:

  • Why traditional auth models hit limits as you scale
  • What makes REBAC and SpiceDB so spicy (yep, Dune fans, we see you)
  • The realities of plugging in centralized, flexible auth—from early MVPs to massive teams
  • Real code, real stories, and real advice from devs in the trenches

Let’s get cozy and authentication-ready! 😺

Introduction: Auth is Different from Authz

Before we get too deep:

Authentication (Authn) is about confirming who you are.

Authorization (Authz) is about what you're allowed to do.

We keep hearing these terms thrown together, swapped around, and even merged in some products, but in reality, they're different worlds with different problems, tradeoffs, and risks. If you skip Authz or just tack it on, you’re basically throwing the doors open on your data. Yikes.

Why Should You Care?

  • Growing apps means growing complexity
  • Hacky “role” logic balloons fast (ever heard of role explosion?)
  • Users expect Google Docs–level sharing, not Windows 95 levels of access
  • Mistakes here cost trust, money, and security

If you’ve built an app and hit a wall with permissions, this post is for you. If you’re just getting started—awesome: you can skip some pain.

Meet the Experts: Sam, SpiceDB, and the CodingCat.dev Crew

Who’s Who?

I'm your trusty guide from CodingCat.dev, usually found herding cats and wrangling code. Today, I chatted with Sam—a Software Engineer at Authzed, creators of SpiceDB and all-around authority on fixing access management at scale.

Sam’s journey started hands-on, writing code and building the main open-source project. Now, he splits his time between direct engineering, community building, and showing teams a better way to do Authz. He's all about making complex topics approachable—just the way we like it.

“I've been at Authzed for over four years. Day to day, I'm still building, but recently I've shifted to helping more people get introduced to better access control.”

In Short: You’ll get a developer’s perspective with a heavy dose of practical advice and relatable “been there, fixed that” stories throughout.

The ABCs of Permission Models: RBAC, ABAC, PBAC, and REBAC Explained

There’s an alphabet soup of access control models. Each has its place, its strengths—and its pain points. Let’s break them down, developer to developer.

1. RBAC: Role-Based Access Control

This is the familiar one:

  • Roles like admin, editor, viewer
  • “If you’re an admin, do X. If you’re an editor, do Y.”

Good:

  • Easy to grok and quick to implement
  • Great for UIs and small teams

Bad:

  • Doesn’t handle complexity (e.g. “View this doc if you’re on the X team and created it”)
  • Roles multiply—fast (“role explosion”)

Example:

if (user.role === 'admin') { // Show admin features } else if (user.role === 'editor') { // Show editor features } 
Enter fullscreen mode Exit fullscreen mode

2. ABAC: Attribute-Based Access Control

Uses attributes, not just roles.

  • Attributes = any data: department, region, time-of-day, etc.
  • Rules can get more granular (“If user.department === 'finance' and resource.region === 'US'”)

Good:

  • More flexible than RBAC
  • Machines (not just humans) can use it

Bad:

  • Policies can become unwieldy, hard to audit
  • “Attribute explosion” is real

Common in AWS IAM!

Ever wrangled JSON policy statements? You’ve seen ABAC.

3. PBAC: Policy-Based Access Control

Policies define how access works. You still have attributes, but you wrap decision-making into reusable policies.

  • Think: central policy engine ("Can user X perform Y on resource Z?")

Good:

  • Intuitive if you like writing “policy as code”
  • Used in Rails plugins and many frameworks

Bad:

  • Policies can sprawl
  • Tightly coupled to codebase unless you plan ahead

4. REBAC: Relationship-Based Access Control

The flexible, modern model. Everything is a relationship:

  • Users
  • Teams
  • Resources
  • Permissions

Think “graphs” of relationships (“Sam is in Team A; Team A can view Document B; therefore Sam can view Document B”).

"With REBAC, you can actually model the previous three access control approaches… It’s a very generic construct. You have objects, you have relationships between those objects, and you apply rules based on the connections."

Visual: Diagram showing user, team, resource, and their relationships—all leading to a permission decision.---

Enter REBAC: Relationships Rule Everything Around Permissions

Let’s say you want to represent:

  • Alice is a member of Engineering
  • Engineering has access to Budget.xlsx

With REBAC, you create relationships:

(representation)Alice MEMBER_OF EngineeringEngineering ACCESS Budget.xlsx 
Enter fullscreen mode Exit fullscreen mode

Want to check if Alice can read Budget.xlsx? Just check if there’s a path through these relationships.

“If you can define the objects and relationships, you can almost model anything... [REBAC] generalizes to any permission scenario.”

Bonus:

REBAC lets you evolve. Model gets more complex? No problem—you add new relationships and types.

Visual: Flowchart of access via relationship path (user -> team -> resource).---

Scaling Authz: Lessons from Google Zanzibar

You ever hear about Google’s own permission system? No? Here’s the TL;DR:

What is Zanzibar?

  • Internal system powering permissions for Google apps (Docs, Drive, Calendar, etc.)
  • Centralizes authorization—one system, many models
  • Handles a ridiculous amount of requests (think billions, fast, reliably)

The 2019 Zanzibar paper explains how they modeled relationships, scaled with consistency, solved “new enemy” (revocation) problems, and kept performance up.

“The reason Google built Zanzibar is they only wanted one system... for every application to use for unique permissions.”

Visual: Timeline of Google tech from research paper to open source—Kubernetes, Zanzibar, SpiceDB.---

SpiceDB: Open Source Auth for Modern Apps

If Zanzibar is the OG, SpiceDB is the open source flavor. Built on Zanzibar’s principles, it drops into any app stack.

What Is SpiceDB?

  • An open source, “database for scalably storing and querying fine-grained authorization data”
  • Not a generic graph DB, but a purpose-built permission engine
  • Developer-friendly schema (less internal “secret sauce” needed)
  • Handles arbitrary objects, subjects, and relationships

Visual: Side-by-side snippet of Zanzibar’s internal config vs. SpiceDB’s schema DSL.#### Example: Defining Permissions in SpiceDB

Zanzibar’s Way (hard to read)
// Internal, not super friendlyobject_type: document {relation: viewer: user} 
Enter fullscreen mode Exit fullscreen mode
SpiceDB’s Way (JavaScript-ish DSL)
definition document {relation viewer: userpermission view = viewer} 
Enter fullscreen mode Exit fullscreen mode

How It Works In Practice

  • Define a schema: what are your objects, relationships, and permissions?
  • Write the relationships: who owns, who can read, who can edit, etc.?
  • Query at runtime: “Can Alice do X to Y resource?”

“It’s kind of like a relational DB—SpiceDB has a schema for objects, relations, and permissions, and the data forms a graph.”

RBAC and JWTs Are Not Always Enough

Auth “Quick Wins” (And When They Hurt)

Most web apps start with JWTs (JSON Web Tokens) and RBAC:

  • User logs in
  • JWT encodes their role(s) or permissions
  • App checks role when serving endpoints

Common pattern:

const hasPermission = userToken.permissions.includes('read:reports');if (hasPermission) {// Allow} else {// Deny} 
Enter fullscreen mode Exit fullscreen mode

Sounds fine… until real life steps in.

Real-World Headaches

  • Want per-report access? Now you need read:report:1, read:report:2, etc.—hello, permissions explosion!
  • Teams and group sharing? JWT gets huge, and permission checks become spaghetti
  • Someone’s role changes—now you have revocation lag (user still has their old JWT till it expires)
From the transcript:

“Multiply that by every user... now you have ‘n’ number of read reports. Obviously no one's gonna do that.”

It Gets Worse
  • Add group-based permissions? You’ll have to change the JWT claims and the application code!
  • Need to revoke instantly? JWTs are cached and can’t be revoked (that’s why you want short lifetimes).

Visual: Flow from login, JWT issued, user role changes, with lingering access due to long-lived JWT.---

Evolving Your Authorization Model as You Scale

Biggest question teams face: Should we start “the right way” from day one, or patch later?

Three Stages Most Teams Go Through

  1. MVP Mode: Quick and dirty; roles in the JWT, RBAC in the code.
  2. Growth Pains: Business logic and permissions intertwine—“custom authorization hell.”
  3. What Now? The company wants Google Docs–style sharing and needs to scale to new teams, regions, and resources… but the current system can’t keep up.
Quoting Our Guest:

“What if you didn’t have to take on so much tech debt? Some teams now just choose SpiceDB from day one—even if their permissions are easy, they know they’ll need to grow later.”

When Should You Move from RBAC/JWT to REBAC/SpiceDB?

  • As soon as you want more than basic roles or per-resource checks
  • When “who can see what” depends on relationships, teams, projects, or sharing
  • If you want centralization, dynamic policy changes, or audits

Pro Tip:

Starting too simple means future rewrites. Investing in a flexible model early pays off.

How to Start Building with SpiceDB and Authzed

Getting Set Up

1. Model Your Permissions (Before Coding)

Use the Authzed Playground to:

  • Define objects, relations, and permissions
  • Test out real-world scenarios in your browser
  • Tweak, evolve, and validate models without touching app code

Visual: Screenshot of the Authzed Playground interface, showing schema definition and relationship graph.#### 2. Integrate with Your App

Once you’ve got the model baked:

  • In your app, write relationships as you create objects (e.g., “Sam owns Doc123”)
  • Check permissions at key points (“Can Sam view Doc123?”)
  • SpiceDB acts as the source of truth; your code just asks for a yes/no
Sample Schema
// Example SpiceDB schema for docs and teamsdefinition user {}definition team {relation member: user}definition document {relation owner: user | teampermission read = owner} 
Enter fullscreen mode Exit fullscreen mode
Adding Relationships

Assume we use the SpiceDB client library:

relationship := &v1.Relationship{Resource: &v1.ObjectReference{ ... }, // e.g., "document:doc123"Relation: "owner",Subject: &v1.ObjectReference{ ... }, // e.g., "user:sam"}// Add the relationshipclient.WriteRelationships(ctx, []*v1.Relationship{relationship}) 
Enter fullscreen mode Exit fullscreen mode
Checking Permissions
checkRequest := &v1.CheckPermissionRequest{Resource: &v1.ObjectReference{ ... }, // "document:doc123"Permission: "read",Subject: &v1.ObjectReference{ ... }, // "user:sam"}permResp, _ := client.CheckPermission(ctx, checkRequest)if permResp.Permissionship == v1.CheckPermissionResponse_HAS_PERMISSION {// Grant access} else {// Deny access} 
Enter fullscreen mode Exit fullscreen mode

3. Build, Test, and Ship

  • Build integration tests around permission checks
  • Use the schema evolution tools (as your model grows)
  • Rely on SpiceDB’s auditing, debugging, and instant propagation for safety

Visual: Diagram showing application, SpiceDB, and relationship-based permissions flow.---

Best Practices, Gotchas, and Next Steps

Tips from the Trenches

  1. Model Before You Code: Use the playground, design outside your app—faster feedback, less churn.
  2. Write Minimal App Logic: Your app only writes relationships and does permission checks—NOT complex logic.
  3. Separate Authn and Authz: Authentication (JWT/providers) establishes identity; authorization is who can do what. Don’t muddle the two.
  4. Revocations Are Hard (but SpiceDB Solves It): The “new enemy problem” (e.g., fired users keeping access) is solved with SpiceDB’s linearized events—no more stale tokens.
  5. Don’t Embed Permissions in JWTs (for dynamic checks): It works for static roles, but not for resource-specific or frequently-changing access.
  6. Start Simple but Scalable: Even if your app is small, SpiceDB lets you start with RBAC and upgrade seamlessly when you need more.

Common Pitfalls

  • Role Explosion: Too many roles, too much code—switch to relationships sooner.
  • Confusing Authn and Authz: Each has distinct responsibilities and risks.
  • Delaying Centralization: Siloed permissions mean headaches; centralize early.

“You can authenticate someone, validate who they are, but that alone doesn't get you much. You need to do something with that identity—in other words, you need authorization.”

Visual: Venn diagram showing separation of Authn and Authz.---

Resources & Further Reading

Official Docs & Playground:

Technical Deep Dives:

Community & Open Source:

On CodingCat.dev:

Video Walkthroughs:

Wrapping Up: Build the App, Not the Boilerplate

Let’s cut to the chase: authorization is hard, but it doesn’t have to be a mess. From RBAC to REBAC, the field has matured—a ton. With tools like SpiceDB, you get future-proofing and a better dev experience.

“Let us give you friendly APIs so that you can focus on your stuff, and we'll handle the nuances and the complexity.”

Whether you're a one-person startup, an engineering lead at a growing team, or just curious about next-gen access control, you now have superpowers to solve these puzzles right.

To recap:

  • Model outside your app, iterate, then plug in
  • Avoid embedding fast-changing permissions in JWTs
  • Let relationships—not roles—drive your logic when needed
  • Centralize early, scale confidently

Celebrate your newfound permission prowess—and let’s keep building... with way less tech debt.

Got Questions? Want More Demos?

Check out the full video for hands-on demos and more cool stuff, or jump into the Authzed Playground and try your own scenarios.

Smash that follow, and drop us your questions at CodingCat.dev! Happy (authorized) coding!

Quick Reference: Sample SpiceDB Schema (Copy/Paste Ready)

definition user {}definition team {relation member: user}definition document {relation owner: user | teampermission read = ownerpermission update = ownerpermission delete = owner} 
Enter fullscreen mode Exit fullscreen mode

Example: Permission Check in Node.js

const authzed = require('authzed'); async function canUserViewDocument(userId, docId) { const client = new authzed.Client({ /* config */ }); const res = await client.checkPermission({ resource: `document:${docId}`, permission: 'read', subject: `user:${userId}`, }); return res.hasPermission; } 
Enter fullscreen mode Exit fullscreen mode

If You Remember One Thing...

Start modeling your access before you need it. You’ll thank yourself later.

Catch y’all in the next episode—and keep those code snacks spicy!

Visual: CodingCat mascot giving a thumbs-up with a stack of code and a “permissions approved” stamp.

This post was created with insights from Sam at Authzed, the CodingCat.dev community, and real stories from the trenches. All opinions, code samples, and cats are our own.

Top comments (0)