Skip to content

Building a SaaS with OwlAuth ​

OwlAuth is a self-hosted authentication service, not a hosted multi-tenant control product. It does not provide organizations, tenant roles, customer API keys, subscriptions, billing, fleet placement, or tenant-scoped Control credentials.

You can nevertheless use ordinary OwlAuth deployments as the authentication cells behind a SaaS product. Your service owns tenant identity, authorization, commercial policy, and orchestration; OwlAuth continues to own Project users, login, sessions, tokens, provider configuration, and signing keys.

Integration guide, not a built-in mode

This chapter describes an architecture you can build around OwlAuth. The repository does not ship a hosted SaaS service, tenant API or CLI client, tenant console, billing system, or managed-cell orchestrator. Do not expose OwlAuth's deployment operator key to customers.

System boundary ​

A production design normally has three distinct authorities:

  1. your SaaS control service, with its own database for accounts, organizations, memberships, roles, subscriptions, and managed-resource ownership;
  2. an optional, isolated platform identity deployment used to authenticate people entering your SaaS console;
  3. one or more managed OwlAuth cells that serve customer Projects.

The SaaS service is the tenant policy-enforcement point. It calls only published OwlAuth Control APIs; it must not import owlauth-server, share its repositories, or read or write an OwlAuth database directly.

A managed cell is one OwlAuth administrative trust domain. It includes an owlauth-server deployment, PostgreSQL, a separately preserved software custody root or custom-provider authority, Auth ingress for both public Runtime and backend-only Server API routes, plus private Control ingress, and one deployment operator key. A cell can hold Projects for several organizations only when your trusted SaaS service is the sole operator.

Own traffic governance at the SaaS ingress ​

OwlAuth Core does not provide deployment-wide IP, route, Project, global, bot/risk, traffic-shaping, or commercial quota enforcement. A managed SaaS must apply those controls at its trusted edge or ingress, where it has the correct network, tenant, plan, and fleet context.

ControlOwning layer
IP/network abuse, bot detection, reputation, and traffic shapingedge/WAF/Auth ingress
Per-route, per-tenant, global, and fleet capacity quotasSaaS gateway or Auth ingress
Subscription, entitlement, and billable usage limitsSaaS policy and metering authority
Request bytes, deadlines, accepted connections, and in-flight workingress plus OwlAuth local transport bounds
PostgreSQL pool and provider/worker concurrencyOwlAuth local resource-safety bounds
OTP attempts, generation/proof lifecycle, recipient side-effect suppression, active mail backlog safetyOwlAuth PostgreSQL protocol authority

Core's declared 408 request_timeout means that the local listener deadline expired while waiting for in-flight capacity or running the handler. It is not a rate-limit response and does not prove that a dispatched mutation had no effect; official Runtime SDKs therefore quarantine ambiguous handoff, refresh, and logout state. Ingress traffic policy may return 429, but that is a SaaS contract rather than a Core OpenAPI guarantee. Official Runtime SDKs recognize the optional extension only when it has the exact closed Runtime error envelope with code set to rate_limited, a bounded safe message and request_id, plus exactly one decimal-seconds Retry-After value in 0..=86400; other gateway or WAF 429 shapes remain conservative protocol or indeterminate failures. Apply the denial before forwarding any Core authority work, keep its dimensions free of raw credentials and email addresses, and do not use an ingress allow decision to authenticate a Project, Application, server key, session, or proof.

Core identity semantics still fail closed independently of ingress policy. In particular, removing or resetting an edge quota cannot reset OTP attempts, bypass generation policy, revive an older challenge, or repeat a consumed proof. Passwordless email also serializes a Project-wide side-effect decision in PostgreSQL: a recent actual enqueue to the same canonical recipient or the hard active-outbox safety bound can commit the real newest generation as terminal without creating mail, while returning the same generic accepted response. That mechanism protects protocol side effects and enumeration safety; it is not IP/route admission, plan quota, billing policy, or a Core 429. Conversely, an edge denial must not mutate those PostgreSQL state machines.

Keep identities separate ​

The same person can have several unrelated identities:

IdentityMeaningAuthority
SaaS accountperson allowed to authenticate to your management productplatform identity plus current SaaS account state
Organization memberSaaS account with current roles in one organizationyour SaaS database
Service accountnon-human principal belonging to one organizationyour SaaS database
Project userend user authenticating to one customer Projectthe assigned OwlAuth cell

A Project user must never gain organization administration rights merely because an email address, provider account, or display name matches a SaaS account. Authentication proves a subject; your SaaS database remains authoritative for current membership, role, resource ownership, and commercial state.

Data ownership ​

Keep one clear authority for each fact:

