---
title: Authorization with SpiceDB
description: Relationship-based authorization for Cuitty Code Apps and Registry.
section: Code
order: 15
updatedAt: 2026-05-24
slug: code/authz-spicedb
---
Cuitty Git uses SpiceDB for relationship-based authorization across repositories, organizations, apps, installs, packages, and registry resources. The database remains the source of metadata, while SpiceDB answers permission checks.

## Required services

- Cuitty Git 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

```bash
SPICEDB_ENDPOINT=http://localhost:50051
SPICEDB_PRESHARED_KEY=dev-secret
AUTH_ISSUER=http://localhost:7705
AUTH_CLIENT_ID=cuitty-git
```

Use TLS and managed secrets for production SpiceDB deployments.

## 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`
- `registry_namespace`
- `package`
- `code_registry_namespace`
- `code_package`

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, 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)
- [Code Registry](/docs/code/registry)
- [App execution with Airflow](/docs/code/app-execution-airflow)
- [Operator runbook](/docs/code/operator-runbook)