Help us shape the future of Go! Take the 2026 Go Developer Survey

tenantkit

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 3, 2026 License: MIT Imports: 1 Imported by: 0

README

tenantkit

A store-agnostic multi-tenancy library for Go services.

Most multi-tenant services end up solving the same handful of problems from scratch: figure out which tenant a request belongs to, authenticate whoever is making it, look up tenant/user/API-key records, and make all of that available to request handlers. tenantkit packages that recurring shape as a library instead of a framework, so you don't re-derive it for every new service.

What it does

  • Tenant resolution — a pluggable TenantResolver chain figures out which tenant a request belongs to (API key, mTLS client cert, session, header, subdomain, or a strategy you write yourself), for both HTTP and gRPC. A tenant can support multiple credential types at once.
  • User + credential management — interfaces for storing and looking up tenants, users, API keys, and client certs (tenant-level or user-level), so identity data can live in whatever database you already use.
  • Pluggable identity — the same IdentityProvider interface is satisfied by a built-in local implementation (WebAuthn/bcrypt + sessions) and by an OIDC adapter, so you can swap in an external identity provider (Auth0, Okta, Clerk, Keycloak, Zitadel, or anything else that speaks OIDC) without changing anything downstream.
  • Middleware, not a framework — net/http middleware and gRPC interceptors populate request context with the resolved tenant and identity; everything else about your service stays exactly as it was.

What it deliberately doesn't do

  • No database access. tenantkit defines storage interfaces (TenantStore, UserStore, APIKeyStore, ClientCertStore, OIDCProviderStore); it never talks to a database itself. You implement those interfaces against whatever you're already using — SQL, NoSQL, or otherwise.
  • No store-specific data isolation. Row-level security, tenant-scoped query filters, and similar enforcement live in your own data layer, since they're inherently specific to whatever store you're using.
  • No authorization/RBAC engine. Identities carry a list of role strings; interpreting them is up to you. Pair tenantkit with a policy engine if you need one.
  • No opinionated admin HTTP API. Tenant/user/key provisioning is a CLI (tools/cmd/tenantkit-admin), production-usable on its own (subcommands, confirmation prompts, --dry-run, --json output) and backed by an importable operations package (tenantkit/admin) for consumers who need to compose provisioning with their own extra steps.

Status

The foundation, tenant resolution and middleware, admin tooling, and password/passkey identity are implemented: core types, the five store interfaces (including per-tenant OIDC IdP registration via OIDCProviderStore), an in-memory reference store (store/memstore) and a persistent SQLite-backed store (store/sqlite), an interface-conformance test suite (storetest) any store implementation can run against itself, the API-key generation/hashing/rotation helpers, a pluggable TenantResolver chain (resolve) with net/http and gRPC middleware (httpmw, grpcmw), the provisioning operations package (tenantkit/admin), the admin CLI (tools/cmd/tenantkit-admin), and identity/local — password (bcrypt) and WebAuthn (passkey) authentication, opaque-token sessions, password reset, and pluggable account-lockout rate-limiting (LoginLimiter, with an in-memory reference implementation), plus a persistent SQLite-backed store for it (identity/local/sqlite); and identity/oidc — an OAuth2 Authorization Code adapter for an external OIDC-compliant IdP (Auth0, Okta, Keycloak, etc.), with an in-memory reference session/ephemeral store (identity/oidc/memstore) and a conformance suite (identity/oidc/storetest) for a future persistent backend. Both satisfy the same IdentityProvider interface httpmw/grpcmw already consume, so either (or both) can be configured interchangeably. Remaining gaps: no persistent (SQLite) backend yet for identity/oidc's sessions, or for identity/local's LoginLimiter — see docs/superpowers/specs/ for the full design and docs/superpowers/plans/ for implementation status. Not yet ready for production use.

License

MIT — see LICENSE.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func WithIdentity

func WithIdentity(ctx context.Context, id *Identity) context.Context

WithIdentity returns a copy of ctx carrying id, retrievable via IdentityFromContext.

func WithTenant

func WithTenant(ctx context.Context, t *Tenant) context.Context

WithTenant returns a copy of ctx carrying t, retrievable via TenantFromContext.

Types

type APIKey

type APIKey struct {
	Hash     string
	TenantID string
	UserID   string
}

