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