provider_trait.rs 54 lignes · 2075 octets
use crate::error::AppError;
use async_trait::async_trait;

/// Information about a user obtained from an OAuth/OIDC provider.
#[derive(Debug, Clone)]
pub struct ProviderUserInfo {
    /// Unique identifier for the user as assigned by the OAuth provider.
    pub provider_user_id: String,
    /// Email address reported by the provider (may be absent).
    pub email: Option<String>,
    /// Whether the provider has verified the email address.
    pub email_verified: bool,
    /// Display name reported by the provider.
    pub display_name: Option<String>,
    /// URL of the user's avatar image reported by the provider.
    pub avatar_url: Option<String>,
}

/// Authorization URL and associated security state.
pub struct AuthorizationUrl {
    /// The full authorization URL to redirect the user to.
    pub url: String,
    /// CSRF state token to validate on callback.
    pub csrf_state: String,
    /// OIDC nonce value stored in the session for replay protection.
    pub nonce: Option<String>,
    /// PKCE code verifier stored in the session (S256 challenge sent to provider).
    pub pkce_verifier: Option<String>,
}

/// Trait that all OAuth/OIDC providers must implement.
/// This enables a modular architecture where new providers can be added
/// by implementing this trait without changing the core service.
#[async_trait]
pub trait OAuthProvider: Send + Sync {
    /// Unique name for this provider (e.g. "google", "github", "discord").
    fn name(&self) -> &str;

    /// Human-readable display name (e.g. "Google", "GitHub", "Discord").
    fn display_name(&self) -> &str;

    /// Build the authorization URL that the user will be redirected to.
    fn authorization_url(&self, redirect_uri: &str) -> Result<AuthorizationUrl, AppError>;

    /// Exchange an authorization code for user info.
    /// Validates the state, nonce, and PKCE verifier.
    async fn exchange_code(
        &self,
        code: &str,
        redirect_uri: &str,
        pkce_verifier: Option<&str>,
        nonce: Option<&str>,
    ) -> Result<ProviderUserInfo, AppError>;
}