Skip to main content

qcs_api_client_openapi/apis/
authentication_api.rs

1// Copyright 2026 Rigetti Computing
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/*
16 * Rigetti QCS API
17 *
18 * # Introduction  This is the documentation for the Rigetti QCS HTTP API.  You can find out more about Rigetti at [https://rigetti.com](https://rigetti.com), and also interact with QCS via the web at [https://qcs.rigetti.com](https://qcs.rigetti.com).  This API is documented in **OpenAPI format** and so is compatible with the dozens of language-specific client generators available [here](https://github.com/OpenAPITools/openapi-generator) and elsewhere on the web.  # Principles  This API follows REST design principles where appropriate, and otherwise an HTTP RPC paradigm. We adhere to the Google [API Improvement Proposals](https://google.aip.dev/general) where reasonable to provide a consistent, intuitive developer experience. HTTP response codes match their specifications, and error messages fit a common format.  # Authentication  All access to the QCS API requires OAuth2 authentication provided by Okta. You can request access [here](https://www.rigetti.com/get-quantum). Once you have a user account, you can download your access token from QCS [here](https://qcs.rigetti.com/auth/token).   That access token is valid for 24 hours after issuance. The value of `access_token` within the JSON file is the token used for authentication (don't use the entire JSON file).  Authenticate requests using the `Authorization` header and a `Bearer` prefix:  ``` curl --header \"Authorization: Bearer eyJraW...Iow\" ```  # Quantum Processor Access  Access to the quantum processors themselves is not yet provided directly by this HTTP API, but is instead performed over ZeroMQ/[rpcq](https://github.com/rigetti/rpcq). Until that changes, we suggest using [pyquil](https://github.com/rigetti/pyquil) to build and execute quantum programs via the Legacy API.  # Legacy API  Our legacy HTTP API remains accessible at https://forest-server.qcs.rigetti.com, and it shares a source of truth with this API's services. You can use either service with the same user account and means of authentication. We strongly recommend using the API documented here, as the legacy API is on the path to deprecation.
19 *
20 * The version of the OpenAPI document: 2020-07-31
21 * Contact: support@rigetti.com
22 * Generated by: https://openapi-generator.tech
23 */
24
25use super::{ContentType, Error, configuration};
26use crate::{apis::ResponseContent, models};
27use ::qcs_api_client_common::backoff::{
28    ExponentialBackoff, duration_from_io_error, duration_from_reqwest_error, duration_from_response,
29};
30#[cfg(feature = "tracing")]
31use qcs_api_client_common::configuration::tokens::TokenRefresher;
32use qcs_dependencies_client::reqwest::{self, StatusCode};
33use serde::{Deserialize, Serialize};
34
35#[cfg(feature = "clap")]
36#[allow(unused, reason = "not used in all templates, but required in some")]
37use ::{miette::IntoDiagnostic as _, qcs_api_client_common::clap_utils::JsonMaybeStdin};
38
39/// Serialize command-line arguments for [`auth_email_password_reset_token`]
40#[cfg(feature = "clap")]
41#[derive(Debug, clap::Args)]
42pub struct AuthEmailPasswordResetTokenClapParams {
43    pub auth_email_password_reset_token_request:
44        Option<JsonMaybeStdin<crate::models::AuthEmailPasswordResetTokenRequest>>,
45}
46
47#[cfg(feature = "clap")]
48impl AuthEmailPasswordResetTokenClapParams {
49    pub async fn execute(
50        self,
51        configuration: &configuration::Configuration,
52    ) -> Result<(), miette::Error> {
53        let request = self
54            .auth_email_password_reset_token_request
55            .map(|body| body.into_inner().into_inner());
56
57        auth_email_password_reset_token(configuration, request)
58            .await
59            .into_diagnostic()
60    }
61}
62
63/// Serialize command-line arguments for [`auth_get_user`]
64#[cfg(feature = "clap")]
65#[derive(Debug, clap::Args)]
66pub struct AuthGetUserClapParams {}
67
68#[cfg(feature = "clap")]
69impl AuthGetUserClapParams {
70    pub async fn execute(
71        self,
72        configuration: &configuration::Configuration,
73    ) -> Result<models::User, miette::Error> {
74        auth_get_user(configuration).await.into_diagnostic()
75    }
76}
77
78/// Serialize command-line arguments for [`auth_reset_password`]
79#[cfg(feature = "clap")]
80#[derive(Debug, clap::Args)]
81pub struct AuthResetPasswordClapParams {
82    pub auth_reset_password_request: JsonMaybeStdin<crate::models::AuthResetPasswordRequest>,
83}
84
85#[cfg(feature = "clap")]
86impl AuthResetPasswordClapParams {
87    pub async fn execute(
88        self,
89        configuration: &configuration::Configuration,
90    ) -> Result<(), miette::Error> {
91        let request = self.auth_reset_password_request.into_inner().into_inner();
92
93        auth_reset_password(configuration, request)
94            .await
95            .into_diagnostic()
96    }
97}
98
99/// Serialize command-line arguments for [`auth_reset_password_with_token`]
100#[cfg(feature = "clap")]
101#[derive(Debug, clap::Args)]
102pub struct AuthResetPasswordWithTokenClapParams {
103    pub auth_reset_password_with_token_request:
104        JsonMaybeStdin<crate::models::AuthResetPasswordWithTokenRequest>,
105}
106
107#[cfg(feature = "clap")]
108impl AuthResetPasswordWithTokenClapParams {
109    pub async fn execute(
110        self,
111        configuration: &configuration::Configuration,
112    ) -> Result<(), miette::Error> {
113        let request = self
114            .auth_reset_password_with_token_request
115            .into_inner()
116            .into_inner();
117
118        auth_reset_password_with_token(configuration, request)
119            .await
120            .into_diagnostic()
121    }
122}
123
124/// struct for typed errors of method [`auth_email_password_reset_token`]
125#[derive(Debug, Clone, Serialize, Deserialize)]
126#[serde(untagged)]
127pub enum AuthEmailPasswordResetTokenError {
128    Status422(models::Error),
129    UnknownValue(serde_json::Value),
130}
131
132/// struct for typed errors of method [`auth_get_user`]
133#[derive(Debug, Clone, Serialize, Deserialize)]
134#[serde(untagged)]
135pub enum AuthGetUserError {
136    Status401(models::Error),
137    Status404(models::Error),
138    UnknownValue(serde_json::Value),
139}
140
141/// struct for typed errors of method [`auth_reset_password`]
142#[derive(Debug, Clone, Serialize, Deserialize)]
143#[serde(untagged)]
144pub enum AuthResetPasswordError {
145    Status401(models::Error),
146    Status422(models::Error),
147    UnknownValue(serde_json::Value),
148}
149
150/// struct for typed errors of method [`auth_reset_password_with_token`]
151#[derive(Debug, Clone, Serialize, Deserialize)]
152#[serde(untagged)]
153pub enum AuthResetPasswordWithTokenError {
154    Status404(models::Error),
155    Status422(models::Error),
156    UnknownValue(serde_json::Value),
157}
158
159async fn auth_email_password_reset_token_inner(
160    configuration: &configuration::Configuration,
161    backoff: &mut ExponentialBackoff,
162    auth_email_password_reset_token_request: Option<
163        crate::models::AuthEmailPasswordResetTokenRequest,
164    >,
165) -> Result<(), Error<AuthEmailPasswordResetTokenError>> {
166    let local_var_configuration = configuration;
167    // add a prefix to parameters to efficiently prevent name collisions
168    let p_body_auth_email_password_reset_token_request = auth_email_password_reset_token_request;
169
170    let local_var_client = &local_var_configuration.client;
171
172    let local_var_uri_str = format!(
173        "{}/v1/auth:emailPasswordResetToken",
174        local_var_configuration.qcs_config.api_url()
175    );
176    let mut local_var_req_builder =
177        local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
178
179    #[cfg(feature = "tracing")]
180    {
181        // Ignore parsing errors if the URL is invalid for some reason.
182        // If it is invalid, it will turn up as an error later when actually making the request.
183        let local_var_do_tracing = local_var_uri_str
184            .parse::<::url::Url>()
185            .ok()
186            .is_none_or(|url| {
187                configuration
188                    .qcs_config
189                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
190            });
191
192        if local_var_do_tracing {
193            ::tracing::debug!(
194                url=%local_var_uri_str,
195                method="POST",
196                "making auth_email_password_reset_token request",
197            );
198        }
199    }
200
201    // Use the QCS Bearer token if a client OAuthSession is present,
202    // but do not require one when the security schema says it is optional.
203    {
204        use qcs_api_client_common::configuration::TokenError;
205
206        #[allow(
207            clippy::nonminimal_bool,
208            clippy::eq_op,
209            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
210        )]
211        let is_jwt_bearer_optional: bool = false;
212
213        let token = local_var_configuration
214            .qcs_config
215            .get_bearer_access_token()
216            .await;
217
218        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
219            // the client is configured without any OAuthSession, but this call does not require one.
220            #[cfg(feature = "tracing")]
221            tracing::debug!(
222                "No client credentials found, but this call does not require authentication."
223            );
224        } else {
225            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
226        }
227    }
228
229    local_var_req_builder =
230        local_var_req_builder.json(&p_body_auth_email_password_reset_token_request);
231
232    let local_var_req = local_var_req_builder.build()?;
233    let local_var_resp = local_var_client.execute(local_var_req).await?;
234
235    let local_var_status = local_var_resp.status();
236
237    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
238        Ok(())
239    } else {
240        let local_var_retry_delay =
241            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
242        let local_var_content = local_var_resp.text().await?;
243        let local_var_entity: Option<AuthEmailPasswordResetTokenError> =
244            serde_json::from_str(&local_var_content).ok();
245        let local_var_error = ResponseContent {
246            status: local_var_status,
247            content: local_var_content,
248            entity: local_var_entity,
249            retry_delay: local_var_retry_delay,
250        };
251        Err(Error::ResponseError(local_var_error))
252    }
253}
254
255/// Send a password reset link to the provided email address, if that email matches a registered user.
256pub async fn auth_email_password_reset_token(
257    configuration: &configuration::Configuration,
258    auth_email_password_reset_token_request: Option<
259        crate::models::AuthEmailPasswordResetTokenRequest,
260    >,
261) -> Result<(), Error<AuthEmailPasswordResetTokenError>> {
262    let mut backoff = configuration.backoff.clone();
263    let mut refreshed_credentials = false;
264    let method = reqwest::Method::POST;
265    loop {
266        let result = auth_email_password_reset_token_inner(
267            configuration,
268            &mut backoff,
269            auth_email_password_reset_token_request.clone(),
270        )
271        .await;
272
273        match result {
274            Ok(result) => return Ok(result),
275            Err(Error::ResponseError(response)) => {
276                if !refreshed_credentials
277                    && matches!(
278                        response.status,
279                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
280                    )
281                {
282                    // Attempt to refresh credentials
283                    match configuration.qcs_config.refresh().await {
284                        Ok(_) => {
285                            refreshed_credentials = true;
286                            continue;
287                        }
288                        Err(::qcs_api_client_common::configuration::TokenError::Write {
289                            error,
290                            oauth_session: _,
291                        }) => {
292                            // Token refresh succeeded but persistence failed
293                            // The token is already in memory and will be used for this request
294                            #[cfg(feature = "tracing")]
295                            tracing::warn!(
296                                "Token refresh succeeded but failed to persist: {}. Continuing with in-memory token.",
297                                error
298                            );
299                            refreshed_credentials = true;
300                            continue;
301                        }
302                        Err(e) => return Err(e.into()),
303                    }
304                } else if let Some(duration) = response.retry_delay {
305                    tokio::time::sleep(duration).await;
306                    continue;
307                }
308
309                return Err(Error::ResponseError(response));
310            }
311            Err(Error::Reqwest(error)) => {
312                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
313                    tokio::time::sleep(duration).await;
314                    continue;
315                }
316
317                return Err(Error::Reqwest(error));
318            }
319            Err(Error::Io(error)) => {
320                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
321                    tokio::time::sleep(duration).await;
322                    continue;
323                }
324
325                return Err(Error::Io(error));
326            }
327            Err(error) => return Err(error),
328        }
329    }
330}
331async fn auth_get_user_inner(
332    configuration: &configuration::Configuration,
333    backoff: &mut ExponentialBackoff,
334) -> Result<models::User, Error<AuthGetUserError>> {
335    let local_var_configuration = configuration;
336
337    let local_var_client = &local_var_configuration.client;
338
339    let local_var_uri_str = format!(
340        "{}/v1/auth:getUser",
341        local_var_configuration.qcs_config.api_url()
342    );
343    let mut local_var_req_builder =
344        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
345
346    #[cfg(feature = "tracing")]
347    {
348        // Ignore parsing errors if the URL is invalid for some reason.
349        // If it is invalid, it will turn up as an error later when actually making the request.
350        let local_var_do_tracing = local_var_uri_str
351            .parse::<::url::Url>()
352            .ok()
353            .is_none_or(|url| {
354                configuration
355                    .qcs_config
356                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
357            });
358
359        if local_var_do_tracing {
360            ::tracing::debug!(
361                url=%local_var_uri_str,
362                method="GET",
363                "making auth_get_user request",
364            );
365        }
366    }
367
368    // Use the QCS Bearer token if a client OAuthSession is present,
369    // but do not require one when the security schema says it is optional.
370    {
371        use qcs_api_client_common::configuration::TokenError;
372
373        #[allow(
374            clippy::nonminimal_bool,
375            clippy::eq_op,
376            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
377        )]
378        let is_jwt_bearer_optional: bool = false || "JWTBearer" == "JWTBearerOptional";
379
380        let token = local_var_configuration
381            .qcs_config
382            .get_bearer_access_token()
383            .await;
384
385        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
386            // the client is configured without any OAuthSession, but this call does not require one.
387            #[cfg(feature = "tracing")]
388            tracing::debug!(
389                "No client credentials found, but this call does not require authentication."
390            );
391        } else {
392            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
393        }
394    }
395
396    let local_var_req = local_var_req_builder.build()?;
397    let local_var_resp = local_var_client.execute(local_var_req).await?;
398
399    let local_var_status = local_var_resp.status();
400    let local_var_raw_content_type = local_var_resp
401        .headers()
402        .get("content-type")
403        .and_then(|v| v.to_str().ok())
404        .unwrap_or("application/octet-stream")
405        .to_string();
406    let local_var_content_type = super::ContentType::from(local_var_raw_content_type.as_str());
407
408    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
409        let local_var_content = local_var_resp.text().await?;
410        match local_var_content_type {
411            ContentType::Json => serde_path_to_error::deserialize(
412                &mut serde_json::Deserializer::from_str(&local_var_content),
413            )
414            .map_err(Error::from),
415            ContentType::Text => Err(Error::InvalidContentType {
416                content_type: local_var_raw_content_type,
417                return_type: "models::User",
418            }),
419            ContentType::Unsupported(unknown_type) => Err(Error::InvalidContentType {
420                content_type: unknown_type,
421                return_type: "models::User",
422            }),
423        }
424    } else {
425        let local_var_retry_delay =
426            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
427        let local_var_content = local_var_resp.text().await?;
428        let local_var_entity: Option<AuthGetUserError> =
429            serde_json::from_str(&local_var_content).ok();
430        let local_var_error = ResponseContent {
431            status: local_var_status,
432            content: local_var_content,
433            entity: local_var_entity,
434            retry_delay: local_var_retry_delay,
435        };
436        Err(Error::ResponseError(local_var_error))
437    }
438}
439
440/// Retrieve the profile of the authenticated user.
441pub async fn auth_get_user(
442    configuration: &configuration::Configuration,
443) -> Result<models::User, Error<AuthGetUserError>> {
444    let mut backoff = configuration.backoff.clone();
445    let mut refreshed_credentials = false;
446    let method = reqwest::Method::GET;
447    loop {
448        let result = auth_get_user_inner(configuration, &mut backoff).await;
449
450        match result {
451            Ok(result) => return Ok(result),
452            Err(Error::ResponseError(response)) => {
453                if !refreshed_credentials
454                    && matches!(
455                        response.status,
456                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
457                    )
458                {
459                    // Attempt to refresh credentials
460                    match configuration.qcs_config.refresh().await {
461                        Ok(_) => {
462                            refreshed_credentials = true;
463                            continue;
464                        }
465                        Err(::qcs_api_client_common::configuration::TokenError::Write {
466                            error,
467                            oauth_session: _,
468                        }) => {
469                            // Token refresh succeeded but persistence failed
470                            // The token is already in memory and will be used for this request
471                            #[cfg(feature = "tracing")]
472                            tracing::warn!(
473                                "Token refresh succeeded but failed to persist: {}. Continuing with in-memory token.",
474                                error
475                            );
476                            refreshed_credentials = true;
477                            continue;
478                        }
479                        Err(e) => return Err(e.into()),
480                    }
481                } else if let Some(duration) = response.retry_delay {
482                    tokio::time::sleep(duration).await;
483                    continue;
484                }
485
486                return Err(Error::ResponseError(response));
487            }
488            Err(Error::Reqwest(error)) => {
489                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
490                    tokio::time::sleep(duration).await;
491                    continue;
492                }
493
494                return Err(Error::Reqwest(error));
495            }
496            Err(Error::Io(error)) => {
497                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
498                    tokio::time::sleep(duration).await;
499                    continue;
500                }
501
502                return Err(Error::Io(error));
503            }
504            Err(error) => return Err(error),
505        }
506    }
507}
508async fn auth_reset_password_inner(
509    configuration: &configuration::Configuration,
510    backoff: &mut ExponentialBackoff,
511    auth_reset_password_request: crate::models::AuthResetPasswordRequest,
512) -> Result<(), Error<AuthResetPasswordError>> {
513    let local_var_configuration = configuration;
514    // add a prefix to parameters to efficiently prevent name collisions
515    let p_body_auth_reset_password_request = auth_reset_password_request;
516
517    let local_var_client = &local_var_configuration.client;
518
519    let local_var_uri_str = format!(
520        "{}/v1/auth:resetPassword",
521        local_var_configuration.qcs_config.api_url()
522    );
523    let mut local_var_req_builder =
524        local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
525
526    #[cfg(feature = "tracing")]
527    {
528        // Ignore parsing errors if the URL is invalid for some reason.
529        // If it is invalid, it will turn up as an error later when actually making the request.
530        let local_var_do_tracing = local_var_uri_str
531            .parse::<::url::Url>()
532            .ok()
533            .is_none_or(|url| {
534                configuration
535                    .qcs_config
536                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
537            });
538
539        if local_var_do_tracing {
540            ::tracing::debug!(
541                url=%local_var_uri_str,
542                method="POST",
543                "making auth_reset_password request",
544            );
545        }
546    }
547
548    // Use the QCS Bearer token if a client OAuthSession is present,
549    // but do not require one when the security schema says it is optional.
550    {
551        use qcs_api_client_common::configuration::TokenError;
552
553        #[allow(
554            clippy::nonminimal_bool,
555            clippy::eq_op,
556            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
557        )]
558        let is_jwt_bearer_optional: bool = false || "JWTBearer" == "JWTBearerOptional";
559
560        let token = local_var_configuration
561            .qcs_config
562            .get_bearer_access_token()
563            .await;
564
565        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
566            // the client is configured without any OAuthSession, but this call does not require one.
567            #[cfg(feature = "tracing")]
568            tracing::debug!(
569                "No client credentials found, but this call does not require authentication."
570            );
571        } else {
572            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
573        }
574    }
575
576    local_var_req_builder = local_var_req_builder.json(&p_body_auth_reset_password_request);
577
578    let local_var_req = local_var_req_builder.build()?;
579    let local_var_resp = local_var_client.execute(local_var_req).await?;
580
581    let local_var_status = local_var_resp.status();
582
583    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
584        Ok(())
585    } else {
586        let local_var_retry_delay =
587            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
588        let local_var_content = local_var_resp.text().await?;
589        let local_var_entity: Option<AuthResetPasswordError> =
590            serde_json::from_str(&local_var_content).ok();
591        let local_var_error = ResponseContent {
592            status: local_var_status,
593            content: local_var_content,
594            entity: local_var_entity,
595            retry_delay: local_var_retry_delay,
596        };
597        Err(Error::ResponseError(local_var_error))
598    }
599}
600
601/// Reset the password using the user's existing password. Note, this is an authenticated route.
602pub async fn auth_reset_password(
603    configuration: &configuration::Configuration,
604    auth_reset_password_request: crate::models::AuthResetPasswordRequest,
605) -> Result<(), Error<AuthResetPasswordError>> {
606    let mut backoff = configuration.backoff.clone();
607    let mut refreshed_credentials = false;
608    let method = reqwest::Method::POST;
609    loop {
610        let result = auth_reset_password_inner(
611            configuration,
612            &mut backoff,
613            auth_reset_password_request.clone(),
614        )
615        .await;
616
617        match result {
618            Ok(result) => return Ok(result),
619            Err(Error::ResponseError(response)) => {
620                if !refreshed_credentials
621                    && matches!(
622                        response.status,
623                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
624                    )
625                {
626                    // Attempt to refresh credentials
627                    match configuration.qcs_config.refresh().await {
628                        Ok(_) => {
629                            refreshed_credentials = true;
630                            continue;
631                        }
632                        Err(::qcs_api_client_common::configuration::TokenError::Write {
633                            error,
634                            oauth_session: _,
635                        }) => {
636                            // Token refresh succeeded but persistence failed
637                            // The token is already in memory and will be used for this request
638                            #[cfg(feature = "tracing")]
639                            tracing::warn!(
640                                "Token refresh succeeded but failed to persist: {}. Continuing with in-memory token.",
641                                error
642                            );
643                            refreshed_credentials = true;
644                            continue;
645                        }
646                        Err(e) => return Err(e.into()),
647                    }
648                } else if let Some(duration) = response.retry_delay {
649                    tokio::time::sleep(duration).await;
650                    continue;
651                }
652
653                return Err(Error::ResponseError(response));
654            }
655            Err(Error::Reqwest(error)) => {
656                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
657                    tokio::time::sleep(duration).await;
658                    continue;
659                }
660
661                return Err(Error::Reqwest(error));
662            }
663            Err(Error::Io(error)) => {
664                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
665                    tokio::time::sleep(duration).await;
666                    continue;
667                }
668
669                return Err(Error::Io(error));
670            }
671            Err(error) => return Err(error),
672        }
673    }
674}
675async fn auth_reset_password_with_token_inner(
676    configuration: &configuration::Configuration,
677    backoff: &mut ExponentialBackoff,
678    auth_reset_password_with_token_request: crate::models::AuthResetPasswordWithTokenRequest,
679) -> Result<(), Error<AuthResetPasswordWithTokenError>> {
680    let local_var_configuration = configuration;
681    // add a prefix to parameters to efficiently prevent name collisions
682    let p_body_auth_reset_password_with_token_request = auth_reset_password_with_token_request;
683
684    let local_var_client = &local_var_configuration.client;
685
686    let local_var_uri_str = format!(
687        "{}/v1/auth:resetPasswordWithToken",
688        local_var_configuration.qcs_config.api_url()
689    );
690    let mut local_var_req_builder =
691        local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
692
693    #[cfg(feature = "tracing")]
694    {
695        // Ignore parsing errors if the URL is invalid for some reason.
696        // If it is invalid, it will turn up as an error later when actually making the request.
697        let local_var_do_tracing = local_var_uri_str
698            .parse::<::url::Url>()
699            .ok()
700            .is_none_or(|url| {
701                configuration
702                    .qcs_config
703                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
704            });
705
706        if local_var_do_tracing {
707            ::tracing::debug!(
708                url=%local_var_uri_str,
709                method="POST",
710                "making auth_reset_password_with_token request",
711            );
712        }
713    }
714
715    // Use the QCS Bearer token if a client OAuthSession is present,
716    // but do not require one when the security schema says it is optional.
717    {
718        use qcs_api_client_common::configuration::TokenError;
719
720        #[allow(
721            clippy::nonminimal_bool,
722            clippy::eq_op,
723            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
724        )]
725        let is_jwt_bearer_optional: bool = false;
726
727        let token = local_var_configuration
728            .qcs_config
729            .get_bearer_access_token()
730            .await;
731
732        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
733            // the client is configured without any OAuthSession, but this call does not require one.
734            #[cfg(feature = "tracing")]
735            tracing::debug!(
736                "No client credentials found, but this call does not require authentication."
737            );
738        } else {
739            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
740        }
741    }
742
743    local_var_req_builder =
744        local_var_req_builder.json(&p_body_auth_reset_password_with_token_request);
745
746    let local_var_req = local_var_req_builder.build()?;
747    let local_var_resp = local_var_client.execute(local_var_req).await?;
748
749    let local_var_status = local_var_resp.status();
750
751    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
752        Ok(())
753    } else {
754        let local_var_retry_delay =
755            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
756        let local_var_content = local_var_resp.text().await?;
757        let local_var_entity: Option<AuthResetPasswordWithTokenError> =
758            serde_json::from_str(&local_var_content).ok();
759        let local_var_error = ResponseContent {
760            status: local_var_status,
761            content: local_var_content,
762            entity: local_var_entity,
763            retry_delay: local_var_retry_delay,
764        };
765        Err(Error::ResponseError(local_var_error))
766    }
767}
768
769/// Complete the forgot password flow, resetting the new password in exchange for an emailed token.
770pub async fn auth_reset_password_with_token(
771    configuration: &configuration::Configuration,
772    auth_reset_password_with_token_request: crate::models::AuthResetPasswordWithTokenRequest,
773) -> Result<(), Error<AuthResetPasswordWithTokenError>> {
774    let mut backoff = configuration.backoff.clone();
775    let mut refreshed_credentials = false;
776    let method = reqwest::Method::POST;
777    loop {
778        let result = auth_reset_password_with_token_inner(
779            configuration,
780            &mut backoff,
781            auth_reset_password_with_token_request.clone(),
782        )
783        .await;
784
785        match result {
786            Ok(result) => return Ok(result),
787            Err(Error::ResponseError(response)) => {
788                if !refreshed_credentials
789                    && matches!(
790                        response.status,
791                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
792                    )
793                {
794                    // Attempt to refresh credentials
795                    match configuration.qcs_config.refresh().await {
796                        Ok(_) => {
797                            refreshed_credentials = true;
798                            continue;
799                        }
800                        Err(::qcs_api_client_common::configuration::TokenError::Write {
801                            error,
802                            oauth_session: _,
803                        }) => {
804                            // Token refresh succeeded but persistence failed
805                            // The token is already in memory and will be used for this request
806                            #[cfg(feature = "tracing")]
807                            tracing::warn!(
808                                "Token refresh succeeded but failed to persist: {}. Continuing with in-memory token.",
809                                error
810                            );
811                            refreshed_credentials = true;
812                            continue;
813                        }
814                        Err(e) => return Err(e.into()),
815                    }
816                } else if let Some(duration) = response.retry_delay {
817                    tokio::time::sleep(duration).await;
818                    continue;
819                }
820
821                return Err(Error::ResponseError(response));
822            }
823            Err(Error::Reqwest(error)) => {
824                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
825                    tokio::time::sleep(duration).await;
826                    continue;
827                }
828
829                return Err(Error::Reqwest(error));
830            }
831            Err(Error::Io(error)) => {
832                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
833                    tokio::time::sleep(duration).await;
834                    continue;
835                }
836
837                return Err(Error::Io(error));
838            }
839            Err(error) => return Err(error),
840        }
841    }
842}