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

Commit 19e1207

Browse files
feat(user-management): add list auth factors (#48)
1 parent a56606f commit 19e1207

2 files changed

Lines changed: 160 additions & 0 deletions

File tree

src/user_management/operations.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod get_logout_url;
1515
mod get_magic_auth;
1616
mod get_password_reset;
1717
mod get_user_identities;
18+
mod list_auth_factors;
1819
mod list_users;
1920
mod reset_password;
2021

@@ -35,5 +36,6 @@ pub use get_logout_url::*;
3536
pub use get_magic_auth::*;
3637
pub use get_password_reset::*;
3738
pub use get_user_identities::*;
39+
pub use list_auth_factors::*;
3840
pub use list_users::*;
3941
pub use reset_password::*;
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
use async_trait::async_trait;
2+
use serde::Serialize;
3+
use thiserror::Error;
4+
5+
use crate::mfa::AuthenticationFactor;
6+
use crate::user_management::{UserId, UserManagement};
7+
use crate::{PaginatedList, PaginationParams, ResponseExt, WorkOsError, WorkOsResult};
8+
9+
/// Parameters for the [`ListAuthFactors`] function.
10+
#[derive(Debug, Serialize)]
11+
pub struct ListAuthFactorsParams<'a> {
12+
/// The user ID to list the authentication factors for.
13+
#[serde(skip)]
14+
pub id: &'a UserId,
15+
16+
/// The pagination parameters to use when listing authentication factors.
17+
#[serde(flatten)]
18+
pub pagination: PaginationParams<'a>,
19+
}
20+
21+
/// An error returned from [`ListAuthFactors`].
22+
#[derive(Debug, Error)]
23+
pub enum ListAuthFactorsError {}
24+
25+
impl From<ListAuthFactorsError> for WorkOsError<ListAuthFactorsError> {
26+
fn from(err: ListAuthFactorsError) -> Self {
27+
Self::Operation(err)
28+
}
29+
}
30+
31+
/// [WorkOS Docs: List authentication factors](https://workos.com/docs/reference/user-management/mfa/list-auth-factors)
32+
#[async_trait]
33+
pub trait ListAuthFactors {
34+
/// Lists the authentication factors for a user.
35+
///
36+
/// [WorkOS Docs: List authentication factors](https://workos.com/docs/reference/user-management/mfa/list-auth-factors)
37+
///
38+
/// # Examples
39+
///
40+
/// ```
41+
/// # use workos_sdk::WorkOsResult;
42+
/// # use workos_sdk::user_management::*;
43+
/// use workos_sdk::{ApiKey, WorkOs};
44+
///
45+
/// # async fn run() -> WorkOsResult<(), ()> {
46+
/// let workos = WorkOs::new(&ApiKey::from("sk_example_123456789"));
47+
///
48+
/// let paginated_auth_factors = workos
49+
/// .user_management()
50+
/// .list_auth_factors(&ListAuthFactorsParams {
51+
/// id: &UserId::from("user_01E4ZCR3C56J083X43JQXF3JK5"),
52+
/// pagination: Default::default(),
53+
/// })
54+
/// .await?;
55+
/// # Ok(())
56+
/// # }
57+
/// ```
58+
async fn list_auth_factors(
59+
&self,
60+
params: &ListAuthFactorsParams<'_>,
61+
) -> WorkOsResult<PaginatedList<AuthenticationFactor>, ()>;
62+
}
63+
64+
#[async_trait]
65+
impl ListAuthFactors for UserManagement<'_> {
66+
async fn list_auth_factors(
67+
&self,
68+
params: &ListAuthFactorsParams<'_>,
69+
) -> WorkOsResult<PaginatedList<AuthenticationFactor>, ()> {
70+
let url = self.workos.base_url().join(&format!(
71+
"/user_management/users/{}/auth_factors",
72+
params.id
73+
))?;
74+
75+
let organizations = self
76+
.workos
77+
.client()
78+
.get(url)
79+
.query(&params)
80+
.bearer_auth(self.workos.key())
81+
.send()
82+
.await?
83+
.handle_unauthorized_or_generic_error()?
84+
.json::<PaginatedList<AuthenticationFactor>>()
85+
.await?;
86+
87+
Ok(organizations)
88+
}
89+
}
90+
91+
#[cfg(test)]
92+
mod test {
93+
use mockito::Matcher;
94+
use serde_json::json;
95+
use tokio;
96+
97+
use crate::{ApiKey, WorkOs};
98+
99+
use super::*;
100+
101+
#[tokio::test]
102+
async fn it_calls_the_list_auth_factors_endpoint() {
103+
let mut server = mockito::Server::new_async().await;
104+
105+
let workos = WorkOs::builder(&ApiKey::from("sk_example_123456789"))
106+
.base_url(&server.url())
107+
.unwrap()
108+
.build();
109+
110+
server
111+
.mock("GET", "/user_management/users/user_01FVYZ5QM8N98T9ME5BCB2BBMJ/auth_factors")
112+
.match_query(Matcher::UrlEncoded("order".to_string(), "desc".to_string()))
113+
.match_header("Authorization", "Bearer sk_example_123456789")
114+
.with_status(200)
115+
.with_body(
116+
json!({
117+
"data": [
118+
{
119+
"object": "authentication_factor",
120+
"id": "auth_factor_01FVYZ5QM8N98T9ME5BCB2BBMJ",
121+
"created_at": "2022-02-15T15:14:19.392Z",
122+
"updated_at": "2022-02-15T15:14:19.392Z",
123+
"type": "totp",
124+
"totp": {
125+
"issuer": "Foo Corp",
126+
"user": "alan.turing@example.com",
127+
"qr_code": "data:image/png;base64,{base64EncodedPng}",
128+
"secret": "NAGCCFS3EYRB422HNAKAKY3XDUORMSRF",
129+
"uri": "otpauth://totp/FooCorp:alan.turing@example.com?secret=NAGCCFS3EYRB422HNAKAKY3XDUORMSRF&issuer=FooCorp"
130+
},
131+
"userId": "user_01FVYZ5QM8N98T9ME5BCB2BBMJ"
132+
}
133+
],
134+
"list_metadata": {
135+
"before": "auth_factor_01FVYZ5QM8N98T9ME5BCB2BBMJ",
136+
"after": "auth_factor_01FVYZ5QM8N98T9ME5BCB2BBMJ",
137+
}
138+
})
139+
.to_string(),
140+
)
141+
.create_async()
142+
.await;
143+
144+
let paginated_list = workos
145+
.user_management()
146+
.list_auth_factors(&ListAuthFactorsParams {
147+
id: &UserId::from("user_01FVYZ5QM8N98T9ME5BCB2BBMJ"),
148+
pagination: Default::default(),
149+
})
150+
.await
151+
.unwrap();
152+
153+
assert_eq!(
154+
paginated_list.metadata.after,
155+
Some("auth_factor_01FVYZ5QM8N98T9ME5BCB2BBMJ".to_string())
156+
)
157+
}
158+
}

0 commit comments

Comments
 (0)