oauth2/
lib.rs

1#![warn(missing_docs)]
2//!
3//! An extensible, strongly-typed implementation of OAuth2
4//! ([RFC 6749](https://tools.ietf.org/html/rfc6749)) including token introspection ([RFC 7662](https://tools.ietf.org/html/rfc7662))
5//! and token revocation ([RFC 7009](https://tools.ietf.org/html/rfc7009)).
6//!
7//! # Contents
8//! * [Importing `oauth2`: selecting an HTTP client interface](#importing-oauth2-selecting-an-http-client-interface)
9//! * [Getting started: Authorization Code Grant w/ PKCE](#getting-started-authorization-code-grant-w-pkce)
10//!   * [Example: Synchronous (blocking) API](#example-synchronous-blocking-api)
11//!   * [Example: Asynchronous API](#example-asynchronous-api)
12//! * [Implicit Grant](#implicit-grant)
13//! * [Resource Owner Password Credentials Grant](#resource-owner-password-credentials-grant)
14//! * [Client Credentials Grant](#client-credentials-grant)
15//! * [Device Code Flow](#device-code-flow)
16//! * [Other examples](#other-examples)
17//!   * [Contributed Examples](#contributed-examples)
18//!
19//! # Importing `oauth2`: selecting an HTTP client interface
20//!
21//! This library offers a flexible HTTP client interface with two modes:
22//!  * **Synchronous (blocking)**
23//!  * **Asynchronous**
24//!
25//! For the HTTP client modes described above, the following HTTP client implementations can be
26//! used:
27//!  * **[`reqwest`]**
28//!
29//!    The `reqwest` HTTP client supports both the synchronous and asynchronous modes and is enabled
30//!    by default.
31//!
32//!    Synchronous client: [`reqwest::http_client`]
33//!
34//!    Asynchronous client: [`reqwest::async_http_client`]
35//!
36//!  * **[`curl`]**
37//!
38//!    The `curl` HTTP client only supports the synchronous HTTP client mode and can be enabled in
39//!    `Cargo.toml` via the `curl` feature flag.
40//!
41//!    Synchronous client: [`curl::http_client`]
42//!
43//! * **[`ureq`]**
44//!
45//!    The `ureq` HTTP client is a simple HTTP client with minimal dependencies. It only supports
46//!    the synchronous HTTP client mode and can be enabled in `Cargo.toml` via the `ureq` feature
47//!     flag.
48//!
49//!  * **Custom**
50//!
51//!    In addition to the clients above, users may define their own HTTP clients, which must accept
52//!    an [`HttpRequest`] and return an [`HttpResponse`] or error. Users writing their own clients
53//!    may wish to disable the default `reqwest` dependency by specifying
54//!    `default-features = false` in `Cargo.toml` (replacing `...` with the desired version of this
55//!    crate):
56//!    ```toml
57//!    oauth2 = { version = "...", default-features = false }
58//!    ```
59//!
60//!    Synchronous HTTP clients should implement the following trait:
61//!    ```rust,ignore
62//!    FnOnce(HttpRequest) -> Result<HttpResponse, RE>
63//!    where RE: std::error::Error + 'static
64//!    ```
65//!
66//!    Asynchronous HTTP clients should implement the following trait:
67//!    ```rust,ignore
68//!    FnOnce(HttpRequest) -> F
69//!    where
70//!      F: Future<Output = Result<HttpResponse, RE>>,
71//!      RE: std::error::Error + 'static
72//!    ```
73//!
74//! # Getting started: Authorization Code Grant w/ PKCE
75//!
76//! This is the most common OAuth2 flow. PKCE is recommended whenever the OAuth2 client has no
77//! client secret or has a client secret that cannot remain confidential (e.g., native, mobile, or
78//! client-side web applications).
79//!
80//! ## Example: Synchronous (blocking) API
81//!
82//! This example works with `oauth2`'s default feature flags, which include `reqwest`.
83//!
84//! ```rust,no_run
85//! use anyhow;
86//! use oauth2::{
87//!     AuthorizationCode,
88//!     AuthUrl,
89//!     ClientId,
90//!     ClientSecret,
91//!     CsrfToken,
92//!     PkceCodeChallenge,
93//!     RedirectUrl,
94//!     Scope,
95//!     TokenResponse,
96//!     TokenUrl
97//! };
98//! use oauth2::basic::BasicClient;
99//! use oauth2::reqwest::http_client;
100//! use url::Url;
101//!
102//! # fn err_wrapper() -> Result<(), anyhow::Error> {
103//! // Create an OAuth2 client by specifying the client ID, client secret, authorization URL and
104//! // token URL.
105//! let client =
106//!     BasicClient::new(
107//!         ClientId::new("client_id".to_string()),
108//!         Some(ClientSecret::new("client_secret".to_string())),
109//!         AuthUrl::new("http://authorize".to_string())?,
110//!         Some(TokenUrl::new("http://token".to_string())?)
111//!     )
112//!     // Set the URL the user will be redirected to after the authorization process.
113//!     .set_redirect_uri(RedirectUrl::new("http://redirect".to_string())?);
114//!
115//! // Generate a PKCE challenge.
116//! let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
117//!
118//! // Generate the full authorization URL.
119//! let (auth_url, csrf_token) = client
120//!     .authorize_url(CsrfToken::new_random)
121//!     // Set the desired scopes.
122//!     .add_scope(Scope::new("read".to_string()))
123//!     .add_scope(Scope::new("write".to_string()))
124//!     // Set the PKCE code challenge.
125//!     .set_pkce_challenge(pkce_challenge)
126//!     .url();
127//!
128//! // This is the URL you should redirect the user to, in order to trigger the authorization
129//! // process.
130//! println!("Browse to: {}", auth_url);
131//!
132//! // Once the user has been redirected to the redirect URL, you'll have access to the
133//! // authorization code. For security reasons, your code should verify that the `state`
134//! // parameter returned by the server matches `csrf_state`.
135//!
136//! // Now you can trade it for an access token.
137//! let token_result =
138//!     client
139//!         .exchange_code(AuthorizationCode::new("some authorization code".to_string()))
140//!         // Set the PKCE code verifier.
141//!         .set_pkce_verifier(pkce_verifier)
142//!         .request(http_client)?;
143//!
144//! // Unwrapping token_result will either produce a Token or a RequestTokenError.
145//! # Ok(())
146//! # }
147//! ```
148//!
149//! ## Example: Asynchronous API
150//!
151//! The example below uses async/await:
152//!
153//! ```rust,no_run
154//! use anyhow;
155//! use oauth2::{
156//!     AuthorizationCode,
157//!     AuthUrl,
158//!     ClientId,
159//!     ClientSecret,
160//!     CsrfToken,
161//!     PkceCodeChallenge,
162//!     RedirectUrl,
163//!     Scope,
164//!     TokenResponse,
165//!     TokenUrl
166//! };
167//! use oauth2::basic::BasicClient;
168//! # #[cfg(feature = "reqwest")]
169//! use oauth2::reqwest::async_http_client;
170//! use url::Url;
171//!
172//! # #[cfg(feature = "reqwest")]
173//! # async fn err_wrapper() -> Result<(), anyhow::Error> {
174//! // Create an OAuth2 client by specifying the client ID, client secret, authorization URL and
175//! // token URL.
176//! let client =
177//!     BasicClient::new(
178//!         ClientId::new("client_id".to_string()),
179//!         Some(ClientSecret::new("client_secret".to_string())),
180//!         AuthUrl::new("http://authorize".to_string())?,
181//!         Some(TokenUrl::new("http://token".to_string())?)
182//!     )
183//!     // Set the URL the user will be redirected to after the authorization process.
184//!     .set_redirect_uri(RedirectUrl::new("http://redirect".to_string())?);
185//!
186//! // Generate a PKCE challenge.
187//! let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256();
188//!
189//! // Generate the full authorization URL.
190//! let (auth_url, csrf_token) = client
191//!     .authorize_url(CsrfToken::new_random)
192//!     // Set the desired scopes.
193//!     .add_scope(Scope::new("read".to_string()))
194//!     .add_scope(Scope::new("write".to_string()))
195//!     // Set the PKCE code challenge.
196//!     .set_pkce_challenge(pkce_challenge)
197//!     .url();
198//!
199//! // This is the URL you should redirect the user to, in order to trigger the authorization
200//! // process.
201//! println!("Browse to: {}", auth_url);
202//!
203//! // Once the user has been redirected to the redirect URL, you'll have access to the
204//! // authorization code. For security reasons, your code should verify that the `state`
205//! // parameter returned by the server matches `csrf_state`.
206//!
207//! // Now you can trade it for an access token.
208//! let token_result = client
209//!     .exchange_code(AuthorizationCode::new("some authorization code".to_string()))
210//!     // Set the PKCE code verifier.
211//!     .set_pkce_verifier(pkce_verifier)
212//!     .request_async(async_http_client)
213//!     .await?;
214//!
215//! // Unwrapping token_result will either produce a Token or a RequestTokenError.
216//! # Ok(())
217//! # }
218//! ```
219//!
220//! # Implicit Grant
221//!
222//! This flow fetches an access token directly from the authorization endpoint. Be sure to
223//! understand the security implications of this flow before using it. In most cases, the
224//! Authorization Code Grant flow is preferable to the Implicit Grant flow.
225//!
226//! ## Example
227//!
228//! ```rust,no_run
229//! use anyhow;
230//! use oauth2::{
231//!     AuthUrl,
232//!     ClientId,
233//!     ClientSecret,
234//!     CsrfToken,
235//!     RedirectUrl,
236//!     Scope
237//! };
238//! use oauth2::basic::BasicClient;
239//! use url::Url;
240//!
241//! # fn err_wrapper() -> Result<(), anyhow::Error> {
242//! let client =
243//!     BasicClient::new(
244//!         ClientId::new("client_id".to_string()),
245//!         Some(ClientSecret::new("client_secret".to_string())),
246//!         AuthUrl::new("http://authorize".to_string())?,
247//!         None
248//!     );
249//!
250//! // Generate the full authorization URL.
251//! let (auth_url, csrf_token) = client
252//!     .authorize_url(CsrfToken::new_random)
253//!     .use_implicit_flow()
254//!     .url();
255//!
256//! // This is the URL you should redirect the user to, in order to trigger the authorization
257//! // process.
258//! println!("Browse to: {}", auth_url);
259//!
260//! // Once the user has been redirected to the redirect URL, you'll have the access code.
261//! // For security reasons, your code should verify that the `state` parameter returned by the
262//! // server matches `csrf_state`.
263//!
264//! # Ok(())
265//! # }
266//! ```
267//!
268//! # Resource Owner Password Credentials Grant
269//!
270//! You can ask for a *password* access token by calling the `Client::exchange_password` method,
271//! while including the username and password.
272//!
273//! ## Example
274//!
275//! ```rust,no_run
276//! use anyhow;
277//! use oauth2::{
278//!     AuthUrl,
279//!     ClientId,
280//!     ClientSecret,
281//!     ResourceOwnerPassword,
282//!     ResourceOwnerUsername,
283//!     Scope,
284//!     TokenResponse,
285//!     TokenUrl
286//! };
287//! use oauth2::basic::BasicClient;
288//! use oauth2::reqwest::http_client;
289//! use url::Url;
290//!
291//! # fn err_wrapper() -> Result<(), anyhow::Error> {
292//! let client =
293//!     BasicClient::new(
294//!         ClientId::new("client_id".to_string()),
295//!         Some(ClientSecret::new("client_secret".to_string())),
296//!         AuthUrl::new("http://authorize".to_string())?,
297//!         Some(TokenUrl::new("http://token".to_string())?)
298//!     );
299//!
300//! let token_result =
301//!     client
302//!         .exchange_password(
303//!             &ResourceOwnerUsername::new("user".to_string()),
304//!             &ResourceOwnerPassword::new("pass".to_string())
305//!         )
306//!         .add_scope(Scope::new("read".to_string()))
307//!         .request(http_client)?;
308//! # Ok(())
309//! # }
310//! ```
311//!
312//! # Client Credentials Grant
313//!
314//! You can ask for a *client credentials* access token by calling the
315//! `Client::exchange_client_credentials` method.
316//!
317//! ## Example
318//!
319//! ```rust,no_run
320//! use anyhow;
321//! use oauth2::{
322//!     AuthUrl,
323//!     ClientId,
324//!     ClientSecret,
325//!     Scope,
326//!     TokenResponse,
327//!     TokenUrl
328//! };
329//! use oauth2::basic::BasicClient;
330//! use oauth2::reqwest::http_client;
331//! use url::Url;
332//!
333//! # fn err_wrapper() -> Result<(), anyhow::Error> {
334//! let client =
335//!     BasicClient::new(
336//!         ClientId::new("client_id".to_string()),
337//!         Some(ClientSecret::new("client_secret".to_string())),
338//!         AuthUrl::new("http://authorize".to_string())?,
339//!         Some(TokenUrl::new("http://token".to_string())?),
340//!     );
341//!
342//! let token_result = client
343//!     .exchange_client_credentials()
344//!     .add_scope(Scope::new("read".to_string()))
345//!     .request(http_client)?;
346//! # Ok(())
347//! # }
348//! ```
349//!
350//! # Device Code Flow
351//!
352//! Device Code Flow allows users to sign in on browserless or input-constrained
353//! devices.  This is a two-stage process; first a user-code and verification
354//! URL are obtained by using the `Client::exchange_client_credentials`
355//! method. Those are displayed to the user, then are used in a second client
356//! to poll the token endpoint for a token.
357//!
358//! ## Example
359//!
360//! ```rust,no_run
361//! use anyhow;
362//! use oauth2::{
363//!     AuthUrl,
364//!     ClientId,
365//!     ClientSecret,
366//!     DeviceAuthorizationUrl,
367//!     Scope,
368//!     TokenResponse,
369//!     TokenUrl
370//! };
371//! use oauth2::basic::BasicClient;
372//! use oauth2::devicecode::StandardDeviceAuthorizationResponse;
373//! use oauth2::reqwest::http_client;
374//! use url::Url;
375//!
376//! # fn err_wrapper() -> Result<(), anyhow::Error> {
377//! let device_auth_url = DeviceAuthorizationUrl::new("http://deviceauth".to_string())?;
378//! let client =
379//!     BasicClient::new(
380//!         ClientId::new("client_id".to_string()),
381//!         Some(ClientSecret::new("client_secret".to_string())),
382//!         AuthUrl::new("http://authorize".to_string())?,
383//!         Some(TokenUrl::new("http://token".to_string())?),
384//!     )
385//!     .set_device_authorization_url(device_auth_url);
386//!
387//! let details: StandardDeviceAuthorizationResponse = client
388//!     .exchange_device_code()?
389//!     .add_scope(Scope::new("read".to_string()))
390//!     .request(http_client)?;
391//!
392//! println!(
393//!     "Open this URL in your browser:\n{}\nand enter the code: {}",
394//!     details.verification_uri().to_string(),
395//!     details.user_code().secret().to_string()
396//! );
397//!
398//! let token_result =
399//!     client
400//!     .exchange_device_access_token(&details)
401//!     .request(http_client, std::thread::sleep, None)?;
402//!
403//! # Ok(())
404//! # }
405//! ```
406//!
407//! # Other examples
408//!
409//! More specific implementations are available as part of the examples:
410//!
411//! - [Google](https://github.com/ramosbugs/oauth2-rs/blob/main/examples/google.rs) (includes token revocation)
412//! - [Github](https://github.com/ramosbugs/oauth2-rs/blob/main/examples/github.rs)
413//! - [Microsoft Device Code Flow (async)](https://github.com/ramosbugs/oauth2-rs/blob/main/examples/microsoft_devicecode.rs)
414//! - [Microsoft Graph](https://github.com/ramosbugs/oauth2-rs/blob/main/examples/msgraph.rs)
415//! - [Wunderlist](https://github.com/ramosbugs/oauth2-rs/blob/main/examples/wunderlist.rs)
416//!
417//! ## Contributed Examples
418//!
419//! - [`actix-web-oauth2`](https://github.com/pka/actix-web-oauth2) (version 2.x of this crate)
420//!
421use std::borrow::Cow;
422use std::error::Error;
423use std::fmt::Error as FormatterError;
424use std::fmt::{Debug, Display, Formatter};
425use std::future::Future;
426use std::marker::PhantomData;
427use std::sync::Arc;
428use std::time::Duration;
429
430use chrono::serde::ts_seconds_option;
431use chrono::{DateTime, Utc};
432use http::header::{HeaderMap, HeaderValue, ACCEPT, AUTHORIZATION, CONTENT_TYPE};
433use http::status::StatusCode;
434use serde::de::DeserializeOwned;
435use serde::{Deserialize, Serialize};
436use url::{form_urlencoded, Url};
437
438use crate::devicecode::DeviceAccessTokenPollResult;
439
440///
441/// Basic OAuth2 implementation with no extensions
442/// ([RFC 6749](https://tools.ietf.org/html/rfc6749)).
443///
444pub mod basic;
445
446///
447/// HTTP client backed by the [curl](https://crates.io/crates/curl) crate.
448/// Requires "curl" feature.
449///
450#[cfg(all(feature = "curl", not(target_arch = "wasm32")))]
451pub mod curl;
452
453#[cfg(all(feature = "curl", target_arch = "wasm32"))]
454compile_error!("wasm32 is not supported with the `curl` feature. Use the `reqwest` backend or a custom backend for wasm32 support");
455
456///
457/// Device Code Flow OAuth2 implementation
458/// ([RFC 8628](https://tools.ietf.org/html/rfc8628)).
459///
460pub mod devicecode;
461
462///
463/// OAuth 2.0 Token Revocation implementation
464/// ([RFC 7009](https://tools.ietf.org/html/rfc7009)).
465///
466pub mod revocation;
467
468///
469/// Helper methods used by OAuth2 implementations/extensions.
470///
471pub mod helpers;
472
473///
474/// HTTP client backed by the [reqwest](https://crates.io/crates/reqwest) crate.
475/// Requires "reqwest" feature.
476///
477#[cfg(feature = "reqwest")]
478pub mod reqwest;
479
480#[cfg(test)]
481mod tests;
482
483mod types;
484
485///
486/// HTTP client backed by the [ureq](https://crates.io/crates/ureq) crate.
487/// Requires "ureq" feature.
488///
489#[cfg(feature = "ureq")]
490pub mod ureq;
491
492///
493/// Public re-exports of types used for HTTP client interfaces.
494///
495pub use http;
496pub use url;
497
498pub use devicecode::{
499    DeviceAuthorizationResponse, DeviceCodeErrorResponse, DeviceCodeErrorResponseType,
500    EmptyExtraDeviceAuthorizationFields, ExtraDeviceAuthorizationFields,
501    StandardDeviceAuthorizationResponse,
502};
503
504pub use types::{
505    AccessToken, AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken,
506    DeviceAuthorizationUrl, DeviceCode, EndUserVerificationUrl, IntrospectionUrl,
507    PkceCodeChallenge, PkceCodeChallengeMethod, PkceCodeVerifier, RedirectUrl, RefreshToken,
508    ResourceOwnerPassword, ResourceOwnerUsername, ResponseType, RevocationUrl, Scope, TokenUrl,
509    UserCode, VerificationUriComplete,
510};
511
512pub use revocation::{RevocableToken, RevocationErrorResponseType, StandardRevocableToken};
513
514const CONTENT_TYPE_JSON: &str = "application/json";
515const CONTENT_TYPE_FORMENCODED: &str = "application/x-www-form-urlencoded";
516
517///
518/// There was a problem configuring the request.
519///
520#[non_exhaustive]
521#[derive(Debug, thiserror::Error)]
522pub enum ConfigurationError {
523    ///
524    /// The endpoint URL tp be contacted is missing.
525    ///
526    #[error("No {0} endpoint URL specified")]
527    MissingUrl(&'static str),
528    ///
529    /// The endpoint URL to be contacted MUST be HTTPS.
530    ///
531    #[error("Scheme for {0} endpoint URL must be HTTPS")]
532    InsecureUrl(&'static str),
533}
534
535///
536/// Indicates whether requests to the authorization server should use basic authentication or
537/// include the parameters in the request body for requests in which either is valid.
538///
539/// The default AuthType is *BasicAuth*, following the recommendation of
540/// [Section 2.3.1 of RFC 6749](https://tools.ietf.org/html/rfc6749#section-2.3.1).
541///
542#[derive(Clone, Debug)]
543#[non_exhaustive]
544pub enum AuthType {
545    /// The client_id and client_secret (if set) will be included as part of the request body.
546    RequestBody,
547    /// The client_id and client_secret will be included using the basic auth authentication scheme.
548    BasicAuth,
549}
550
551///
552/// Stores the configuration for an OAuth2 client.
553///
554/// # Error Types
555///
556/// To enable compile time verification that only the correct and complete set of errors for the `Client` function being
557/// invoked are exposed to the caller, the `Client` type is specialized on multiple implementations of the
558/// [`ErrorResponse`] trait. The exact [`ErrorResponse`] implementation returned varies by the RFC that the invoked
559/// `Client` function implements:
560///
561///   - Generic type `TE` (aka Token Error) for errors defined by [RFC 6749 OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749).
562///   - Generic type `TRE` (aka Token Revocation Error) for errors defined by [RFC 7009 OAuth 2.0 Token Revocation](https://tools.ietf.org/html/rfc7009).
563///
564/// For example when revoking a token, error code `unsupported_token_type` (from RFC 7009) may be returned:
565/// ```rust
566/// # use thiserror::Error;
567/// # use http::status::StatusCode;
568/// # use http::header::{HeaderValue, CONTENT_TYPE};
569/// # use oauth2::{*, basic::*};
570/// # let client = BasicClient::new(
571/// #     ClientId::new("aaa".to_string()),
572/// #     Some(ClientSecret::new("bbb".to_string())),
573/// #     AuthUrl::new("https://example.com/auth".to_string()).unwrap(),
574/// #     Some(TokenUrl::new("https://example.com/token".to_string()).unwrap()),
575/// # )
576/// # .set_revocation_uri(RevocationUrl::new("https://revocation/url".to_string()).unwrap());
577/// #
578/// # #[derive(Debug, Error)]
579/// # enum FakeError {
580/// #     #[error("error")]
581/// #     Err,
582/// # }
583/// #
584/// # let http_client = |_| -> Result<HttpResponse, FakeError> {
585/// #     Ok(HttpResponse {
586/// #         status_code: StatusCode::BAD_REQUEST,
587/// #         headers: vec![(
588/// #             CONTENT_TYPE,
589/// #             HeaderValue::from_str("application/json").unwrap(),
590/// #         )]
591/// #         .into_iter()
592/// #         .collect(),
593/// #         body: "{\"error\": \"unsupported_token_type\", \"error_description\": \"stuff happened\", \
594/// #                \"error_uri\": \"https://errors\"}"
595/// #             .to_string()
596/// #             .into_bytes(),
597/// #     })
598/// # };
599/// #
600/// let res = client
601///     .revoke_token(AccessToken::new("some token".to_string()).into())
602///     .unwrap()
603///     .request(http_client);
604///
605/// assert!(matches!(res, Err(
606///     RequestTokenError::ServerResponse(err)) if matches!(err.error(),
607///         RevocationErrorResponseType::UnsupportedTokenType)));
608/// ```
609///
610#[derive(Clone, Debug)]
611pub struct Client<TE, TR, TT, TIR, RT, TRE>
612where
613    TE: ErrorResponse,
614    TR: TokenResponse<TT>,
615    TT: TokenType,
616    TIR: TokenIntrospectionResponse<TT>,
617    RT: RevocableToken,
618    TRE: ErrorResponse,
619{
620    client_id: ClientId,
621    client_secret: Option<ClientSecret>,
622    auth_url: AuthUrl,
623    auth_type: AuthType,
624    token_url: Option<TokenUrl>,
625    redirect_url: Option<RedirectUrl>,
626    introspection_url: Option<IntrospectionUrl>,
627    revocation_url: Option<RevocationUrl>,
628    device_authorization_url: Option<DeviceAuthorizationUrl>,
629    phantom: PhantomData<(TE, TR, TT, TIR, RT, TRE)>,
630}
631
632impl<TE, TR, TT, TIR, RT, TRE> Client<TE, TR, TT, TIR, RT, TRE>
633where
634    TE: ErrorResponse + 'static,
635    TR: TokenResponse<TT>,
636    TT: TokenType,
637    TIR: TokenIntrospectionResponse<TT>,
638    RT: RevocableToken,
639    TRE: ErrorResponse + 'static,
640{
641    ///
642    /// Initializes an OAuth2 client with the fields common to most OAuth2 flows.
643    ///
644    /// # Arguments
645    ///
646    /// * `client_id` -  Client ID
647    /// * `client_secret` -  Optional client secret. A client secret is generally used for private
648    ///   (server-side) OAuth2 clients and omitted from public (client-side or native app) OAuth2
649    ///   clients (see [RFC 8252](https://tools.ietf.org/html/rfc8252)).
650    /// * `auth_url` -  Authorization endpoint: used by the client to obtain authorization from
651    ///   the resource owner via user-agent redirection. This URL is used in all standard OAuth2
652    ///   flows except the [Resource Owner Password Credentials
653    ///   Grant](https://tools.ietf.org/html/rfc6749#section-4.3) and the
654    ///   [Client Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.4).
655    /// * `token_url` - Token endpoint: used by the client to exchange an authorization grant
656    ///   (code) for an access token, typically with client authentication. This URL is used in
657    ///   all standard OAuth2 flows except the
658    ///   [Implicit Grant](https://tools.ietf.org/html/rfc6749#section-4.2). If this value is set
659    ///   to `None`, the `exchange_*` methods will return `Err(RequestTokenError::Other(_))`.
660    ///
661    pub fn new(
662        client_id: ClientId,
663        client_secret: Option<ClientSecret>,
664        auth_url: AuthUrl,
665        token_url: Option<TokenUrl>,
666    ) -> Self {
667        Client {
668            client_id,
669            client_secret,
670            auth_url,
671            auth_type: AuthType::BasicAuth,
672            token_url,
673            redirect_url: None,
674            introspection_url: None,
675            revocation_url: None,
676            device_authorization_url: None,
677            phantom: PhantomData,
678        }
679    }
680
681    ///
682    /// Configures the type of client authentication used for communicating with the authorization
683    /// server.
684    ///
685    /// The default is to use HTTP Basic authentication, as recommended in
686    /// [Section 2.3.1 of RFC 6749](https://tools.ietf.org/html/rfc6749#section-2.3.1). Note that
687    /// if a client secret is omitted (i.e., `client_secret` is set to `None` when calling
688    /// [`Client::new`]), [`AuthType::RequestBody`] is used regardless of the `auth_type` passed to
689    /// this function.
690    ///
691    pub fn set_auth_type(mut self, auth_type: AuthType) -> Self {
692        self.auth_type = auth_type;
693
694        self
695    }
696
697    ///
698    /// Sets the redirect URL used by the authorization endpoint.
699    ///
700    pub fn set_redirect_uri(mut self, redirect_url: RedirectUrl) -> Self {
701        self.redirect_url = Some(redirect_url);
702
703        self
704    }
705
706    ///
707    /// Sets the introspection URL for contacting the ([RFC 7662](https://tools.ietf.org/html/rfc7662))
708    /// introspection endpoint.
709    ///
710    pub fn set_introspection_uri(mut self, introspection_url: IntrospectionUrl) -> Self {
711        self.introspection_url = Some(introspection_url);
712
713        self
714    }
715
716    ///
717    /// Sets the revocation URL for contacting the revocation endpoint ([RFC 7009](https://tools.ietf.org/html/rfc7009)).
718    ///
719    /// See: [`revoke_token()`](Self::revoke_token())
720    ///
721    pub fn set_revocation_uri(mut self, revocation_url: RevocationUrl) -> Self {
722        self.revocation_url = Some(revocation_url);
723
724        self
725    }
726
727    ///
728    /// Sets the the device authorization URL used by the device authorization endpoint.
729    /// Used for Device Code Flow, as per [RFC 8628](https://tools.ietf.org/html/rfc8628).
730    ///
731    pub fn set_device_authorization_url(
732        mut self,
733        device_authorization_url: DeviceAuthorizationUrl,
734    ) -> Self {
735        self.device_authorization_url = Some(device_authorization_url);
736
737        self
738    }
739
740    ///
741    /// Generates an authorization URL for a new authorization request.
742    ///
743    /// # Arguments
744    ///
745    /// * `state_fn` - A function that returns an opaque value used by the client to maintain state
746    ///   between the request and callback. The authorization server includes this value when
747    ///   redirecting the user-agent back to the client.
748    ///
749    /// # Security Warning
750    ///
751    /// Callers should use a fresh, unpredictable `state` for each authorization request and verify
752    /// that this value matches the `state` parameter passed by the authorization server to the
753    /// redirect URI. Doing so mitigates
754    /// [Cross-Site Request Forgery](https://tools.ietf.org/html/rfc6749#section-10.12)
755    ///  attacks. To disable CSRF protections (NOT recommended), use `insecure::authorize_url`
756    ///  instead.
757    ///
758    pub fn authorize_url<S>(&self, state_fn: S) -> AuthorizationRequest
759    where
760        S: FnOnce() -> CsrfToken,
761    {
762        AuthorizationRequest {
763            auth_url: &self.auth_url,
764            client_id: &self.client_id,
765            extra_params: Vec::new(),
766            pkce_challenge: None,
767            redirect_url: self.redirect_url.as_ref().map(Cow::Borrowed),
768            response_type: "code".into(),
769            scopes: Vec::new(),
770            state: state_fn(),
771        }
772    }
773
774    ///
775    /// Exchanges a code produced by a successful authorization process with an access token.
776    ///
777    /// Acquires ownership of the `code` because authorization codes may only be used once to
778    /// retrieve an access token from the authorization server.
779    ///
780    /// See <https://tools.ietf.org/html/rfc6749#section-4.1.3>.
781    ///
782    pub fn exchange_code(&self, code: AuthorizationCode) -> CodeTokenRequest<TE, TR, TT> {
783        CodeTokenRequest {
784            auth_type: &self.auth_type,
785            client_id: &self.client_id,
786            client_secret: self.client_secret.as_ref(),
787            code,
788            extra_params: Vec::new(),
789            pkce_verifier: None,
790            token_url: self.token_url.as_ref(),
791            redirect_url: self.redirect_url.as_ref().map(Cow::Borrowed),
792            _phantom: PhantomData,
793        }
794    }
795
796    ///
797    /// Requests an access token for the *password* grant type.
798    ///
799    /// See <https://tools.ietf.org/html/rfc6749#section-4.3.2>.
800    ///
801    pub fn exchange_password<'a, 'b>(
802        &'a self,
803        username: &'b ResourceOwnerUsername,
804        password: &'b ResourceOwnerPassword,
805    ) -> PasswordTokenRequest<'b, TE, TR, TT>
806    where
807        'a: 'b,
808    {
809        PasswordTokenRequest::<'b> {
810            auth_type: &self.auth_type,
811            client_id: &self.client_id,
812            client_secret: self.client_secret.as_ref(),
813            username,
814            password,
815            extra_params: Vec::new(),
816            scopes: Vec::new(),
817            token_url: self.token_url.as_ref(),
818            _phantom: PhantomData,
819        }
820    }
821
822    ///
823    /// Requests an access token for the *client credentials* grant type.
824    ///
825    /// See <https://tools.ietf.org/html/rfc6749#section-4.4.2>.
826    ///
827    pub fn exchange_client_credentials(&self) -> ClientCredentialsTokenRequest<TE, TR, TT> {
828        ClientCredentialsTokenRequest {
829            auth_type: &self.auth_type,
830            client_id: &self.client_id,
831            client_secret: self.client_secret.as_ref(),
832            extra_params: Vec::new(),
833            scopes: Vec::new(),
834            token_url: self.token_url.as_ref(),
835            _phantom: PhantomData,
836        }
837    }
838
839    ///
840    /// Exchanges a refresh token for an access token
841    ///
842    /// See <https://tools.ietf.org/html/rfc6749#section-6>.
843    ///
844    pub fn exchange_refresh_token<'a, 'b>(
845        &'a self,
846        refresh_token: &'b RefreshToken,
847    ) -> RefreshTokenRequest<'b, TE, TR, TT>
848    where
849        'a: 'b,
850    {
851        RefreshTokenRequest {
852            auth_type: &self.auth_type,
853            client_id: &self.client_id,
854            client_secret: self.client_secret.as_ref(),
855            extra_params: Vec::new(),
856            refresh_token,
857            scopes: Vec::new(),
858            token_url: self.token_url.as_ref(),
859            _phantom: PhantomData,
860        }
861    }
862
863    ///
864    /// Perform a device authorization request as per
865    /// <https://tools.ietf.org/html/rfc8628#section-3.1>.
866    ///
867    pub fn exchange_device_code(
868        &self,
869    ) -> Result<DeviceAuthorizationRequest<TE>, ConfigurationError> {
870        Ok(DeviceAuthorizationRequest {
871            auth_type: &self.auth_type,
872            client_id: &self.client_id,
873            client_secret: self.client_secret.as_ref(),
874            extra_params: Vec::new(),
875            scopes: Vec::new(),
876            device_authorization_url: self
877                .device_authorization_url
878                .as_ref()
879                .ok_or(ConfigurationError::MissingUrl("device authorization_url"))?,
880            _phantom: PhantomData,
881        })
882    }
883
884    ///
885    /// Perform a device access token request as per
886    /// <https://tools.ietf.org/html/rfc8628#section-3.4>.
887    ///
888    pub fn exchange_device_access_token<'a, 'b, 'c, EF>(
889        &'a self,
890        auth_response: &'b DeviceAuthorizationResponse<EF>,
891    ) -> DeviceAccessTokenRequest<'b, 'c, TR, TT, EF>
892    where
893        'a: 'b,
894        EF: ExtraDeviceAuthorizationFields,
895    {
896        DeviceAccessTokenRequest {
897            auth_type: &self.auth_type,
898            client_id: &self.client_id,
899            client_secret: self.client_secret.as_ref(),
900            extra_params: Vec::new(),
901            token_url: self.token_url.as_ref(),
902            dev_auth_resp: auth_response,
903            time_fn: Arc::new(Utc::now),
904            max_backoff_interval: None,
905            _phantom: PhantomData,
906        }
907    }
908
909    ///
910    /// Query the authorization server [`RFC 7662 compatible`](https://tools.ietf.org/html/rfc7662) introspection
911    /// endpoint to determine the set of metadata for a previously received token.
912    ///
913    /// Requires that [`set_introspection_uri()`](Self::set_introspection_uri()) have already been called to set the
914    /// introspection endpoint URL.
915    ///
916    /// Attempting to submit the generated request without calling [`set_introspection_uri()`](Self::set_introspection_uri())
917    /// first will result in an error.
918    ///
919    pub fn introspect<'a>(
920        &'a self,
921        token: &'a AccessToken,
922    ) -> Result<IntrospectionRequest<'a, TE, TIR, TT>, ConfigurationError> {
923        Ok(IntrospectionRequest {
924            auth_type: &self.auth_type,
925            client_id: &self.client_id,
926            client_secret: self.client_secret.as_ref(),
927            extra_params: Vec::new(),
928            introspection_url: self
929                .introspection_url
930                .as_ref()
931                .ok_or(ConfigurationError::MissingUrl("introspection"))?,
932            token,
933            token_type_hint: None,
934            _phantom: PhantomData,
935        })
936    }
937
938    ///
939    /// Attempts to revoke the given previously received token using an [RFC 7009 OAuth 2.0 Token Revocation](https://tools.ietf.org/html/rfc7009)
940    /// compatible endpoint.
941    ///
942    /// Requires that [`set_revocation_uri()`](Self::set_revocation_uri()) have already been called to set the
943    /// revocation endpoint URL.
944    ///
945    /// Attempting to submit the generated request without calling [`set_revocation_uri()`](Self::set_revocation_uri())
946    /// first will result in an error.
947    ///
948    pub fn revoke_token(
949        &self,
950        token: RT,
951    ) -> Result<RevocationRequest<RT, TRE>, ConfigurationError> {
952        // https://tools.ietf.org/html/rfc7009#section-2 states:
953        //   "The client requests the revocation of a particular token by making an
954        //    HTTP POST request to the token revocation endpoint URL.  This URL
955        //    MUST conform to the rules given in [RFC6749], Section 3.1.  Clients
956        //    MUST verify that the URL is an HTTPS URL."
957        let revocation_url = match self.revocation_url.as_ref() {
958            Some(url) if url.url().scheme() == "https" => Ok(url),
959            Some(_) => Err(ConfigurationError::InsecureUrl("revocation")),
960            None => Err(ConfigurationError::MissingUrl("revocation")),
961        }?;
962
963        Ok(RevocationRequest {
964            auth_type: &self.auth_type,
965            client_id: &self.client_id,
966            client_secret: self.client_secret.as_ref(),
967            extra_params: Vec::new(),
968            revocation_url,
969            token,
970            _phantom: PhantomData,
971        })
972    }
973
974    ///
975    /// Returns the Client ID.
976    ///
977    pub fn client_id(&self) -> &ClientId {
978        &self.client_id
979    }
980
981    ///
982    /// Returns the authorization endpoint.
983    ///
984    pub fn auth_url(&self) -> &AuthUrl {
985        &self.auth_url
986    }
987
988    ///
989    /// Returns the type of client authentication used for communicating with the authorization
990    /// server.
991    ///
992    pub fn auth_type(&self) -> &AuthType {
993        &self.auth_type
994    }
995
996    ///
997    /// Returns the token endpoint.
998    ///
999    pub fn token_url(&self) -> Option<&TokenUrl> {
1000        self.token_url.as_ref()
1001    }
1002
1003    ///
1004    /// Returns the redirect URL used by the authorization endpoint.
1005    ///
1006    pub fn redirect_url(&self) -> Option<&RedirectUrl> {
1007        self.redirect_url.as_ref()
1008    }
1009
1010    ///
1011    /// Returns the introspection URL for contacting the ([RFC 7662](https://tools.ietf.org/html/rfc7662))
1012    /// introspection endpoint.
1013    ///
1014    pub fn introspection_url(&self) -> Option<&IntrospectionUrl> {
1015        self.introspection_url.as_ref()
1016    }
1017
1018    ///
1019    /// Returns the revocation URL for contacting the revocation endpoint ([RFC 7009](https://tools.ietf.org/html/rfc7009)).
1020    ///
1021    /// See: [`revoke_token()`](Self::revoke_token())
1022    ///
1023    pub fn revocation_url(&self) -> Option<&RevocationUrl> {
1024        self.revocation_url.as_ref()
1025    }
1026
1027    ///
1028    /// Returns the the device authorization URL used by the device authorization endpoint.
1029    ///
1030    pub fn device_authorization_url(&self) -> Option<&DeviceAuthorizationUrl> {
1031        self.device_authorization_url.as_ref()
1032    }
1033}
1034
1035///
1036/// A request to the authorization endpoint
1037///
1038#[derive(Debug)]
1039pub struct AuthorizationRequest<'a> {
1040    auth_url: &'a AuthUrl,
1041    client_id: &'a ClientId,
1042    extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
1043    pkce_challenge: Option<PkceCodeChallenge>,
1044    redirect_url: Option<Cow<'a, RedirectUrl>>,
1045    response_type: Cow<'a, str>,
1046    scopes: Vec<Cow<'a, Scope>>,
1047    state: CsrfToken,
1048}
1049impl<'a> AuthorizationRequest<'a> {
1050    ///
1051    /// Appends a new scope to the authorization URL.
1052    ///
1053    pub fn add_scope(mut self, scope: Scope) -> Self {
1054        self.scopes.push(Cow::Owned(scope));
1055        self
1056    }
1057
1058    ///
1059    /// Appends a collection of scopes to the token request.
1060    ///
1061    pub fn add_scopes<I>(mut self, scopes: I) -> Self
1062    where
1063        I: IntoIterator<Item = Scope>,
1064    {
1065        self.scopes.extend(scopes.into_iter().map(Cow::Owned));
1066        self
1067    }
1068
1069    ///
1070    /// Appends an extra param to the authorization URL.
1071    ///
1072    /// This method allows extensions to be used without direct support from
1073    /// this crate. If `name` conflicts with a parameter managed by this crate, the
1074    /// behavior is undefined. In particular, do not set parameters defined by
1075    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
1076    /// [RFC 7636](https://tools.ietf.org/html/rfc7636).
1077    ///
1078    /// # Security Warning
1079    ///
1080    /// Callers should follow the security recommendations for any OAuth2 extensions used with
1081    /// this function, which are beyond the scope of
1082    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
1083    ///
1084    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
1085    where
1086        N: Into<Cow<'a, str>>,
1087        V: Into<Cow<'a, str>>,
1088    {
1089        self.extra_params.push((name.into(), value.into()));
1090        self
1091    }
1092
1093    ///
1094    /// Enables the [Implicit Grant](https://tools.ietf.org/html/rfc6749#section-4.2) flow.
1095    ///
1096    pub fn use_implicit_flow(mut self) -> Self {
1097        self.response_type = "token".into();
1098        self
1099    }
1100
1101    ///
1102    /// Enables custom flows other than the `code` and `token` (implicit flow) grant.
1103    ///
1104    pub fn set_response_type(mut self, response_type: &ResponseType) -> Self {
1105        self.response_type = (&**response_type).to_owned().into();
1106        self
1107    }
1108
1109    ///
1110    /// Enables the use of [Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636)
1111    /// (PKCE).
1112    ///
1113    /// PKCE is *highly recommended* for all public clients (i.e., those for which there
1114    /// is no client secret or for which the client secret is distributed with the client,
1115    /// such as in a native, mobile app, or browser app).
1116    ///
1117    pub fn set_pkce_challenge(mut self, pkce_code_challenge: PkceCodeChallenge) -> Self {
1118        self.pkce_challenge = Some(pkce_code_challenge);
1119        self
1120    }
1121
1122    ///
1123    /// Overrides the `redirect_url` to the one specified.
1124    ///
1125    pub fn set_redirect_uri(mut self, redirect_url: Cow<'a, RedirectUrl>) -> Self {
1126        self.redirect_url = Some(redirect_url);
1127        self
1128    }
1129
1130    ///
1131    /// Returns the full authorization URL and CSRF state for this authorization
1132    /// request.
1133    ///
1134    pub fn url(self) -> (Url, CsrfToken) {
1135        let scopes = self
1136            .scopes
1137            .iter()
1138            .map(|s| s.to_string())
1139            .collect::<Vec<_>>()
1140            .join(" ");
1141
1142        let url = {
1143            let mut pairs: Vec<(&str, &str)> = vec![
1144                ("response_type", self.response_type.as_ref()),
1145                ("client_id", &self.client_id),
1146                ("state", self.state.secret()),
1147            ];
1148
1149            if let Some(ref pkce_challenge) = self.pkce_challenge {
1150                pairs.push(("code_challenge", &pkce_challenge.as_str()));
1151                pairs.push(("code_challenge_method", &pkce_challenge.method().as_str()));
1152            }
1153
1154            if let Some(ref redirect_url) = self.redirect_url {
1155                pairs.push(("redirect_uri", redirect_url.as_str()));
1156            }
1157
1158            if !scopes.is_empty() {
1159                pairs.push(("scope", &scopes));
1160            }
1161
1162            let mut url: Url = self.auth_url.url().to_owned();
1163
1164            url.query_pairs_mut()
1165                .extend_pairs(pairs.iter().map(|&(k, v)| (k, &v[..])));
1166
1167            url.query_pairs_mut()
1168                .extend_pairs(self.extra_params.iter().cloned());
1169            url
1170        };
1171
1172        (url, self.state)
1173    }
1174}
1175
1176///
1177/// An HTTP request.
1178///
1179#[derive(Clone, Debug)]
1180pub struct HttpRequest {
1181    // These are all owned values so that the request can safely be passed between
1182    // threads.
1183    /// URL to which the HTTP request is being made.
1184    pub url: Url,
1185    /// HTTP request method for this request.
1186    pub method: http::method::Method,
1187    /// HTTP request headers to send.
1188    pub headers: HeaderMap,
1189    /// HTTP request body (typically for POST requests only).
1190    pub body: Vec<u8>,
1191}
1192
1193///
1194/// An HTTP response.
1195///
1196#[derive(Clone, Debug)]
1197pub struct HttpResponse {
1198    /// HTTP status code returned by the server.
1199    pub status_code: http::status::StatusCode,
1200    /// HTTP response headers returned by the server.
1201    pub headers: HeaderMap,
1202    /// HTTP response body returned by the server.
1203    pub body: Vec<u8>,
1204}
1205
1206///
1207/// A request to exchange an authorization code for an access token.
1208///
1209/// See <https://tools.ietf.org/html/rfc6749#section-4.1.3>.
1210///
1211#[derive(Debug)]
1212pub struct CodeTokenRequest<'a, TE, TR, TT>
1213where
1214    TE: ErrorResponse,
1215    TR: TokenResponse<TT>,
1216    TT: TokenType,
1217{
1218    auth_type: &'a AuthType,
1219    client_id: &'a ClientId,
1220    client_secret: Option<&'a ClientSecret>,
1221    code: AuthorizationCode,
1222    extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
1223    pkce_verifier: Option<PkceCodeVerifier>,
1224    token_url: Option<&'a TokenUrl>,
1225    redirect_url: Option<Cow<'a, RedirectUrl>>,
1226    _phantom: PhantomData<(TE, TR, TT)>,
1227}
1228impl<'a, TE, TR, TT> CodeTokenRequest<'a, TE, TR, TT>
1229where
1230    TE: ErrorResponse + 'static,
1231    TR: TokenResponse<TT>,
1232    TT: TokenType,
1233{
1234    ///
1235    /// Appends an extra param to the token request.
1236    ///
1237    /// This method allows extensions to be used without direct support from
1238    /// this crate. If `name` conflicts with a parameter managed by this crate, the
1239    /// behavior is undefined. In particular, do not set parameters defined by
1240    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
1241    /// [RFC 7636](https://tools.ietf.org/html/rfc7636).
1242    ///
1243    /// # Security Warning
1244    ///
1245    /// Callers should follow the security recommendations for any OAuth2 extensions used with
1246    /// this function, which are beyond the scope of
1247    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
1248    ///
1249    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
1250    where
1251        N: Into<Cow<'a, str>>,
1252        V: Into<Cow<'a, str>>,
1253    {
1254        self.extra_params.push((name.into(), value.into()));
1255        self
1256    }
1257
1258    ///
1259    /// Completes the [Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636)
1260    /// (PKCE) protocol flow.
1261    ///
1262    /// This method must be called if `set_pkce_challenge` was used during the authorization
1263    /// request.
1264    ///
1265    pub fn set_pkce_verifier(mut self, pkce_verifier: PkceCodeVerifier) -> Self {
1266        self.pkce_verifier = Some(pkce_verifier);
1267        self
1268    }
1269
1270    ///
1271    /// Overrides the `redirect_url` to the one specified.
1272    ///
1273    pub fn set_redirect_uri(mut self, redirect_url: Cow<'a, RedirectUrl>) -> Self {
1274        self.redirect_url = Some(redirect_url);
1275        self
1276    }
1277
1278    fn prepare_request<RE>(self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
1279    where
1280        RE: Error + 'static,
1281    {
1282        let mut params = vec![
1283            ("grant_type", "authorization_code"),
1284            ("code", self.code.secret()),
1285        ];
1286        if let Some(ref pkce_verifier) = self.pkce_verifier {
1287            params.push(("code_verifier", pkce_verifier.secret()));
1288        }
1289
1290        Ok(endpoint_request(
1291            self.auth_type,
1292            self.client_id,
1293            self.client_secret,
1294            &self.extra_params,
1295            self.redirect_url,
1296            None,
1297            self.token_url
1298                .ok_or_else(|| RequestTokenError::Other("no token_url provided".to_string()))?
1299                .url(),
1300            params,
1301        ))
1302    }
1303
1304    ///
1305    /// Synchronously sends the request to the authorization server and awaits a response.
1306    ///
1307    pub fn request<F, RE>(self, http_client: F) -> Result<TR, RequestTokenError<RE, TE>>
1308    where
1309        F: FnOnce(HttpRequest) -> Result<HttpResponse, RE>,
1310        RE: Error + 'static,
1311    {
1312        http_client(self.prepare_request()?)
1313            .map_err(RequestTokenError::Request)
1314            .and_then(endpoint_response)
1315    }
1316
1317    ///
1318    /// Asynchronously sends the request to the authorization server and returns a Future.
1319    ///
1320    pub async fn request_async<C, F, RE>(
1321        self,
1322        http_client: C,
1323    ) -> Result<TR, RequestTokenError<RE, TE>>
1324    where
1325        C: FnOnce(HttpRequest) -> F,
1326        F: Future<Output = Result<HttpResponse, RE>>,
1327        RE: Error + 'static,
1328    {
1329        let http_request = self.prepare_request()?;
1330        let http_response = http_client(http_request)
1331            .await
1332            .map_err(RequestTokenError::Request)?;
1333        endpoint_response(http_response)
1334    }
1335}
1336
1337///
1338/// A request to exchange a refresh token for an access token.
1339///
1340/// See <https://tools.ietf.org/html/rfc6749#section-6>.
1341///
1342#[derive(Debug)]
1343pub struct RefreshTokenRequest<'a, TE, TR, TT>
1344where
1345    TE: ErrorResponse,
1346    TR: TokenResponse<TT>,
1347    TT: TokenType,
1348{
1349    auth_type: &'a AuthType,
1350    client_id: &'a ClientId,
1351    client_secret: Option<&'a ClientSecret>,
1352    extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
1353    refresh_token: &'a RefreshToken,
1354    scopes: Vec<Cow<'a, Scope>>,
1355    token_url: Option<&'a TokenUrl>,
1356    _phantom: PhantomData<(TE, TR, TT)>,
1357}
1358impl<'a, TE, TR, TT> RefreshTokenRequest<'a, TE, TR, TT>
1359where
1360    TE: ErrorResponse + 'static,
1361    TR: TokenResponse<TT>,
1362    TT: TokenType,
1363{
1364    ///
1365    /// Appends an extra param to the token request.
1366    ///
1367    /// This method allows extensions to be used without direct support from
1368    /// this crate. If `name` conflicts with a parameter managed by this crate, the
1369    /// behavior is undefined. In particular, do not set parameters defined by
1370    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
1371    /// [RFC 7636](https://tools.ietf.org/html/rfc7636).
1372    ///
1373    /// # Security Warning
1374    ///
1375    /// Callers should follow the security recommendations for any OAuth2 extensions used with
1376    /// this function, which are beyond the scope of
1377    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
1378    ///
1379    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
1380    where
1381        N: Into<Cow<'a, str>>,
1382        V: Into<Cow<'a, str>>,
1383    {
1384        self.extra_params.push((name.into(), value.into()));
1385        self
1386    }
1387
1388    ///
1389    /// Appends a new scope to the token request.
1390    ///
1391    pub fn add_scope(mut self, scope: Scope) -> Self {
1392        self.scopes.push(Cow::Owned(scope));
1393        self
1394    }
1395
1396    ///
1397    /// Appends a collection of scopes to the token request.
1398    ///
1399    pub fn add_scopes<I>(mut self, scopes: I) -> Self
1400    where
1401        I: IntoIterator<Item = Scope>,
1402    {
1403        self.scopes.extend(scopes.into_iter().map(Cow::Owned));
1404        self
1405    }
1406
1407    ///
1408    /// Synchronously sends the request to the authorization server and awaits a response.
1409    ///
1410    pub fn request<F, RE>(self, http_client: F) -> Result<TR, RequestTokenError<RE, TE>>
1411    where
1412        F: FnOnce(HttpRequest) -> Result<HttpResponse, RE>,
1413        RE: Error + 'static,
1414    {
1415        http_client(self.prepare_request()?)
1416            .map_err(RequestTokenError::Request)
1417            .and_then(endpoint_response)
1418    }
1419    ///
1420    /// Asynchronously sends the request to the authorization server and awaits a response.
1421    ///
1422    pub async fn request_async<C, F, RE>(
1423        self,
1424        http_client: C,
1425    ) -> Result<TR, RequestTokenError<RE, TE>>
1426    where
1427        C: FnOnce(HttpRequest) -> F,
1428        F: Future<Output = Result<HttpResponse, RE>>,
1429        RE: Error + 'static,
1430    {
1431        let http_request = self.prepare_request()?;
1432        let http_response = http_client(http_request)
1433            .await
1434            .map_err(RequestTokenError::Request)?;
1435        endpoint_response(http_response)
1436    }
1437
1438    fn prepare_request<RE>(&self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
1439    where
1440        RE: Error + 'static,
1441    {
1442        Ok(endpoint_request(
1443            self.auth_type,
1444            self.client_id,
1445            self.client_secret,
1446            &self.extra_params,
1447            None,
1448            Some(&self.scopes),
1449            self.token_url
1450                .ok_or_else(|| RequestTokenError::Other("no token_url provided".to_string()))?
1451                .url(),
1452            vec![
1453                ("grant_type", "refresh_token"),
1454                ("refresh_token", self.refresh_token.secret()),
1455            ],
1456        ))
1457    }
1458}
1459
1460///
1461/// A request to exchange resource owner credentials for an access token.
1462///
1463/// See <https://tools.ietf.org/html/rfc6749#section-4.3>.
1464///
1465#[derive(Debug)]
1466pub struct PasswordTokenRequest<'a, TE, TR, TT>
1467where
1468    TE: ErrorResponse,
1469    TR: TokenResponse<TT>,
1470    TT: TokenType,
1471{
1472    auth_type: &'a AuthType,
1473    client_id: &'a ClientId,
1474    client_secret: Option<&'a ClientSecret>,
1475    extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
1476    username: &'a ResourceOwnerUsername,
1477    password: &'a ResourceOwnerPassword,
1478    scopes: Vec<Cow<'a, Scope>>,
1479    token_url: Option<&'a TokenUrl>,
1480    _phantom: PhantomData<(TE, TR, TT)>,
1481}
1482impl<'a, TE, TR, TT> PasswordTokenRequest<'a, TE, TR, TT>
1483where
1484    TE: ErrorResponse + 'static,
1485    TR: TokenResponse<TT>,
1486    TT: TokenType,
1487{
1488    ///
1489    /// Appends an extra param to the token request.
1490    ///
1491    /// This method allows extensions to be used without direct support from
1492    /// this crate. If `name` conflicts with a parameter managed by this crate, the
1493    /// behavior is undefined. In particular, do not set parameters defined by
1494    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
1495    /// [RFC 7636](https://tools.ietf.org/html/rfc7636).
1496    ///
1497    /// # Security Warning
1498    ///
1499    /// Callers should follow the security recommendations for any OAuth2 extensions used with
1500    /// this function, which are beyond the scope of
1501    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
1502    ///
1503    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
1504    where
1505        N: Into<Cow<'a, str>>,
1506        V: Into<Cow<'a, str>>,
1507    {
1508        self.extra_params.push((name.into(), value.into()));
1509        self
1510    }
1511
1512    ///
1513    /// Appends a new scope to the token request.
1514    ///
1515    pub fn add_scope(mut self, scope: Scope) -> Self {
1516        self.scopes.push(Cow::Owned(scope));
1517        self
1518    }
1519
1520    ///
1521    /// Appends a collection of scopes to the token request.
1522    ///
1523    pub fn add_scopes<I>(mut self, scopes: I) -> Self
1524    where
1525        I: IntoIterator<Item = Scope>,
1526    {
1527        self.scopes.extend(scopes.into_iter().map(Cow::Owned));
1528        self
1529    }
1530
1531    ///
1532    /// Synchronously sends the request to the authorization server and awaits a response.
1533    ///
1534    pub fn request<F, RE>(self, http_client: F) -> Result<TR, RequestTokenError<RE, TE>>
1535    where
1536        F: FnOnce(HttpRequest) -> Result<HttpResponse, RE>,
1537        RE: Error + 'static,
1538    {
1539        http_client(self.prepare_request()?)
1540            .map_err(RequestTokenError::Request)
1541            .and_then(endpoint_response)
1542    }
1543
1544    ///
1545    /// Asynchronously sends the request to the authorization server and awaits a response.
1546    ///
1547    pub async fn request_async<C, F, RE>(
1548        self,
1549        http_client: C,
1550    ) -> Result<TR, RequestTokenError<RE, TE>>
1551    where
1552        C: FnOnce(HttpRequest) -> F,
1553        F: Future<Output = Result<HttpResponse, RE>>,
1554        RE: Error + 'static,
1555    {
1556        let http_request = self.prepare_request()?;
1557        let http_response = http_client(http_request)
1558            .await
1559            .map_err(RequestTokenError::Request)?;
1560        endpoint_response(http_response)
1561    }
1562
1563    fn prepare_request<RE>(&self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
1564    where
1565        RE: Error + 'static,
1566    {
1567        Ok(endpoint_request(
1568            self.auth_type,
1569            self.client_id,
1570            self.client_secret,
1571            &self.extra_params,
1572            None,
1573            Some(&self.scopes),
1574            self.token_url
1575                .ok_or_else(|| RequestTokenError::Other("no token_url provided".to_string()))?
1576                .url(),
1577            vec![
1578                ("grant_type", "password"),
1579                ("username", self.username),
1580                ("password", self.password.secret()),
1581            ],
1582        ))
1583    }
1584}
1585
1586///
1587/// A request to exchange client credentials for an access token.
1588///
1589/// See <https://tools.ietf.org/html/rfc6749#section-4.4>.
1590///
1591#[derive(Debug)]
1592pub struct ClientCredentialsTokenRequest<'a, TE, TR, TT>
1593where
1594    TE: ErrorResponse,
1595    TR: TokenResponse<TT>,
1596    TT: TokenType,
1597{
1598    auth_type: &'a AuthType,
1599    client_id: &'a ClientId,
1600    client_secret: Option<&'a ClientSecret>,
1601    extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
1602    scopes: Vec<Cow<'a, Scope>>,
1603    token_url: Option<&'a TokenUrl>,
1604    _phantom: PhantomData<(TE, TR, TT)>,
1605}
1606impl<'a, TE, TR, TT> ClientCredentialsTokenRequest<'a, TE, TR, TT>
1607where
1608    TE: ErrorResponse + 'static,
1609    TR: TokenResponse<TT>,
1610    TT: TokenType,
1611{
1612    ///
1613    /// Appends an extra param to the token request.
1614    ///
1615    /// This method allows extensions to be used without direct support from
1616    /// this crate. If `name` conflicts with a parameter managed by this crate, the
1617    /// behavior is undefined. In particular, do not set parameters defined by
1618    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
1619    /// [RFC 7636](https://tools.ietf.org/html/rfc7636).
1620    ///
1621    /// # Security Warning
1622    ///
1623    /// Callers should follow the security recommendations for any OAuth2 extensions used with
1624    /// this function, which are beyond the scope of
1625    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
1626    ///
1627    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
1628    where
1629        N: Into<Cow<'a, str>>,
1630        V: Into<Cow<'a, str>>,
1631    {
1632        self.extra_params.push((name.into(), value.into()));
1633        self
1634    }
1635
1636    ///
1637    /// Appends a new scope to the token request.
1638    ///
1639    pub fn add_scope(mut self, scope: Scope) -> Self {
1640        self.scopes.push(Cow::Owned(scope));
1641        self
1642    }
1643
1644    ///
1645    /// Appends a collection of scopes to the token request.
1646    ///
1647    pub fn add_scopes<I>(mut self, scopes: I) -> Self
1648    where
1649        I: IntoIterator<Item = Scope>,
1650    {
1651        self.scopes.extend(scopes.into_iter().map(Cow::Owned));
1652        self
1653    }
1654
1655    ///
1656    /// Synchronously sends the request to the authorization server and awaits a response.
1657    ///
1658    pub fn request<F, RE>(self, http_client: F) -> Result<TR, RequestTokenError<RE, TE>>
1659    where
1660        F: FnOnce(HttpRequest) -> Result<HttpResponse, RE>,
1661        RE: Error + 'static,
1662    {
1663        http_client(self.prepare_request()?)
1664            .map_err(RequestTokenError::Request)
1665            .and_then(endpoint_response)
1666    }
1667
1668    ///
1669    /// Asynchronously sends the request to the authorization server and awaits a response.
1670    ///
1671    pub async fn request_async<C, F, RE>(
1672        self,
1673        http_client: C,
1674    ) -> Result<TR, RequestTokenError<RE, TE>>
1675    where
1676        C: FnOnce(HttpRequest) -> F,
1677        F: Future<Output = Result<HttpResponse, RE>>,
1678        RE: Error + 'static,
1679    {
1680        let http_request = self.prepare_request()?;
1681        let http_response = http_client(http_request)
1682            .await
1683            .map_err(RequestTokenError::Request)?;
1684        endpoint_response(http_response)
1685    }
1686
1687    fn prepare_request<RE>(&self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
1688    where
1689        RE: Error + 'static,
1690    {
1691        Ok(endpoint_request(
1692            self.auth_type,
1693            self.client_id,
1694            self.client_secret,
1695            &self.extra_params,
1696            None,
1697            Some(&self.scopes),
1698            self.token_url
1699                .ok_or_else(|| RequestTokenError::Other("no token_url provided".to_string()))?
1700                .url(),
1701            vec![("grant_type", "client_credentials")],
1702        ))
1703    }
1704}
1705
1706///
1707/// A request to introspect an access token.
1708///
1709/// See <https://tools.ietf.org/html/rfc7662#section-2.1>.
1710///
1711#[derive(Debug)]
1712pub struct IntrospectionRequest<'a, TE, TIR, TT>
1713where
1714    TE: ErrorResponse,
1715    TIR: TokenIntrospectionResponse<TT>,
1716    TT: TokenType,
1717{
1718    token: &'a AccessToken,
1719    token_type_hint: Option<Cow<'a, str>>,
1720
1721    auth_type: &'a AuthType,
1722    client_id: &'a ClientId,
1723    client_secret: Option<&'a ClientSecret>,
1724    extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
1725    introspection_url: &'a IntrospectionUrl,
1726
1727    _phantom: PhantomData<(TE, TIR, TT)>,
1728}
1729
1730impl<'a, TE, TIR, TT> IntrospectionRequest<'a, TE, TIR, TT>
1731where
1732    TE: ErrorResponse + 'static,
1733    TIR: TokenIntrospectionResponse<TT>,
1734    TT: TokenType,
1735{
1736    ///
1737    /// Sets the optional token_type_hint parameter.
1738    ///
1739    /// See <https://tools.ietf.org/html/rfc7662#section-2.1>.
1740    ///
1741    /// OPTIONAL.  A hint about the type of the token submitted for
1742    ///       introspection.  The protected resource MAY pass this parameter to
1743    ///       help the authorization server optimize the token lookup.  If the
1744    ///       server is unable to locate the token using the given hint, it MUST
1745    ///      extend its search across all of its supported token types.  An
1746    ///      authorization server MAY ignore this parameter, particularly if it
1747    ///      is able to detect the token type automatically.  Values for this
1748    ///      field are defined in the "OAuth Token Type Hints" registry defined
1749    ///      in OAuth Token Revocation [RFC7009](https://tools.ietf.org/html/rfc7009).
1750    ///
1751    pub fn set_token_type_hint<V>(mut self, value: V) -> Self
1752    where
1753        V: Into<Cow<'a, str>>,
1754    {
1755        self.token_type_hint = Some(value.into());
1756
1757        self
1758    }
1759
1760    ///
1761    /// Appends an extra param to the token introspection request.
1762    ///
1763    /// This method allows extensions to be used without direct support from
1764    /// this crate. If `name` conflicts with a parameter managed by this crate, the
1765    /// behavior is undefined. In particular, do not set parameters defined by
1766    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
1767    /// [RFC 7662](https://tools.ietf.org/html/rfc7662).
1768    ///
1769    /// # Security Warning
1770    ///
1771    /// Callers should follow the security recommendations for any OAuth2 extensions used with
1772    /// this function, which are beyond the scope of
1773    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
1774    ///
1775    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
1776    where
1777        N: Into<Cow<'a, str>>,
1778        V: Into<Cow<'a, str>>,
1779    {
1780        self.extra_params.push((name.into(), value.into()));
1781        self
1782    }
1783
1784    fn prepare_request<RE>(self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
1785    where
1786        RE: Error + 'static,
1787    {
1788        let mut params: Vec<(&str, &str)> = vec![("token", self.token.secret())];
1789        if let Some(ref token_type_hint) = self.token_type_hint {
1790            params.push(("token_type_hint", token_type_hint));
1791        }
1792
1793        Ok(endpoint_request(
1794            self.auth_type,
1795            self.client_id,
1796            self.client_secret,
1797            &self.extra_params,
1798            None,
1799            None,
1800            self.introspection_url.url(),
1801            params,
1802        ))
1803    }
1804
1805    ///
1806    /// Synchronously sends the request to the authorization server and awaits a response.
1807    ///
1808    pub fn request<F, RE>(self, http_client: F) -> Result<TIR, RequestTokenError<RE, TE>>
1809    where
1810        F: FnOnce(HttpRequest) -> Result<HttpResponse, RE>,
1811        RE: Error + 'static,
1812    {
1813        http_client(self.prepare_request()?)
1814            .map_err(RequestTokenError::Request)
1815            .and_then(endpoint_response)
1816    }
1817
1818    ///
1819    /// Asynchronously sends the request to the authorization server and returns a Future.
1820    ///
1821    pub async fn request_async<C, F, RE>(
1822        self,
1823        http_client: C,
1824    ) -> Result<TIR, RequestTokenError<RE, TE>>
1825    where
1826        C: FnOnce(HttpRequest) -> F,
1827        F: Future<Output = Result<HttpResponse, RE>>,
1828        RE: Error + 'static,
1829    {
1830        let http_request = self.prepare_request()?;
1831        let http_response = http_client(http_request)
1832            .await
1833            .map_err(RequestTokenError::Request)?;
1834        endpoint_response(http_response)
1835    }
1836}
1837
1838///
1839/// A request to revoke a token via an [`RFC 7009`](https://tools.ietf.org/html/rfc7009#section-2.1) compatible
1840/// endpoint.
1841///
1842#[derive(Debug)]
1843pub struct RevocationRequest<'a, RT, TE>
1844where
1845    RT: RevocableToken,
1846    TE: ErrorResponse,
1847{
1848    token: RT,
1849
1850    auth_type: &'a AuthType,
1851    client_id: &'a ClientId,
1852    client_secret: Option<&'a ClientSecret>,
1853    extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
1854    revocation_url: &'a RevocationUrl,
1855
1856    _phantom: PhantomData<(RT, TE)>,
1857}
1858
1859impl<'a, RT, TE> RevocationRequest<'a, RT, TE>
1860where
1861    RT: RevocableToken,
1862    TE: ErrorResponse + 'static,
1863{
1864    ///
1865    /// Appends an extra param to the token revocation request.
1866    ///
1867    /// This method allows extensions to be used without direct support from
1868    /// this crate. If `name` conflicts with a parameter managed by this crate, the
1869    /// behavior is undefined. In particular, do not set parameters defined by
1870    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
1871    /// [RFC 7662](https://tools.ietf.org/html/rfc7662).
1872    ///
1873    /// # Security Warning
1874    ///
1875    /// Callers should follow the security recommendations for any OAuth2 extensions used with
1876    /// this function, which are beyond the scope of
1877    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
1878    ///
1879    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
1880    where
1881        N: Into<Cow<'a, str>>,
1882        V: Into<Cow<'a, str>>,
1883    {
1884        self.extra_params.push((name.into(), value.into()));
1885        self
1886    }
1887
1888    fn prepare_request<RE>(self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
1889    where
1890        RE: Error + 'static,
1891    {
1892        let mut params: Vec<(&str, &str)> = vec![("token", self.token.secret())];
1893        if let Some(type_hint) = self.token.type_hint() {
1894            params.push(("token_type_hint", type_hint));
1895        }
1896
1897        Ok(endpoint_request(
1898            self.auth_type,
1899            self.client_id,
1900            self.client_secret,
1901            &self.extra_params,
1902            None,
1903            None,
1904            self.revocation_url.url(),
1905            params,
1906        ))
1907    }
1908
1909    ///
1910    /// Synchronously sends the request to the authorization server and awaits a response.
1911    ///
1912    /// A successful response indicates that the server either revoked the token or the token was not known to the
1913    /// server.
1914    ///
1915    /// Error [`UnsupportedTokenType`](crate::revocation::RevocationErrorResponseType::UnsupportedTokenType) will be returned if the
1916    /// type of token type given is not supported by the server.
1917    ///
1918    pub fn request<F, RE>(self, http_client: F) -> Result<(), RequestTokenError<RE, TE>>
1919    where
1920        F: FnOnce(HttpRequest) -> Result<HttpResponse, RE>,
1921        RE: Error + 'static,
1922    {
1923        // From https://tools.ietf.org/html/rfc7009#section-2.2:
1924        //   "The content of the response body is ignored by the client as all
1925        //    necessary information is conveyed in the response code."
1926        http_client(self.prepare_request()?)
1927            .map_err(RequestTokenError::Request)
1928            .and_then(endpoint_response_status_only)
1929    }
1930
1931    ///
1932    /// Asynchronously sends the request to the authorization server and returns a Future.
1933    ///
1934    pub async fn request_async<C, F, RE>(
1935        self,
1936        http_client: C,
1937    ) -> Result<(), RequestTokenError<RE, TE>>
1938    where
1939        C: FnOnce(HttpRequest) -> F,
1940        F: Future<Output = Result<HttpResponse, RE>>,
1941        RE: Error + 'static,
1942    {
1943        let http_request = self.prepare_request()?;
1944        let http_response = http_client(http_request)
1945            .await
1946            .map_err(RequestTokenError::Request)?;
1947        endpoint_response_status_only(http_response)
1948    }
1949}
1950
1951#[allow(clippy::too_many_arguments)]
1952fn endpoint_request<'a>(
1953    auth_type: &'a AuthType,
1954    client_id: &'a ClientId,
1955    client_secret: Option<&'a ClientSecret>,
1956    extra_params: &'a [(Cow<'a, str>, Cow<'a, str>)],
1957    redirect_url: Option<Cow<'a, RedirectUrl>>,
1958    scopes: Option<&'a Vec<Cow<'a, Scope>>>,
1959    url: &'a Url,
1960    params: Vec<(&'a str, &'a str)>,
1961) -> HttpRequest {
1962    let mut headers = HeaderMap::new();
1963    headers.append(ACCEPT, HeaderValue::from_static(CONTENT_TYPE_JSON));
1964    headers.append(
1965        CONTENT_TYPE,
1966        HeaderValue::from_static(CONTENT_TYPE_FORMENCODED),
1967    );
1968
1969    let scopes_opt = scopes.and_then(|scopes| {
1970        if !scopes.is_empty() {
1971            Some(
1972                scopes
1973                    .iter()
1974                    .map(|s| s.to_string())
1975                    .collect::<Vec<_>>()
1976                    .join(" "),
1977            )
1978        } else {
1979            None
1980        }
1981    });
1982
1983    let mut params: Vec<(&str, &str)> = params;
1984    if let Some(ref scopes) = scopes_opt {
1985        params.push(("scope", scopes));
1986    }
1987
1988    // FIXME: add support for auth extensions? e.g., client_secret_jwt and private_key_jwt
1989    match (auth_type, client_secret) {
1990        // Basic auth only makes sense when a client secret is provided. Otherwise, always pass the
1991        // client ID in the request body.
1992        (AuthType::BasicAuth, Some(secret)) => {
1993            // Section 2.3.1 of RFC 6749 requires separately url-encoding the id and secret
1994            // before using them as HTTP Basic auth username and password. Note that this is
1995            // not standard for ordinary Basic auth, so curl won't do it for us.
1996            let urlencoded_id: String =
1997                form_urlencoded::byte_serialize(&client_id.as_bytes()).collect();
1998            let urlencoded_secret: String =
1999                form_urlencoded::byte_serialize(secret.secret().as_bytes()).collect();
2000            let b64_credential =
2001                base64::encode(&format!("{}:{}", &urlencoded_id, urlencoded_secret));
2002            headers.append(
2003                AUTHORIZATION,
2004                HeaderValue::from_str(&format!("Basic {}", &b64_credential)).unwrap(),
2005            );
2006        }
2007        (AuthType::RequestBody, _) | (AuthType::BasicAuth, None) => {
2008            params.push(("client_id", client_id));
2009            if let Some(ref client_secret) = client_secret {
2010                params.push(("client_secret", client_secret.secret()));
2011            }
2012        }
2013    }
2014
2015    if let Some(ref redirect_url) = redirect_url {
2016        params.push(("redirect_uri", redirect_url.as_str()));
2017    }
2018
2019    params.extend_from_slice(
2020        extra_params
2021            .iter()
2022            .map(|&(ref k, ref v)| (k.as_ref(), v.as_ref()))
2023            .collect::<Vec<_>>()
2024            .as_slice(),
2025    );
2026
2027    let body = url::form_urlencoded::Serializer::new(String::new())
2028        .extend_pairs(params)
2029        .finish()
2030        .into_bytes();
2031
2032    HttpRequest {
2033        url: url.to_owned(),
2034        method: http::method::Method::POST,
2035        headers,
2036        body,
2037    }
2038}
2039
2040fn endpoint_response<RE, TE, DO>(
2041    http_response: HttpResponse,
2042) -> Result<DO, RequestTokenError<RE, TE>>
2043where
2044    RE: Error + 'static,
2045    TE: ErrorResponse,
2046    DO: DeserializeOwned,
2047{
2048    check_response_status(&http_response)?;
2049
2050    check_response_body(&http_response)?;
2051
2052    let response_body = http_response.body.as_slice();
2053    serde_path_to_error::deserialize(&mut serde_json::Deserializer::from_slice(response_body))
2054        .map_err(|e| RequestTokenError::Parse(e, response_body.to_vec()))
2055}
2056
2057fn endpoint_response_status_only<RE, TE>(
2058    http_response: HttpResponse,
2059) -> Result<(), RequestTokenError<RE, TE>>
2060where
2061    RE: Error + 'static,
2062    TE: ErrorResponse,
2063{
2064    check_response_status(&http_response)
2065}
2066
2067fn check_response_status<RE, TE>(
2068    http_response: &HttpResponse,
2069) -> Result<(), RequestTokenError<RE, TE>>
2070where
2071    RE: Error + 'static,
2072    TE: ErrorResponse,
2073{
2074    if http_response.status_code != StatusCode::OK {
2075        let reason = http_response.body.as_slice();
2076        if reason.is_empty() {
2077            return Err(RequestTokenError::Other(
2078                "Server returned empty error response".to_string(),
2079            ));
2080        } else {
2081            let error = match serde_path_to_error::deserialize::<_, TE>(
2082                &mut serde_json::Deserializer::from_slice(reason),
2083            ) {
2084                Ok(error) => RequestTokenError::ServerResponse(error),
2085                Err(error) => RequestTokenError::Parse(error, reason.to_vec()),
2086            };
2087            return Err(error);
2088        }
2089    }
2090
2091    Ok(())
2092}
2093
2094fn check_response_body<RE, TE>(
2095    http_response: &HttpResponse,
2096) -> Result<(), RequestTokenError<RE, TE>>
2097where
2098    RE: Error + 'static,
2099    TE: ErrorResponse,
2100{
2101    // Validate that the response Content-Type is JSON.
2102    http_response
2103        .headers
2104        .get(CONTENT_TYPE)
2105        .map_or(Ok(()), |content_type|
2106            // Section 3.1.1.1 of RFC 7231 indicates that media types are case insensitive and
2107            // may be followed by optional whitespace and/or a parameter (e.g., charset).
2108            // See https://tools.ietf.org/html/rfc7231#section-3.1.1.1.
2109            if content_type.to_str().ok().filter(|ct| ct.to_lowercase().starts_with(CONTENT_TYPE_JSON)).is_none() {
2110                Err(
2111                    RequestTokenError::Other(
2112                        format!(
2113                            "Unexpected response Content-Type: {:?}, should be `{}`",
2114                            content_type,
2115                            CONTENT_TYPE_JSON
2116                        )
2117                    )
2118                )
2119            } else {
2120                Ok(())
2121            }
2122        )?;
2123
2124    if http_response.body.is_empty() {
2125        return Err(RequestTokenError::Other(
2126            "Server returned empty response body".to_string(),
2127        ));
2128    }
2129
2130    Ok(())
2131}
2132
2133///
2134/// The request for a set of verification codes from the authorization server.
2135///
2136/// See <https://tools.ietf.org/html/rfc8628#section-3.1>.
2137///
2138#[derive(Debug)]
2139pub struct DeviceAuthorizationRequest<'a, TE>
2140where
2141    TE: ErrorResponse,
2142{
2143    auth_type: &'a AuthType,
2144    client_id: &'a ClientId,
2145    client_secret: Option<&'a ClientSecret>,
2146    extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
2147    scopes: Vec<Cow<'a, Scope>>,
2148    device_authorization_url: &'a DeviceAuthorizationUrl,
2149    _phantom: PhantomData<TE>,
2150}
2151
2152impl<'a, TE> DeviceAuthorizationRequest<'a, TE>
2153where
2154    TE: ErrorResponse + 'static,
2155{
2156    ///
2157    /// Appends an extra param to the token request.
2158    ///
2159    /// This method allows extensions to be used without direct support from
2160    /// this crate. If `name` conflicts with a parameter managed by this crate, the
2161    /// behavior is undefined. In particular, do not set parameters defined by
2162    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
2163    /// [RFC 7636](https://tools.ietf.org/html/rfc7636).
2164    ///
2165    /// # Security Warning
2166    ///
2167    /// Callers should follow the security recommendations for any OAuth2 extensions used with
2168    /// this function, which are beyond the scope of
2169    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
2170    ///
2171    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
2172    where
2173        N: Into<Cow<'a, str>>,
2174        V: Into<Cow<'a, str>>,
2175    {
2176        self.extra_params.push((name.into(), value.into()));
2177        self
2178    }
2179
2180    ///
2181    /// Appends a new scope to the token request.
2182    ///
2183    pub fn add_scope(mut self, scope: Scope) -> Self {
2184        self.scopes.push(Cow::Owned(scope));
2185        self
2186    }
2187
2188    ///
2189    /// Appends a collection of scopes to the token request.
2190    ///
2191    pub fn add_scopes<I>(mut self, scopes: I) -> Self
2192    where
2193        I: IntoIterator<Item = Scope>,
2194    {
2195        self.scopes.extend(scopes.into_iter().map(Cow::Owned));
2196        self
2197    }
2198
2199    fn prepare_request<RE>(self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
2200    where
2201        RE: Error + 'static,
2202    {
2203        Ok(endpoint_request(
2204            self.auth_type,
2205            self.client_id,
2206            self.client_secret,
2207            &self.extra_params,
2208            None,
2209            Some(&self.scopes),
2210            self.device_authorization_url.url(),
2211            vec![],
2212        ))
2213    }
2214
2215    ///
2216    /// Synchronously sends the request to the authorization server and awaits a response.
2217    ///
2218    pub fn request<F, RE, EF>(
2219        self,
2220        http_client: F,
2221    ) -> Result<DeviceAuthorizationResponse<EF>, RequestTokenError<RE, TE>>
2222    where
2223        F: FnOnce(HttpRequest) -> Result<HttpResponse, RE>,
2224        RE: Error + 'static,
2225        EF: ExtraDeviceAuthorizationFields,
2226    {
2227        http_client(self.prepare_request()?)
2228            .map_err(RequestTokenError::Request)
2229            .and_then(endpoint_response)
2230    }
2231
2232    ///
2233    /// Asynchronously sends the request to the authorization server and returns a Future.
2234    ///
2235    pub async fn request_async<C, F, RE, EF>(
2236        self,
2237        http_client: C,
2238    ) -> Result<DeviceAuthorizationResponse<EF>, RequestTokenError<RE, TE>>
2239    where
2240        C: FnOnce(HttpRequest) -> F,
2241        F: Future<Output = Result<HttpResponse, RE>>,
2242        RE: Error + 'static,
2243        EF: ExtraDeviceAuthorizationFields,
2244    {
2245        let http_request = self.prepare_request()?;
2246        let http_response = http_client(http_request)
2247            .await
2248            .map_err(RequestTokenError::Request)?;
2249        endpoint_response(http_response)
2250    }
2251}
2252
2253///
2254/// The request for an device access token from the authorization server.
2255///
2256/// See <https://tools.ietf.org/html/rfc8628#section-3.4>.
2257///
2258#[derive(Clone)]
2259pub struct DeviceAccessTokenRequest<'a, 'b, TR, TT, EF>
2260where
2261    TR: TokenResponse<TT>,
2262    TT: TokenType,
2263    EF: ExtraDeviceAuthorizationFields,
2264{
2265    auth_type: &'a AuthType,
2266    client_id: &'a ClientId,
2267    client_secret: Option<&'a ClientSecret>,
2268    extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
2269    token_url: Option<&'a TokenUrl>,
2270    dev_auth_resp: &'a DeviceAuthorizationResponse<EF>,
2271    time_fn: Arc<dyn Fn() -> DateTime<Utc> + 'b + Send + Sync>,
2272    max_backoff_interval: Option<Duration>,
2273    _phantom: PhantomData<(TR, TT, EF)>,
2274}
2275
2276impl<'a, 'b, TR, TT, EF> DeviceAccessTokenRequest<'a, 'b, TR, TT, EF>
2277where
2278    TR: TokenResponse<TT>,
2279    TT: TokenType,
2280    EF: ExtraDeviceAuthorizationFields,
2281{
2282    ///
2283    /// Appends an extra param to the token request.
2284    ///
2285    /// This method allows extensions to be used without direct support from
2286    /// this crate. If `name` conflicts with a parameter managed by this crate, the
2287    /// behavior is undefined. In particular, do not set parameters defined by
2288    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
2289    /// [RFC 7636](https://tools.ietf.org/html/rfc7636).
2290    ///
2291    /// # Security Warning
2292    ///
2293    /// Callers should follow the security recommendations for any OAuth2 extensions used with
2294    /// this function, which are beyond the scope of
2295    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
2296    ///
2297    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
2298    where
2299        N: Into<Cow<'a, str>>,
2300        V: Into<Cow<'a, str>>,
2301    {
2302        self.extra_params.push((name.into(), value.into()));
2303        self
2304    }
2305
2306    ///
2307    /// Specifies a function for returning the current time.
2308    ///
2309    /// This function is used while polling the authorization server.
2310    ///
2311    pub fn set_time_fn<T>(mut self, time_fn: T) -> Self
2312    where
2313        T: Fn() -> DateTime<Utc> + 'b + Send + Sync,
2314    {
2315        self.time_fn = Arc::new(time_fn);
2316        self
2317    }
2318
2319    ///
2320    /// Sets the upper limit of the sleep interval to use for polling the token endpoint when the
2321    /// HTTP client returns an error (e.g., in case of connection timeout).
2322    ///
2323    pub fn set_max_backoff_interval(mut self, interval: Duration) -> Self {
2324        self.max_backoff_interval = Some(interval);
2325        self
2326    }
2327
2328    ///
2329    /// Synchronously polls the authorization server for a response, waiting
2330    /// using a user defined sleep function.
2331    ///
2332    pub fn request<F, S, RE>(
2333        self,
2334        http_client: F,
2335        sleep_fn: S,
2336        timeout: Option<Duration>,
2337    ) -> Result<TR, RequestTokenError<RE, DeviceCodeErrorResponse>>
2338    where
2339        F: Fn(HttpRequest) -> Result<HttpResponse, RE>,
2340        S: Fn(Duration),
2341        RE: Error + 'static,
2342    {
2343        // Get the request timeout and starting interval
2344        let timeout_dt = self.compute_timeout(timeout)?;
2345        let mut interval = self.dev_auth_resp.interval();
2346
2347        // Loop while requesting a token.
2348        loop {
2349            let now = (*self.time_fn)();
2350            if now > timeout_dt {
2351                break Err(RequestTokenError::ServerResponse(
2352                    DeviceCodeErrorResponse::new(
2353                        DeviceCodeErrorResponseType::ExpiredToken,
2354                        Some(String::from("This device code has expired.")),
2355                        None,
2356                    ),
2357                ));
2358            }
2359
2360            match self.process_response(http_client(self.prepare_request()?), interval) {
2361                DeviceAccessTokenPollResult::ContinueWithNewPollInterval(new_interval) => {
2362                    interval = new_interval
2363                }
2364                DeviceAccessTokenPollResult::Done(res, _) => break res,
2365            }
2366
2367            // Sleep here using the provided sleep function.
2368            sleep_fn(interval);
2369        }
2370    }
2371
2372    ///
2373    /// Asynchronously sends the request to the authorization server and awaits a response.
2374    ///
2375    pub async fn request_async<C, F, S, SF, RE>(
2376        self,
2377        http_client: C,
2378        sleep_fn: S,
2379        timeout: Option<Duration>,
2380    ) -> Result<TR, RequestTokenError<RE, DeviceCodeErrorResponse>>
2381    where
2382        C: Fn(HttpRequest) -> F,
2383        F: Future<Output = Result<HttpResponse, RE>>,
2384        S: Fn(Duration) -> SF,
2385        SF: Future<Output = ()>,
2386        RE: Error + 'static,
2387    {
2388        // Get the request timeout and starting interval
2389        let timeout_dt = self.compute_timeout(timeout)?;
2390        let mut interval = self.dev_auth_resp.interval();
2391
2392        // Loop while requesting a token.
2393        loop {
2394            let now = (*self.time_fn)();
2395            if now > timeout_dt {
2396                break Err(RequestTokenError::ServerResponse(
2397                    DeviceCodeErrorResponse::new(
2398                        DeviceCodeErrorResponseType::ExpiredToken,
2399                        Some(String::from("This device code has expired.")),
2400                        None,
2401                    ),
2402                ));
2403            }
2404
2405            match self.process_response(http_client(self.prepare_request()?).await, interval) {
2406                DeviceAccessTokenPollResult::ContinueWithNewPollInterval(new_interval) => {
2407                    interval = new_interval
2408                }
2409                DeviceAccessTokenPollResult::Done(res, _) => break res,
2410            }
2411
2412            // Sleep here using the provided sleep function.
2413            sleep_fn(interval).await;
2414        }
2415    }
2416
2417    fn prepare_request<RE>(
2418        &self,
2419    ) -> Result<HttpRequest, RequestTokenError<RE, DeviceCodeErrorResponse>>
2420    where
2421        RE: Error + 'static,
2422    {
2423        Ok(endpoint_request(
2424            self.auth_type,
2425            self.client_id,
2426            self.client_secret,
2427            &self.extra_params,
2428            None,
2429            None,
2430            self.token_url
2431                .ok_or_else(|| RequestTokenError::Other("no token_url provided".to_string()))?
2432                .url(),
2433            vec![
2434                ("grant_type", "urn:ietf:params:oauth:grant-type:device_code"),
2435                ("device_code", self.dev_auth_resp.device_code().secret()),
2436            ],
2437        ))
2438    }
2439
2440    fn process_response<RE>(
2441        &self,
2442        res: Result<HttpResponse, RE>,
2443        current_interval: Duration,
2444    ) -> DeviceAccessTokenPollResult<TR, RE, DeviceCodeErrorResponse, TT>
2445    where
2446        RE: Error + 'static,
2447    {
2448        let http_response = match res {
2449            Ok(inner) => inner,
2450            Err(_) => {
2451                // RFC 8628 requires a backoff in cases of connection timeout, but we can't
2452                // distinguish between connection timeouts and other HTTP client request errors
2453                // here. Set a maximum backoff so that the client doesn't effectively backoff
2454                // infinitely when there are network issues unrelated to server load.
2455                const DEFAULT_MAX_BACKOFF_INTERVAL: Duration = Duration::from_secs(10);
2456                let new_interval = std::cmp::min(
2457                    current_interval.checked_mul(2).unwrap_or(current_interval),
2458                    self.max_backoff_interval
2459                        .unwrap_or(DEFAULT_MAX_BACKOFF_INTERVAL),
2460                );
2461                return DeviceAccessTokenPollResult::ContinueWithNewPollInterval(new_interval);
2462            }
2463        };
2464
2465        // Explicitly process the response with a DeviceCodeErrorResponse
2466        let res = endpoint_response::<RE, DeviceCodeErrorResponse, TR>(http_response);
2467        match res {
2468            // On a ServerResponse error, the error needs inspecting as a DeviceCodeErrorResponse
2469            // to work out whether a retry needs to happen.
2470            Err(RequestTokenError::ServerResponse(dcer)) => {
2471                match dcer.error() {
2472                    // On AuthorizationPending, a retry needs to happen with the same poll interval.
2473                    DeviceCodeErrorResponseType::AuthorizationPending => {
2474                        DeviceAccessTokenPollResult::ContinueWithNewPollInterval(current_interval)
2475                    }
2476                    // On SlowDown, a retry needs to happen with a larger poll interval.
2477                    DeviceCodeErrorResponseType::SlowDown => {
2478                        DeviceAccessTokenPollResult::ContinueWithNewPollInterval(
2479                            current_interval + Duration::from_secs(5),
2480                        )
2481                    }
2482
2483                    // On any other error, just return the error.
2484                    _ => DeviceAccessTokenPollResult::Done(
2485                        Err(RequestTokenError::ServerResponse(dcer)),
2486                        PhantomData,
2487                    ),
2488                }
2489            }
2490
2491            // On any other success or failure, return the failure.
2492            res => DeviceAccessTokenPollResult::Done(res, PhantomData),
2493        }
2494    }
2495
2496    fn compute_timeout<RE>(
2497        &self,
2498        timeout: Option<Duration>,
2499    ) -> Result<DateTime<Utc>, RequestTokenError<RE, DeviceCodeErrorResponse>>
2500    where
2501        RE: Error + 'static,
2502    {
2503        // Calculate the request timeout - if the user specified a timeout,
2504        // use that, otherwise use the value given by the device authorization
2505        // response.
2506        let timeout_dur = timeout.unwrap_or_else(|| self.dev_auth_resp.expires_in());
2507        let chrono_timeout = chrono::Duration::from_std(timeout_dur)
2508            .map_err(|_| RequestTokenError::Other("Failed to convert duration".to_string()))?;
2509
2510        // Calculate the DateTime at which the request times out.
2511        let timeout_dt = (*self.time_fn)()
2512            .checked_add_signed(chrono_timeout)
2513            .ok_or_else(|| RequestTokenError::Other("Failed to calculate timeout".to_string()))?;
2514
2515        Ok(timeout_dt)
2516    }
2517}
2518
2519///
2520/// Trait for OAuth2 access tokens.
2521///
2522pub trait TokenType: Clone + DeserializeOwned + Debug + PartialEq + Serialize {}
2523
2524///
2525/// Trait for adding extra fields to the `TokenResponse`.
2526///
2527pub trait ExtraTokenFields: DeserializeOwned + Debug + Serialize {}
2528
2529///
2530/// Empty (default) extra token fields.
2531///
2532#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
2533pub struct EmptyExtraTokenFields {}
2534impl ExtraTokenFields for EmptyExtraTokenFields {}
2535
2536///
2537/// Common methods shared by all OAuth2 token implementations.
2538///
2539/// The methods in this trait are defined in
2540/// [Section 5.1 of RFC 6749](https://tools.ietf.org/html/rfc6749#section-5.1). This trait exists
2541/// separately from the `StandardTokenResponse` struct to support customization by clients,
2542/// such as supporting interoperability with non-standards-complaint OAuth2 providers.
2543///
2544pub trait TokenResponse<TT>: Debug + DeserializeOwned + Serialize
2545where
2546    TT: TokenType,
2547{
2548    ///
2549    /// REQUIRED. The access token issued by the authorization server.
2550    ///
2551    fn access_token(&self) -> &AccessToken;
2552    ///
2553    /// REQUIRED. The type of the token issued as described in
2554    /// [Section 7.1](https://tools.ietf.org/html/rfc6749#section-7.1).
2555    /// Value is case insensitive and deserialized to the generic `TokenType` parameter.
2556    ///
2557    fn token_type(&self) -> &TT;
2558    ///
2559    /// RECOMMENDED. The lifetime in seconds of the access token. For example, the value 3600
2560    /// denotes that the access token will expire in one hour from the time the response was
2561    /// generated. If omitted, the authorization server SHOULD provide the expiration time via
2562    /// other means or document the default value.
2563    ///
2564    fn expires_in(&self) -> Option<Duration>;
2565    ///
2566    /// OPTIONAL. The refresh token, which can be used to obtain new access tokens using the same
2567    /// authorization grant as described in
2568    /// [Section 6](https://tools.ietf.org/html/rfc6749#section-6).
2569    ///
2570    fn refresh_token(&self) -> Option<&RefreshToken>;
2571    ///
2572    /// OPTIONAL, if identical to the scope requested by the client; otherwise, REQUIRED. The
2573    /// scope of the access token as described by
2574    /// [Section 3.3](https://tools.ietf.org/html/rfc6749#section-3.3). If included in the response,
2575    /// this space-delimited field is parsed into a `Vec` of individual scopes. If omitted from
2576    /// the response, this field is `None`.
2577    ///
2578    fn scopes(&self) -> Option<&Vec<Scope>>;
2579}
2580
2581///
2582/// Standard OAuth2 token response.
2583///
2584/// This struct includes the fields defined in
2585/// [Section 5.1 of RFC 6749](https://tools.ietf.org/html/rfc6749#section-5.1), as well as
2586/// extensions defined by the `EF` type parameter.
2587///
2588#[derive(Clone, Debug, Deserialize, Serialize)]
2589pub struct StandardTokenResponse<EF, TT>
2590where
2591    EF: ExtraTokenFields,
2592    TT: TokenType,
2593{
2594    access_token: AccessToken,
2595    #[serde(bound = "TT: TokenType")]
2596    #[serde(deserialize_with = "helpers::deserialize_untagged_enum_case_insensitive")]
2597    token_type: TT,
2598    #[serde(skip_serializing_if = "Option::is_none")]
2599    expires_in: Option<u64>,
2600    #[serde(skip_serializing_if = "Option::is_none")]
2601    refresh_token: Option<RefreshToken>,
2602    #[serde(rename = "scope")]
2603    #[serde(deserialize_with = "helpers::deserialize_space_delimited_vec")]
2604    #[serde(serialize_with = "helpers::serialize_space_delimited_vec")]
2605    #[serde(skip_serializing_if = "Option::is_none")]
2606    #[serde(default)]
2607    scopes: Option<Vec<Scope>>,
2608
2609    #[serde(bound = "EF: ExtraTokenFields")]
2610    #[serde(flatten)]
2611    extra_fields: EF,
2612}
2613impl<EF, TT> StandardTokenResponse<EF, TT>
2614where
2615    EF: ExtraTokenFields,
2616    TT: TokenType,
2617{
2618    ///
2619    /// Instantiate a new OAuth2 token response.
2620    ///
2621    pub fn new(access_token: AccessToken, token_type: TT, extra_fields: EF) -> Self {
2622        Self {
2623            access_token,
2624            token_type,
2625            expires_in: None,
2626            refresh_token: None,
2627            scopes: None,
2628            extra_fields,
2629        }
2630    }
2631
2632    ///
2633    /// Set the `access_token` field.
2634    ///
2635    pub fn set_access_token(&mut self, access_token: AccessToken) {
2636        self.access_token = access_token;
2637    }
2638
2639    ///
2640    /// Set the `token_type` field.
2641    ///
2642    pub fn set_token_type(&mut self, token_type: TT) {
2643        self.token_type = token_type;
2644    }
2645
2646    ///
2647    /// Set the `expires_in` field.
2648    ///
2649    pub fn set_expires_in(&mut self, expires_in: Option<&Duration>) {
2650        self.expires_in = expires_in.map(Duration::as_secs);
2651    }
2652
2653    ///
2654    /// Set the `refresh_token` field.
2655    ///
2656    pub fn set_refresh_token(&mut self, refresh_token: Option<RefreshToken>) {
2657        self.refresh_token = refresh_token;
2658    }
2659
2660    ///
2661    /// Set the `scopes` field.
2662    ///
2663    pub fn set_scopes(&mut self, scopes: Option<Vec<Scope>>) {
2664        self.scopes = scopes;
2665    }
2666
2667    ///
2668    /// Extra fields defined by the client application.
2669    ///
2670    pub fn extra_fields(&self) -> &EF {
2671        &self.extra_fields
2672    }
2673
2674    ///
2675    /// Set the extra fields defined by the client application.
2676    ///
2677    pub fn set_extra_fields(&mut self, extra_fields: EF) {
2678        self.extra_fields = extra_fields;
2679    }
2680}
2681impl<EF, TT> TokenResponse<TT> for StandardTokenResponse<EF, TT>
2682where
2683    EF: ExtraTokenFields,
2684    TT: TokenType,
2685{
2686    ///
2687    /// REQUIRED. The access token issued by the authorization server.
2688    ///
2689    fn access_token(&self) -> &AccessToken {
2690        &self.access_token
2691    }
2692    ///
2693    /// REQUIRED. The type of the token issued as described in
2694    /// [Section 7.1](https://tools.ietf.org/html/rfc6749#section-7.1).
2695    /// Value is case insensitive and deserialized to the generic `TokenType` parameter.
2696    ///
2697    fn token_type(&self) -> &TT {
2698        &self.token_type
2699    }
2700    ///
2701    /// RECOMMENDED. The lifetime in seconds of the access token. For example, the value 3600
2702    /// denotes that the access token will expire in one hour from the time the response was
2703    /// generated. If omitted, the authorization server SHOULD provide the expiration time via
2704    /// other means or document the default value.
2705    ///
2706    fn expires_in(&self) -> Option<Duration> {
2707        self.expires_in.map(Duration::from_secs)
2708    }
2709    ///
2710    /// OPTIONAL. The refresh token, which can be used to obtain new access tokens using the same
2711    /// authorization grant as described in
2712    /// [Section 6](https://tools.ietf.org/html/rfc6749#section-6).
2713    ///
2714    fn refresh_token(&self) -> Option<&RefreshToken> {
2715        self.refresh_token.as_ref()
2716    }
2717    ///
2718    /// OPTIONAL, if identical to the scope requested by the client; otherwise, REQUIRED. The
2719    /// scope of the access token as described by
2720    /// [Section 3.3](https://tools.ietf.org/html/rfc6749#section-3.3). If included in the response,
2721    /// this space-delimited field is parsed into a `Vec` of individual scopes. If omitted from
2722    /// the response, this field is `None`.
2723    ///
2724    fn scopes(&self) -> Option<&Vec<Scope>> {
2725        self.scopes.as_ref()
2726    }
2727}
2728
2729///
2730/// Common methods shared by all OAuth2 token introspection implementations.
2731///
2732/// The methods in this trait are defined in
2733/// [Section 2.2 of RFC 7662](https://tools.ietf.org/html/rfc7662#section-2.2). This trait exists
2734/// separately from the `StandardTokenIntrospectionResponse` struct to support customization by
2735/// clients, such as supporting interoperability with non-standards-complaint OAuth2 providers.
2736///
2737pub trait TokenIntrospectionResponse<TT>: Debug + DeserializeOwned + Serialize
2738where
2739    TT: TokenType,
2740{
2741    ///
2742    /// REQUIRED.  Boolean indicator of whether or not the presented token
2743    /// is currently active.  The specifics of a token's "active" state
2744    /// will vary depending on the implementation of the authorization
2745    /// server and the information it keeps about its tokens, but a "true"
2746    /// value return for the "active" property will generally indicate
2747    /// that a given token has been issued by this authorization server,
2748    /// has not been revoked by the resource owner, and is within its
2749    /// given time window of validity (e.g., after its issuance time and
2750    /// before its expiration time).
2751    ///
2752    fn active(&self) -> bool;
2753    ///
2754    ///
2755    /// OPTIONAL.  A JSON string containing a space-separated list of
2756    /// scopes associated with this token, in the format described in
2757    /// [Section 3.3 of RFC 7662](https://tools.ietf.org/html/rfc7662#section-3.3).
2758    /// If included in the response,
2759    /// this space-delimited field is parsed into a `Vec` of individual scopes. If omitted from
2760    /// the response, this field is `None`.
2761    ///
2762    fn scopes(&self) -> Option<&Vec<Scope>>;
2763    ///
2764    /// OPTIONAL.  Client identifier for the OAuth 2.0 client that
2765    /// requested this token.
2766    ///
2767    fn client_id(&self) -> Option<&ClientId>;
2768    ///
2769    /// OPTIONAL.  Human-readable identifier for the resource owner who
2770    /// authorized this token.
2771    ///
2772    fn username(&self) -> Option<&str>;
2773    ///
2774    /// OPTIONAL.  Type of the token as defined in
2775    /// [Section 5.1 of RFC 7662](https://tools.ietf.org/html/rfc7662#section-5.1).
2776    /// Value is case insensitive and deserialized to the generic `TokenType` parameter.
2777    ///
2778    fn token_type(&self) -> Option<&TT>;
2779    ///
2780    /// OPTIONAL.  Integer timestamp, measured in the number of seconds
2781    /// since January 1 1970 UTC, indicating when this token will expire,
2782    /// as defined in JWT [RFC7519](https://tools.ietf.org/html/rfc7519).
2783    ///
2784    fn exp(&self) -> Option<DateTime<Utc>>;
2785    ///
2786    /// OPTIONAL.  Integer timestamp, measured in the number of seconds
2787    /// since January 1 1970 UTC, indicating when this token was
2788    /// originally issued, as defined in JWT [RFC7519](https://tools.ietf.org/html/rfc7519).
2789    ///
2790    fn iat(&self) -> Option<DateTime<Utc>>;
2791    ///
2792    /// OPTIONAL.  Integer timestamp, measured in the number of seconds
2793    /// since January 1 1970 UTC, indicating when this token is not to be
2794    /// used before, as defined in JWT [RFC7519](https://tools.ietf.org/html/rfc7519).
2795    ///
2796    fn nbf(&self) -> Option<DateTime<Utc>>;
2797    ///
2798    /// OPTIONAL.  Subject of the token, as defined in JWT [RFC7519](https://tools.ietf.org/html/rfc7519).
2799    /// Usually a machine-readable identifier of the resource owner who
2800    /// authorized this token.
2801    ///
2802    fn sub(&self) -> Option<&str>;
2803    ///
2804    /// OPTIONAL.  Service-specific string identifier or list of string
2805    /// identifiers representing the intended audience for this token, as
2806    /// defined in JWT [RFC7519](https://tools.ietf.org/html/rfc7519).
2807    ///
2808    fn aud(&self) -> Option<&Vec<String>>;
2809    ///
2810    /// OPTIONAL.  String representing the issuer of this token, as
2811    /// defined in JWT [RFC7519](https://tools.ietf.org/html/rfc7519).
2812    ///
2813    fn iss(&self) -> Option<&str>;
2814    ///
2815    /// OPTIONAL.  String identifier for the token, as defined in JWT
2816    /// [RFC7519](https://tools.ietf.org/html/rfc7519).
2817    ///
2818    fn jti(&self) -> Option<&str>;
2819}
2820
2821///
2822/// Standard OAuth2 token introspection response.
2823///
2824/// This struct includes the fields defined in
2825/// [Section 2.2 of RFC 7662](https://tools.ietf.org/html/rfc7662#section-2.2), as well as
2826/// extensions defined by the `EF` type parameter.
2827///
2828#[derive(Clone, Debug, Deserialize, Serialize)]
2829pub struct StandardTokenIntrospectionResponse<EF, TT>
2830where
2831    EF: ExtraTokenFields,
2832    TT: TokenType + 'static,
2833{
2834    active: bool,
2835    #[serde(rename = "scope")]
2836    #[serde(deserialize_with = "helpers::deserialize_space_delimited_vec")]
2837    #[serde(serialize_with = "helpers::serialize_space_delimited_vec")]
2838    #[serde(skip_serializing_if = "Option::is_none")]
2839    #[serde(default)]
2840    scopes: Option<Vec<Scope>>,
2841    #[serde(skip_serializing_if = "Option::is_none")]
2842    client_id: Option<ClientId>,
2843    #[serde(skip_serializing_if = "Option::is_none")]
2844    username: Option<String>,
2845    #[serde(
2846        bound = "TT: TokenType",
2847        skip_serializing_if = "Option::is_none",
2848        deserialize_with = "helpers::deserialize_untagged_enum_case_insensitive",
2849        default = "none_field"
2850    )]
2851    token_type: Option<TT>,
2852    #[serde(skip_serializing_if = "Option::is_none")]
2853    #[serde(with = "ts_seconds_option")]
2854    #[serde(default)]
2855    exp: Option<DateTime<Utc>>,
2856    #[serde(skip_serializing_if = "Option::is_none")]
2857    #[serde(with = "ts_seconds_option")]
2858    #[serde(default)]
2859    iat: Option<DateTime<Utc>>,
2860    #[serde(skip_serializing_if = "Option::is_none")]
2861    #[serde(with = "ts_seconds_option")]
2862    #[serde(default)]
2863    nbf: Option<DateTime<Utc>>,
2864    #[serde(skip_serializing_if = "Option::is_none")]
2865    sub: Option<String>,
2866    #[serde(skip_serializing_if = "Option::is_none")]
2867    #[serde(default)]
2868    #[serde(deserialize_with = "helpers::deserialize_optional_string_or_vec_string")]
2869    aud: Option<Vec<String>>,
2870    #[serde(skip_serializing_if = "Option::is_none")]
2871    iss: Option<String>,
2872    #[serde(skip_serializing_if = "Option::is_none")]
2873    jti: Option<String>,
2874
2875    #[serde(bound = "EF: ExtraTokenFields")]
2876    #[serde(flatten)]
2877    extra_fields: EF,
2878}
2879
2880fn none_field<T>() -> Option<T> {
2881    None
2882}
2883
2884impl<EF, TT> StandardTokenIntrospectionResponse<EF, TT>
2885where
2886    EF: ExtraTokenFields,
2887    TT: TokenType,
2888{
2889    ///
2890    /// Instantiate a new OAuth2 token introspection response.
2891    ///
2892    pub fn new(active: bool, extra_fields: EF) -> Self {
2893        Self {
2894            active,
2895
2896            scopes: None,
2897            client_id: None,
2898            username: None,
2899            token_type: None,
2900            exp: None,
2901            iat: None,
2902            nbf: None,
2903            sub: None,
2904            aud: None,
2905            iss: None,
2906            jti: None,
2907            extra_fields,
2908        }
2909    }
2910
2911    ///
2912    /// Sets the `set_active` field.
2913    ///
2914    pub fn set_active(&mut self, active: bool) {
2915        self.active = active;
2916    }
2917    ///
2918    /// Sets the `set_scopes` field.
2919    ///
2920    pub fn set_scopes(&mut self, scopes: Option<Vec<Scope>>) {
2921        self.scopes = scopes;
2922    }
2923    ///
2924    /// Sets the `set_client_id` field.
2925    ///
2926    pub fn set_client_id(&mut self, client_id: Option<ClientId>) {
2927        self.client_id = client_id;
2928    }
2929    ///
2930    /// Sets the `set_username` field.
2931    ///
2932    pub fn set_username(&mut self, username: Option<String>) {
2933        self.username = username;
2934    }
2935    ///
2936    /// Sets the `set_token_type` field.
2937    ///
2938    pub fn set_token_type(&mut self, token_type: Option<TT>) {
2939        self.token_type = token_type;
2940    }
2941    ///
2942    /// Sets the `set_exp` field.
2943    ///
2944    pub fn set_exp(&mut self, exp: Option<DateTime<Utc>>) {
2945        self.exp = exp;
2946    }
2947    ///
2948    /// Sets the `set_iat` field.
2949    ///
2950    pub fn set_iat(&mut self, iat: Option<DateTime<Utc>>) {
2951        self.iat = iat;
2952    }
2953    ///
2954    /// Sets the `set_nbf` field.
2955    ///
2956    pub fn set_nbf(&mut self, nbf: Option<DateTime<Utc>>) {
2957        self.nbf = nbf;
2958    }
2959    ///
2960    /// Sets the `set_sub` field.
2961    ///
2962    pub fn set_sub(&mut self, sub: Option<String>) {
2963        self.sub = sub;
2964    }
2965    ///
2966    /// Sets the `set_aud` field.
2967    ///
2968    pub fn set_aud(&mut self, aud: Option<Vec<String>>) {
2969        self.aud = aud;
2970    }
2971    ///
2972    /// Sets the `set_iss` field.
2973    ///
2974    pub fn set_iss(&mut self, iss: Option<String>) {
2975        self.iss = iss;
2976    }
2977    ///
2978    /// Sets the `set_jti` field.
2979    ///
2980    pub fn set_jti(&mut self, jti: Option<String>) {
2981        self.jti = jti;
2982    }
2983    ///
2984    /// Extra fields defined by the client application.
2985    ///
2986    pub fn extra_fields(&self) -> &EF {
2987        &self.extra_fields
2988    }
2989    ///
2990    /// Sets the `set_extra_fields` field.
2991    ///
2992    pub fn set_extra_fields(&mut self, extra_fields: EF) {
2993        self.extra_fields = extra_fields;
2994    }
2995}
2996impl<EF, TT> TokenIntrospectionResponse<TT> for StandardTokenIntrospectionResponse<EF, TT>
2997where
2998    EF: ExtraTokenFields,
2999    TT: TokenType,
3000{
3001    fn active(&self) -> bool {
3002        self.active
3003    }
3004
3005    fn scopes(&self) -> Option<&Vec<Scope>> {
3006        self.scopes.as_ref()
3007    }
3008
3009    fn client_id(&self) -> Option<&ClientId> {
3010        self.client_id.as_ref()
3011    }
3012
3013    fn username(&self) -> Option<&str> {
3014        self.username.as_deref()
3015    }
3016
3017    fn token_type(&self) -> Option<&TT> {
3018        self.token_type.as_ref()
3019    }
3020
3021    fn exp(&self) -> Option<DateTime<Utc>> {
3022        self.exp
3023    }
3024
3025    fn iat(&self) -> Option<DateTime<Utc>> {
3026        self.iat
3027    }
3028
3029    fn nbf(&self) -> Option<DateTime<Utc>> {
3030        self.nbf
3031    }
3032
3033    fn sub(&self) -> Option<&str> {
3034        self.sub.as_deref()
3035    }
3036
3037    fn aud(&self) -> Option<&Vec<String>> {
3038        self.aud.as_ref()
3039    }
3040
3041    fn iss(&self) -> Option<&str> {
3042        self.iss.as_deref()
3043    }
3044
3045    fn jti(&self) -> Option<&str> {
3046        self.jti.as_deref()
3047    }
3048}
3049
3050///
3051/// Server Error Response
3052///
3053/// This trait exists separately from the `StandardErrorResponse` struct
3054/// to support customization by clients, such as supporting interoperability with
3055/// non-standards-complaint OAuth2 providers
3056///
3057pub trait ErrorResponse: Debug + DeserializeOwned + Serialize {}
3058
3059///
3060/// Error types enum.
3061///
3062/// NOTE: The serialization must return the `snake_case` representation of
3063/// this error type. This value must match the error type from the relevant OAuth 2.0 standards
3064/// (RFC 6749 or an extension).
3065///
3066pub trait ErrorResponseType: Debug + DeserializeOwned + Serialize {}
3067
3068///
3069/// Error response returned by server after requesting an access token.
3070///
3071/// The fields in this structure are defined in
3072/// [Section 5.2 of RFC 6749](https://tools.ietf.org/html/rfc6749#section-5.2). This
3073/// trait is parameterized by a `ErrorResponseType` to support error types specific to future OAuth2
3074/// authentication schemes and extensions.
3075///
3076#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
3077pub struct StandardErrorResponse<T: ErrorResponseType> {
3078    #[serde(bound = "T: ErrorResponseType")]
3079    error: T,
3080    #[serde(default)]
3081    #[serde(skip_serializing_if = "Option::is_none")]
3082    error_description: Option<String>,
3083    #[serde(default)]
3084    #[serde(skip_serializing_if = "Option::is_none")]
3085    error_uri: Option<String>,
3086}
3087
3088impl<T: ErrorResponseType> StandardErrorResponse<T> {
3089    ///
3090    /// Instantiate a new `ErrorResponse`.
3091    ///
3092    /// # Arguments
3093    ///
3094    /// * `error` - REQUIRED. A single ASCII error code deserialized to the generic parameter.
3095    ///   `ErrorResponseType`.
3096    /// * `error_description` - OPTIONAL. Human-readable ASCII text providing additional
3097    ///   information, used to assist the client developer in understanding the error that
3098    ///   occurred. Values for this parameter MUST NOT include characters outside the set
3099    ///   `%x20-21 / %x23-5B / %x5D-7E`.
3100    /// * `error_uri` - OPTIONAL. A URI identifying a human-readable web page with information
3101    ///   about the error used to provide the client developer with additional information about
3102    ///   the error. Values for the "error_uri" parameter MUST conform to the URI-reference
3103    ///   syntax and thus MUST NOT include characters outside the set `%x21 / %x23-5B / %x5D-7E`.
3104    ///
3105    pub fn new(error: T, error_description: Option<String>, error_uri: Option<String>) -> Self {
3106        Self {
3107            error,
3108            error_description,
3109            error_uri,
3110        }
3111    }
3112
3113    ///
3114    /// REQUIRED. A single ASCII error code deserialized to the generic parameter
3115    /// `ErrorResponseType`.
3116    ///
3117    pub fn error(&self) -> &T {
3118        &self.error
3119    }
3120    ///
3121    /// OPTIONAL. Human-readable ASCII text providing additional information, used to assist
3122    /// the client developer in understanding the error that occurred. Values for this
3123    /// parameter MUST NOT include characters outside the set `%x20-21 / %x23-5B / %x5D-7E`.
3124    ///
3125    pub fn error_description(&self) -> Option<&String> {
3126        self.error_description.as_ref()
3127    }
3128    ///
3129    /// OPTIONAL. URI identifying a human-readable web page with information about the error,
3130    /// used to provide the client developer with additional information about the error.
3131    /// Values for the "error_uri" parameter MUST conform to the URI-reference syntax and
3132    /// thus MUST NOT include characters outside the set `%x21 / %x23-5B / %x5D-7E`.
3133    ///
3134    pub fn error_uri(&self) -> Option<&String> {
3135        self.error_uri.as_ref()
3136    }
3137}
3138
3139impl<T> ErrorResponse for StandardErrorResponse<T> where T: ErrorResponseType + 'static {}
3140
3141impl<TE> Display for StandardErrorResponse<TE>
3142where
3143    TE: ErrorResponseType + Display,
3144{
3145    fn fmt(&self, f: &mut Formatter) -> Result<(), FormatterError> {
3146        let mut formatted = self.error().to_string();
3147
3148        if let Some(error_description) = self.error_description() {
3149            formatted.push_str(": ");
3150            formatted.push_str(error_description);
3151        }
3152
3153        if let Some(error_uri) = self.error_uri() {
3154            formatted.push_str(" / See ");
3155            formatted.push_str(error_uri);
3156        }
3157
3158        write!(f, "{}", formatted)
3159    }
3160}
3161
3162///
3163/// Error encountered while requesting access token.
3164///
3165#[derive(Debug, thiserror::Error)]
3166pub enum RequestTokenError<RE, T>
3167where
3168    RE: Error + 'static,
3169    T: ErrorResponse + 'static,
3170{
3171    ///
3172    /// Error response returned by authorization server. Contains the parsed `ErrorResponse`
3173    /// returned by the server.
3174    ///
3175    #[error("Server returned error response")]
3176    ServerResponse(T),
3177    ///
3178    /// An error occurred while sending the request or receiving the response (e.g., network
3179    /// connectivity failed).
3180    ///
3181    #[error("Request failed")]
3182    Request(#[source] RE),
3183    ///
3184    /// Failed to parse server response. Parse errors may occur while parsing either successful
3185    /// or error responses.
3186    ///
3187    #[error("Failed to parse server response")]
3188    Parse(
3189        #[source] serde_path_to_error::Error<serde_json::error::Error>,
3190        Vec<u8>,
3191    ),
3192    ///
3193    /// Some other type of error occurred (e.g., an unexpected server response).
3194    ///
3195    #[error("Other error: {}", _0)]
3196    Other(String),
3197}