Skip to main content

better_auth_api/plugins/organization/
mod.rs

1pub mod config;
2pub mod handlers;
3pub mod rbac;
4pub mod types;
5
6use async_trait::async_trait;
7use better_auth_core::adapters::DatabaseAdapter;
8use better_auth_core::error::AuthResult;
9use better_auth_core::plugin::{AuthContext, AuthPlugin, AuthRoute};
10use better_auth_core::types::{AuthRequest, AuthResponse, HttpMethod};
11pub use config::OrganizationConfig;
12
13/// Organization plugin for multi-tenancy support
14pub struct OrganizationPlugin {
15    config: OrganizationConfig,
16}
17
18impl OrganizationPlugin {
19    pub fn new() -> Self {
20        Self {
21            config: OrganizationConfig::default(),
22        }
23    }
24
25    pub fn with_config(config: OrganizationConfig) -> Self {
26        Self { config }
27    }
28
29    // Builder methods
30    pub fn allow_user_to_create_organization(mut self, allow: bool) -> Self {
31        self.config.allow_user_to_create_organization = allow;
32        self
33    }
34
35    pub fn organization_limit(mut self, limit: usize) -> Self {
36        self.config.organization_limit = Some(limit);
37        self
38    }
39
40    pub fn membership_limit(mut self, limit: usize) -> Self {
41        self.config.membership_limit = Some(limit);
42        self
43    }
44
45    pub fn creator_role(mut self, role: impl Into<String>) -> Self {
46        self.config.creator_role = role.into();
47        self
48    }
49
50    pub fn invitation_expires_in(mut self, seconds: u64) -> Self {
51        self.config.invitation_expires_in = seconds;
52        self
53    }
54
55    pub fn invitation_limit(mut self, limit: usize) -> Self {
56        self.config.invitation_limit = Some(limit);
57        self
58    }
59
60    pub fn disable_organization_deletion(mut self, disable: bool) -> Self {
61        self.config.disable_organization_deletion = disable;
62        self
63    }
64}
65
66impl Default for OrganizationPlugin {
67    fn default() -> Self {
68        Self::new()
69    }
70}
71
72#[async_trait]
73impl<DB: DatabaseAdapter> AuthPlugin<DB> for OrganizationPlugin {
74    fn name(&self) -> &'static str {
75        "organization"
76    }
77
78    fn routes(&self) -> Vec<AuthRoute> {
79        vec![
80            // Organization CRUD
81            AuthRoute::post("/organization/create", "create_organization"),
82            AuthRoute::post("/organization/update", "update_organization"),
83            AuthRoute::post("/organization/delete", "delete_organization"),
84            AuthRoute::get("/organization/list", "list_organizations"),
85            AuthRoute::get(
86                "/organization/get-full-organization",
87                "get_full_organization",
88            ),
89            AuthRoute::post("/organization/check-slug", "check_slug"),
90            AuthRoute::post("/organization/set-active", "set_active_organization"),
91            AuthRoute::post("/organization/leave", "leave_organization"),
92            // Member management
93            AuthRoute::get("/organization/get-active-member", "get_active_member"),
94            AuthRoute::get("/organization/list-members", "list_members"),
95            AuthRoute::post("/organization/remove-member", "remove_member"),
96            AuthRoute::post("/organization/update-member-role", "update_member_role"),
97            // Invitations
98            AuthRoute::post("/organization/invite-member", "invite_member"),
99            AuthRoute::get("/organization/get-invitation", "get_invitation"),
100            AuthRoute::get("/organization/list-invitations", "list_invitations"),
101            AuthRoute::get(
102                "/organization/list-user-invitations",
103                "list_user_invitations",
104            ),
105            AuthRoute::post("/organization/accept-invitation", "accept_invitation"),
106            AuthRoute::post("/organization/reject-invitation", "reject_invitation"),
107            AuthRoute::post("/organization/cancel-invitation", "cancel_invitation"),
108            // Permission check
109            AuthRoute::post("/organization/has-permission", "has_permission"),
110        ]
111    }
112
113    async fn on_request(
114        &self,
115        req: &AuthRequest,
116        ctx: &AuthContext<DB>,
117    ) -> AuthResult<Option<AuthResponse>> {
118        match (req.method(), req.path()) {
119            // Organization CRUD
120            (HttpMethod::Post, "/organization/create") => Ok(Some(
121                handlers::org::handle_create_organization(req, ctx, &self.config).await?,
122            )),
123            (HttpMethod::Post, "/organization/update") => Ok(Some(
124                handlers::org::handle_update_organization(req, ctx, &self.config).await?,
125            )),
126            (HttpMethod::Post, "/organization/delete") => Ok(Some(
127                handlers::org::handle_delete_organization(req, ctx, &self.config).await?,
128            )),
129            (HttpMethod::Get, "/organization/list") => Ok(Some(
130                handlers::org::handle_list_organizations(req, ctx).await?,
131            )),
132            (HttpMethod::Get, "/organization/get-full-organization") => Ok(Some(
133                handlers::org::handle_get_full_organization(req, ctx).await?,
134            )),
135            (HttpMethod::Post, "/organization/check-slug") => {
136                Ok(Some(handlers::org::handle_check_slug(req, ctx).await?))
137            }
138            (HttpMethod::Post, "/organization/set-active") => Ok(Some(
139                handlers::org::handle_set_active_organization(req, ctx).await?,
140            )),
141            (HttpMethod::Post, "/organization/leave") => Ok(Some(
142                handlers::org::handle_leave_organization(req, ctx).await?,
143            )),
144            // Member management
145            (HttpMethod::Get, "/organization/get-active-member") => Ok(Some(
146                handlers::member::handle_get_active_member(req, ctx).await?,
147            )),
148            (HttpMethod::Get, "/organization/list-members") => {
149                Ok(Some(handlers::member::handle_list_members(req, ctx).await?))
150            }
151            (HttpMethod::Post, "/organization/remove-member") => Ok(Some(
152                handlers::member::handle_remove_member(req, ctx, &self.config).await?,
153            )),
154            (HttpMethod::Post, "/organization/update-member-role") => Ok(Some(
155                handlers::member::handle_update_member_role(req, ctx, &self.config).await?,
156            )),
157            // Invitations
158            (HttpMethod::Post, "/organization/invite-member") => Ok(Some(
159                handlers::invitation::handle_invite_member(req, ctx, &self.config).await?,
160            )),
161            (HttpMethod::Get, "/organization/get-invitation") => Ok(Some(
162                handlers::invitation::handle_get_invitation(req, ctx).await?,
163            )),
164            (HttpMethod::Get, "/organization/list-invitations") => Ok(Some(
165                handlers::invitation::handle_list_invitations(req, ctx).await?,
166            )),
167            (HttpMethod::Get, "/organization/list-user-invitations") => Ok(Some(
168                handlers::invitation::handle_list_user_invitations(req, ctx).await?,
169            )),
170            (HttpMethod::Post, "/organization/accept-invitation") => Ok(Some(
171                handlers::invitation::handle_accept_invitation(req, ctx, &self.config).await?,
172            )),
173            (HttpMethod::Post, "/organization/reject-invitation") => Ok(Some(
174                handlers::invitation::handle_reject_invitation(req, ctx).await?,
175            )),
176            (HttpMethod::Post, "/organization/cancel-invitation") => Ok(Some(
177                handlers::invitation::handle_cancel_invitation(req, ctx, &self.config).await?,
178            )),
179            // Permission check
180            (HttpMethod::Post, "/organization/has-permission") => Ok(Some(
181                handlers::handle_has_permission(req, ctx, &self.config).await?,
182            )),
183            _ => Ok(None),
184        }
185    }
186}