Skip to main content

Embedded SpiceDB for Python — embedded authorization using the standard gRPC API

Project description

spicedb-embedded (Python)

Sometimes you need a simple way to run access checks without spinning up a new service. This library provides an embedded version of SpiceDB in various languages. Each implementation is based on a C-shared library (compiled from the SpiceDB source code) with a very thin FFI binding on top of it. This means that it runs the native SpiceDB code within your already-running process.

from spicedb_embedded import EmbeddedSpiceDB
from authzed.api.v1 import (
    CheckPermissionRequest,
    CheckPermissionResponse,
    Consistency,
    ObjectReference,
    Relationship,
    SubjectReference,
)

schema = """
definition user {}

definition document {
    relation reader: user
    permission read = reader
}
"""

rel = Relationship(
    resource=ObjectReference(object_type="document", object_id="readme"),
    relation="reader",
    subject=SubjectReference(object=ObjectReference(object_type="user", object_id="alice")),
)

with EmbeddedSpiceDB(schema, [rel]) as spicedb:
    req = CheckPermissionRequest(
        consistency=Consistency(fully_consistent=True),
        resource=ObjectReference(object_type="document", object_id="readme"),
        permission="read",
        subject=SubjectReference(object=ObjectReference(object_type="user", object_id="alice")),
    )
    resp = spicedb.permissions().CheckPermission(req)
    allowed = resp.permissionship == CheckPermissionResponse.PERMISSIONSHIP_HAS_PERMISSION

Who should consider using this?

If you want to spin up SpiceDB, but don't want the overhead of managing another service, this might be for you.

If you want an embedded server for your unit tests and don't have access to Docker / Testcontainers, this might be for you.

If you have a schema and set of permissions that are static / readonly, this might be for you.

Who should avoid using this?

If you live in a world of microservices that each need to perform permission checks, you should almost certainly spin up a centralized SpiceDB deployment.

If you want visibility into metrics for SpiceDB, you should avoid this.

How does storage work?

The default datastore is "memory" (memdb). If you use this datastore, keep in mind that it will reset on each app startup. This is a great option if you can easily provide your schema and relationships at runtime. This way, there are no external network calls to check relationships at runtime.

If you need a longer term storage, you can use any SpiceDB-compatible datastores.

from spicedb_embedded import EmbeddedSpiceDB

# Run migrations first: spicedb datastore migrate head --datastore-engine postgres --datastore-conn-uri "postgres://..."
schema = """
definition user {}

definition document {
    relation reader: user
    permission read = reader
}
"""

with EmbeddedSpiceDB(schema, [], options={
    "datastore": "postgres",
    "datastore_uri": "postgres://user:pass@localhost:5432/spicedb",
}) as spicedb:
    # Use full Permissions API (writeRelationships, checkPermission, etc.)
    pass

Running code written in Go compiled to a C-shared library within my service sounds scary

It is scary! Using a C-shared library via FFI bindings introduces memory management in languages that don't typically have to worry about it.

However, this library purposely limits the FFI layer. The only thing it is used for is to spawn the SpiceDB server (and to dispose of it when you shut down the embedded server). Once the SpiceDB server is running, it exposes a gRPC interface that listens over Unix Sockets (default on Linux/macOS) or TCP (default on Windows).

So you get the benefits of (1) using the same generated gRPC code to communicate with SpiceDB that would in a non-embedded world, and (2) communication happens out-of-band so that no memory allocations happen in the FFI layer once the embedded server is running.

Installation

pip install spicedb-embedded

Or from source:

cd python && pip install -e .

Prerequisites: Go 1.23+ with CGO enabled. Build the shared library first:

cd shared/c && CGO_ENABLED=1 go build -buildmode=c-shared -o libspicedb.dylib .  # macOS
cd shared/c && CGO_ENABLED=1 go build -buildmode=c-shared -o libspicedb.so .      # Linux

The library looks for libspicedb.dylib (macOS) or libspicedb.so (Linux) in SPICEDB_LIBRARY_PATH or relative to the working directory (shared/c, ../shared/c, etc.). Override with SPICEDB_LIBRARY_PATH=/path/to/shared/c.

Usage

