SpiceDB Schema Guide¶
This guide explains the SpiceDB authorization schema used in CoreForge.
Base Schema¶
CoreForge provides a base schema for common authorization patterns:
definition principal {}
definition organization {
relation owner: principal
relation admin: principal
relation member: principal
relation viewer: principal
// Owners and admins can manage the organization
permission manage = owner + admin
// Anyone in the org can view it
permission view = manage + member + viewer
// Editors can edit (owners, admins, members)
permission edit = manage + member
// Only owners can delete
permission delete = owner
}
definition platform {
relation admin: principal
// Platform admins have all permissions
permission manage = admin
permission view = admin
}
Entity Types¶
| Type | Description |
|---|---|
principal |
A user, application, agent, or service that can perform actions |
organization |
A tenant or workspace containing resources |
platform |
The global platform (singleton: platform:global) |
Organization Roles¶
| Role | Relations | Permissions |
|---|---|---|
| Owner | owner |
manage, edit, view, delete |
| Admin | admin |
manage, edit, view |
| Member | member |
edit, view |
| Viewer | viewer |
view |
Permission Inheritance¶
Custom Resource Schemas¶
Use ResourceSchema() to generate schemas for your application's resources:
This produces:
definition project {
relation org: organization
relation owner: principal
relation editor: principal
relation viewer: principal
// Owners can do everything
permission manage = owner + org->admin
// Editors can edit (includes owners and org admins)
permission edit = manage + editor + org->member
// Viewers can view (includes editors and org viewers)
permission view = edit + viewer + org->viewer
// Only owners and org admins can delete
permission delete = owner + org->admin
}
Resource Permission Model¶
| Permission | Who Has Access |
|---|---|
manage |
Resource owner, org admins |
edit |
Manage + explicit editors + org members |
view |
Edit + explicit viewers + org viewers |
delete |
Resource owner + org admins |
Using Custom Resources¶
// Write combined schema
fullSchema := spicedb.BaseSchema + spicedb.ResourceSchema("project")
if err := client.WriteSchema(ctx, fullSchema); err != nil {
return err
}
// Create a project owned by a user in an organization
client.WriteRelationship(ctx, &spicedb.Relationship{
ResourceType: "project",
ResourceID: projectID.String(),
Relation: "owner",
SubjectType: "principal",
SubjectID: userID.String(),
})
// Link project to organization
client.WriteRelationship(ctx, &spicedb.Relationship{
ResourceType: "project",
ResourceID: projectID.String(),
Relation: "org",
SubjectType: "organization",
SubjectID: orgID.String(),
})
Relationship Types¶
Direct Relationships¶
A principal has a direct relationship to a resource:
Computed Permissions¶
Permissions can be computed from relationships:
If a principal has manage permission (via owner or admin relation), they automatically have view.
Organization-Scoped Access¶
Resources linked to organizations inherit permissions:
Organization viewers automatically get view access to projects in that org.
Common Patterns¶
Personal Organizations¶
Every user has a personal organization where they are the owner:
Team Organizations¶
Team organizations have multiple members:
// Create team org with creator as owner
syncer.RegisterOrganization(ctx, teamOrgID, creatorID)
// Invite members
syncer.AddOrgMembership(ctx, inviteeID, teamOrgID, "member")
// Promote to admin
syncer.UpdateOrgMembership(ctx, inviteeID, teamOrgID, "member", "admin")
Platform Administrators¶
Platform admins have elevated access across all organizations:
syncer.SetPlatformAdmin(ctx, adminID, true)
// Check if user is platform admin
isAdmin, _ := provider.IsPlatformAdmin(ctx, authz.Principal{ID: adminID})
Hierarchical Resources¶
For nested resources (e.g., projects contain tasks):
definition task {
relation project: project
relation assignee: principal
permission edit = assignee + project->edit
permission view = edit + project->view
}
Best Practices¶
1. Use Organization Scoping¶
Always link resources to organizations for consistent access patterns:
definition document {
relation org: organization // Always include
relation owner: principal
// ...
}
2. Follow Least Privilege¶
Start with minimal permissions and add explicitly:
// Add as viewer first
syncer.AddOrgMembership(ctx, userID, orgID, "viewer")
// Promote later if needed
syncer.UpdateOrgMembership(ctx, userID, orgID, "viewer", "member")
3. Use Consistent Role Names¶
Stick to the standard roles:
owner- Full control including deletionadmin- Management except deletionmember- Standard accessviewer- Read-only
4. Check Permissions at API Boundaries¶
func (h *Handler) UpdateProject(ctx context.Context, req *UpdateRequest) error {
principal := getPrincipalFromContext(ctx)
canEdit, err := h.provider.Can(ctx, principal, "edit", authz.Resource{
Type: "project",
ID: &req.ProjectID,
})
if err != nil {
return err
}
if !canEdit {
return ErrForbidden
}
// Proceed with update
}
Debugging¶
Read Current Schema¶
Check Relationships¶
Use the SpiceDB CLI or API to inspect relationships:
Test Permission Checks¶
// Quick permission test
can, _ := provider.Can(ctx, principal, "edit", resource)
log.Printf("Principal %s can edit %s: %v", principal.ID, resource.ID, can)
Next Steps¶
- Integration Guide - Detailed integration patterns
- SpiceDB Setup - Deployment configuration