ConcernAuthority
Accounts, organizations, memberships, invitations, roles, and service accountsSaaS database
Customer API-key digests, scopes, expiry, and revocationSaaS database
Subscription, entitlement, quota, and billing interpretationSaaS database and the explicitly reconciled payment-provider contract
Cell placement and organization-to-Project registrySaaS database
Project users, identities, applications, providers, sessions, tokens, and signing keysassigned OwlAuth cell
OwlAuth Project belongs_tochecked copy of an external organization identifier, never ownership authority by itself
External actor attributionSaaS audit record
Accepted OwlAuth Control actionOwlAuth audit record with the fixed deployment_operator actor

An organization may own several managed Projects. A managed Project should have one stable organization owner and cell assignment in your registry. Treat cell migration as an explicit migration product because issuer URLs, callbacks, keys, sessions, provider secrets, and recovery authority are deployment-sensitive.

Tenant authorization gateway ​

OwlAuth Control accepts one OWLAUTH_CONTROL_API_KEY and grants it full authority over the deployment. It does not attenuate that key by organization, role, Project, or belongs_to. Your gateway must perform every narrower authorization decision before using it.

For each customer management request:

  1. parse and bound the request;
  2. authenticate exactly one SaaS account or service account;
  3. resolve current principal and organization status;
  4. resolve current membership or service-account grants;
  5. authorize one concrete product permission;
  6. resolve the target managed resource through your registry;
  7. verify that the target belongs to the authorized organization;
  8. evaluate current entitlement, lifecycle state, and revisions;
  9. commit a durable actor-bound operation before any external side effect;
  10. map the operation to a closed, typed OwlAuth Control command;
  11. call the trusted cell Control origin with its operator key;
  12. finalize or reconcile the original operation and preserve correlation across both audit streams.

Never expose a generic Control proxy, arbitrary path and body forwarding, caller-selected cell origins, or raw OwlAuth Project IDs that bypass organization-qualified lookup. A valid operator key would make any such mistake deployment-wide.

Use belongs_to only as a consistency check ​

When provisioning a managed Project, set its OwlAuth belongs_to metadata to your organization's stable opaque public identifier. Store the returned OwlAuth Project IDs and metadata revision in your own managed-Project registry.

Before sensitive Project-bound mutations, resolve the Project from your registry and verify the exact current belongs_to and metadata revision. A mismatch should:

  • fail the customer operation closed;
  • create a security and reconciliation signal;
  • prevent best-effort mutation;
  • require repair from authoritative registry and OwlAuth state.

Caller-supplied belongs_to is never proof of ownership. Changing it alone is not a safe organization-transfer workflow.

Provision Projects with a durable saga ​

Your SaaS database and OwlAuth PostgreSQL cannot share one transaction. Provisioning therefore needs an explicit, idempotent saga:

Derive a globally unique Control idempotency key from the durable SaaS operation ID; do not forward a customer idempotency value directly into OwlAuth's deployment-wide namespace. If the external result is ambiguous, reconcile the same operation using the retained idempotent result or authoritative reads. Do not create a replacement Project merely because a timeout occurred.

Useful managed-resource states include provisioning, active, updating, suspending, disabled, provisioning_failed, and reconciliation_required. Protect those transitions with your own monotonic revision independently of OwlAuth's metadata revision.

Keep Auth off the management critical path ​

Customer applications and end users should use the assigned OwlAuth Auth endpoint's Runtime routes directly. Customer backends should use the same Auth endpoint's Server API routes with a Project server key for user-directory reads, exact lookup, Application projection reads, and online token introspection. A healthy Auth request should not synchronously depend on:

  • your SaaS API or console;
  • platform identity;
  • the payment provider;
  • the cell's Control listener;
  • a fleet reconciliation worker.

If you place a global Runtime edge in front of cells, it needs an authoritative and safely cached Project-to-cell routing design. Public Project identifiers must be fleet-unique when routing by Project ID alone; otherwise include an authoritative cell or region namespace. Do not turn the Runtime edge into a synchronous tenant-RBAC or billing dependency.

Credential boundaries ​

Use different credentials and secret namespaces for each trust domain:

CredentialAccepted byMeaning
Platform identity credentialSaaS APIauthenticated management subject only
Customer API keySaaS APISaaS principal plus a scope ceiling
Cell operator API keyone managed cell Control listenerfull deployment Control authority
Project server keyServer API routes on one cell's Authone Project's backend directory/introspection authority
Application publishable keymanaged Runtimepublic Application identification
Project access or refresh tokenmanaged Runtime/customer backendProject user and Application session context

