Skip to main content

systemprompt_security/
error.rs

1//! Error types raised by the security infrastructure.
2//!
3//! Public APIs in this crate return `thiserror`-derived error enums:
4//!
5//! - [`AuthError`] — request validation, JWT decoding, claim extraction.
6//! - [`JwtError`] — JWT minting (admin tokens, session tokens).
7//! - [`ManifestSigningError`] — Ed25519 signing of bridge manifests.
8//!
9//! All three implement `std::error::Error` and can be composed into larger
10//! `thiserror` enums via `#[from]`.
11
12use thiserror::Error;
13
14#[derive(Debug, Error)]
15pub enum AuthError {
16    #[error("missing authorization header")]
17    MissingAuthorization,
18
19    #[error("invalid JWT token: {0}")]
20    InvalidToken(#[source] jsonwebtoken::errors::Error),
21
22    #[error("missing session_id in token")]
23    MissingSessionId,
24
25    #[error("hook token: missing or non-`hook` audience")]
26    HookAudienceMissing,
27
28    #[error("hook token: required scope `{0}` not present")]
29    HookScopeMissing(&'static str),
30
31    #[error("hook token: missing `plugin_id` claim")]
32    HookPluginIdMissing,
33
34    #[error(
35        "hook token: plugin_id `{actual}` in claim does not match request plugin_id `{expected}`"
36    )]
37    HookPluginIdMismatch { expected: String, actual: String },
38
39    #[error("token has unsupported algorithm `{got}`; only RS256 is accepted")]
40    UnsupportedAlgorithm { got: String },
41
42    #[error("token is missing `kid` header")]
43    MissingKid,
44
45    #[error("token `kid` `{0}` does not match any known signing key")]
46    UnknownKid(String),
47
48    #[error("signing key lookup failed: {0}")]
49    KeyLookup(String),
50
51    #[error("issuer `{0}` is not trusted")]
52    UntrustedIssuer(String),
53
54    #[error("JWKS fetch failed for issuer `{issuer}`: {source}")]
55    JwksFetch {
56        issuer: String,
57        #[source]
58        source: crate::keys::JwksClientError,
59    },
60
61    #[error("token `act` delegation chain exceeds maximum depth of {max} (got {depth})")]
62    ActChainTooDeep { depth: usize, max: usize },
63
64    #[error("token is missing the `scope` claim")]
65    MissingScope,
66
67    #[error("token `user_type` claim `{claimed}` does not match permissions (derived `{derived}`)")]
68    UserTypeMismatch {
69        claimed: systemprompt_models::auth::UserType,
70        derived: systemprompt_models::auth::UserType,
71    },
72}
73
74#[derive(Debug, Error)]
75pub enum JwtError {
76    #[error("jwt encoding failed: {0}")]
77    Encoding(#[from] jsonwebtoken::errors::Error),
78
79    #[error("jwt signing key unavailable: {0}")]
80    Signing(String),
81}
82
83#[derive(Debug, Error)]
84pub enum ManifestSigningError {
85    #[error("manifest signing seed unavailable: {0}")]
86    SeedUnavailable(String),
87
88    #[error("jcs canonicalize: {0}")]
89    Canonicalize(String),
90
91    #[error("signing key missing after initialization")]
92    KeyMissing,
93}
94
95pub type AuthResult<T> = Result<T, AuthError>;
96
97pub type JwtResult<T> = Result<T, JwtError>;
98
99pub type ManifestSigningResult<T> = Result<T, ManifestSigningError>;