Skip to main content

better_auth_api/plugins/admin/
native.rs

1use super::{AdminConfig, AdminPlugin, AdminUserResponse, CreateAdminUser, MESSAGE_CREATE_USERS};
2use better_auth_core::{
3    AuthContext, AuthError, AuthRequest, AuthResponse, AuthResult, AuthSchema, HttpMethod,
4    NativeRequest, wire::UserView,
5};
6use std::collections::HashMap;
7
8/// Administrator operations bound to the registered plugin configuration.
9/// Dynamic URL policy resolves supplied host headers or the configured fallback before any writes.
10pub struct AdminApi<'a, S: AuthSchema> {
11    plugin: AdminPlugin,
12    context: &'a AuthContext<S>,
13}
14impl<'a, S: AuthSchema> AdminApi<'a, S> {
15    pub fn from_context(context: &'a AuthContext<S>) -> AuthResult<Self> {
16        let config = context
17            .extensions
18            .get::<AdminConfig>()
19            .ok_or_else(|| AuthError::config("AdminPlugin is not registered"))?;
20        Ok(Self {
21            plugin: AdminPlugin::with_config(config.clone()),
22            context,
23        })
24    }
25
26    /// Omit headers only for trusted server provisioning. Any supplied headers require a session.
27    pub async fn create_user(
28        &self,
29        body: &CreateAdminUser,
30        headers: Option<&HashMap<String, String>>,
31    ) -> AuthResult<AdminUserResponse<UserView>> {
32        self.context
33            .with_native_context(
34                NativeRequest {
35                    request: None,
36                    headers,
37                },
38                |context| async move {
39                    let request = AuthRequest::new(HttpMethod::Post, "/admin/create-user")
40                        .with_optional_headers(headers.cloned());
41                    let mut hook_context =
42                        better_auth_core::RequestHookContext::from_request(&request)?;
43                    hook_context.body =
44                        better_auth_core::FieldValue::from_json(serde_json::to_value(body)?)?;
45                    better_auth_core::with_request_hook_context_value(hook_context, async {
46                        let session = if headers.is_some() {
47                            let session = context
48                                .require_authoritative_session(&request)
49                                .await
50                                .map_err(|error| match error {
51                                    AuthError::Unauthenticated => {
52                                        AuthError::from(AuthResponse::new(401))
53                                    }
54                                    error => error,
55                                })?;
56                            self.plugin.authorize(
57                                &session.0,
58                                "user",
59                                "create",
60                                MESSAGE_CREATE_USERS,
61                            )?;
62                            Some(session)
63                        } else {
64                            None
65                        };
66                        super::handlers::create_user_core(
67                            body,
68                            None,
69                            session,
70                            &self.plugin.config,
71                            &context,
72                        )
73                        .await
74                    })
75                    .await
76                },
77            )
78            .await
79    }
80}