atproto_oauth/
errors.rs

1//! # Structured Error Types for OAuth Operations
2//!
3//! Comprehensive error handling for AT Protocol OAuth operations using structured error types
4//! with the `thiserror` library. All errors follow the project convention of prefixed error codes
5//! with descriptive messages.
6//!
7//! ## Error Categories
8//!
9//! - **`JWTError`** (jwt-1 to jwt-18): JSON Web Token validation, parsing, and verification errors
10//! - **`JWKError`** (jwk-1 to jwk-7): JSON Web Key conversion, processing, and thumbprint errors
11//! - **`OAuthClientError`** (client-1 to client-14): OAuth client operations and server communication errors
12//! - **`ResourceValidationError`** (resource-1 to resource-2): OAuth protected resource configuration validation errors
13//! - **`AuthServerValidationError`** (auth-server-1 to auth-server-12): OAuth authorization server configuration validation errors  
14//! - **`DpopError`** (dpop-1 to dpop-6): DPoP (Demonstration of Proof-of-Possession) operation errors
15//! - **`OAuthStorageError`** (storage-1 to storage-4): OAuth request storage operations including cache lock failures and data access errors
16//!
17//! ## Error Format
18//!
19//! All errors use the standardized format: `error-atproto-oauth-{domain}-{number} {message}: {details}`
20
21use thiserror::Error;
22
23/// Error types that can occur when working with JSON Web Tokens
24#[derive(Debug, Error)]
25pub enum JWTError {
26    /// Occurs when JWT does not have the expected 3-part format (header.payload.signature)
27    #[error("error-atproto-oauth-jwt-1 Invalid JWT format: expected 3 parts separated by dots")]
28    InvalidFormat,
29
30    /// Occurs when JWT header cannot be base64 decoded or parsed as JSON
31    #[error("error-atproto-oauth-jwt-2 Invalid JWT header: failed to decode or parse")]
32    InvalidHeader,
33
34    /// Occurs when JWT algorithm does not match the provided key type
35    #[error(
36        "error-atproto-oauth-jwt-3 Unsupported JWT algorithm: algorithm {algorithm} incompatible with key type {key_type}"
37    )]
38    UnsupportedAlgorithm {
39        /// The algorithm specified in the JWT header
40        algorithm: String,
41        /// The type of key provided for verification
42        key_type: String,
43    },
44
45    /// Occurs when JWT claims cannot be base64 decoded or parsed as JSON
46    #[error("error-atproto-oauth-jwt-4 Invalid JWT claims: failed to decode or parse")]
47    InvalidClaims,
48
49    /// Occurs when JWT signature cannot be base64 decoded
50    #[error("error-atproto-oauth-jwt-5 Invalid JWT signature: failed to decode signature")]
51    InvalidSignature,
52
53    /// Occurs when system time cannot be obtained for timestamp validation
54    #[error("error-atproto-oauth-jwt-6 System time error: unable to get current timestamp")]
55    SystemTimeError,
56
57    /// Occurs when JWT has passed its expiration time
58    #[error("error-atproto-oauth-jwt-7 JWT expired: token is past expiration time")]
59    TokenExpired,
60
61    /// Occurs when JWT is used before its not-before time
62    #[error("error-atproto-oauth-jwt-8 JWT not valid yet: token is before not-before time")]
63    TokenNotValidYet,
64
65    /// Occurs when signature verification fails
66    #[error("error-atproto-oauth-jwt-9 Signature verification failed: invalid signature")]
67    SignatureVerificationFailed,
68
69    /// Occurs when JWT payload cannot be base64 decoded
70    #[error("error-atproto-oauth-jwt-10 Invalid JWT payload: failed to decode payload")]
71    InvalidPayload,
72
73    /// Occurs when JWT payload cannot be parsed as JSON
74    #[error("error-atproto-oauth-jwt-11 Invalid JWT payload JSON: failed to parse payload as JSON")]
75    InvalidPayloadJson,
76
77    /// Occurs when a required JWT claim is missing
78    #[error("error-atproto-oauth-jwt-12 Missing required claim: {claim}")]
79    MissingClaim {
80        /// The name of the missing claim
81        claim: String,
82    },
83
84    /// Occurs when JWT type field has wrong value
85    #[error("error-atproto-oauth-jwt-13 Invalid token type: expected '{expected}', got '{actual}'")]
86    InvalidTokenType {
87        /// The expected token type
88        expected: String,
89        /// The actual token type found
90        actual: String,
91    },
92
93    /// Occurs when HTTP method in JWT doesn't match expected value
94    #[error(
95        "error-atproto-oauth-jwt-14 HTTP method mismatch: expected '{expected}', got '{actual}'"
96    )]
97    HttpMethodMismatch {
98        /// The expected HTTP method
99        expected: String,
100        /// The actual HTTP method in the JWT
101        actual: String,
102    },
103
104    /// Occurs when HTTP URI in JWT doesn't match expected value
105    #[error("error-atproto-oauth-jwt-15 HTTP URI mismatch: expected '{expected}', got '{actual}'")]
106    HttpUriMismatch {
107        /// The expected HTTP URI
108        expected: String,
109        /// The actual HTTP URI in the JWT
110        actual: String,
111    },
112
113    /// Occurs when access token hash validation fails
114    #[error("error-atproto-oauth-jwt-16 Access token hash mismatch: invalid 'ath' claim")]
115    AccessTokenHashMismatch,
116
117    /// Occurs when nonce value is not in the expected values list
118    #[error("error-atproto-oauth-jwt-17 Invalid nonce: value '{nonce}' not in expected values")]
119    InvalidNonce {
120        /// The nonce value that was not found in expected values
121        nonce: String,
122    },
123
124    /// Occurs when JWT has invalid timestamp claim
125    #[error("error-atproto-oauth-jwt-18 Invalid timestamp: {reason}")]
126    InvalidTimestamp {
127        /// The reason for the timestamp validation failure
128        reason: String,
129    },
130}
131
132/// Error types that can occur when working with JSON Web Keys
133#[derive(Debug, Error)]
134pub enum JWKError {
135    /// Occurs when P-256 JWK conversion to KeyData fails
136    #[error("error-atproto-oauth-jwk-1 P-256 JWK conversion failed: unable to convert to KeyData")]
137    P256ConversionFailed,
138
139    /// Occurs when P-384 JWK conversion to KeyData fails
140    #[error("error-atproto-oauth-jwk-2 P-384 JWK conversion failed: unable to convert to KeyData")]
141    P384ConversionFailed,
142
143    /// Occurs when K-256 JWK conversion to KeyData fails
144    #[error("error-atproto-oauth-jwk-3 K-256 JWK conversion failed: unable to convert to KeyData")]
145    K256ConversionFailed,
146
147    /// Occurs when an unsupported elliptic curve is encountered
148    #[error("error-atproto-oauth-jwk-4 Unsupported curve: {curve}")]
149    UnsupportedCurve {
150        /// The unsupported curve name
151        curve: String,
152    },
153
154    /// Occurs when an unsupported key type is encountered
155    #[error("error-atproto-oauth-jwk-5 Unsupported key type: {kty}")]
156    UnsupportedKeyType {
157        /// The unsupported key type
158        kty: String,
159    },
160
161    /// Occurs when a required field is missing from the JWK
162    #[error("error-atproto-oauth-jwk-6 Missing required field: {field}")]
163    MissingField {
164        /// The missing field name
165        field: String,
166    },
167
168    /// Occurs when JWK serialization fails
169    #[error("error-atproto-oauth-jwk-7 JWK serialization failed: {message}")]
170    SerializationError {
171        /// The serialization error message
172        message: String,
173    },
174}
175
176/// Represents errors that can occur during OAuth client operations.
177///
178/// These errors are related to the OAuth client functionality, including
179/// interacting with authorization servers, protected resources, and token management.
180#[derive(Debug, Error)]
181pub enum OAuthClientError {
182    /// Error when a request to the authorization server fails.
183    ///
184    /// This error occurs when the OAuth client fails to establish a connection
185    /// or complete a request to the authorization server.
186    #[error("error-atproto-oauth-client-1 Authorization Server Request Failed: {0:?}")]
187    AuthorizationServerRequestFailed(reqwest::Error),
188
189    /// Error when the authorization server response is malformed.
190    ///
191    /// This error occurs when the response from the authorization server
192    /// cannot be properly parsed or processed.
193    #[error("error-atproto-oauth-client-2 Malformed Authorization Server Response: {0:?}")]
194    MalformedAuthorizationServerResponse(reqwest::Error),
195
196    /// Error when the authorization server response is invalid.
197    ///
198    /// This error occurs when the response from the authorization server
199    /// is well-formed but contains invalid or unexpected data.
200    #[error("error-atproto-oauth-client-3 Invalid Authorization Server Response: {0:?}")]
201    InvalidAuthorizationServerResponse(anyhow::Error),
202
203    /// Error when an OAuth protected resource is invalid.
204    ///
205    /// This error occurs when trying to access a protected resource that
206    /// is not properly configured for OAuth access.
207    #[error("error-atproto-oauth-client-4 Invalid OAuth Protected Resource")]
208    InvalidOAuthProtectedResource,
209
210    /// Error when a request to an OAuth protected resource fails.
211    ///
212    /// This error occurs when the OAuth client fails to establish a connection
213    /// or complete a request to a protected resource.
214    #[error("error-atproto-oauth-client-5 OAuth Protected Resource Request Failed: {0:?}")]
215    OAuthProtectedResourceRequestFailed(reqwest::Error),
216
217    /// Error when a protected resource response is malformed.
218    ///
219    /// This error occurs when the response from a protected resource
220    /// cannot be properly parsed or processed.
221    #[error("error-atproto-oauth-client-6 Malformed OAuth Protected Resource Response: {0:?}")]
222    MalformedOAuthProtectedResourceResponse(reqwest::Error),
223
224    /// Error when a protected resource response is invalid.
225    ///
226    /// This error occurs when the response from a protected resource
227    /// is well-formed but contains invalid or unexpected data.
228    #[error("error-atproto-oauth-client-7 Invalid OAuth Protected Resource Response: {0:?}")]
229    InvalidOAuthProtectedResourceResponse(anyhow::Error),
230
231    /// Error when token minting fails.
232    ///
233    /// This error occurs when the system fails to mint (create) a new
234    /// OAuth token, typically due to cryptographic or validation issues.
235    #[error("error-atproto-oauth-client-8 Token minting failed: {0:?}")]
236    MintTokenFailed(anyhow::Error),
237
238    /// Error when JWT header creation from key data fails.
239    ///
240    /// This error occurs when attempting to create a JWT header from
241    /// cryptographic key data during OAuth workflow operations.
242    #[error("error-atproto-oauth-client-9 JWT header creation from key failed: {0:?}")]
243    JWTHeaderCreationFailed(anyhow::Error),
244
245    /// Error when DPoP token creation fails.
246    ///
247    /// This error occurs when attempting to create a DPoP proof token
248    /// during OAuth workflow operations.
249    #[error("error-atproto-oauth-client-10 DPoP token creation failed: {0:?}")]
250    DpopTokenCreationFailed(anyhow::Error),
251
252    /// Error when PAR (Pushed Authorization Request) HTTP request fails.
253    ///
254    /// This error occurs when the HTTP request to the pushed authorization
255    /// request endpoint fails during OAuth workflow operations.
256    #[error("error-atproto-oauth-client-11 PAR HTTP request failed: {0:?}")]
257    PARHttpRequestFailed(reqwest_middleware::Error),
258
259    /// Error when PAR response JSON parsing fails.
260    ///
261    /// This error occurs when the response from the pushed authorization
262    /// request endpoint cannot be parsed as JSON.
263    #[error("error-atproto-oauth-client-12 PAR response JSON parsing failed: {0:?}")]
264    PARResponseJsonParsingFailed(reqwest::Error),
265
266    /// Error when token endpoint HTTP request fails.
267    ///
268    /// This error occurs when the HTTP request to the token endpoint
269    /// fails during OAuth token exchange operations.
270    #[error("error-atproto-oauth-client-13 Token endpoint HTTP request failed: {0:?}")]
271    TokenHttpRequestFailed(reqwest_middleware::Error),
272
273    /// Error when token response JSON parsing fails.
274    ///
275    /// This error occurs when the response from the token endpoint
276    /// cannot be parsed as JSON.
277    #[error("error-atproto-oauth-client-14 Token response JSON parsing failed: {0:?}")]
278    TokenResponseJsonParsingFailed(reqwest::Error),
279}
280
281/// Represents errors that can occur during OAuth resource validation.
282///
283/// These errors occur when validating the configuration of an OAuth resource server
284/// against the requirements of the AT Protocol.
285#[derive(Debug, Error)]
286pub enum ResourceValidationError {
287    /// Error when the resource server URI doesn't match the PDS URI.
288    ///
289    /// This error occurs when the resource server URI in the OAuth configuration
290    /// does not match the expected Personal Data Server (PDS) URI, which is required
291    /// for proper AT Protocol OAuth integration.
292    #[error("error-atproto-oauth-resource-1 Resource must match PDS")]
293    ResourceMustMatchPds,
294
295    /// Error when the authorization servers list doesn't contain exactly one server.
296    ///
297    /// This error occurs when the OAuth resource configuration doesn't specify
298    /// exactly one authorization server as required by AT Protocol specification.
299    #[error("error-atproto-oauth-resource-2 Authorization servers must contain exactly one server")]
300    AuthorizationServersMustContainExactlyOne,
301}
302
303/// Represents errors that can occur during OAuth authorization server validation.
304///
305/// These errors occur when validating the configuration of an OAuth authorization server
306/// against the requirements specified by the AT Protocol.
307#[derive(Debug, Error)]
308pub enum AuthServerValidationError {
309    /// Error when the authorization server issuer doesn't match the PDS.
310    ///
311    /// This error occurs when the issuer URI in the OAuth authorization server metadata
312    /// does not match the expected Personal Data Server (PDS) URI.
313    #[error("error-atproto-oauth-auth-server-1 Issuer must match PDS")]
314    IssuerMustMatchPds,
315
316    /// Error when the 'code' response type is not supported.
317    ///
318    /// This error occurs when the authorization server doesn't support the 'code' response type,
319    /// which is required for the authorization code grant flow in AT Protocol.
320    #[error("error-atproto-oauth-auth-server-2 Response types supported must include 'code'")]
321    ResponseTypesSupportMustIncludeCode,
322
323    /// Error when the 'authorization_code' grant type is not supported.
324    ///
325    /// This error occurs when the authorization server doesn't support the 'authorization_code'
326    /// grant type, which is required for the AT Protocol OAuth flow.
327    #[error(
328        "error-atproto-oauth-auth-server-3 Grant types supported must include 'authorization_code'"
329    )]
330    GrantTypesSupportMustIncludeAuthorizationCode,
331
332    /// Error when the 'refresh_token' grant type is not supported.
333    ///
334    /// This error occurs when the authorization server doesn't support the 'refresh_token'
335    /// grant type, which is required for maintaining long-term access in AT Protocol.
336    #[error("error-atproto-oauth-auth-server-4 Grant types supported must include 'refresh_token'")]
337    GrantTypesSupportMustIncludeRefreshToken,
338
339    /// Error when the 'S256' code challenge method is not supported.
340    ///
341    /// This error occurs when the authorization server doesn't support the 'S256' code
342    /// challenge method for PKCE, which is required for secure authorization code flow.
343    #[error(
344        "error-atproto-oauth-auth-server-5 Code challenge methods supported must include 'S256'"
345    )]
346    CodeChallengeMethodsSupportedMustIncludeS256,
347
348    /// Error when the 'none' token endpoint auth method is not supported.
349    ///
350    /// This error occurs when the authorization server doesn't support the 'none'
351    /// token endpoint authentication method, which is used for public clients.
352    #[error(
353        "error-atproto-oauth-auth-server-6 Token endpoint auth methods supported must include 'none'"
354    )]
355    TokenEndpointAuthMethodsSupportedMustIncludeNone,
356
357    /// Error when the 'private_key_jwt' token endpoint auth method is not supported.
358    ///
359    /// This error occurs when the authorization server doesn't support the 'private_key_jwt'
360    /// token endpoint authentication method, which is required for AT Protocol clients.
361    #[error(
362        "error-atproto-oauth-auth-server-7 Token endpoint auth methods supported must include 'private_key_jwt'"
363    )]
364    TokenEndpointAuthMethodsSupportedMustIncludePrivateKeyJwt,
365
366    /// Error when the 'ES256' signing algorithm is not supported for token endpoint auth.
367    ///
368    /// This error occurs when the authorization server doesn't support the 'ES256' signing
369    /// algorithm for token endpoint authentication, which is required for AT Protocol.
370    #[error(
371        "error-atproto-oauth-auth-server-8 Token endpoint auth signing algorithm values must include 'ES256'"
372    )]
373    TokenEndpointAuthSigningAlgValuesMustIncludeES256,
374
375    /// Error when the 'atproto' scope is not supported.
376    ///
377    /// This error occurs when the authorization server doesn't support the 'atproto'
378    /// scope, which is required for accessing AT Protocol resources.
379    #[error("error-atproto-oauth-auth-server-9 Scopes supported must include 'atproto'")]
380    ScopesSupportedMustIncludeAtProto,
381
382    /// Error when the 'transition:generic' scope is not supported.
383    ///
384    /// This error occurs when the authorization server doesn't support the 'transition:generic'
385    /// scope, which is required for transitional functionality in AT Protocol.
386    #[error(
387        "error-atproto-oauth-auth-server-10 Scopes supported must include 'transition:generic'"
388    )]
389    ScopesSupportedMustIncludeTransitionGeneric,
390
391    /// Error when the 'ES256' DPoP signing algorithm is not supported.
392    ///
393    /// This error occurs when the authorization server doesn't support the 'ES256'
394    /// signing algorithm for DPoP proofs, which is required for AT Protocol security.
395    #[error(
396        "error-atproto-oauth-auth-server-11 DPoP signing algorithm values supported must include 'ES256'"
397    )]
398    DpopSigningAlgValuesSupportedMustIncludeES256,
399
400    /// Error when required server features are not supported.
401    ///
402    /// This error occurs when the authorization server doesn't support required features
403    /// such as pushed authorization requests, client ID metadata, or authorization response parameters.
404    #[error(
405        "error-atproto-oauth-auth-server-12 Authorization response parameters, pushed requests, client ID metadata must be supported"
406    )]
407    RequiredServerFeaturesMustBeSupported,
408}
409
410/// Represents errors that can occur during DPoP (Demonstration of Proof-of-Possession) operations.
411///
412/// These errors occur when creating, validating, or using DPoP proofs for OAuth security.
413#[derive(Debug, Error)]
414pub enum DpopError {
415    /// Error when server returns an unexpected OAuth error.
416    ///
417    /// This error occurs when the server returns an OAuth error other than
418    /// the expected "use_dpop_nonce" error during DPoP nonce handling.
419    #[error("error-atproto-oauth-dpop-1 Unexpected OAuth error: {error}")]
420    UnexpectedOAuthError {
421        /// The unexpected error returned by the server
422        error: String,
423    },
424
425    /// Error when DPoP-Nonce header is missing from server response.
426    ///
427    /// This error occurs when the server indicates that a DPoP nonce is required
428    /// but fails to include the DPoP-Nonce header in the response.
429    #[error("error-atproto-oauth-dpop-2 Missing DPoP-Nonce response header")]
430    MissingDpopNonceHeader,
431
432    /// Error when DPoP token minting fails.
433    ///
434    /// This error occurs when the system fails to create (mint) a DPoP proof token,
435    /// typically due to cryptographic key issues or claim validation problems.
436    #[error("error-atproto-oauth-dpop-3 DPoP token minting failed: {0:?}")]
437    TokenMintingFailed(anyhow::Error),
438
439    /// Error when HTTP header creation fails.
440    ///
441    /// This error occurs when the DPoP proof token cannot be converted into
442    /// a valid HTTP header value, typically due to invalid characters.
443    #[error("error-atproto-oauth-dpop-4 HTTP header creation failed: {0:?}")]
444    HeaderCreationFailed(reqwest::header::InvalidHeaderValue),
445
446    /// Error when response body JSON parsing fails.
447    ///
448    /// This error occurs when the server response body cannot be properly
449    /// parsed as JSON, typically due to malformed content or network issues.
450    #[error("error-atproto-oauth-dpop-5 Response body JSON parsing failed: {0:?}")]
451    ResponseBodyParsingFailed(reqwest::Error),
452
453    /// Error when response body is not a valid JSON object.
454    ///
455    /// This error occurs when the server response body is valid JSON but
456    /// not in the expected object format for OAuth error responses.
457    #[error("error-atproto-oauth-dpop-6 Response body is not a valid JSON object")]
458    ResponseBodyObjectParsingFailed,
459}
460
461/// Error types that can occur when working with OAuth request storage operations
462#[derive(Debug, Error)]
463pub enum OAuthStorageError {
464    /// Occurs when cache lock acquisition fails during OAuth request retrieval operations
465    #[error(
466        "error-atproto-oauth-storage-1 Cache lock acquisition failed for get operation: {details}"
467    )]
468    CacheLockFailedGet {
469        /// Details about the lock failure
470        details: String,
471    },
472
473    /// Occurs when cache lock acquisition fails during OAuth request insertion operations
474    #[error(
475        "error-atproto-oauth-storage-2 Cache lock acquisition failed for insert operation: {details}"
476    )]
477    CacheLockFailedInsert {
478        /// Details about the lock failure
479        details: String,
480    },
481
482    /// Occurs when cache lock acquisition fails during OAuth request deletion operations
483    #[error(
484        "error-atproto-oauth-storage-3 Cache lock acquisition failed for delete operation: {details}"
485    )]
486    CacheLockFailedDelete {
487        /// Details about the lock failure
488        details: String,
489    },
490
491    /// Occurs when cache lock acquisition fails during expired OAuth request cleanup operations
492    #[error(
493        "error-atproto-oauth-storage-4 Cache lock acquisition failed for cleanup operation: {details}"
494    )]
495    CacheLockFailedCleanup {
496        /// Details about the lock failure
497        details: String,
498    },
499}