APIKey is a service or user credential used for tenant-scoped access. UserID is empty for a tenant-level key (e.g. a service ingestion credential not tied to any one person) and non-empty for a user-level key.

type ClaimsMapping

type ClaimsMapping struct {
	TenantIDClaim string
	UserIDClaim   string
	UsernameClaim string
	RolesClaim    string
}

ClaimsMapping says which of a verified OIDC ID token's claims identity/oidc reads to build an Identity. TenantIDClaim is required (no standard claim holds a tenant ID); the rest default when empty: UserIDClaim to "sub", UsernameClaim to "email", RolesClaim to "roles" (its claim value must be a JSON array of strings).

type ClientCert

type ClientCert struct {
	Fingerprint string
	TenantID    string
	UserID      string
}

ClientCert is an mTLS client-certificate credential used for tenant-scoped access, an alternative (or complement) to APIKey. Fingerprint is the SHA-256 hex digest of the DER-encoded cert -- not a secret, just an identifier; TLS itself already verified the cert against a CA before tenantkit ever sees the request. UserID is empty for a tenant-level cert, non-empty for a user-level cert.

type Identity

type Identity struct {
	UserID   string
	TenantID string
	Username string
	// Roles is opaque to tenantkit -- it's carried through for a
	// consumer's own authorization logic to interpret, never read or
	// written by tenantkit itself.
	Roles []string
}

Identity is an authenticated user: the result of an IdentityProvider authenticating a request, or a record looked up directly via store.UserStore.

func IdentityFromContext

func IdentityFromContext(ctx context.Context) (*Identity, bool)

IdentityFromContext returns the identity previously attached via WithIdentity, or ok=false if none was (e.g. pure API-key/service traffic with no per-user identity).

type OIDCProvider

type OIDCProvider struct {
	TenantID      string
	ProviderID    string // slug, unique within a tenant, e.g. "okta", "google"
	Name          string // display label for a login picker, e.g. "Acme Corp Okta"
	IssuerURL     string
	ClientID      string
	ClientSecret  string   // plain text -- see store package doc for why
	Scopes        []string // e.g. []string{"email", "profile"} -- "openid" is added automatically
	Domains       []string // e.g. []string{"acme.com", "acme.co.uk"} -- globally unique across all tenants
	ClaimsMapping ClaimsMapping
}

OIDCProvider is a tenant's registration of an external OIDC-compliant IdP. A tenant may register more than one (ProviderID is unique per tenant, not globally); Domains must be globally unique across every tenant and provider (see store.OIDCProviderStore.GetOIDCProviderByDomain).

type Tenant

type Tenant struct {
	ID          string
	DisplayName string
	Active      bool
}

Tenant is a single tenant's record as tenantkit understands it. A consumer's store implementation may track additional fields of its own; tenantkit only needs these three.

func TenantFromContext

func TenantFromContext(ctx context.Context) (*Tenant, bool)

TenantFromContext returns the tenant previously attached via WithTenant, or ok=false if none was.

Directories

