Skip to main content

Embedded Python SDK for building multi-tenant SaaS products with users, services, groups, and AI agents.

Project description

SaaSBase

PyPI Python versions License

Embedded SDK for building multi-tenant SaaS products. First-class support for users, services, groups, and AI agents — all treated as actors with per-resource role-based authorization, durable audit trails, and execution tracing for agentic workflows.

Modelled around a simple resource hierarchy: Organization → Project → { Document | ApiCall }. Pluggable backends for storage, database, and authorization. No Django/Flask/Spring baggage — just a Python API you wire into whatever HTTP layer you already use (an optional async FastAPI adapter ships in the box).

Ships alongside a Java SDK with a byte-identical database schema, so a single database can be driven by either SDK.

Highlights

  • Actors as first-class citizensUSER, SERVICE, AGENT, GROUP, API_KEY. Every operation is attributed to one.
  • Role-based authorization with scope inheritance — grants on an organization automatically flow to its projects, documents, and API calls.
  • Named document versioning — stable document IDs; named versions ("draft", "v2", "final") each with their own content and metadata.
  • Execution tracing — start/complete/fail flows for agent and service operations, with correlation IDs, parent/child relationships, and model provenance.
  • API keys — scoped to an organization or project, carrying a single role. sbk_<prefix>.<secret> tokens, soft revocation, optional expiry, last_used_at tracking.
  • Durable audit log — every mutation flows through a configurable sink with explicit retention policies.
  • Pluggable backends — SQLite or PostgreSQL, local filesystem or S3, in-memory or OpenFGA authorization.
  • Optional async FastAPI surfacecreate_app(sb) exposes every domain API over HTTP with automatic Bearer-token authentication for API keys and OpenAPI docs at /docs.

Install

pip install saasbase                   # core (SQLite + local storage + in-memory authz)
pip install "saasbase[postgres]"       # + PostgreSQL
pip install "saasbase[s3]"             # + S3-compatible storage
pip install "saasbase[openfga]"        # + OpenFGA authorization
pip install "saasbase[fastapi]"        # + async FastAPI REST surface
pip install "saasbase[all]"            # everything

Python 3.11 or newer.

Quick start

from saasbase import SaaSBase

sb = (
    SaaSBase.builder()
    .sqlite()                           # or .postgres(), or .db_url("...")
    .local_storage("./data")            # or .s3_storage(...)
    .build()
)

with sb.as_user("alice") as ctx:
    org = ctx.organizations.create("acme", name="Acme Corp")
    project = ctx.projects.create(org.id, "platform")

    with open("invoice.pdf", "rb") as f:
        doc = ctx.documents.upload(
            project.id,
            name="invoice.pdf",
            content=f,
            media_type="application/pdf",
        )

    print(doc.current_version_name)     # "v1"
    print(doc.checksum)                 # sha-256 hex

sb.close()

Change the actor to change who audit events are attributed to:

with sb.as_service("billing") as ctx: ...
with sb.as_agent("ocr-v1") as ctx: ...

API keys

Each key binds to one resource (ORGANIZATION or PROJECT) and carries a single Role. When a key authenticates, it acts as an API_KEY actor whose permissions are exactly the role's actions on the scoped resource — and inherited scopes. An ORG_OWNER key, for example, can act on any project, document, or API call inside its organization.

from saasbase import CreateApiKeyRequest, Role

with sb.as_user("alice") as ctx:
    created = ctx.api_keys.create(
        CreateApiKeyRequest(scope=project.ref, role=Role.PROJECT_EDITOR, name="ci")
    )
    # The raw `token` is visible exactly once — store it in a secret manager.
    print(created.token)                # sbk_<prefix>.<secret>
    print(created.api_key.id)

    # Authenticate a token back to an active API key:
    resolved = ctx.api_keys.authenticate(created.token)
    assert resolved is not None and resolved.is_active

    # Soft-revoke — record is kept for audit; future auth fails.
    ctx.api_keys.revoke(created.api_key.id)

expires_at, last_used_at (touched on each successful authentication), and free-form metadata are all supported.

FastAPI integration (optional)

saasbase.fastapi exposes every domain API over async HTTP. Handlers are async def and offload blocking SaaSBase calls to a thread pool via anyio.to_thread.run_sync, so concurrent requests don't stall the event loop.

from saasbase import SaaSBase
from saasbase.fastapi import create_app

sb = SaaSBase.builder().sqlite().local_storage("./data").build()
app = create_app(sb)

