Production infrastructure for AI agents
Website · Documentation · Guides · Core · Template · Discord
systemprompt-security
Every agent and tool call passes one decision plane before it runs. This crate authenticates the request, resolves it against your access-control rules with deny-overrides, and records the verdict, using signing keys you hold rather than a secret shared to a vendor.
Layer: Infra. Infrastructure primitives consumed by the domain and application crates. Part of the systemprompt-core workspace.
What it does
The crate owns the request-level security shared by the HTTP API and the runtime. Tokens are signed RS256 against an in-process signing-key authority that holds the deployment's RSA private key and caches federated JWKS documents under a bounded LRU with an HTTPS allowlist. HS256 is rejected on validation. Authorization runs the same deny-overrides resolver for the gateway /v1/messages proxy and the MCP RBAC middleware, so one audit shape covers both enforcement sites. There is no shared secret to plumb through API surfaces.
Modules
| Module | Purpose |
|---|---|
keys |
The signing-key plane. RsaSigningKey (generate, load/persist PKCS#8 PEM, deterministic kid), the process-wide authority submodule (init, signing_key, encoding_key, active_kid, decoding_key_for_kid), the jwks document builder, and the jwks_client federated fetcher with cache. |
jwt |
Admin-token minting and validation (decode, mint, validate submodules); JwtService, AdminTokenParams. |
session |
Session-scoped token generation and claim validation (SessionGenerator, SessionParams, ValidatedSessionClaims). |
extraction |
Token extraction from Authorization headers, MCP proxy headers, and cookies, plus header injection for context propagation. |
auth |
Request validation into a RequestContext (AuthValidationService) and bridge hook-token verification. |
authz |
Unified authorization decision plane: the deny-overrides resolve, the access_control_rules repository, the AuthzDecisionHook surface with built-in impls, ingestion, and Postgres audit sinks. |
policy |
Shared tool-use governance types (GovernancePolicy, GovernanceChain, PolicyContext) that produce the same Decision shape the authz resolver returns. |
at_rest |
HMAC-SHA256 keyed hashing (hmac_sha256, hmac_sha256_hex) under the deployment oauth_at_rest_pepper, used to store refresh-token ids and authorisation codes as digests rather than plaintext. |
manifest_signing |
Ed25519 bridge-manifest signing with RFC 8785 JCS canonicalisation, keyed independently of the JWT signing key. |
services |
Lightweight scanner / bot detection (ScannerDetector). |
error |
AuthError, JwtError, ManifestSigningError and their result aliases. |
Authz schema DDL and migrations live in authz/schema/.
auth
Authentication validation with configurable enforcement modes plus bridge hook-token verification.
| Export | Type | Purpose |
|---|---|---|
AuthValidationService |
Struct | Validates JWT tokens and constructs RequestContext |
AuthMode |
Enum | Required, Optional, Disabled enforcement levels |
HookTokenValidator |
Struct | Verifies short-lived hook tokens minted for the bridge |
ValidatedHookClaims |
Struct | Claims extracted from a verified hook token |
extraction
Token extraction from multiple sources with fallback chain support.
| Export | Type | Purpose |
|---|---|---|
TokenExtractor |
Struct | Extracts tokens from headers/cookies with configurable fallback |
ExtractionMethod |
Enum | AuthorizationHeader, McpProxyHeader, Cookie |
TokenExtractionError |
Enum | Specific error types for extraction failures |
HeaderExtractor |
Struct | Extracts trace_id, context_id, agent_name from headers |
HeaderInjector |
Struct | Injects RequestContext fields into outgoing headers |
HeaderInjectionError |
Struct | Error type for header injection failures |
CookieExtractor |
Struct | Dedicated cookie-based token extraction |
CookieExtractionError |
Enum | Cookie-specific error types |
jwt
JWT token generation for administrative access.
| Export | Type | Purpose |
|---|---|---|
JwtService |
Struct | Generates admin JWT tokens with RS256, keyed off the active signing-key authority (keys::authority) |
AdminTokenParams |
Struct | Configuration for admin token creation |
services
Security services for request classification.
| Export | Type | Purpose |
|---|---|---|
ScannerDetector |
Struct | Detects bot/scanner requests by path, user-agent, velocity |
session
Session token generation and claim validation.
| Export | Type | Purpose |
|---|---|---|
SessionGenerator |
Struct | Generates session-scoped JWT tokens |
SessionParams |
Struct | Configuration for session token creation |
ValidatedSessionClaims |
Struct | Extracted claims after JWT validation |
authz
Unified authorization decision plane shared by the gateway /v1/messages proxy and the MCP RBAC middleware.
| Export | Type | Purpose |
|---|---|---|
resolve |
Fn | Deny-overrides resolver against access_control_rules |
AuthzDecisionHook |
Trait | Pluggable decision surface; concrete impl is carried on AppContext as SharedAuthzHook |
AllowAllHook / DenyAllHook / WebhookHook |
Struct | Built-in AuthzDecisionHook implementations |
AccessControlRepository |
Struct | CRUD over access_control_rules |
AccessControlIngestionService |
Struct | Loads rule sets from configuration |
AuthzExtension |
Struct | Registers schemas and migrations via the extension framework |
AuthzAuditSink / DbAuditSink / NullAuditSink |
Trait + impls | Sinks for governance decision audit records |
GovernanceDecisionRepository |
Struct | Reads governance_decisions audit rows |
Access / AccessRule / AuthzDecision / AuthzRequest / Decision / EntityKind / RuleType |
Types | Authz request and decision data model |
build_authz_hook |
Fn | Constructs the active SharedAuthzHook (Deny/Allow/Webhook) from governance.authz for the caller to store on its context |
SharedAuthzHook |
Type alias | Arc<dyn AuthzDecisionHook> — the value threaded through DI |
keys
The asymmetric signing-key plane. RsaSigningKey holds the active keypair; the authority submodule exposes it process-wide.
| Export | Type | Purpose |
|---|---|---|
RsaSigningKey |
Struct | RSA keypair: generate, load/persist PKCS#8 PEM, deterministic kid |
authority::{init, signing_key, encoding_key, active_kid, decoding_key_for_kid} |
Fn | Process-wide access to the active signing key and per-kid decoding keys |
Jwks / Jwk |
Struct | JWKS document served at /.well-known/jwks.json |
JwksClient |
Struct | Federated JWKS fetcher with bounded LRU cache and HTTPS allowlist |
at_rest
Keyed hashing so sensitive OAuth identifiers are stored as digests, never plaintext.
| Export | Type | Purpose |
|---|---|---|
hmac_sha256 |
Fn | HMAC-SHA256 digest of a value under the oauth_at_rest_pepper |
hmac_sha256_hex |
Fn | Hex-encoded HMAC-SHA256 digest |
policy
Shared tool-use governance types that produce the same Decision shape as the authz resolver.
| Export | Type | Purpose |
|---|---|---|
GovernancePolicy |
Trait | Contract every tool-call policy in the chain implements |
GovernanceChain |
Struct | Ordered chain of policies (secret scan, scope check, blocklist, rate limit) |
PolicyContext / McpToolInput / AgentScope |
Types | Inputs a policy evaluates against |
manifest_signing
Ed25519 signing for bridge manifests, keyed independently of the JWT signing key.
| Export | Type | Purpose |
|---|---|---|
sign_value<T: Serialize> |
Fn | RFC 8785 canonicalise + Ed25519 sign |
canonicalize<T: Serialize> |
Fn | RFC 8785 JCS canonical JSON |
signing_key |
Fn | Loads the Ed25519 signing key from manifest_signing_secret_seed |
Usage
[]
= "0.21"
Token Extraction
use ;
let extractor = standard;
let token = extractor.extract?;
let browser_extractor = browser_only
.with_cookie_name;
Authentication Validation
use ;
let service = new;
let context = service.validate_request?;
Token signing and verification both resolve the active kid through the
process-wide signing-key authority (keys::authority), which loads the
deployment's RSA private key from signing_key_path and fetches JWKS
documents for every entry in profile.security.trusted_issuers. There is
no shared secret to plumb through API surfaces.
Admin Token Generation
use ;
let params = AdminTokenParams ;
let token = generate_admin_token?;
Session Token Generation
use ;
use ;
let generator = new;
let params = SessionParams ;
let token = generator.generate?;
Dependencies
| Crate | Purpose |
|---|---|
systemprompt-models |
Shared models (JwtClaims, UserType, Permission) |
systemprompt-identifiers |
Typed identifiers (UserId, SessionId, TraceId) |
systemprompt-config |
Profile and secrets access for signing keys |
systemprompt-database |
DbPool for authz repositories and audit sinks |
systemprompt-extension |
Extension trait used by AuthzExtension |
jsonwebtoken |
JWT encoding/decoding with RS256 |
rsa, pkcs8 |
RSA keypair generation and PKCS#8 PEM encoding |
sha2, hmac, hex |
kid derivation and HMAC-SHA256 at-rest hashing |
lru |
Bounded JWKS document cache |
url |
JWKS issuer HTTPS-allowlist parsing |
ed25519-dalek + serde_jcs |
Ed25519 signing and RFC 8785 canonical JSON |
base64, serde, serde_json |
Encoding and serialisation |
axum |
HTTP types (HeaderMap, HeaderValue) |
sqlx |
Authz repository and audit sink queries |
reqwest |
WebhookHook outbound calls |
metrics |
Authz decision counters |
uuid |
Token and record identifiers |
inventory |
Extension registration |
chrono |
Timestamp handling |
async-trait, thiserror |
dyn-compatible authz hooks and typed errors |
tracing |
Structured logging |
License
BSL-1.1 (Business Source License). Source-available for evaluation, testing, and non-production use. Production use requires a commercial license. Each version converts to Apache 2.0 four years after publication. See LICENSE.
systemprompt.io · Documentation · Guides · Live Demo · Template · crates.io · docs.rs · Discord
Infra layer · Own how your organization uses AI.