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}