oauth2/token/
mod.rs

1use crate::endpoint::{endpoint_request, endpoint_response};
2use crate::{
3    AccessToken, AsyncHttpClient, AuthType, AuthorizationCode, Client, ClientId, ClientSecret,
4    EndpointState, ErrorResponse, HttpRequest, PkceCodeVerifier, RedirectUrl, RefreshToken,
5    RequestTokenError, ResourceOwnerPassword, ResourceOwnerUsername, RevocableToken, Scope,
6    SyncHttpClient, TokenIntrospectionResponse, TokenUrl,
7};
8
9use serde::de::DeserializeOwned;
10use serde::{Deserialize, Serialize};
11
12use std::borrow::Cow;
13use std::error::Error;
14use std::fmt::Debug;
15use std::future::Future;
16use std::marker::PhantomData;
17use std::time::Duration;
18
19#[cfg(test)]
20mod tests;
21
22impl<
23        TE,
24        TR,
25        TIR,
26        RT,
27        TRE,
28        HasAuthUrl,
29        HasDeviceAuthUrl,
30        HasIntrospectionUrl,
31        HasRevocationUrl,
32        HasTokenUrl,
33    >
34    Client<
35        TE,
36        TR,
37        TIR,
38        RT,
39        TRE,
40        HasAuthUrl,
41        HasDeviceAuthUrl,
42        HasIntrospectionUrl,
43        HasRevocationUrl,
44        HasTokenUrl,
45    >
46where
47    TE: ErrorResponse + 'static,
48    TR: TokenResponse,
49    TIR: TokenIntrospectionResponse,
50    RT: RevocableToken,
51    TRE: ErrorResponse + 'static,
52    HasAuthUrl: EndpointState,
53    HasDeviceAuthUrl: EndpointState,
54    HasIntrospectionUrl: EndpointState,
55    HasRevocationUrl: EndpointState,
56    HasTokenUrl: EndpointState,
57{
58    pub(crate) fn exchange_client_credentials_impl<'a>(
59        &'a self,
60        token_url: &'a TokenUrl,
61    ) -> ClientCredentialsTokenRequest<'a, TE, TR> {
62        ClientCredentialsTokenRequest {
63            auth_type: &self.auth_type,
64            client_id: &self.client_id,
65            client_secret: self.client_secret.as_ref(),
66            extra_params: Vec::new(),
67            scopes: Vec::new(),
68            token_url,
69            _phantom: PhantomData,
70        }
71    }
72
73    pub(crate) fn exchange_code_impl<'a>(
74        &'a self,
75        token_url: &'a TokenUrl,
76        code: AuthorizationCode,
77    ) -> CodeTokenRequest<'a, TE, TR> {
78        CodeTokenRequest {
79            auth_type: &self.auth_type,
80            client_id: &self.client_id,
81            client_secret: self.client_secret.as_ref(),
82            code,
83            extra_params: Vec::new(),
84            pkce_verifier: None,
85            token_url,
86            redirect_url: self.redirect_url.as_ref().map(Cow::Borrowed),
87            _phantom: PhantomData,
88        }
89    }
90
91    pub(crate) fn exchange_password_impl<'a>(
92        &'a self,
93        token_url: &'a TokenUrl,
94        username: &'a ResourceOwnerUsername,
95        password: &'a ResourceOwnerPassword,
96    ) -> PasswordTokenRequest<'a, TE, TR> {
97        PasswordTokenRequest {
98            auth_type: &self.auth_type,
99            client_id: &self.client_id,
100            client_secret: self.client_secret.as_ref(),
101            username,
102            password,
103            extra_params: Vec::new(),
104            scopes: Vec::new(),
105            token_url,
106            _phantom: PhantomData,
107        }
108    }
109
110    pub(crate) fn exchange_refresh_token_impl<'a>(
111        &'a self,
112        token_url: &'a TokenUrl,
113        refresh_token: &'a RefreshToken,
114    ) -> RefreshTokenRequest<'a, TE, TR> {
115        RefreshTokenRequest {
116            auth_type: &self.auth_type,
117            client_id: &self.client_id,
118            client_secret: self.client_secret.as_ref(),
119            extra_params: Vec::new(),
120            refresh_token,
121            scopes: Vec::new(),
122            token_url,
123            _phantom: PhantomData,
124        }
125    }
126}
127
128/// A request to exchange an authorization code for an access token.
129///
130/// See <https://tools.ietf.org/html/rfc6749#section-4.1.3>.
131#[derive(Debug)]
132pub struct CodeTokenRequest<'a, TE, TR>
133where
134    TE: ErrorResponse,
135    TR: TokenResponse,
136{
137    pub(crate) auth_type: &'a AuthType,
138    pub(crate) client_id: &'a ClientId,
139    pub(crate) client_secret: Option<&'a ClientSecret>,
140    pub(crate) code: AuthorizationCode,
141    pub(crate) extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
142    pub(crate) pkce_verifier: Option<PkceCodeVerifier>,
143    pub(crate) token_url: &'a TokenUrl,
144    pub(crate) redirect_url: Option<Cow<'a, RedirectUrl>>,
145    pub(crate) _phantom: PhantomData<(TE, TR)>,
146}
147impl<'a, TE, TR> CodeTokenRequest<'a, TE, TR>
148where
149    TE: ErrorResponse + 'static,
150    TR: TokenResponse,
151{
152    /// Appends an extra param to the token request.
153    ///
154    /// This method allows extensions to be used without direct support from
155    /// this crate. If `name` conflicts with a parameter managed by this crate, the
156    /// behavior is undefined. In particular, do not set parameters defined by
157    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
158    /// [RFC 7636](https://tools.ietf.org/html/rfc7636).
159    ///
160    /// # Security Warning
161    ///
162    /// Callers should follow the security recommendations for any OAuth2 extensions used with
163    /// this function, which are beyond the scope of
164    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
165    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
166    where
167        N: Into<Cow<'a, str>>,
168        V: Into<Cow<'a, str>>,
169    {
170        self.extra_params.push((name.into(), value.into()));
171        self
172    }
173
174    /// Completes the [Proof Key for Code Exchange](https://tools.ietf.org/html/rfc7636)
175    /// (PKCE) protocol flow.
176    ///
177    /// This method must be called if [`crate::AuthorizationRequest::set_pkce_challenge`] was used
178    /// during the authorization request.
179    pub fn set_pkce_verifier(mut self, pkce_verifier: PkceCodeVerifier) -> Self {
180        self.pkce_verifier = Some(pkce_verifier);
181        self
182    }
183
184    /// Overrides the `redirect_url` to the one specified.
185    pub fn set_redirect_uri(mut self, redirect_url: Cow<'a, RedirectUrl>) -> Self {
186        self.redirect_url = Some(redirect_url);
187        self
188    }
189
190    fn prepare_request<RE>(self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
191    where
192        RE: Error + 'static,
193    {
194        let mut params = vec![
195            ("grant_type", "authorization_code"),
196            ("code", self.code.secret()),
197        ];
198        if let Some(ref pkce_verifier) = self.pkce_verifier {
199            params.push(("code_verifier", pkce_verifier.secret()));
200        }
201
202        endpoint_request(
203            self.auth_type,
204            self.client_id,
205            self.client_secret,
206            &self.extra_params,
207            self.redirect_url,
208            None,
209            self.token_url.url(),
210            params,
211        )
212        .map_err(|err| RequestTokenError::Other(format!("failed to prepare request: {err}")))
213    }
214
215    /// Synchronously sends the request to the authorization server and awaits a response.
216    pub fn request<C>(
217        self,
218        http_client: &C,
219    ) -> Result<TR, RequestTokenError<<C as SyncHttpClient>::Error, TE>>
220    where
221        C: SyncHttpClient,
222    {
223        endpoint_response(http_client.call(self.prepare_request()?)?)
224    }
225
226    /// Asynchronously sends the request to the authorization server and returns a Future.
227    pub fn request_async<'c, C>(
228        self,
229        http_client: &'c C,
230    ) -> impl Future<Output = Result<TR, RequestTokenError<<C as AsyncHttpClient<'c>>::Error, TE>>> + 'c
231    where
232        Self: 'c,
233        C: AsyncHttpClient<'c>,
234    {
235        Box::pin(async move { endpoint_response(http_client.call(self.prepare_request()?).await?) })
236    }
237}
238
239/// A request to exchange a refresh token for an access token.
240///
241/// See <https://tools.ietf.org/html/rfc6749#section-6>.
242#[derive(Debug)]
243pub struct RefreshTokenRequest<'a, TE, TR>
244where
245    TE: ErrorResponse,
246    TR: TokenResponse,
247{
248    pub(crate) auth_type: &'a AuthType,
249    pub(crate) client_id: &'a ClientId,
250    pub(crate) client_secret: Option<&'a ClientSecret>,
251    pub(crate) extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
252    pub(crate) refresh_token: &'a RefreshToken,
253    pub(crate) scopes: Vec<Cow<'a, Scope>>,
254    pub(crate) token_url: &'a TokenUrl,
255    pub(crate) _phantom: PhantomData<(TE, TR)>,
256}
257impl<'a, TE, TR> RefreshTokenRequest<'a, TE, TR>
258where
259    TE: ErrorResponse + 'static,
260    TR: TokenResponse,
261{
262    /// Appends an extra param to the token request.
263    ///
264    /// This method allows extensions to be used without direct support from
265    /// this crate. If `name` conflicts with a parameter managed by this crate, the
266    /// behavior is undefined. In particular, do not set parameters defined by
267    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
268    /// [RFC 7636](https://tools.ietf.org/html/rfc7636).
269    ///
270    /// # Security Warning
271    ///
272    /// Callers should follow the security recommendations for any OAuth2 extensions used with
273    /// this function, which are beyond the scope of
274    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
275    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
276    where
277        N: Into<Cow<'a, str>>,
278        V: Into<Cow<'a, str>>,
279    {
280        self.extra_params.push((name.into(), value.into()));
281        self
282    }
283
284    /// Appends a new scope to the token request.
285    pub fn add_scope(mut self, scope: Scope) -> Self {
286        self.scopes.push(Cow::Owned(scope));
287        self
288    }
289
290    /// Appends a collection of scopes to the token request.
291    pub fn add_scopes<I>(mut self, scopes: I) -> Self
292    where
293        I: IntoIterator<Item = Scope>,
294    {
295        self.scopes.extend(scopes.into_iter().map(Cow::Owned));
296        self
297    }
298
299    /// Synchronously sends the request to the authorization server and awaits a response.
300    pub fn request<C>(
301        self,
302        http_client: &C,
303    ) -> Result<TR, RequestTokenError<<C as SyncHttpClient>::Error, TE>>
304    where
305        C: SyncHttpClient,
306    {
307        endpoint_response(http_client.call(self.prepare_request()?)?)
308    }
309    /// Asynchronously sends the request to the authorization server and awaits a response.
310    pub fn request_async<'c, C>(
311        self,
312        http_client: &'c C,
313    ) -> impl Future<Output = Result<TR, RequestTokenError<<C as AsyncHttpClient<'c>>::Error, TE>>> + 'c
314    where
315        Self: 'c,
316        C: AsyncHttpClient<'c>,
317    {
318        Box::pin(async move { endpoint_response(http_client.call(self.prepare_request()?).await?) })
319    }
320
321    fn prepare_request<RE>(&self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
322    where
323        RE: Error + 'static,
324    {
325        endpoint_request(
326            self.auth_type,
327            self.client_id,
328            self.client_secret,
329            &self.extra_params,
330            None,
331            Some(&self.scopes),
332            self.token_url.url(),
333            vec![
334                ("grant_type", "refresh_token"),
335                ("refresh_token", self.refresh_token.secret()),
336            ],
337        )
338        .map_err(|err| RequestTokenError::Other(format!("failed to prepare request: {err}")))
339    }
340}
341
342/// A request to exchange resource owner credentials for an access token.
343///
344/// See <https://tools.ietf.org/html/rfc6749#section-4.3>.
345#[derive(Debug)]
346pub struct PasswordTokenRequest<'a, TE, TR>
347where
348    TE: ErrorResponse,
349    TR: TokenResponse,
350{
351    pub(crate) auth_type: &'a AuthType,
352    pub(crate) client_id: &'a ClientId,
353    pub(crate) client_secret: Option<&'a ClientSecret>,
354    pub(crate) extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
355    pub(crate) username: &'a ResourceOwnerUsername,
356    pub(crate) password: &'a ResourceOwnerPassword,
357    pub(crate) scopes: Vec<Cow<'a, Scope>>,
358    pub(crate) token_url: &'a TokenUrl,
359    pub(crate) _phantom: PhantomData<(TE, TR)>,
360}
361impl<'a, TE, TR> PasswordTokenRequest<'a, TE, TR>
362where
363    TE: ErrorResponse + 'static,
364    TR: TokenResponse,
365{
366    /// Appends an extra param to the token request.
367    ///
368    /// This method allows extensions to be used without direct support from
369    /// this crate. If `name` conflicts with a parameter managed by this crate, the
370    /// behavior is undefined. In particular, do not set parameters defined by
371    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
372    /// [RFC 7636](https://tools.ietf.org/html/rfc7636).
373    ///
374    /// # Security Warning
375    ///
376    /// Callers should follow the security recommendations for any OAuth2 extensions used with
377    /// this function, which are beyond the scope of
378    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
379    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
380    where
381        N: Into<Cow<'a, str>>,
382        V: Into<Cow<'a, str>>,
383    {
384        self.extra_params.push((name.into(), value.into()));
385        self
386    }
387
388    /// Appends a new scope to the token request.
389    pub fn add_scope(mut self, scope: Scope) -> Self {
390        self.scopes.push(Cow::Owned(scope));
391        self
392    }
393
394    /// Appends a collection of scopes to the token request.
395    pub fn add_scopes<I>(mut self, scopes: I) -> Self
396    where
397        I: IntoIterator<Item = Scope>,
398    {
399        self.scopes.extend(scopes.into_iter().map(Cow::Owned));
400        self
401    }
402
403    /// Synchronously sends the request to the authorization server and awaits a response.
404    pub fn request<C>(
405        self,
406        http_client: &C,
407    ) -> Result<TR, RequestTokenError<<C as SyncHttpClient>::Error, TE>>
408    where
409        C: SyncHttpClient,
410    {
411        endpoint_response(http_client.call(self.prepare_request()?)?)
412    }
413
414    /// Asynchronously sends the request to the authorization server and awaits a response.
415    pub fn request_async<'c, C>(
416        self,
417        http_client: &'c C,
418    ) -> impl Future<Output = Result<TR, RequestTokenError<<C as AsyncHttpClient<'c>>::Error, TE>>> + 'c
419    where
420        Self: 'c,
421        C: AsyncHttpClient<'c>,
422    {
423        Box::pin(async move { endpoint_response(http_client.call(self.prepare_request()?).await?) })
424    }
425
426    fn prepare_request<RE>(&self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
427    where
428        RE: Error + 'static,
429    {
430        endpoint_request(
431            self.auth_type,
432            self.client_id,
433            self.client_secret,
434            &self.extra_params,
435            None,
436            Some(&self.scopes),
437            self.token_url.url(),
438            vec![
439                ("grant_type", "password"),
440                ("username", self.username),
441                ("password", self.password.secret()),
442            ],
443        )
444        .map_err(|err| RequestTokenError::Other(format!("failed to prepare request: {err}")))
445    }
446}
447
448/// A request to exchange client credentials for an access token.
449///
450/// See <https://tools.ietf.org/html/rfc6749#section-4.4>.
451#[derive(Debug)]
452pub struct ClientCredentialsTokenRequest<'a, TE, TR>
453where
454    TE: ErrorResponse,
455    TR: TokenResponse,
456{
457    pub(crate) auth_type: &'a AuthType,
458    pub(crate) client_id: &'a ClientId,
459    pub(crate) client_secret: Option<&'a ClientSecret>,
460    pub(crate) extra_params: Vec<(Cow<'a, str>, Cow<'a, str>)>,
461    pub(crate) scopes: Vec<Cow<'a, Scope>>,
462    pub(crate) token_url: &'a TokenUrl,
463    pub(crate) _phantom: PhantomData<(TE, TR)>,
464}
465impl<'a, TE, TR> ClientCredentialsTokenRequest<'a, TE, TR>
466where
467    TE: ErrorResponse + 'static,
468    TR: TokenResponse,
469{
470    /// Appends an extra param to the token request.
471    ///
472    /// This method allows extensions to be used without direct support from
473    /// this crate. If `name` conflicts with a parameter managed by this crate, the
474    /// behavior is undefined. In particular, do not set parameters defined by
475    /// [RFC 6749](https://tools.ietf.org/html/rfc6749) or
476    /// [RFC 7636](https://tools.ietf.org/html/rfc7636).
477    ///
478    /// # Security Warning
479    ///
480    /// Callers should follow the security recommendations for any OAuth2 extensions used with
481    /// this function, which are beyond the scope of
482    /// [RFC 6749](https://tools.ietf.org/html/rfc6749).
483    pub fn add_extra_param<N, V>(mut self, name: N, value: V) -> Self
484    where
485        N: Into<Cow<'a, str>>,
486        V: Into<Cow<'a, str>>,
487    {
488        self.extra_params.push((name.into(), value.into()));
489        self
490    }
491
492    /// Appends a new scope to the token request.
493    pub fn add_scope(mut self, scope: Scope) -> Self {
494        self.scopes.push(Cow::Owned(scope));
495        self
496    }
497
498    /// Appends a collection of scopes to the token request.
499    pub fn add_scopes<I>(mut self, scopes: I) -> Self
500    where
501        I: IntoIterator<Item = Scope>,
502    {
503        self.scopes.extend(scopes.into_iter().map(Cow::Owned));
504        self
505    }
506
507    /// Synchronously sends the request to the authorization server and awaits a response.
508    pub fn request<C>(
509        self,
510        http_client: &C,
511    ) -> Result<TR, RequestTokenError<<C as SyncHttpClient>::Error, TE>>
512    where
513        C: SyncHttpClient,
514    {
515        endpoint_response(http_client.call(self.prepare_request()?)?)
516    }
517
518    /// Asynchronously sends the request to the authorization server and awaits a response.
519    pub fn request_async<'c, C>(
520        self,
521        http_client: &'c C,
522    ) -> impl Future<Output = Result<TR, RequestTokenError<<C as AsyncHttpClient<'c>>::Error, TE>>> + 'c
523    where
524        Self: 'c,
525        C: AsyncHttpClient<'c>,
526    {
527        Box::pin(async move { endpoint_response(http_client.call(self.prepare_request()?).await?) })
528    }
529
530    fn prepare_request<RE>(&self) -> Result<HttpRequest, RequestTokenError<RE, TE>>
531    where
532        RE: Error + 'static,
533    {
534        endpoint_request(
535            self.auth_type,
536            self.client_id,
537            self.client_secret,
538            &self.extra_params,
539            None,
540            Some(&self.scopes),
541            self.token_url.url(),
542            vec![("grant_type", "client_credentials")],
543        )
544        .map_err(|err| RequestTokenError::Other(format!("failed to prepare request: {err}")))
545    }
546}
547
548/// Type of OAuth2 access token.
549pub trait TokenType: Clone + DeserializeOwned + Debug + PartialEq + Serialize {}
550
551/// Trait for adding extra fields to the `TokenResponse`.
552pub trait ExtraTokenFields: DeserializeOwned + Debug + Serialize {}
553
554/// Empty (default) extra token fields.
555#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
556pub struct EmptyExtraTokenFields {}
557impl ExtraTokenFields for EmptyExtraTokenFields {}
558
559/// Common methods shared by all OAuth2 token implementations.
560///
561/// The methods in this trait are defined in
562/// [Section 5.1 of RFC 6749](https://tools.ietf.org/html/rfc6749#section-5.1). This trait exists
563/// separately from the `StandardTokenResponse` struct to support customization by clients,
564/// such as supporting interoperability with non-standards-complaint OAuth2 providers.
565pub trait TokenResponse: Debug + DeserializeOwned + Serialize {
566    /// Type of OAuth2 access token included in this response.
567    type TokenType: TokenType;
568
569    /// REQUIRED. The access token issued by the authorization server.
570    fn access_token(&self) -> &AccessToken;
571    /// REQUIRED. The type of the token issued as described in
572    /// [Section 7.1](https://tools.ietf.org/html/rfc6749#section-7.1).
573    /// Value is case insensitive and deserialized to the generic `TokenType` parameter.
574    fn token_type(&self) -> &Self::TokenType;
575    /// RECOMMENDED. The lifetime in seconds of the access token. For example, the value 3600
576    /// denotes that the access token will expire in one hour from the time the response was
577    /// generated. If omitted, the authorization server SHOULD provide the expiration time via
578    /// other means or document the default value.
579    fn expires_in(&self) -> Option<Duration>;
580    /// OPTIONAL. The refresh token, which can be used to obtain new access tokens using the same
581    /// authorization grant as described in
582    /// [Section 6](https://tools.ietf.org/html/rfc6749#section-6).
583    fn refresh_token(&self) -> Option<&RefreshToken>;
584    /// OPTIONAL, if identical to the scope requested by the client; otherwise, REQUIRED. The
585    /// scope of the access token as described by
586    /// [Section 3.3](https://tools.ietf.org/html/rfc6749#section-3.3). If included in the response,
587    /// this space-delimited field is parsed into a `Vec` of individual scopes. If omitted from
588    /// the response, this field is `None`.
589    fn scopes(&self) -> Option<&Vec<Scope>>;
590}
591
592/// Standard OAuth2 token response.
593///
594/// This struct includes the fields defined in
595/// [Section 5.1 of RFC 6749](https://tools.ietf.org/html/rfc6749#section-5.1), as well as
596/// extensions defined by the `EF` type parameter.
597#[derive(Clone, Debug, Deserialize, Serialize)]
598pub struct StandardTokenResponse<EF, TT>
599where
600    EF: ExtraTokenFields,
601    TT: TokenType,
602{
603    access_token: AccessToken,
604    #[serde(bound = "TT: TokenType")]
605    #[serde(deserialize_with = "crate::helpers::deserialize_untagged_enum_case_insensitive")]
606    token_type: TT,
607    #[serde(skip_serializing_if = "Option::is_none")]
608    expires_in: Option<u64>,
609    #[serde(skip_serializing_if = "Option::is_none")]
610    refresh_token: Option<RefreshToken>,
611    #[serde(rename = "scope")]
612    #[serde(deserialize_with = "crate::helpers::deserialize_space_delimited_vec")]
613    #[serde(serialize_with = "crate::helpers::serialize_space_delimited_vec")]
614    #[serde(skip_serializing_if = "Option::is_none")]
615    #[serde(default)]
616    scopes: Option<Vec<Scope>>,
617
618    #[serde(bound = "EF: ExtraTokenFields")]
619    #[serde(flatten)]
620    extra_fields: EF,
621}
622impl<EF, TT> StandardTokenResponse<EF, TT>
623where
624    EF: ExtraTokenFields,
625    TT: TokenType,
626{
627    /// Instantiate a new OAuth2 token response.
628    pub fn new(access_token: AccessToken, token_type: TT, extra_fields: EF) -> Self {
629        Self {
630            access_token,
631            token_type,
632            expires_in: None,
633            refresh_token: None,
634            scopes: None,
635            extra_fields,
636        }
637    }
638
639    /// Set the `access_token` field.
640    pub fn set_access_token(&mut self, access_token: AccessToken) {
641        self.access_token = access_token;
642    }
643
644    /// Set the `token_type` field.
645    pub fn set_token_type(&mut self, token_type: TT) {
646        self.token_type = token_type;
647    }
648
649    /// Set the `expires_in` field.
650    pub fn set_expires_in(&mut self, expires_in: Option<&Duration>) {
651        self.expires_in = expires_in.map(Duration::as_secs);
652    }
653
654    /// Set the `refresh_token` field.
655    pub fn set_refresh_token(&mut self, refresh_token: Option<RefreshToken>) {
656        self.refresh_token = refresh_token;
657    }
658
659    /// Set the `scopes` field.
660    pub fn set_scopes(&mut self, scopes: Option<Vec<Scope>>) {
661        self.scopes = scopes;
662    }
663
664    /// Extra fields defined by the client application.
665    pub fn extra_fields(&self) -> &EF {
666        &self.extra_fields
667    }
668
669    /// Set the extra fields defined by the client application.
670    pub fn set_extra_fields(&mut self, extra_fields: EF) {
671        self.extra_fields = extra_fields;
672    }
673}
674impl<EF, TT> TokenResponse for StandardTokenResponse<EF, TT>
675where
676    EF: ExtraTokenFields,
677    TT: TokenType,
678{
679    type TokenType = TT;
680
681    /// REQUIRED. The access token issued by the authorization server.
682    fn access_token(&self) -> &AccessToken {
683        &self.access_token
684    }
685    /// REQUIRED. The type of the token issued as described in
686    /// [Section 7.1](https://tools.ietf.org/html/rfc6749#section-7.1).
687    /// Value is case insensitive and deserialized to the generic `TokenType` parameter.
688    fn token_type(&self) -> &TT {
689        &self.token_type
690    }
691    /// RECOMMENDED. The lifetime in seconds of the access token. For example, the value 3600
692    /// denotes that the access token will expire in one hour from the time the response was
693    /// generated. If omitted, the authorization server SHOULD provide the expiration time via
694    /// other means or document the default value.
695    fn expires_in(&self) -> Option<Duration> {
696        self.expires_in.map(Duration::from_secs)
697    }
698    /// OPTIONAL. The refresh token, which can be used to obtain new access tokens using the same
699    /// authorization grant as described in
700    /// [Section 6](https://tools.ietf.org/html/rfc6749#section-6).
701    fn refresh_token(&self) -> Option<&RefreshToken> {
702        self.refresh_token.as_ref()
703    }
704    /// OPTIONAL, if identical to the scope requested by the client; otherwise, REQUIRED. The
705    /// scope of the access token as described by
706    /// [Section 3.3](https://tools.ietf.org/html/rfc6749#section-3.3). If included in the response,
707    /// this space-delimited field is parsed into a `Vec` of individual scopes. If omitted from
708    /// the response, this field is `None`.
709    fn scopes(&self) -> Option<&Vec<Scope>> {
710        self.scopes.as_ref()
711    }
712}