Secure AI Access Control Using: SpiceDB
Sponsors
Welcome back, CodingCats! If you’re itching to untangle the furball that is app permissions, you’re in the right place. This is CodingCat.dev, where the dev snacks are always fresh, and today, we're serving a feast of practical authorization wizardry for your modern full stack projects.
In this mega post:
- We’ll break down why building your own Authz is a waste of precious dev time
- Dive deep into live SpiceDB Playground tricks
- Demo rich Google Docs–style ACL modeling
- Use code and schema to empower comment, edit, and view flows
- See LLMs, SpiceDB, and the cloud come together for AI-powered authorization Q&A
- Explore modern tooling, compliance, Edge caching, bulk permission checks, and scalable strategies
- Compare top platforms: Authzed, WorkOS, Okta FGA, and Cerbos
- Show how to leverage all this in React and NextJS—check out our Ultimate NextJS Guide too!
So grab snacks and a notepad—let’s tame NOT ONLY Authz code, but also your whole approach to permissions, once and for all.
“Stop building Authz. Start building value.”
—A rallying cry from today’s guest experts!
Why Authz? Why Now?
Let’s face it: Most apps go through the same growing pains with permissions:
- “Add a new feature? Time for days lost in auth spaghetti!”
- “Business pivot? Ouch, I’ve gotta refactor our fragile object ACL logic.”
- “How did Bob get access to this? Who has edit here?”
Authorization (authz) is the backbone of scale—think Dropbox, Google Docs, even your favorite project management apps. But building and maintaining a robust, flexible, and scalable authorization layer is hard and boring, and distracts your team from delivering features that matter.
If you’re still rolling custom permission tables and hand-coding complex checks, it’s time to rethink your approach.
Stop DIYing Permissions: What’s the Point?
Before we dig into code and tools, let’s be honest: Why do most developers roll their own Authz?
- “It’s simple… until it isn’t.”
- “My use-case is different.”
- “Third-party tools seem overkill for my MVP.”
It always starts simple:
// The archetypal home-grown check:if (userId === doc.ownerId || doc.sharedWith.includes(userId)) {// show the doc}
But soon you have editors, commenters, nested folders, group sharing, org-wide rules, audit requirements, and suddenly your code looks like spaghetti mixed with cheese sauce and sad.
And the more “value” you build, the less you want to touch that fragile Authz tower!
That’s where platforms like SpiceDB and Authzed come in—they’re built on decades of learning by Google, Dropbox, Okta, and more. You get robust, scalable logic without tying your dev time in knots.
Meet the Playground: Real SpiceDB in Your Browser
Let’s start with something hands-on:
Imagine if you could instantly try out your actual Authz schema, live, in your browser.
That’s what the SpiceDB Playground gives you.
What’s unique here?
- Runs a real, compiled-to-WASM instance of SpiceDB in the browser
- NOT a fake rules engine or mock, but the same engine your production code could hit
- You can define objects, relationships, permissions—test scenarios instantly!
Let’s take a tour:
To get started, try this:
- Launch the playground (see SpiceDB's Playground or codingcat.dev)
- Check out sample schemas (like our Google Docs-style sharing below)
- Define objects:
user
,document
- Create relations: who can read? who can write?
- Add permissions, like
edit
,view
,comment
- Test with sample data. Does Alice have view on Doc X?
Google Docs-Style Permissions: Modeling with SpiceDB
Google Docs set the standard for powerful, granular sharing—let’s see how you can build that using SpiceDB.
Say you want:
- Users
- Documents
- Relations like “reader”, “writer”, “commenter”
- Permissions derived from those roles
A simplified version of your schema might look like this:
definition user {}definition document {relation writer: userrelation reader: userrelation commenter: userpermission edit = writerpermission view = reader + editpermission comment = commenter + edit}
What’s going on here?
writer
andreader
are relations (think: “Alice is a reader of Document1”)edit
permission is whoever is a writerview
permission is anyone who’s a reader or a writercomment
covers both commenters and writers (but not plain readers)
When a user shares a doc
When Alice shares a doc with Bob:
- The system writes a “Bob is a reader of Document1” relationship into the DB
- When Bob hits the link, the system asks: “Does Bob have view permission on Document1?”
- SpiceDB answers YES/NO by evaluating schema and relationships live
“You don’t have to manually figure out which roles grant which permissions every time.
Just ask: Can Bob view this doc? Your schema does the heavy lifting.”
Step-By-Step: Schema, Relationships & Queries
Let’s break down a real workflow.
1. Define Types and Relations
definition user {}definition document {relation writer: userrelation reader: userpermission edit = writerpermission view = reader + edit}
2. Add a “Commenter” Role
But what if you want some users to just comment (not edit)?
Add:
definition document {...relation commenter: user...permission comment = commenter + editpermission view = reader + edit + comment}
Pro tip: View is now anyone who’s a reader, an editor, or a commenter.
3. Writing Relationships
In production, your app writes relationships as users interact:
# "Sam" is a commenter on "DocA"document:DocA#commenter@user:sam
Or in the playground’s “test relationships” area:
document:firstDoc#commenter@user:sam
4. Querying: Does Sam have comment permission?
This is done via a simple API call:
POST /check_permission{"resource": "document:firstDoc","permission": "comment","subject": "user:sam"}
Result: YES!
5. Test-Driven Permissions
Worried about a new schema breaking old assumptions?
- Use the playground to model and test before deploying.
- Add/check relationships and see if permission trees evaluate as expected.
Richer Permissions: “Commenter” and Beyond
Let’s go wild: Suppose you want a completely custom role, like “auditor” or “guest editor.”
Just add a relation and permission:
relation auditor: userpermission audit = auditor# Combine with existingpermission view = reader + edit + comment + audit
Your app can now add users to any role and derive permissions through combinations.
Set Operations
The +
operator in SpiceDB schema is like a union of sets. Think:
“The set of everyone who can edit, combined with everyone who can comment…”
You get composite permissions as easily as combining sets.
Testing and TDD for Permissions
A killer feature of the playground is how it visualizes the logic tree for each permission check:
- View the full computation:
“Is Sam a commenter?” NO
“Does Sam have edit?” NO
...
Result: YES/NO - Try failing and passing scenarios, all visualized:
- Add new relationships: Did you just grant someone access by mistake?
- Change schema and instantly see if breakages appear.
Key lesson:
Model your perms before you code business logic!
Just like TDD for backend code, test-driven permissions lets you iterate quickly and avoid costly mistakes.
How Frontends (like React) Use Permission Results
So you have these fancy checks—how do you actually wire them up in your web app?
Typically:
- Your server wraps features/components in permission checks
- If the check returns YES, show the button/feature; if NO, don’t render
Example in React:
const canComment = usePermission('comment', docId, userId);return (<div><DocumentView docId={docId} />{canComment && <CommentSection docId={docId} />}</div>);
Question:
Should you hit SpiceDB over and over from the UI?
Answer: Maybe not—there are options.
- Bulk permission checks:
Ask for all relevant permissions in one round-trip. - Cache results at the edge (e.g., popular docs, org-wide roles).
- Keep latency in mind:
SpiceDB is blazingly fast—single to double-digit ms with proper config.
“With a 20ms round trip, your permission checks likely aren’t the bottleneck—focus on bigger page loads or DB calls.”
Going Beyond: Bulk Checks, Latency, and Edge Caching
As your app grows, don’t let authz checks slow you down.
Bulk Checks:
Need view, edit, and comment permissions for 10 docs and 1 user?
Use the bulk API to ask all in one shot.
POST /bulk_check{"requests": [{"resource": "doc:abc", "permission": "view", "subject": "user:sam"},// more...]}
Edge and Caching:
Permissions may change during a session—cache them, but be ready to invalidate if the user’s roles update.
Scaling to millions:
SpiceDB and Authzed can handle millions of rels and users, but be aware:
- Lookup APIs (who has access to X?)—optimized for big scales with features like Materialize
- For super-complex scenarios, talk to their team (or check out CodingCat.dev guides).
RBAC, ABAC, Policy Engines, and Where SpiceDB Fits
Let’s clear up jargon:
- RBAC: Role-Based Access Control (“editors”, “admins”)
- ABAC: Attribute-Based Access Control (permission based on user or resource attributes)
- Policy Enginers (like Cerbos): Define rules in policy code (often in YAML); can be powerful, but may require more wiring up
SpiceDB/Zanzibar-style:
Based on graphs of relationships—users, groups, objects, and composite permissions
Most modern “fine-grained auth” tools are inspired by Zanzibar*, Google’s system.*
Both SpiceDB and Authzed treat the original paper almost as gospel, providing the most “Zanzibar-like” open-source experience you can get outside Google.
Role Explosion? No Problem! User-Defined Roles
Suppose your admin dashboard says:
“Add a new role: [_________]”
That’s a user-defined role—not just “admin” or “editor,” but anything your business needs (say, “auditor,” “contributor,” or “regional manager”).
SpiceDB handles this with another level of indirection:
- You write relationships like
project:foo#role:auditor@user:alice
- Define what that role can do in the schema
Example schema snippet:
definition role {relation member: user}definition project {relation admin: userrelation assigned_role: rolepermission manage = admin + assigned_role->member}
Here’s what happens:
- Create a new role in the playground or via code
- Assign users to that role
- Grant permissions at both the direct and role levels
“You don’t need to hardcode every possible permission. Design for flexibility from Day 1.”
Automating Authz: The Rise of MCP and LLM-Driven Access
The future is not just writing schemas and APIs—it’s making Authz approachable even for people who don’t grok graphs.
Enter MCP (Model Context Protocol)
Originally from Anthropic, MCP is like the USB-C plug for AI → backend plugins:
- Exposes your live SpiceDB instance to LLMs or AI tools
- Now you can ask permission questions in English and get real answers against live data
For example:
“Who has access to project PiedPiper?”
Or,
“Can Jared resolve issue #17 in project FooBar?”
Here’s how you vibe code up an MCP server:
- Build the server with AI (see the transcript’s “vibe coding” story—AI cost <$3!)
- Attach to running SpiceDB instances (local or prod mirror)
- Plug MCP into Claude Desktop or other AI devtools
Key Use Cases:
- Answer “who has what permission” for compliance, audits, onboarding — no query-writing required!
- Generate test scenarios, write relationships, scaffold schemas using English
“AI is the new junior dev, answering complex Authz questions faster than you can grep logs.”
Compliance, Reporting, and “Who Has What?”
Auditors and managers don’t want to grep logs or learn Zanzibar. With MCP + SpiceDB, you can enable questions like:
“Find all users who can edit Project X”
“After deprecating this project, who needs to be notified?”
“Which users have ‘admin’ roles in this workspace?”
These are NOT simple lookups—your schema might have N levels of indirection, groups, nested roles, custom attribute blends. But with lookup APIs (and LLMs), you can get:
- Who can act (for a given permission)
- Why (role → group → resource chain)
- How was this permission granted? (visual tree)
Performance:
Even with millions of users, lookup queries can run in milliseconds, especially when using Materialize or batch APIs.
No-Dev Reporting:
Picture giving a compliance officer a prompt bar, not a query engine. “Show me all users with access to this doc.”
Scaffolding Test Scenarios—With Just English!
Ever spent more time setting up test data than building the feature?
With the MCP + SpiceDB stack, you can say:
“Set up a scenario where Jared has the Auditor role on Project PiedPiper.”
And it generates the right relationships:
# Writes:role:auditor#member@user:jaredproject:PiedPiper#assigned_role@role:auditor
Checks its work, verifies with permission checks, and you get instant feedback.
Caveats:
- Don’t run on prod without audit!
- LLM outputs are non-deterministic, but perfect for dev, test, and learning.
- Combine with your TDD flows for painless regressions.
Platform Showdown: Authzed vs WorkOS, Okta FGA, Cerbos
Authzed/SpiceDB
- Open, Zanzibar truthers — core model matches Google's approach
- Schema-first, composable, with console/playground
- Docs
- Great for wide use-cases, community-backed
WorkOS / Warrant / FGA
- Rebased on Warrant, now integrated into WorkOS’s identity platform
- Similar schema, but tightly coupled to WorkOS's broader SSO suite
- FGA: Fine Grained Authorization, OpenAPI, available as open source (see docs)
Okta FGA
- Enterprise-focused, integrates tightly with Okta ecosystem
- Okta’s FGA project
- Integrated policies with auth
Cerbos
- Policy-first, more ABAC
- YAML-based policy definitions
- Good for orgs who want to express rules programmatically (think: “senior engineer can approve up to $10,000”)
- See Cerbos
“While there’s no true portability or standard, if you model Authz as asking “does X have permission Y on Z?”, you can swap backends later if needed.”
How Granular Can You Get? Limits & Best Practices
You’re not limited to just “admin/editor/reader.”
You can model:
- Teams, orgs, time-bound roles
- “Guest” and “external” access
- Nested folders, inherited roles
- Sharing links
- Feature flags
- Fine-grained row-level security a la Supabase
BUT:
- More granularity = more data and more to manage
- Sometimes, the simplest approach suffices
"Sometimes people get lost in the weeds, over-engineering for use-cases they don’t have. Start simple—you can always evolve your schema."
Try it Yourself! Community, Open Source, and Next Steps
- Try the community edition of FusionAuth for auth, and open-source SpiceDB for Authz.
- Experiment with the playground (here)
- Model your real-world permission scenarios—Google Docs, Notion with comments, Trello-style boards, you name it.
- Don’t reinvent the wheel—plug, play, customize, and focus on building your app, not debugging access rules.
Hands-On Tutorials
- Building tiered permissions in NextJS
- How to write effective SpiceDB schemas
- Understanding Zanzibar (classic reading!)
Further Reading & Next-Level Learning
- Authz and OAuth: What’s the Difference?
- Building Secure SaaS: Real-World Patterns
- Another look at LLMs and Permissions
- Supabase RLS Demystified
- Bulk permission checking patterns
- Choosing the right Authz platform
- Understanding role explosions and escaping the role matrix
The CodingCat Takeaway
Building robust, scalable authorization isn’t just about plugging in a third-party tool—it’s about shifting your mindset:
- Define permissions as questions, not hardcoded booleans
- Model your reality, starting simple but scaling as needed
- Use open-source building blocks, invest your time in features your users love—not plumbing
Whether you run with SpiceDB, plug into Authzed, or explore the fusion of AI and access control, the path is the same: stop fighting with Authz, start shipping value.
Got questions?
Jump into the CodingCat Dev Community! Or hit us up on Discord for live coding sessions and schema reviews.
—
"You can have your cake and eat it too. Build the exact permissions model your product needs—without owning the gnarly complexity."
—Sam, Authzed/SpiceDB Guru
See you all next time for live coding and more dev snacks. Don’t miss our upcoming features on Authz with LLM workflows, NextJS RBAC hooks, and more—subscribe to CodingCat.dev and never miss a purr.