Path Synopsis
Package admin implements tenantkit's tenant/user/key/cert provisioning operations, working purely against the store interfaces -- the same operations cmd/tenantkit-admin's CLI wraps.
Package admin implements tenantkit's tenant/user/key/cert provisioning operations, working purely against the store interfaces -- the same operations cmd/tenantkit-admin's CLI wraps.
Package grpcmw provides gRPC unary and stream server interceptors that resolve the tenant for each incoming call via resolve.TenantResolver, confirm it exists and is active against a store.TenantStore, and optionally authenticate the caller via an identity.IdentityProvider -- rejecting the call with an Unauthenticated/PermissionDenied status on failure and otherwise attaching the resolved tenant (and identity, if any) to the call context before invoking the handler.
Package grpcmw provides gRPC unary and stream server interceptors that resolve the tenant for each incoming call via resolve.TenantResolver, confirm it exists and is active against a store.TenantStore, and optionally authenticate the caller via an identity.IdentityProvider -- rejecting the call with an Unauthenticated/PermissionDenied status on failure and otherwise attaching the resolved tenant (and identity, if any) to the call context before invoking the handler.
Package httpmw provides net/http middleware that resolves the tenant for each incoming request via resolve.TenantResolver, confirms it exists and is active against a store.TenantStore, and optionally authenticates the caller via an identity.IdentityProvider -- rejecting the request with 401/403 on failure and otherwise attaching the resolved tenant (and identity, if any) to the request context before calling the next handler.
Package httpmw provides net/http middleware that resolves the tenant for each incoming request via resolve.TenantResolver, confirms it exists and is active against a store.TenantStore, and optionally authenticates the caller via an identity.IdentityProvider -- rejecting the request with 401/403 on failure and otherwise attaching the resolved tenant (and identity, if any) to the request context before calling the next handler.
Package identity defines tenantkit's identity-provider abstraction.
Package identity defines tenantkit's identity-provider abstraction.
local
Package local is tenantkit's built-in identity.IdentityProvider implementation: password (bcrypt) and WebAuthn (passkey) authentication, opaque-token sessions, and a password-reset token flow.
Package local is tenantkit's built-in identity.IdentityProvider implementation: password (bcrypt) and WebAuthn (passkey) authentication, opaque-token sessions, and a password-reset token flow.
local/memstore
Package memstore is an in-memory implementation of identity/local's storage interfaces, including a LoginLimiter (see NewLoginLimiter).
Package memstore is an in-memory implementation of identity/local's storage interfaces, including a LoginLimiter (see NewLoginLimiter).
local/sqlite
Package sqlite is a SQLite-backed implementation of identity/local's storage interfaces (CredentialStore, SessionStore, EphemeralStore), using the same pure-Go modernc.org/sqlite driver, Open/Close, and schema-migration pattern as tenantkit/store/sqlite.
Package sqlite is a SQLite-backed implementation of identity/local's storage interfaces (CredentialStore, SessionStore, EphemeralStore), using the same pure-Go modernc.org/sqlite driver, Open/Close, and schema-migration pattern as tenantkit/store/sqlite.
local/storetest
Package storetest provides interface-conformance test helpers for identity/local's storage interfaces.
Package storetest provides interface-conformance test helpers for identity/local's storage interfaces.
oidc
Package oidc is tenantkit's built-in identity.IdentityProvider implementation wrapping an external OIDC-compliant identity provider: the OAuth2 Authorization Code ceremony (BeginLogin/BeginLoginByDomain/FinishLogin), verified-ID token claims mapped to a tenantkit.Identity, and opaque-token sessions.
Package oidc is tenantkit's built-in identity.IdentityProvider implementation wrapping an external OIDC-compliant identity provider: the OAuth2 Authorization Code ceremony (BeginLogin/BeginLoginByDomain/FinishLogin), verified-ID token claims mapped to a tenantkit.Identity, and opaque-token sessions.
oidc/memstore
Package memstore is an in-memory implementation of identity/oidc's storage interfaces.
Package memstore is an in-memory implementation of identity/oidc's storage interfaces.
oidc/storetest
Package storetest provides interface-conformance test helpers for identity/oidc's storage interfaces.
Package storetest provides interface-conformance test helpers for identity/oidc's storage interfaces.
Package resolve provides tenantkit's tenant-resolution abstractions: Source, a transport-agnostic view of an incoming request, and TenantResolver, a pluggable strategy for extracting a tenant ID from one.
Package resolve provides tenantkit's tenant-resolution abstractions: Source, a transport-agnostic view of an incoming request, and TenantResolver, a pluggable strategy for extracting a tenant ID from one.
Package store defines tenantkit's storage interfaces.
Package store defines tenantkit's storage interfaces.
memstore
Package memstore is an in-memory implementation of tenantkit's store interfaces.
Package memstore is an in-memory implementation of tenantkit's store interfaces.
sqlite
Package sqlite is a SQLite-backed implementation of all four tenantkit/store interfaces (TenantStore, UserStore, APIKeyStore, ClientCertStore), using the pure-Go modernc.org/sqlite driver -- no cgo, no server process, just a library reading/writing one file (or ":memory:" for tests).
Package sqlite is a SQLite-backed implementation of all four tenantkit/store interfaces (TenantStore, UserStore, APIKeyStore, ClientCertStore), using the pure-Go modernc.org/sqlite driver -- no cgo, no server process, just a library reading/writing one file (or ":memory:" for tests).
Package storetest provides interface-conformance test helpers for tenantkit's store interfaces.
Package storetest provides interface-conformance test helpers for tenantkit's store interfaces.
tools module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL