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

Commit 8b1c263

Browse files
feat(widgets): add widgets (#167)
1 parent a83cca3 commit 8b1c263

6 files changed

Lines changed: 194 additions & 1 deletion

File tree

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub mod portal;
1515
pub mod roles;
1616
pub mod sso;
1717
pub mod user_management;
18+
pub mod widgets;
1819

1920
pub use crate::core::*;
2021
pub use crate::workos::*;

src/portal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub struct Portal<'a> {
1818
}
1919

2020
impl<'a> Portal<'a> {
21-
/// Returns a new [`AdminPortal`] instance for the provided WorkOS client.
21+
/// Returns a new [`Portal`] instance for the provided WorkOS client.
2222
pub fn new(workos: &'a WorkOs) -> Self {
2323
Self { workos }
2424
}

src/widgets.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//! A module for interacting with the WorkOS Widgets API.
2+
//!
3+
//! [WorkOS Docs: Widgets Guide](https://workos.com/docs/authkit/widgets)
4+
5+
mod operations;
6+
7+
pub use operations::*;
8+
9+
use crate::WorkOs;
10+
11+
/// Widgets.
12+
///
13+
/// [WorkOS Docs: Widgets Guide](https://workos.com/docs/authkit/widgets)
14+
pub struct Widgets<'a> {
15+
workos: &'a WorkOs,
16+
}
17+
18+
impl<'a> Widgets<'a> {
19+
/// Returns a new [`Widget`] instance for the provided WorkOS client.
20+
pub fn new(workos: &'a WorkOs) -> Self {
21+
Self { workos }
22+
}
23+
}

