qcs_api_client_openapi/apis/
authentication_api.rs

1// Copyright 2022 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::{configuration, Error};
26use crate::apis::ResponseContent;
27use ::qcs_api_client_common::backoff::{
28    duration_from_io_error, duration_from_reqwest_error, duration_from_response, ExponentialBackoff,
29};
30#[cfg(feature = "tracing")]
31use qcs_api_client_common::configuration::tokens::TokenRefresher;
32use reqwest::StatusCode;
33use serde::{Deserialize, Serialize};
34
35/// struct for typed errors of method [`auth_email_password_reset_token`]
36#[derive(Debug, Clone, Serialize, Deserialize)]
37#[serde(untagged)]
38pub enum AuthEmailPasswordResetTokenError {
39    Status422(crate::models::Error),
40    UnknownValue(serde_json::Value),
41}
42
43/// struct for typed errors of method [`auth_get_user`]
44#[derive(Debug, Clone, Serialize, Deserialize)]
45#[serde(untagged)]
46pub enum AuthGetUserError {
47    Status401(crate::models::Error),
48    Status404(crate::models::Error),
49    UnknownValue(serde_json::Value),
50}
51
52/// struct for typed errors of method [`auth_reset_password`]
53#[derive(Debug, Clone, Serialize, Deserialize)]
54#[serde(untagged)]
55pub enum AuthResetPasswordError {
56    Status401(crate::models::Error),
57    Status422(crate::models::Error),
58    UnknownValue(serde_json::Value),
59}
60
61/// struct for typed errors of method [`auth_reset_password_with_token`]
62#[derive(Debug, Clone, Serialize, Deserialize)]
63#[serde(untagged)]
64pub enum AuthResetPasswordWithTokenError {
65    Status404(crate::models::Error),
66    Status422(crate::models::Error),
67    UnknownValue(serde_json::Value),
68}
69
70async fn auth_email_password_reset_token_inner(
71    configuration: &configuration::Configuration,
72    backoff: &mut ExponentialBackoff,
73    auth_email_password_reset_token_request: Option<
74        crate::models::AuthEmailPasswordResetTokenRequest,
75    >,
76) -> Result<(), Error<AuthEmailPasswordResetTokenError>> {
77    let local_var_configuration = configuration;
78
79    let local_var_client = &local_var_configuration.client;
80
81    let local_var_uri_str = format!(
82        "{}/v1/auth:emailPasswordResetToken",
83        local_var_configuration.qcs_config.api_url()
84    );
85    let mut local_var_req_builder =
86        local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
87
88    #[cfg(feature = "tracing")]
89    {
90        // Ignore parsing errors if the URL is invalid for some reason.
91        // If it is invalid, it will turn up as an error later when actually making the request.
92        let local_var_do_tracing = local_var_uri_str
93            .parse::<::url::Url>()
94            .ok()
95            .is_none_or(|url| {
96                configuration
97                    .qcs_config
98                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
99            });
100
101        if local_var_do_tracing {
102            ::tracing::debug!(
103                url=%local_var_uri_str,
104                method="POST",
105                "making auth_email_password_reset_token request",
106            );
107        }
108    }
109
110    // Use the QCS Bearer token if a client OAuthSession is present,
111    // but do not require one when the security schema says it is optional.
112    {
113        use qcs_api_client_common::configuration::TokenError;
114
115        #[allow(
116            clippy::nonminimal_bool,
117            clippy::eq_op,
118            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
119        )]
120        let is_jwt_bearer_optional: bool = false;
121
122        let token = local_var_configuration
123            .qcs_config
124            .get_bearer_access_token()
125            .await;
126
127        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
128            // the client is configured without any OAuthSession, but this call does not require one.
129            #[cfg(feature = "tracing")]
130            tracing::debug!(
131                "No client credentials found, but this call does not require authentication."
132            );
133        } else {
134            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
135        }
136    }
137
138    local_var_req_builder = local_var_req_builder.json(&auth_email_password_reset_token_request);
139
140    let local_var_req = local_var_req_builder.build()?;
141    let local_var_resp = local_var_client.execute(local_var_req).await?;
142
143    let local_var_status = local_var_resp.status();
144
145    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
146        Ok(())
147    } else {
148        let local_var_retry_delay =
149            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
150        let local_var_content = local_var_resp.text().await?;
151        let local_var_entity: Option<AuthEmailPasswordResetTokenError> =
152            serde_json::from_str(&local_var_content).ok();
153        let local_var_error = ResponseContent {
154            status: local_var_status,
155            content: local_var_content,
156            entity: local_var_entity,
157            retry_delay: local_var_retry_delay,
158        };
159        Err(Error::ResponseError(local_var_error))
160    }
161}
162
163/// Send a password reset link to the provided email address, if that email matches a registered user.
164pub async fn auth_email_password_reset_token(
165    configuration: &configuration::Configuration,
166    auth_email_password_reset_token_request: Option<
167        crate::models::AuthEmailPasswordResetTokenRequest,
168    >,
169) -> Result<(), Error<AuthEmailPasswordResetTokenError>> {
170    let mut backoff = configuration.backoff.clone();
171    let mut refreshed_credentials = false;
172    let method = reqwest::Method::POST;
173    loop {
174        let result = auth_email_password_reset_token_inner(
175            configuration,
176            &mut backoff,
177            auth_email_password_reset_token_request.clone(),
178        )
179        .await;
180
181        match result {
182            Ok(result) => return Ok(result),
183            Err(Error::ResponseError(response)) => {
184                if !refreshed_credentials
185                    && matches!(
186                        response.status,
187                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
188                    )
189                {
190                    configuration.qcs_config.refresh().await?;
191                    refreshed_credentials = true;
192                    continue;
193                } else if let Some(duration) = response.retry_delay {
194                    tokio::time::sleep(duration).await;
195                    continue;
196                }
197
198                return Err(Error::ResponseError(response));
199            }
200            Err(Error::Reqwest(error)) => {
201                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
202                    tokio::time::sleep(duration).await;
203                    continue;
204                }
205
206                return Err(Error::Reqwest(error));
207            }
208            Err(Error::Io(error)) => {
209                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
210                    tokio::time::sleep(duration).await;
211                    continue;
212                }
213
214                return Err(Error::Io(error));
215            }
216            Err(error) => return Err(error),
217        }
218    }
219}
220async fn auth_get_user_inner(
221    configuration: &configuration::Configuration,
222    backoff: &mut ExponentialBackoff,
223) -> Result<crate::models::User, Error<AuthGetUserError>> {
224    let local_var_configuration = configuration;
225
226    let local_var_client = &local_var_configuration.client;
227
228    let local_var_uri_str = format!(
229        "{}/v1/auth:getUser",
230        local_var_configuration.qcs_config.api_url()
231    );
232    let mut local_var_req_builder =
233        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
234
235    #[cfg(feature = "tracing")]
236    {
237        // Ignore parsing errors if the URL is invalid for some reason.
238        // If it is invalid, it will turn up as an error later when actually making the request.
239        let local_var_do_tracing = local_var_uri_str
240            .parse::<::url::Url>()
241            .ok()
242            .is_none_or(|url| {
243                configuration
244                    .qcs_config
245                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
246            });
247
248        if local_var_do_tracing {
249            ::tracing::debug!(
250                url=%local_var_uri_str,
251                method="GET",
252                "making auth_get_user request",
253            );
254        }
255    }
256
257    // Use the QCS Bearer token if a client OAuthSession is present,
258    // but do not require one when the security schema says it is optional.
259    {
260        use qcs_api_client_common::configuration::TokenError;
261
262        #[allow(
263            clippy::nonminimal_bool,
264            clippy::eq_op,
265            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
266        )]
267        let is_jwt_bearer_optional: bool = false || "JWTBearer" == "JWTBearerOptional";
268
269        let token = local_var_configuration
270            .qcs_config
271            .get_bearer_access_token()
272            .await;
273
274        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
275            // the client is configured without any OAuthSession, but this call does not require one.
276            #[cfg(feature = "tracing")]
277            tracing::debug!(
278                "No client credentials found, but this call does not require authentication."
279            );
280        } else {
281            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
282        }
283    }
284
285    let local_var_req = local_var_req_builder.build()?;
286    let local_var_resp = local_var_client.execute(local_var_req).await?;
287
288    let local_var_status = local_var_resp.status();
289
290    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
291        let local_var_content = local_var_resp.text().await?;
292        serde_json::from_str(&local_var_content).map_err(Error::from)
293    } else {
294        let local_var_retry_delay =
295            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
296        let local_var_content = local_var_resp.text().await?;
297        let local_var_entity: Option<AuthGetUserError> =
298            serde_json::from_str(&local_var_content).ok();
299        let local_var_error = ResponseContent {
300            status: local_var_status,
301            content: local_var_content,
302            entity: local_var_entity,
303            retry_delay: local_var_retry_delay,
304        };
305        Err(Error::ResponseError(local_var_error))
306    }
307}
308
309/// Retrieve the profile of the authenticated user.
310pub async fn auth_get_user(
311    configuration: &configuration::Configuration,
312) -> Result<crate::models::User, Error<AuthGetUserError>> {
313    let mut backoff = configuration.backoff.clone();
314    let mut refreshed_credentials = false;
315    let method = reqwest::Method::GET;
316    loop {
317        let result = auth_get_user_inner(configuration, &mut backoff).await;
318
319        match result {
320            Ok(result) => return Ok(result),
321            Err(Error::ResponseError(response)) => {
322                if !refreshed_credentials
323                    && matches!(
324                        response.status,
325                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
326                    )
327                {
328                    configuration.qcs_config.refresh().await?;
329                    refreshed_credentials = true;
330                    continue;
331                } else if let Some(duration) = response.retry_delay {
332                    tokio::time::sleep(duration).await;
333                    continue;
334                }
335
336                return Err(Error::ResponseError(response));
337            }
338            Err(Error::Reqwest(error)) => {
339                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
340                    tokio::time::sleep(duration).await;
341                    continue;
342                }
343
344                return Err(Error::Reqwest(error));
345            }
346            Err(Error::Io(error)) => {
347                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
348                    tokio::time::sleep(duration).await;
349                    continue;
350                }
351
352                return Err(Error::Io(error));
353            }
354            Err(error) => return Err(error),
355        }
356    }
357}
358async fn auth_reset_password_inner(
359    configuration: &configuration::Configuration,
360    backoff: &mut ExponentialBackoff,
361    auth_reset_password_request: crate::models::AuthResetPasswordRequest,
362) -> Result<(), Error<AuthResetPasswordError>> {
363    let local_var_configuration = configuration;
364
365    let local_var_client = &local_var_configuration.client;
366
367    let local_var_uri_str = format!(
368        "{}/v1/auth:resetPassword",
369        local_var_configuration.qcs_config.api_url()
370    );
371    let mut local_var_req_builder =
372        local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
373
374    #[cfg(feature = "tracing")]
375    {
376        // Ignore parsing errors if the URL is invalid for some reason.
377        // If it is invalid, it will turn up as an error later when actually making the request.
378        let local_var_do_tracing = local_var_uri_str
379            .parse::<::url::Url>()
380            .ok()
381            .is_none_or(|url| {
382                configuration
383                    .qcs_config
384                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
385            });
386
387        if local_var_do_tracing {
388            ::tracing::debug!(
389                url=%local_var_uri_str,
390                method="POST",
391                "making auth_reset_password request",
392            );
393        }
394    }
395
396    // Use the QCS Bearer token if a client OAuthSession is present,
397    // but do not require one when the security schema says it is optional.
398    {
399        use qcs_api_client_common::configuration::TokenError;
400
401        #[allow(
402            clippy::nonminimal_bool,
403            clippy::eq_op,
404            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
405        )]
406        let is_jwt_bearer_optional: bool = false || "JWTBearer" == "JWTBearerOptional";
407
408        let token = local_var_configuration
409            .qcs_config
410            .get_bearer_access_token()
411            .await;
412
413        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
414            // the client is configured without any OAuthSession, but this call does not require one.
415            #[cfg(feature = "tracing")]
416            tracing::debug!(
417                "No client credentials found, but this call does not require authentication."
418            );
419        } else {
420            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
421        }
422    }
423
424    local_var_req_builder = local_var_req_builder.json(&auth_reset_password_request);
425
426    let local_var_req = local_var_req_builder.build()?;
427    let local_var_resp = local_var_client.execute(local_var_req).await?;
428
429    let local_var_status = local_var_resp.status();
430
431    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
432        Ok(())
433    } else {
434        let local_var_retry_delay =
435            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
436        let local_var_content = local_var_resp.text().await?;
437        let local_var_entity: Option<AuthResetPasswordError> =
438            serde_json::from_str(&local_var_content).ok();
439        let local_var_error = ResponseContent {
440            status: local_var_status,
441            content: local_var_content,
442            entity: local_var_entity,
443            retry_delay: local_var_retry_delay,
444        };
445        Err(Error::ResponseError(local_var_error))
446    }
447}
448
449/// Reset the password using the user's existing password. Note, this is an authenticated route.
450pub async fn auth_reset_password(
451    configuration: &configuration::Configuration,
452    auth_reset_password_request: crate::models::AuthResetPasswordRequest,
453) -> Result<(), Error<AuthResetPasswordError>> {
454    let mut backoff = configuration.backoff.clone();
455    let mut refreshed_credentials = false;
456    let method = reqwest::Method::POST;
457    loop {
458        let result = auth_reset_password_inner(
459            configuration,
460            &mut backoff,
461            auth_reset_password_request.clone(),
462        )
463        .await;
464
465        match result {
466            Ok(result) => return Ok(result),
467            Err(Error::ResponseError(response)) => {
468                if !refreshed_credentials
469                    && matches!(
470                        response.status,
471                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
472                    )
473                {
474                    configuration.qcs_config.refresh().await?;
475                    refreshed_credentials = true;
476                    continue;
477                } else if let Some(duration) = response.retry_delay {
478                    tokio::time::sleep(duration).await;
479                    continue;
480                }
481
482                return Err(Error::ResponseError(response));
483            }
484            Err(Error::Reqwest(error)) => {
485                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
486                    tokio::time::sleep(duration).await;
487                    continue;
488                }
489
490                return Err(Error::Reqwest(error));
491            }
492            Err(Error::Io(error)) => {
493                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
494                    tokio::time::sleep(duration).await;
495                    continue;
496                }
497
498                return Err(Error::Io(error));
499            }
500            Err(error) => return Err(error),
501        }
502    }
503}
504async fn auth_reset_password_with_token_inner(
505    configuration: &configuration::Configuration,
506    backoff: &mut ExponentialBackoff,
507    auth_reset_password_with_token_request: crate::models::AuthResetPasswordWithTokenRequest,
508) -> Result<(), Error<AuthResetPasswordWithTokenError>> {
509    let local_var_configuration = configuration;
510
511    let local_var_client = &local_var_configuration.client;
512
513    let local_var_uri_str = format!(
514        "{}/v1/auth:resetPasswordWithToken",
515        local_var_configuration.qcs_config.api_url()
516    );
517    let mut local_var_req_builder =
518        local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
519
520    #[cfg(feature = "tracing")]
521    {
522        // Ignore parsing errors if the URL is invalid for some reason.
523        // If it is invalid, it will turn up as an error later when actually making the request.
524        let local_var_do_tracing = local_var_uri_str
525            .parse::<::url::Url>()
526            .ok()
527            .is_none_or(|url| {
528                configuration
529                    .qcs_config
530                    .should_trace(&::urlpattern::UrlPatternMatchInput::Url(url))
531            });
532
533        if local_var_do_tracing {
534            ::tracing::debug!(
535                url=%local_var_uri_str,
536                method="POST",
537                "making auth_reset_password_with_token request",
538            );
539        }
540    }
541
542    // Use the QCS Bearer token if a client OAuthSession is present,
543    // but do not require one when the security schema says it is optional.
544    {
545        use qcs_api_client_common::configuration::TokenError;
546
547        #[allow(
548            clippy::nonminimal_bool,
549            clippy::eq_op,
550            reason = "Logic must be done at runtime since it cannot be handled by the mustache template engine."
551        )]
552        let is_jwt_bearer_optional: bool = false;
553
554        let token = local_var_configuration
555            .qcs_config
556            .get_bearer_access_token()
557            .await;
558
559        if is_jwt_bearer_optional && matches!(token, Err(TokenError::NoCredentials)) {
560            // the client is configured without any OAuthSession, but this call does not require one.
561            #[cfg(feature = "tracing")]
562            tracing::debug!(
563                "No client credentials found, but this call does not require authentication."
564            );
565        } else {
566            local_var_req_builder = local_var_req_builder.bearer_auth(token?.secret());
567        }
568    }
569
570    local_var_req_builder = local_var_req_builder.json(&auth_reset_password_with_token_request);
571
572    let local_var_req = local_var_req_builder.build()?;
573    let local_var_resp = local_var_client.execute(local_var_req).await?;
574
575    let local_var_status = local_var_resp.status();
576
577    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
578        Ok(())
579    } else {
580        let local_var_retry_delay =
581            duration_from_response(local_var_resp.status(), local_var_resp.headers(), backoff);
582        let local_var_content = local_var_resp.text().await?;
583        let local_var_entity: Option<AuthResetPasswordWithTokenError> =
584            serde_json::from_str(&local_var_content).ok();
585        let local_var_error = ResponseContent {
586            status: local_var_status,
587            content: local_var_content,
588            entity: local_var_entity,
589            retry_delay: local_var_retry_delay,
590        };
591        Err(Error::ResponseError(local_var_error))
592    }
593}
594
595/// Complete the forgot password flow, resetting the new password in exchange for an emailed token.
596pub async fn auth_reset_password_with_token(
597    configuration: &configuration::Configuration,
598    auth_reset_password_with_token_request: crate::models::AuthResetPasswordWithTokenRequest,
599) -> Result<(), Error<AuthResetPasswordWithTokenError>> {
600    let mut backoff = configuration.backoff.clone();
601    let mut refreshed_credentials = false;
602    let method = reqwest::Method::POST;
603    loop {
604        let result = auth_reset_password_with_token_inner(
605            configuration,
606            &mut backoff,
607            auth_reset_password_with_token_request.clone(),
608        )
609        .await;
610
611        match result {
612            Ok(result) => return Ok(result),
613            Err(Error::ResponseError(response)) => {
614                if !refreshed_credentials
615                    && matches!(
616                        response.status,
617                        StatusCode::FORBIDDEN | StatusCode::UNAUTHORIZED
618                    )
619                {
620                    configuration.qcs_config.refresh().await?;
621                    refreshed_credentials = true;
622                    continue;
623                } else if let Some(duration) = response.retry_delay {
624                    tokio::time::sleep(duration).await;
625                    continue;
626                }
627
628                return Err(Error::ResponseError(response));
629            }
630            Err(Error::Reqwest(error)) => {
631                if let Some(duration) = duration_from_reqwest_error(&method, &error, &mut backoff) {
632                    tokio::time::sleep(duration).await;
633                    continue;
634                }
635
636                return Err(Error::Reqwest(error));
637            }
638            Err(Error::Io(error)) => {
639                if let Some(duration) = duration_from_io_error(&method, &error, &mut backoff) {
640                    tokio::time::sleep(duration).await;
641                    continue;
642                }
643
644                return Err(Error::Io(error));
645            }
646            Err(error) => return Err(error),
647        }
648    }
649}