A customer API key must never be forwarded to OwlAuth. A cell operator key must never appear in customer responses, browsers, tenant records, logs, traces, metrics, support bundles, or agent context. Project server keys are one-time Control reveals that must be acknowledged only after durable external secret-manager storage; they belong exclusively in customer backend custody and never in browsers, Runtime SDK configuration, URLs, or frontend bundles. Use one operator key per cell to limit blast radius, and keep Control ingress private even though network position does not replace Bearer authentication.

If you issue customer API keys, store only a versioned digest and safe lookup metadata after one-time secret display. Effective permission should be the intersection of the key's immutable scope ceiling and the principal's current permissions. Revoking membership or disabling the principal must therefore remove authority immediately.

Cells, failures, and recovery ​

A cell is the unit of administrative trust, capacity, backup, recovery, and incident blast radius. Keep Platform Identity and managed customer cells separate in production, including PostgreSQL authority, operator keys, signer namespaces, secret stores, and recovery paths.

FailureManagement behaviorCustomer Runtime behavior
SaaS database unavailablefail tenant management closedcontinue from cell authority
SaaS API unavailableconsole and automation unavailablecontinue
Platform identity unavailablenew administrator login affectedcontinue
Cell Control unavailableaffected commands fail or reconcileAuth continues if its dependencies are healthy
Cell Auth unavailablebackend and browser Auth requests failaffected cell Auth unavailable
Cell PostgreSQL unavailableaffected cell unavailableaffected cell unavailable
Operator-key mismatchControl calls fail until rotation/reconciliationRuntime and Server credentials remain independent
Payment provider unavailablepreserve bounded last-confirmed commercial state and reconcilecontinue

Bound work per cell with deadlines, concurrency limits, circuit breakers, and queues so one unhealthy cell cannot exhaust fleet control capacity. Persist actor attribution and operation intent before workers perform an external effect. Revalidate organization, managed-resource, entitlement, and OwlAuth revisions immediately before that effect.

Back up the SaaS registry, platform identity deployment, and each managed cell as separate authorities. After restoring different authorities from different points in time, fail ownership-sensitive management closed until the registry and OwlAuth Project metadata are reconciled. Never repair ownership automatically from ambiguous evidence.

Billing and metering ​

Prefer initial billing models derived from SaaS-authoritative management state, such as active managed Projects, configured Applications, administrator seats, enabled features, region, or dedicated-cell class. They avoid placing billing instrumentation in the authentication hot path.

Do not bill from ordinary logs, metrics, or security audit events unless you define a durable meter contract covering:

  • the exact qualifying event;
  • organization and Project attribution;
  • stable idempotency identity;
  • event and receipt time semantics;
  • replay, late arrival, correction, and backfill;
  • retention and privacy;
  • completeness and reconciliation;
  • behavior during source or billing outages.

Runtime-volume billing such as monthly active users or successful authentications requires an explicit durable aggregate or outbox contract. Authentication must not wait synchronously for the SaaS billing service or payment provider. Subscription cancellation should follow deliberate grace, notification, suspension, recovery, export, and retention policy rather than allowing a payment webhook to disable OwlAuth directly.

  1. Build organization, membership, role, and managed-Project registry authority.
  2. Add a narrow typed gateway for the minimum OwlAuth Control operations you expose.
  3. Implement actor-bound durable operations, idempotent provisioning, and reconciliation.
  4. Isolate cell operator keys and private Control networking.
  5. Route customer Runtime traffic independently from management availability.
  6. Add service accounts and customer API keys only when automation needs them.
  7. Start commercial enforcement from management-owned resource limits.
  8. Add Runtime-derived meters only after defining and testing a durable measurement contract.
  9. Add dedicated cells, regions, or migration only when product requirements justify their operational cost.

Security checklist ​

Before serving multiple organizations, verify at least:

  • cross-organization resource and child-ID substitution is denied;
  • caller-supplied cell, Project, and belongs_to values cannot override registry resolution;
  • stale SaaS and OwlAuth revisions fail closed;
  • API-key scope ceilings intersect current principal permissions;
  • disabled accounts, service accounts, organizations, and credentials lose authority;
  • no endpoint behaves as a generic Control proxy;
  • operator keys are redacted and unique per cell;
  • failed and ambiguous provisioning is reconciled without duplicate resources;
  • platform identity and managed customer cells are operationally isolated;
  • Auth remains independent from SaaS, Control, and billing outages;
  • restore-time ownership drift blocks mutation until reconciliation.

OwlAuth's own test suite provides evidence for the specifically exercised Project-isolation and server invariants. It does not certify a deployment or prove the tenant isolation, billing correctness, fleet orchestration, or cross-system recovery of the SaaS layer you build around it.

Released under the BSD 3-Clause License.