aauth_protocol/error.rs
1//! Errors. A signature or token that does not verify carries the registered
2//! code a peer is answered with; everything else is an [`Error`] variant
3//! naming what kind of thing went wrong.
4
5/// An HTTP signature that does not verify, answered with `401` and
6/// `Signature-Error: error=<code>` ([`SignatureError::header_value`]).
7#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
8#[error("{code}: {detail}")]
9pub struct SignatureError {
10 /// The registered code: `invalid_signature`, `invalid_input`,
11 /// `invalid_key`, `unknown_key`, `invalid_jwt`, `unsupported_scheme`,
12 /// `unsupported_algorithm` or `clock_skew`.
13 pub code: &'static str,
14 /// A human-readable explanation, for logs. Not part of the protocol.
15 pub detail: String,
16}
17
18impl SignatureError {
19 /// A signature error with `code` and `detail`.
20 pub fn new(code: &'static str, detail: impl Into<String>) -> Self {
21 Self {
22 code,
23 detail: detail.into(),
24 }
25 }
26
27 /// The `Signature-Error` response header value.
28 pub fn header_value(&self) -> String {
29 format!("error={}", self.code)
30 }
31}
32
33/// A token that does not verify.
34#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
35#[error("{code}: {detail}")]
36pub struct TokenError {
37 /// The code: `invalid_agent_token`, `invalid_person_token`,
38 /// `invalid_auth_token`, `malformed_token`, `unsupported_token_type`,
39 /// `token_type_not_accepted`, `token_expired`, `key_binding_failed`,
40 /// `aud_mismatch`, `clock_skew` or `invalid_configuration`.
41 ///
42 /// `token_expired` and `clock_skew` are reported only once the issuer's
43 /// signature has verified, so a presenter can act on them: refresh the
44 /// token, or wait out the skew.
45 pub code: &'static str,
46 /// A human-readable explanation, for logs. Not part of the protocol.
47 pub detail: String,
48}
49
50impl TokenError {
51 /// A token error with `code` and `detail`.
52 pub fn new(code: &'static str, detail: impl Into<String>) -> Self {
53 Self {
54 code,
55 detail: detail.into(),
56 }
57 }
58}
59
60/// Everything else that can go wrong.
61#[derive(Debug, thiserror::Error)]
62#[non_exhaustive]
63pub enum Error {
64 /// An HTTP signature did not verify.
65 #[error(transparent)]
66 Signature(#[from] SignatureError),
67 /// A token did not verify.
68 #[error(transparent)]
69 Token(#[from] TokenError),
70 /// A key that cannot be read or used.
71 #[error("invalid key: {0}")]
72 Key(String),
73 /// A URL that cannot be parsed, or that this client refuses to call.
74 #[error("url: {0}")]
75 Url(String),
76 /// A metadata document or key set that cannot be fetched, read or trusted.
77 #[error("discovery: {0}")]
78 Discovery(String),
79 /// A peer that could not be reached, failed, or answered with something
80 /// unusable. Never a decision: a refusal is an answer, not an error.
81 #[error("http: {0}")]
82 Http(String),
83 /// A value that is not what the protocol requires.
84 #[error("invalid: {0}")]
85 Invalid(String),
86}
87
88/// `Result` with this crate's [`Error`].
89pub type Result<T, E = Error> = std::result::Result<T, E>;