Skip to content

Security

Architecture you can read, not adjectives.

This page describes how the platform is built and what is tested, in enough detail to be checked. It does not describe secrets, and it claims only what is measured.

01Two planes

The control plane decides. The runtime plane enforces.

A Node control API owns members, applications, products, licenses, resellers, commerce and every administrative decision. A Go gateway owns /v1/auth/* and nothing else, deploys on its own, and shares only the database, never an internal HTTP call. Runtime authentication never passes through the dashboard.

  1. initlicense or bridge token → a signed session
  2. heartbeatevery 5 s · rotate the token · re-read the policy
  3. streamsigned pushes: session ended, config changed
  4. logoutTERMINATED, signed
  1. dashboardmember session cookie + CSRF, same origin
  2. management APIscoped bearer credentials
  3. outboxevents in the change's transaction
  4. workerwebhooks, Discord, campaigns, builds, retention

02Session model

A session is a signed envelope with a thirty-second life.

Every accepted answer is {key_id, payload, signature}: an Ed25519 signature over the exact payload bytes. The SDK verifies it under a key you pin out of band before it reads a single claim.

Signature
Cryptographically signed authorization responses, verified under a key you pin.
Binding
The payload carries the request's challenge, application, environment, a server timestamp within ±30 s of the client's clock, and the session id; an answer that does not match the request it came for is refused by the SDK.
Rotation
Session tokens rotate every heartbeat; a stolen old token is dead on arrival.
Deadline
A session expires 30 s after its last accepted heartbeat. If connectivity is lost, the client stops protected operations at expires_at. There is no offline lease.
Re-evaluation
Every heartbeat re-evaluates the whole policy, not just the token.
Reasons
Denials can carry your reason, signed, so the client can show it.
Key rotation
Signing keys rotate with zero client downtime.

03Replay and devices

Fresh challenges, keyed digests, row locks.

Nonce and clock

Nonce and clock binding on every request; replays are refused before they touch the database.

A used challenge is refused even when the answer was lost; the client discards that token and re-initializes with a fresh nonce. Strict retry semantics were chosen over response caching, which would have required encrypted bearer material.

Device binding

Concurrency-safe first-device binding.

Fingerprints are supplied by the client and are spoofable by design; this is server authority, not DRM.

Revocation

Revocation reaches running sessions: refused at the next heartbeat, and pushed to connected clients.

Propagation time is not a measured SLA; the protocol bound is the heartbeat deadline (30 s) when connectivity is lost.

04Authorization boundaries

Four populations. Four doors.

Operators, members, resellers and customers are separate security populations, with separate cookies, separate sessions and separate tables.

PopulationSurfaceCookieCan reach
Platform operators/operatorobsidian_operatorThe platform: organizations, health, the audit. Every action is audited; support reads and cannot act
Organization members/dashboardobsidian_sessionTheir organization, by role and page grant
Reseller operators/resellerobsidian_resellerTheir reseller's granted products, its licenses, its ledger, and nothing of the member plane
End customers/portalobsidian_portalTheir own licenses, devices, sessions, downloads and orders
Tenant isolation
Tenant isolation enforced in the schema, not just the query.
RBAC
Role-based access from one policy source, asserted route by route on every test run.
Credentials
Scoped management credentials: explicit scopes, application or organization binding, product confinement, rotation with grace.
Which credential lives where
A runtime SDK holds a license key or a bridge token and a session token, never a management credential. None of the SDK examples takes one, and the suite runs the Python and Go examples in an environment that contains none.

05Secrets at rest

Digests where a digest will do. Recoverable only where it must be.

Passwords
Argon2id for members, operators and customers, in separate tables, because the populations have different lifecycles and threat models.
Keys and tokens
License keys, device fingerprints, session tokens, invitations and credentials are stored as HMAC-SHA256 digests under a server pepper with namespace-separated inputs; 32 random bytes of entropy each.
Retained keys
A license key is retained encrypted (AES-256-GCM, versioned key) so it can be shown again, only as an audited reveal and only to who may see it.
Webhook secrets
Recoverable by necessity (sending an HMAC needs the key), so encrypted with AES-256-GCM under a versioned key; rotated with a two-signature grace period.
Signing keys
The Ed25519 seed is held server-side only and rotates through a published overlap. Startup refuses a missing, malformed, repeated or duplicated key on both planes.
Telemetry
OpenTelemetry across both planes, with secrets kept out of spans.

06At the edge

Headers, origins, and what may leave.

Browser surfaces

Per-request nonce CSP with strict-dynamic and no unsafe-inline for scripts; HSTS with preload; nosniff; no-referrer; frame denial; same-origin COOP and CORP. Cookies are HttpOnly, SameSite=Strict, Secure. Every browser mutation is checked for Origin and a CSRF token compared as bytes.

Outbound

Webhook destinations are resolved and pinned to a public address; loopback, private, link-local and reserved ranges are refused; HTTPS on 443 only; no redirects followed; credentials in the URL refused; the response body discarded.

Rate limits

Runtime requests are metered per address and per application before any database work, sized for heartbeat traffic. X-Forwarded-For is believed only from configured proxies; a rate limit reached in normal traffic is treated as a capacity signal, not an attack.

Outage

Fails closed: an outage denies, it never grants.

07What is not claimed

Honest limits.

A security page that lists only strengths is marketing. These are the things Obsidian does not claim, so that what it does claim can be believed.

  • Not DRMHardware fingerprints are supplied by the client and are spoofable by design. Obsidian expresses continuing server authority over a session; it does not claim to make a binary unbreakable, and watermarked builds identify a leaked artifact rather than prevent one.
  • One regionObsidian runs in one region. There is no claim of geographic redundancy.
  • Live status, not a historyThe status page shows the readiness of both planes as probed when you load it; no availability percentage is published.
  • The evidence is the suiteMore than 150 integration tests across concurrency, replay, isolation, delegation and the permission matrix, plus the gateway's Go tests and every SDK's contract test, run on every change.