Keysmith
1.x
Docs/Keysmith/Multi-Tenancy
Open

Reading2 min
Updated31 Jul 2026
Sourcev1/concepts/multi-tenancy.mdx

Keysmith is multi-tenant by design. Every operation is scoped to an app and tenant via context.Context. Cross-tenant data access is structurally impossible.

Setting tenant context01

Standalone mode

Use keysmith.WithTenant to inject app ID and tenant ID into the context.

ctx := keysmith.WithTenant(ctx, "my-app", "tenant-1")

Forge mode

When running as a Forge extension, Keysmith automatically extracts scope from forge.Scope:

// Forge injects scope automatically via middleware.
// AppID comes from forge.ScopeOrganization
// TenantID comes from forge.ScopeOrganization

How isolation works02

LayerMechanism
ContextWithTenant injects app ID and tenant ID into context.Context
EngineEvery operation reads scope from context before querying
StoreAll queries filter by app ID and tenant ID
ValidationKey validation verifies the key belongs to the requesting tenant
Plugin hooksLifecycle events carry tenant context for audit and metrics

Reading scope from context03

appID := keysmith.AppIDFromContext(ctx)
tenantID := keysmith.TenantIDFromContext(ctx)

Store-level isolation04

Every store method receives the app ID and tenant ID from context. Queries are always scoped:

-- Example: listing keys for a tenant
SELECT * FROM keysmith_keys
WHERE app_id = $1 AND tenant_id = $2
ORDER BY created_at DESC

A key created by tenant A is never returned when tenant B queries.

Key validation across tenants05

When a raw API key is validated, the engine:

  1. Hashes the raw key with SHA-256

  2. Looks up the hash in the store (global lookup, not tenant-scoped)

  3. Verifies the found key belongs to the requesting tenant

  4. Returns ErrKeyNotFound if the key belongs to a different tenant

This design allows keys to be globally unique while maintaining strict tenant isolation.