# uvicorn my_module:app --reload

Or let the module build a SaaSBase from env vars — useful in containerized deployments:

export SAASBASE_DB_URL=jdbc:sqlite:./data/saasbase.db
export SAASBASE_STORAGE__LOCAL__BASE_PATH=./data/documents
export SAASBASE_WEB__BASE_PATH=/api
uvicorn my_app:app

Every request is attributed to an actor, resolved in this order:

  1. Authorization: Bearer sbk_<prefix>.<secret> — SaaSBase API key; request acts as the API_KEY actor.
  2. X-SaaSBase-Actor: <type>:<id> header. Values: user:alice, service:billing, agent:tagger-v1, group:admins, api_key:<uuid>.
  3. The configured anonymous fallback (default service:anonymous). Set it empty to force 401.
# Authenticate as an API key
curl -H "Authorization: Bearer sbk_abcdef123456.xxxxxxx" \
     https://api.example.com/api/projects/$PROJECT_ID

# Or as an impersonated user
curl -H "X-SaaSBase-Actor: user:alice" \
     -H "Content-Type: application/json" \
     -d '{"slug":"acme"}' \
     https://api.example.com/api/organizations

create_app(actor_resolver=...) accepts a custom async resolver — e.g. one that decodes a JWT.

Endpoints under the configurable base path (default /api):

  • /organizations, /projects, /documents (multipart upload, streamed download, versioning)
  • /api-calls, /executions (start/complete/fail + correlation listing + children)
  • /memberships, /api-keys
  • /audit-events (query, by-resource, by-correlation, prune)
  • /authz/{check,explain,effective-roles,who-can,who-can-explain}

Interactive OpenAPI docs at /docs.

Examples

Runnable scripts live in the examples/ directory in the repository:

  • example_app.py — end-to-end CLI demo
  • document_centric.py — upload + list + filter documents
  • apicall_centric.py — track API calls with correlation IDs
  • agent_assisted.py — agent execution lifecycle with provenance
  • document_versioning.py — named document versions
  • fastapi_server.py — run the async REST API with uvicorn

Authorization model

Roles carry a fixed action set (see saasbase.AuthorizationPolicy):

Role Typical grant
ORG_OWNER Full control on an org and everything beneath it
ORG_ADMIN Manage projects and members; cannot delete the org
ORG_MEMBER Read-only at the org level
PROJECT_OWNER Full control on one project and its resources
PROJECT_EDITOR Create/update documents and API calls
PROJECT_VIEWER Read-only within a project
DOCUMENT_* Resource-level grants on a single document
API_CALL_* Resource-level grants on a single API call

Grants are evaluated against the resource hierarchy, so a role granted at a higher scope applies to descendants. Use authorization.explain(actor, action, resource) to see which role in which scope allowed (or denied) a call.

Links

License

Licensed under the Apache License, Version 2.0. See LICENSE in the source repository.

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

saasbase-0.1.1.tar.gz (58.8 kB view details)

Uploaded Source

Built Distribution

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

saasbase-0.1.1-py3-none-any.whl (105.1 kB view details)

Uploaded Python 3

File details

Details for the file saasbase-0.1.1.tar.gz.

File metadata

  • Download URL: saasbase-0.1.1.tar.gz
  • Upload date:
  • Size: 58.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for saasbase-0.1.1.tar.gz
Algorithm Hash digest
SHA256 e44454f22b20b4f0a88617228fd56b3c3e03b7a898ab566cd7616df670f30d6e
MD5 86fda4f746fafcc95f05cdff8ca2720b
BLAKE2b-256 19fc9b5f01daadfcb20caec44f4314a061cd48b6db49711e718695d288eac9aa

See more details on using hashes here.

Provenance

The following attestation bundles were made for saasbase-0.1.1.tar.gz:

Publisher: publish-python.yml on sireto/saasbase

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

File details

Details for the file saasbase-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: saasbase-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 105.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for saasbase-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a66775d4e18cb0950d658f8591a6ef4d077490e19a302209406badf43ed6c791
MD5 afc7bdb080c9a6a2e6693870b88598b0
BLAKE2b-256 696b051927be296d69e6086663a433ece7b74e8d363440867b86b7c1c9f0b1f1

See more details on using hashes here.

Provenance

The following attestation bundles were made for saasbase-0.1.1-py3-none-any.whl:

Publisher: publish-python.yml on sireto/saasbase

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