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