API credentials and abuse controls
ServiceStack ApiKeysFeature supplies credentials; SaaS filters bind their lifecycle and access to the organization they were created for.
Credential lifecycle
An interactive authenticated member with api.access creates a named key for an organization, which the request names in RefIdStr. The management UI shows the raw key once and later exposes only a visible fingerprint/metadata. Updates and deletes must match the creating user, who must still be a member of the key's organization.
API-key-authenticated requests can only call APIs that name a scope the key has with [ValidateHasScope]. They cannot create, update, or delete credentials and cannot switch or list the interactive user's organizations. Revoked/expired keys and keys whose owner lost organization membership are rejected.
Accepted headers are:
X-Api-Key: ak-...
Authorization: Bearer ak-...The configured standard scopes are usage:read, usage:write, and workspace:read. The simplified UI intentionally does not let customers compose arbitrary scopes.


Storage sensitivity
The current ServiceStack key verifier looks up the supplied value in the ApiKey table. Treat that table, database credentials, backups, query tooling, and administrator access as credential-bearing sensitive material. A derived product requiring non-recoverable at-rest keys should implement a prefix/identifier plus strong one-way verifier design and a migration/rotation plan.
Never write raw keys to application logs, audit detail, support notes, analytics dimensions, URLs, or client error reporting.

Abuse controls
SaasApiRateLimiter applies fixed one-minute in-process limits to each API key (Saas.ApiKeyRequestsPerMinute) and to each organization across all of its keys (Saas.OrganizationApiRequestsPerMinute), so an organization cannot raise its limit by creating keys. Rejection returns 429 and Retry-After. The limiter runs after authentication, so requests with an invalid key are rejected with 401 without being counted; limit those in front of the application if key guessing is a concern. Commercial quota enforcement is separate and returns QuotaExceeded when a metered allowance is exhausted.
Before scaling horizontally, replace SaasApiRateLimiter with a distributed limiter or enforce limits at a trusted gateway. Add independent limits for IP/organization/endpoint cost, body size, concurrent expensive work, authentication endpoints, and provider-backed operations.
Do not allow many cheap requests to enqueue unlimited expensive jobs. Admission control should happen before durable queue growth.
Rotation and response
Create a replacement, deploy it to the caller, verify traffic, then revoke the old key. Because a raw key cannot be shown again in the UI, loss means replacement.
For compromise, revoke immediately, find usage/audit/request activity by visible fingerprint, user, tenant, request ID, and time, inspect affected resources, and notify the customer according to incident policy.
Verify
Test one-time display, organization filtering, inactive membership, expiry, revocation, management via API key, both header forms, fixed scopes, rate-limit isolation/reset, quota interaction, logs/audit redaction, and multi-instance behavior.
Related documentation
Tenant isolation
The internal Workspace is the tenant boundary shown to customers as an Organization. Files, usage, subscription state, entitlements, members, notifications, audit, credentials, and lifecycle records are organization-bound.
Stripe webhook security
The Stripe webhook is unauthenticated by user session and therefore authenticates the provider message cryptographically before trusting its content.