systemprompt-oauth 0.10.2

OAuth 2.0 / OIDC with PKCE, token introspection, and audience/issuer validation for systemprompt.io AI governance infrastructure. WebAuthn and JWT auth for the MCP governance pipeline.
Documentation
//! User creation/lookup wrapper used by `WebAuthn` flows.

use crate::error::OauthResult as Result;
use std::sync::Arc;
use systemprompt_traits::UserProvider;

pub struct UserCreationService {
    user_provider: Arc<dyn UserProvider>,
}

impl std::fmt::Debug for UserCreationService {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("UserCreationService").finish()
    }
}

impl UserCreationService {
    pub fn new(user_provider: Arc<dyn UserProvider>) -> Self {
        Self { user_provider }
    }

    pub async fn find_or_create_user_with_webauthn_registration(
        &self,
        username: &str,
        email: &str,
        full_name: Option<&str>,
        roles: Option<Vec<String>>,
    ) -> Result<String> {
        if let Some(existing_user) = self
            .user_provider
            .find_by_email(email)
            .await
            .map_err(|e| crate::error::OauthError::Internal(format!("{}", e)))?
        {
            return Ok(existing_user.id.as_str().to_string());
        }

        let roles = roles.unwrap_or_else(|| vec!["user".to_string()]);

        let user = self
            .user_provider
            .create_user(username, email, full_name)
            .await
            .map_err(|e| crate::error::OauthError::Internal(format!("{}", e)))?;

        self.user_provider
            .assign_roles(&user.id, &roles)
            .await
            .map_err(|e| crate::error::OauthError::Internal(format!("{}", e)))?;

        Ok(user.id.as_str().to_string())
    }

    pub async fn create_user_with_webauthn_registration(
        &self,
        username: &str,
        email: &str,
        full_name: Option<&str>,
    ) -> Result<String> {
        if self
            .user_provider
            .find_by_email(email)
            .await
            .map_err(|e| crate::error::OauthError::Internal(format!("{}", e)))?
            .is_some()
        {
            return Err(crate::error::OauthError::Internal(
                "email_already_registered".to_string(),
            ));
        }

        if self
            .user_provider
            .find_by_name(username)
            .await
            .map_err(|e| crate::error::OauthError::Internal(format!("{}", e)))?
            .is_some()
        {
            return Err(crate::error::OauthError::Internal(
                "username_already_taken".to_string(),
            ));
        }

        self.find_or_create_user_with_webauthn_registration(username, email, full_name, None)
            .await
    }
}