src/widgets/operations.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
mod generate_token;
2+
3+
pub use generate_token::*;
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
use async_trait::async_trait;
2+
use serde::{Deserialize, Serialize};
3+
4+
use crate::organizations::OrganizationId;
5+
use crate::user_management::UserId;
6+
use crate::widgets::Widgets;
7+
use crate::{ResponseExt, WorkOsResult};
8+
9+
/// The scope of a widget token.
10+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
11+
pub enum WidgetTokenScope {
12+
/// Manage users.
13+
#[serde(rename = "widgets:users-table:manage")]
14+
ManageUsers,
15+
16+
/// Manage SSO.
17+
#[serde(rename = "widgets:sso:manage")]
18+
ManageSso,
19+
20+
/// Manage domain verification.
21+
#[serde(rename = "widgets:domain-verification:manage")]
22+
ManageDomainVerification,
23+
}
24+
25+
/// The parameters for [`GenerateToken`].
26+
#[derive(Debug, Serialize)]
27+
pub struct GenerateTokenParams<'a> {
28+
/// An Organization identifier.
29+
pub organization_id: &'a OrganizationId,
30+
31+
/// A User identifier.
32+
pub user_id: Option<&'a UserId>,
33+
34+
/// Scopes to include in the widget token.
35+
pub scopes: Option<Vec<WidgetTokenScope>>,
36+
}
37+
38+
/// The response for [`GenerateToken`].
39+
#[derive(Debug, Deserialize)]
40+
pub struct GenerateTokenResponse {
41+
/// An ephemeral token to access WorkOS widgets.
42+
pub token: String,
43+
}
44+
45+
/// An error returned from [`GenerateToken`].
46+
#[derive(Debug)]
47+
pub enum GenerateTokenError {}
48+
49+
/// [WorkOS Docs: Generate a Widget token](https://workos.com/docs/reference/widgets/get-token)
50+
#[async_trait]
51+
pub trait GenerateToken {
52+
/// Generate a widget token scoped to an organization and user with the specified scopes.
53+
///
54+
/// [WorkOS Docs: Generate a Widget token](https://workos.com/docs/reference/widgets/get-token)
55+
///
56+
/// # Examples
57+
///
58+
/// ```
59+
/// # use workos::WorkOsResult;
60+
/// # use workos::organizations::OrganizationId;
61+
/// # use workos::user_management::UserId;
62+
/// # use workos::widgets::*;
63+
/// use workos::{ApiKey, WorkOs};
64+
///
65+
/// # async fn run() -> WorkOsResult<(), GenerateTokenError> {
66+
/// let workos = WorkOs::new(&ApiKey::from("sk_example_123456789"));
67+
///
68+
/// let GenerateTokenResponse { token } = workos
69+
/// .widgets()
70+
/// .generate_token(&GenerateTokenParams {
71+
/// organization_id: &OrganizationId::from("org_01EHZNVPK3SFK441A1RGBFSHRT"),
72+
/// user_id: Some(&UserId::from("usr_01EHZNVPK3SFK441A1RGBFSHRT")),
73+
/// scopes: Some(vec![WidgetTokenScope::ManageUsers]),
74+
/// })
75+
/// .await?;
76+
/// # Ok(())
77+
/// # }
78+
/// ```
79+
async fn generate_token(
80+
&self,
81+
params: &GenerateTokenParams<'_>,
82+
) -> WorkOsResult<GenerateTokenResponse, GenerateTokenError>;
83+
}
84+
85+
#[async_trait]
86+
impl GenerateToken for Widgets<'_> {
87+
async fn generate_token(
88+
&self,
89+
params: &GenerateTokenParams<'_>,
90+
) -> WorkOsResult<GenerateTokenResponse, GenerateTokenError> {
91+
let url = self.workos.base_url().join("/widgets/token")?;
92+
93+
let response = self
94+
.workos
95+
.client()
96+
.post(url)
97+
.bearer_auth(self.workos.key())
98+
.json(&params)
99+
.send()
100+
.await?
101+
.handle_unauthorized_or_generic_error()
102+
.await?
103+
.json::<GenerateTokenResponse>()
104+
.await?;
105+
106+
Ok(response)
107+
}
108+
}
109+
110+
#[cfg(test)]
111+
mod test {
112+
use mockito::Matcher;
113+
use serde_json::json;
114+
use tokio;
115+
116+
use crate::organizations::OrganizationId;
117+
use crate::{ApiKey, WorkOs};
118+
119+
use super::*;
120+
121+
#[tokio::test]
122+
async fn it_calls_the_generate_token_endpoint() {
123+
let mut server = mockito::Server::new_async().await;
124+
125+
let workos = WorkOs::builder(&ApiKey::from("sk_example_123456789"))
126+
.base_url(&dbg!(server.url()))
127+
.unwrap()
128+
.build();
129+
130+
server
131+
.mock("POST", "/widgets/token")
132+
.match_header("Authorization", "Bearer sk_example_123456789")
133+
.match_body(Matcher::Json(json!({
134+
"organization_id": "org_01EHZNVPK3SFK441A1RGBFSHRT",
135+
"user_id": "usr_01EHZNVPK3SFK441A1RGBFSHRT",
136+
"scopes": ["widgets:users-table:manage"]
137+
})))
138+
.with_status(201)
139+
.with_body(
140+
json!({
141+
"token": "token"
142+
})
143+
.to_string(),
144+
)
145+
.create_async()
146+
.await;
147+
148+
let GenerateTokenResponse { token } = workos
149+
.widgets()
150+
.generate_token(&GenerateTokenParams {
151+
organization_id: &OrganizationId::from("org_01EHZNVPK3SFK441A1RGBFSHRT"),
152+
user_id: Some(&UserId::from("usr_01EHZNVPK3SFK441A1RGBFSHRT")),
153+
scopes: Some(vec![WidgetTokenScope::ManageUsers]),
154+
})
155+
.await
156+
.unwrap();
157+
158+
assert_eq!(token, "token".to_string())
159+
}
160+
}

src/workos.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::portal::Portal;
1010
use crate::roles::Roles;
1111
use crate::sso::Sso;
1212
use crate::user_management::UserManagement;
13+
use crate::widgets::Widgets;
1314

1415
/// The WorkOS client.
1516
#[derive(Clone)]
@@ -86,6 +87,11 @@ impl WorkOs {
8687
pub fn user_management(&self) -> UserManagement<'_> {
8788
UserManagement::new(self)
8889
}
90+
91+
/// Returns an [`Widgets`] instance.
92+
pub fn widgets(&self) -> Widgets<'_> {
93+
Widgets::new(self)
94+
}
8995
}
9096

9197
/// A builder for a WorkOS client.

0 commit comments

Comments
 (0)