from spicedb_embedded import EmbeddedSpiceDB
from authzed.api.v1 import (
    CheckPermissionRequest,
    CheckPermissionResponse,
    Consistency,
    ObjectReference,
    Relationship,
    SubjectReference,
)

schema = """
definition user {}

definition document {
    relation reader: user
    permission read = reader
}
"""

rel = Relationship(
    resource=ObjectReference(object_type="document", object_id="readme"),
    relation="reader",
    subject=SubjectReference(object=ObjectReference(object_type="user", object_id="alice")),
)

with EmbeddedSpiceDB(schema, [rel]) as spicedb:
    stub = spicedb.permissions()
    req = CheckPermissionRequest(
        consistency=Consistency(fully_consistent=True),
        resource=ObjectReference(object_type="document", object_id="readme"),
        permission="read",
        subject=SubjectReference(object=ObjectReference(object_type="user", object_id="alice")),
    )
    resp = stub.CheckPermission(req)
    allowed = resp.permissionship == CheckPermissionResponse.PERMISSIONSHIP_HAS_PERMISSION

API

  • EmbeddedSpiceDB(schema, relationships, options=None) — Create an instance. Pass [] for no initial relationships. Pass options dict for datastore/transport config. Supports context manager (with).
  • permissions() — Permissions service stub (CheckPermission, WriteRelationships, ReadRelationships, etc.).
  • schema() — Schema service stub (ReadSchema, WriteSchema, ReflectSchema, etc.).
  • watch() — Watch service stub for relationship changes.
  • channel() — Underlying gRPC channel for custom usage.
  • close() — Dispose the instance and close the channel.

Use types from authzed.api.v1 (ObjectReference, SubjectReference, Relationship, etc.).

Options

options = {
    "datastore": "memory",          # or "postgres", "cockroachdb", "spanner", "mysql"
    "grpc_transport": "unix",       # or "tcp"; default by platform
    "datastore_uri": "postgres://user:pass@localhost:5432/spicedb",  # required for remote
    "spanner_credentials_file": "/path/to/key.json",  # Spanner only
    "spanner_emulator_host": "localhost:9010",       # Spanner emulator
    "mysql_table_prefix": "spicedb_",                 # MySQL only (optional)
    "metrics_enabled": False,                         # default; set True to enable Prometheus metrics
}

with EmbeddedSpiceDB(schema, [], options=options) as spicedb:
    ...

Building & Testing

mise run shared-c-build
cd python
pip install -e ".[dev]"
pytest

Or from the repo root: mise run python-test

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spicedb_embedded-0.1.20.tar.gz (6.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spicedb_embedded-0.1.20-py3-none-any.whl (23.5 MB view details)

Uploaded Python 3

File details

Details for the file spicedb_embedded-0.1.20.tar.gz.

File metadata

  • Download URL: spicedb_embedded-0.1.20.tar.gz
  • Upload date:
  • Size: 6.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for spicedb_embedded-0.1.20.tar.gz
Algorithm Hash digest
SHA256 d2628707bf62186c31a143c02542ab15a17d93343a273f144855a7fe6d1f6a42
MD5 2dd981886c6029d0a4c1a42e4a767f26
BLAKE2b-256 a879b96c05e935d2e151c07916b2542d359392ede9effcc8851e86643fe25f70

See more details on using hashes here.

Provenance

The following attestation bundles were made for spicedb_embedded-0.1.20.tar.gz:

Publisher: release.yml on borkfork/spicedb-embedded

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spicedb_embedded-0.1.20-py3-none-any.whl.

File metadata

File hashes

Hashes for spicedb_embedded-0.1.20-py3-none-any.whl
Algorithm Hash digest
SHA256 f7f6d050a5ddb46846c72b000dde90edf2aceae868db9c043b9d163817b7345b
MD5 57df20f53d661582f8daee3fd539ab00
BLAKE2b-256 898243e1475f09be3a52c538fb2b0c500ff1b81357bdb214226ce0ad919b6164

See more details on using hashes here.

Provenance

The following attestation bundles were made for spicedb_embedded-0.1.20-py3-none-any.whl:

Publisher: release.yml on borkfork/spicedb-embedded

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page