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