A library for ATProtocol identities.
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}