Skip to content
This repository was archived by the owner on May 13, 2026. It is now read-only.

Commit 69daf51

Browse files
feat(user-management): add organization membership (#98)
* feat(user-management): add organization memberships * refactor: cleanup --------- Co-authored-by: Sam Lijin <sam@boundaryml.com>
1 parent 2841e19 commit 69daf51

19 files changed

Lines changed: 1157 additions & 23 deletions

src/user_management/operations.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ mod authenticate_with_password;
66
mod authenticate_with_refresh_token;
77
mod authenticate_with_totp;
88
mod create_magic_auth;
9+
mod create_organization_membership;
910
mod create_password_reset;
1011
mod create_user;
12+
mod deactivate_organization_membership;
13+
mod delete_organization_membership;
1114
mod delete_user;
1215
mod enroll_auth_factor;
1316
mod find_invitation_by_token;
@@ -18,16 +21,20 @@ mod get_jwks;
1821
mod get_jwks_url;
1922
mod get_logout_url;
2023
mod get_magic_auth;
24+
mod get_organization_membership;
2125
mod get_password_reset;
2226
mod get_user;
2327
mod get_user_by_external_id;
2428
mod get_user_identities;
2529
mod list_auth_factors;
2630
mod list_invitations;
31+
mod list_organization_memberships;
2732
mod list_users;
33+
mod reactivate_organization_membership;
2834
mod reset_password;
2935
mod revoke_invitation;
3036
mod send_invitation;
37+
mod update_organization_membership;
3138
mod update_user;
3239

3340
pub use accept_invitation::*;
@@ -38,8 +45,11 @@ pub use authenticate_with_password::*;
3845
pub use authenticate_with_refresh_token::*;
3946
pub use authenticate_with_totp::*;
4047
pub use create_magic_auth::*;
48+
pub use create_organization_membership::*;
4149
pub use create_password_reset::*;
4250
pub use create_user::*;
51+
pub use deactivate_organization_membership::*;
52+
pub use delete_organization_membership::*;
4353
pub use delete_user::*;
4454
pub use enroll_auth_factor::*;
4555
pub use find_invitation_by_token::*;
@@ -50,14 +60,18 @@ pub use get_jwks::*;
5060
pub use get_jwks_url::*;
5161
pub use get_logout_url::*;
5262
pub use get_magic_auth::*;
63+
pub use get_organization_membership::*;
5364
pub use get_password_reset::*;
5465
pub use get_user::*;
5566
pub use get_user_by_external_id::*;
5667
pub use get_user_identities::*;
5768
pub use list_auth_factors::*;
5869
pub use list_invitations::*;
70+
pub use list_organization_memberships::*;
5971
pub use list_users::*;
72+
pub use reactivate_organization_membership::*;
6073
pub use reset_password::*;
6174
pub use revoke_invitation::*;
6275
pub use send_invitation::*;
76+
pub use update_organization_membership::*;
6377
pub use update_user::*;

src/user_management/operations/create_magic_auth.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ impl CreateMagicAuth for UserManagement<'_> {
6565
params: &CreateMagicAuthParams<'_>,
6666
) -> WorkOsResult<MagicAuth, CreateMagicAuthError> {
6767
let url = self.workos.base_url().join("/user_management/magic_auth")?;
68-
let user = self
68+
let magic_auth = self
6969
.workos
7070
.client()
7171
.post(url)
@@ -78,7 +78,7 @@ impl CreateMagicAuth for UserManagement<'_> {
7878
.json::<MagicAuth>()
7979
.await?;
8080

81-
Ok(user)
81+
Ok(magic_auth)
8282
}
8383
}
8484

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
use async_trait::async_trait;
2+
use serde::Serialize;
3+
use thiserror::Error;
4+
5+
use crate::organizations::OrganizationId;
6+
use crate::user_management::{OrganizationMembership, UserId, UserManagement};
7+
use crate::{ResponseExt, WorkOsError, WorkOsResult};
8+
9+
/// The parameters for [`CreateOrganizationMembership`].
10+
#[derive(Debug, Serialize)]
11+
pub struct CreateOrganizationMembershipParams<'a> {
12+
/// The ID of the user.
13+
pub user_id: &'a UserId,
14+
15+
/// The ID of the organization which the user belongs to.
16+
pub organization_id: &'a OrganizationId,
17+
18+
/// The unique role identifier.
19+
///
20+
/// Defaults to `member`.
21+
pub role_slug: Option<&'a str>,
22+
}
23+
24+
/// An error returned from [`CreateOrganizationMembership`].
25+
#[derive(Debug, Error)]
26+
pub enum CreateOrganizationMembershipError {}
27+
28+
impl From<CreateOrganizationMembershipError> for WorkOsError<CreateOrganizationMembershipError> {
29+
fn from(err: CreateOrganizationMembershipError) -> Self {
30+
Self::Operation(err)
31+
}
32+
}
33+
34+
/// [WorkOS Docs: Create an organization membership](https://workos.com/docs/reference/user-management/organization-membership/create)
35+
#[async_trait]
36+
pub trait CreateOrganizationMembership {
37+
/// Creates a new `active` organization membership for the given organization and user.
38+
///
39+
/// Calling this API with an organization and user that match an `inactive` organization membership will activate the membership with the specified role.
40+
///
41+
/// [WorkOS Docs: Create an organization membership](https://workos.com/docs/reference/user-management/organization-membership/create)
42+
///
43+
/// # Examples
44+
///
45+
/// ```
46+
/// # use workos::WorkOsResult;
47+
/// # use workos::organizations::OrganizationId;
48+
/// # use workos::user_management::*;
49+
/// use workos::{ApiKey, WorkOs};
50+
///
51+
/// # async fn run() -> WorkOsResult<(), CreateOrganizationMembershipError> {
52+
/// let workos = WorkOs::new(&ApiKey::from("sk_example_123456789"));
53+
///
54+
/// let organization_membership = workos
55+
/// .user_management()
56+
/// .create_organization_membership(&CreateOrganizationMembershipParams {
57+
/// user_id: &UserId::from("user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E"),
58+
/// organization_id: &OrganizationId::from("org_01E4ZCR3C56J083X43JQXF3JK5"),
59+
/// role_slug: Some("admin"),
60+
/// })
61+
/// .await?;
62+
/// # Ok(())
63+
/// # }
64+
/// ```
65+
async fn create_organization_membership(
66+
&self,
67+
params: &CreateOrganizationMembershipParams<'_>,
68+
) -> WorkOsResult<OrganizationMembership, CreateOrganizationMembershipError>;
69+
}
70+
71+
#[async_trait]
72+
impl CreateOrganizationMembership for UserManagement<'_> {
73+
async fn create_organization_membership(
74+
&self,
75+
params: &CreateOrganizationMembershipParams<'_>,
76+
) -> WorkOsResult<OrganizationMembership, CreateOrganizationMembershipError> {
77+
let url = self
78+
.workos
79+
.base_url()
80+
.join("/user_management/organization_membership")?;
81+
let organization_membership = self
82+
.workos
83+
.client()
84+
.post(url)
85+
.bearer_auth(self.workos.key())
86+
.json(&params)
87+
.send()
88+
.await?
89+
.handle_unauthorized_or_generic_error()
90+
.await?
91+
.json::<OrganizationMembership>()
92+
.await?;
93+
94+
Ok(organization_membership)
95+
}
96+
}
97+
98+
#[cfg(test)]
99+
mod test {
100+
use serde_json::json;
101+
use tokio;
102+
103+
use crate::user_management::OrganizationMembershipId;
104+
use crate::{ApiKey, WorkOs};
105+
106+
use super::*;
107+
108+
#[tokio::test]
109+
async fn it_calls_the_create_organization_membership_endpoint() {
110+
let mut server = mockito::Server::new_async().await;
111+
112+
let workos = WorkOs::builder(&ApiKey::from("sk_example_123456789"))
113+
.base_url(&server.url())
114+
.unwrap()
115+
.build();
116+
117+
server
118+
.mock("POST", "/user_management/organization_membership")
119+
.match_header("Authorization", "Bearer sk_example_123456789")
120+
.with_status(201)
121+
.with_body(
122+
json!({
123+
"object": "organization_membership",
124+
"id": "om_01E4ZCR3C56J083X43JQXF3JK5",
125+
"user_id": "user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E",
126+
"organization_id": "org_01E4ZCR3C56J083X43JQXF3JK5",
127+
"role": {
128+
"slug": "admin"
129+
},
130+
"status": "active",
131+
"created_at": "2021-06-25T19:07:33.155Z",
132+
"updated_at": "2021-06-25T19:07:33.155Z"
133+
})
134+
.to_string(),
135+
)
136+
.create_async()
137+
.await;
138+
139+
let organization_membership = workos
140+
.user_management()
141+
.create_organization_membership(&CreateOrganizationMembershipParams {
142+
user_id: &UserId::from("user_01E4ZCR3C5A4QZ2Z2JQXGKZJ9E"),
143+
organization_id: &OrganizationId::from("org_01E4ZCR3C56J083X43JQXF3JK5"),
144+
role_slug: Some("admin"),
145+
})
146+
.await
147+
.unwrap();
148+
149+
assert_eq!(
150+
organization_membership.id,
151+
OrganizationMembershipId::from("om_01E4ZCR3C56J083X43JQXF3JK5")
152+
)
153+
}
154+
}

src/user_management/operations/create_password_reset.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl CreatePasswordReset for UserManagement<'_> {
105105
.workos
106106
.base_url()
107107
.join("/user_management/password_reset")?;
108-
let user = self
108+
let password_reset = self
109109
.workos
110110
.client()
111111
.post(url)
@@ -119,7 +119,7 @@ impl CreatePasswordReset for UserManagement<'_> {
119119
.json::<PasswordReset>()
120120
.await?;
121121

122-
Ok(user)
122+
Ok(password_reset)
123123
}
124124
}
125125

0 commit comments

Comments
 (0)