Skip to main content

uptrakit_openapi_client/
auth.rs

1use crate::Result;
2use crate::UptrakitClient;
3use crate::types_impl::auth::{
4    AuthResponse, LoginRequest, LogoutRequest, RefreshRequest, RefreshResponse, RegisterRequest,
5    UserResponse,
6};
7use crate::types_impl::device_auth::{
8    DeviceAuthApproveRequest, DeviceAuthApproveResponse, DeviceAuthPollRequest,
9    DeviceAuthPollResponse, DeviceAuthStartRequest, DeviceAuthStartResponse,
10};
11use crate::types_impl::oidc_auth::AuthMethodsResponse;
12
13impl UptrakitClient {
14    /// Register a new user account.
15    ///
16    /// This endpoint does not require authentication.
17    pub async fn register(&self, req: &RegisterRequest) -> Result<AuthResponse> {
18        self.post_json_unauth(crate::paths::auth::REGISTER, req)
19            .await
20    }
21
22    /// Log in with email and password.
23    ///
24    /// This endpoint does not require authentication.
25    pub async fn login(&self, req: &LoginRequest) -> Result<AuthResponse> {
26        self.post_json_unauth(crate::paths::auth::LOGIN, req).await
27    }
28
29    /// Refresh an access token using a refresh token.
30    ///
31    /// This endpoint does not require authentication.
32    pub async fn refresh(&self, req: &RefreshRequest) -> Result<RefreshResponse> {
33        self.post_json_unauth(crate::paths::auth::REFRESH, req)
34            .await
35    }
36
37    /// Log out by revoking a refresh token.
38    pub async fn logout(&self, req: &LogoutRequest) -> Result<()> {
39        self.post_json_no_content(crate::paths::auth::LOGOUT, req)
40            .await
41    }
42
43    /// List available authentication methods.
44    ///
45    /// This endpoint does not require authentication.
46    pub async fn auth_methods(&self) -> Result<AuthMethodsResponse> {
47        self.get_unauth(crate::paths::auth::METHODS).await
48    }
49
50    /// Start a device authorization flow (RFC 8628-style).
51    ///
52    /// This endpoint does not require authentication.
53    pub async fn device_auth_start(
54        &self,
55        req: &DeviceAuthStartRequest,
56    ) -> Result<DeviceAuthStartResponse> {
57        self.post_json_unauth(crate::paths::auth::DEVICE, req).await
58    }
59
60    /// Poll for device authorization completion.
61    ///
62    /// Returns `Err(ClientError::RateLimited)` on HTTP 429 and
63    /// `Err(ClientError::NotFound(...))` on HTTP 404. This endpoint does
64    /// not require authentication.
65    pub async fn device_auth_poll(
66        &self,
67        req: &DeviceAuthPollRequest,
68    ) -> Result<DeviceAuthPollResponse> {
69        self.post_json_unauth(crate::paths::auth::DEVICE_POLL, req)
70            .await
71    }
72
73    /// Approve a pending device authorization request.
74    pub async fn device_auth_approve(
75        &self,
76        req: &DeviceAuthApproveRequest,
77    ) -> Result<DeviceAuthApproveResponse> {
78        self.post_json(crate::paths::auth::DEVICE_APPROVE, req)
79            .await
80    }
81
82    /// Retrieve the current authenticated user's profile.
83    pub async fn me(&self) -> Result<UserResponse> {
84        self.get(crate::paths::auth::ME).await
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use crate::types_impl::SecretString;
91    use crate::types_impl::auth::{LoginRequest, LogoutRequest, RefreshRequest, RegisterRequest};
92    use crate::types_impl::device_auth::{
93        DeviceAuthApproveRequest, DeviceAuthPollRequest, DeviceAuthStartRequest,
94    };
95
96    #[test]
97    fn register_request_serialization() {
98        let req = RegisterRequest {
99            email: "admin@example.com".to_string(),
100            first_name: "Admin".to_string(),
101            last_name: "User".to_string(),
102            password: SecretString::new("SecurePass123"),
103            registration_token: None,
104        };
105        let json = serde_json::to_value(&req).expect("serialize");
106        assert_eq!(json["email"], "admin@example.com");
107        assert_eq!(json["first_name"], "Admin");
108        assert_eq!(json["last_name"], "User");
109        assert_eq!(json["password"], "SecurePass123");
110    }
111
112    #[test]
113    fn register_request_with_token_serialization() {
114        let req = RegisterRequest {
115            email: "admin@example.com".to_string(),
116            first_name: "Admin".to_string(),
117            last_name: "User".to_string(),
118            password: SecretString::new("SecurePass123"),
119            registration_token: Some(SecretString::new("invite-tok-abc")),
120        };
121        let json = serde_json::to_value(&req).expect("serialize");
122        assert_eq!(json["registration_token"], "invite-tok-abc");
123    }
124
125    #[test]
126    fn login_request_serialization() {
127        let req = LoginRequest {
128            email: "admin@example.com".to_string(),
129            password: SecretString::new("SecurePass123"),
130        };
131        let json = serde_json::to_value(&req).expect("serialize");
132        assert_eq!(json["email"], "admin@example.com");
133        assert_eq!(json["password"], "SecurePass123");
134    }
135
136    #[test]
137    fn logout_request_serialization() {
138        let req = LogoutRequest {
139            refresh_token: Some(SecretString::new("refresh-tok-xyz")),
140        };
141        let json = serde_json::to_value(&req).expect("serialize");
142        assert_eq!(json["refresh_token"], "refresh-tok-xyz");
143    }
144
145    #[test]
146    fn refresh_request_serialization() {
147        let req = RefreshRequest {
148            refresh_token: Some(SecretString::new("refresh-tok-xyz")),
149        };
150        let json = serde_json::to_value(&req).expect("serialize");
151        assert_eq!(json["refresh_token"], "refresh-tok-xyz");
152    }
153
154    #[test]
155    fn device_auth_start_request_serialization() {
156        let req = DeviceAuthStartRequest {
157            client_name: Some("cli-host-2026-02-16".to_string()),
158        };
159        let json = serde_json::to_value(&req).expect("serialize");
160        assert_eq!(json["client_name"], "cli-host-2026-02-16");
161    }
162
163    #[test]
164    fn device_auth_poll_request_serialization() {
165        let req = DeviceAuthPollRequest {
166            device_code: "abc-123".to_string(),
167        };
168        let json = serde_json::to_value(&req).expect("serialize");
169        assert_eq!(json["device_code"], "abc-123");
170    }
171
172    #[test]
173    fn device_auth_approve_request_serialization() {
174        let req = DeviceAuthApproveRequest {
175            user_code: "ABCD-1234".to_string(),
176        };
177        let json = serde_json::to_value(&req).expect("serialize");
178        assert_eq!(json["user_code"], "ABCD-1234");
179    }
180}