---
title: Authorization with SpiceDB
description: Relationship-based authorization for Cuitty Code repositories, apps, and Registry integration.
section: Code
order: 15
updatedAt: 2026-06-09
slug: code/authz-spicedb
---
Cuitty Code uses SpiceDB for relationship-based authorization across repositories, organizations, apps, installs, and package integration points. The database remains the source of metadata, while SpiceDB answers permission checks. Standalone Cuitty Registry authorization is documented separately in [Registry authorization](/docs/registry/authz).

## Required services

- Cuitty Code API.
- SpiceDB reachable from the API.
- Database with the `authz_outbox` migration applied.
- A worker path that drains relationship writes from the outbox.

## Environment variables

Production deployments should resolve the preshared key through Cuitty Safe:

```dotenv
SPICEDB_ENDPOINT=https://spicedb.example.com:50051
SPICEDB_PRESHARED_KEY=cuitty-safe:acme/prod/spicedb-preshared-key
AUTH_ISSUER=https://auth.example.com
AUTH_CLIENT_ID=cuitty-git
```

For an isolated local development SpiceDB only, use a disposable placeholder value:

```dotenv
SPICEDB_ENDPOINT=http://localhost:50051
SPICEDB_PRESHARED_KEY=<local-dev-only-spicedb-key>
AUTH_ISSUER=http://localhost:7705
AUTH_CLIENT_ID=cuitty-code
```

Use TLS and Safe-managed secret references for production SpiceDB deployments. Do not promote the local placeholder into shared env files, CI, or self-hosted production configuration.

## Schema and object types

Load the schema before API writes:

```bash
zed schema write spicedb/schema.zed
```

Representative object types include:

- `user`
- `organization`
- `org_invite`
- `account_slug`
- `repository`
- `app_listing`
- `app_installation`
- `code_app`
- `code_app_installation`
- `code_app_grant`
- `package`
- `code_package`
- `registry_namespace` when Registry integration is enabled
- `registry_package` when Registry integration is enabled

Verify representative permissions with known local data:

```bash
zed permission check user:alice read repository:acme/demo
zed permission check user:alice view package:acme/npm/acme-widget
zed permission check user:alice install app_listing:acme/review-bot
```

## Permissions model

Security-expanding writes, such as creating public visibility, granting install permission, or publishing package access, should fail closed if SpiceDB writes cannot be committed. Security-reducing writes, such as revoking access or making a package private, should continue to be retried until the graph reflects the database state.

Private apps and packages may return `404` to callers without view permission. Authenticated callers with partial permission may receive `403` for actions such as publish, install, or settings updates.

## Outbox statuses

Authorization relationship writes are recorded in `authz_outbox` with these statuses:

- `pending`: queued for dispatch.
- `processing`: claimed by a dispatcher.
- `succeeded`: written to SpiceDB.
- `failed_retryable`: failed but should be retried.
- `failed_terminal`: failed in a way that needs operator inspection.

Inspect stuck rows directly when operational tooling is not available:

```sql
SELECT id, operation_kind, resource_kind, resource_id, status, attempts, last_error
FROM authz_outbox
WHERE status IN ('pending', 'processing', 'failed_retryable', 'failed_terminal')
ORDER BY created_at ASC
LIMIT 50;
```

## Replay and reconciliation

Replay retryable relationship writes with the deployment's authz dispatcher or maintenance command. If the deployment exposes only SQL access, mark stale `processing` rows back to `pending` after confirming no dispatcher is running, then restart the API or worker that drains the outbox.

```sql
UPDATE authz_outbox
SET status = 'pending'
WHERE status = 'processing'
  AND updated_at < datetime('now', '-15 minutes');
```

After replay, spot-check resource permissions with `zed permission check` and compare database visibility against SpiceDB relationships.

## Failure modes and recovery

- SpiceDB unavailable: pause security-expanding app, package-target, and transfer writes; restore SpiceDB; drain the outbox.
- Schema not loaded: re-run `zed schema write spicedb/schema.zed` and retry failed rows.
- Retryable backlog: inspect `last_error`, fix connectivity or schema drift, and replay.
- Terminal failures: compare `payload_json` with the current schema and repair the row or resource manually.

## Related pages

- [Cuitty Code Apps](/docs/code/apps)
- [Registry authorization](/docs/registry/authz)
- [App execution with Airflow](/docs/code/app-execution-airflow)
- [Operator runbook](/docs/code/operator-runbook)