Skip to main content

spiral_auth/
error.rs

1//! Failures of credential sources.
2
3use std::error::Error as StdError;
4use std::fmt::Display;
5
6use reqwest::{StatusCode, Url};
7
8/// A credential source could not supply a usable credential.
9#[derive(Debug, thiserror::Error)]
10pub enum CredentialError {
11    /// The source is misconfigured or supplied an unusable credential.
12    #[error("{0}")]
13    Invalid(String),
14    /// The authorization server or a platform identity endpoint rejected a request.
15    #[error("{url} returned {status}: {body}")]
16    Rejected {
17        url: Url,
18        status: StatusCode,
19        body: String,
20    },
21    /// A URL for a credential request is malformed.
22    #[error(transparent)]
23    Url(#[from] url::ParseError),
24    /// A credential request could not be sent or its response read.
25    #[error(transparent)]
26    Http(#[from] reqwest::Error),
27    /// A credential response or saved session was not the expected JSON.
28    #[error(transparent)]
29    Json(#[from] serde_json::Error),
30    /// A saved session could not be read or written.
31    #[error(transparent)]
32    Io(#[from] std::io::Error),
33    /// A credential source supplied by the host application failed.
34    #[error(transparent)]
35    External(Box<dyn StdError + Send + Sync>),
36}
37
38/// The result of consulting a credential source.
39pub type CredentialResult<T> = Result<T, CredentialError>;
40
41impl CredentialError {
42    /// A source is misconfigured or supplied an unusable credential.
43    pub fn invalid(message: impl Display) -> Self {
44        Self::Invalid(message.to_string())
45    }
46
47    /// Wrap the failure of a credential source implemented outside this crate.
48    pub fn external(error: impl Into<Box<dyn StdError + Send + Sync>>) -> Self {
49        Self::External(error.into())
50    }
51}
52
53impl From<reqwest_middleware::Error> for CredentialError {
54    fn from(error: reqwest_middleware::Error) -> Self {
55        match error {
56            reqwest_middleware::Error::Reqwest(error) => Self::Http(error),
57            reqwest_middleware::Error::Middleware(error) => Self::External(error.into()),
58        }
59    }
60}