greentic_oauth_core/
provider.rs

1use std::{error::Error, fmt};
2
3use crate::types::{OAuthFlowRequest, OAuthFlowResult, TokenHandleClaims, TokenSet};
4
5/// Convenience alias for provider interactions.
6pub type ProviderResult<T> = Result<T, ProviderError>;
7
8/// High-level trait all OAuth providers must implement for the broker.
9pub trait Provider: Send + Sync {
10    /// Authorization endpoint for the provider.
11    fn auth_url(&self) -> &str;
12    /// Token endpoint for the provider.
13    fn token_url(&self) -> &str;
14    /// Registered redirect URI the provider will callback with.
15    fn redirect_uri(&self) -> &str;
16    /// Build an authorization redirect response for a flow request.
17    fn build_authorize_redirect(
18        &self,
19        request: &OAuthFlowRequest,
20    ) -> ProviderResult<OAuthFlowResult>;
21    /// Exchange an authorization code for tokens.
22    fn exchange_code(&self, claims: &TokenHandleClaims, code: &str) -> ProviderResult<TokenSet>;
23    /// Refresh an existing token set.
24    fn refresh(&self, claims: &TokenHandleClaims, refresh_token: &str) -> ProviderResult<TokenSet>;
25    /// Revoke an access or refresh token.
26    fn revoke(&self, claims: &TokenHandleClaims, token: &str) -> ProviderResult<()>;
27}
28
29/// Lightweight error type for provider implementers.
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct ProviderError {
32    kind: ProviderErrorKind,
33    message: Option<String>,
34}
35
36impl ProviderError {
37    /// Create a new error for the given kind with an optional detail message.
38    pub fn new(kind: ProviderErrorKind, message: impl Into<Option<String>>) -> Self {
39        Self {
40            kind,
41            message: message.into(),
42        }
43    }
44
45    /// Access the classification of this error.
46    pub fn kind(&self) -> ProviderErrorKind {
47        self.kind
48    }
49
50    /// Optional descriptive message supplied when the error was created.
51    pub fn message(&self) -> Option<&str> {
52        self.message.as_deref()
53    }
54}
55
56impl fmt::Display for ProviderError {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        match &self.message {
59            Some(message) => write!(f, "{}: {}", self.kind, message),
60            None => write!(f, "{}", self.kind),
61        }
62    }
63}
64
65impl Error for ProviderError {}
66
67/// Classification of errors returned by providers.
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub enum ProviderErrorKind {
70    /// Misconfiguration or invalid request was issued.
71    Configuration,
72    /// Upstream transport or network error.
73    Transport,
74    /// Provider rejected the request due to lack of permissions.
75    Authorization,
76    /// Provider returned an unexpected payload.
77    InvalidResponse,
78    /// The operation is not supported by the provider implementation.
79    Unsupported,
80    /// Catch-all for miscellaneous failures.
81    Other,
82}
83
84impl fmt::Display for ProviderErrorKind {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        let label = match self {
87            ProviderErrorKind::Configuration => "configuration error",
88            ProviderErrorKind::Transport => "transport error",
89            ProviderErrorKind::Authorization => "authorization error",
90            ProviderErrorKind::InvalidResponse => "invalid response",
91            ProviderErrorKind::Unsupported => "unsupported operation",
92            ProviderErrorKind::Other => "provider error",
93        };
94        f.write_str(label)
95    }
96}