oxide_auth_async/
code_grant.rs

1pub mod refresh {
2    use oxide_auth::code_grant::refresh::{BearerToken, Error, Input, Output, Refresh, Request};
3    use oxide_auth::primitives::{grant::Grant, registrar::RegistrarError};
4
5    pub trait Endpoint {
6        /// Authenticate the requesting confidential client.
7        fn registrar(&self) -> &(dyn crate::primitives::Registrar + Sync);
8
9        /// Recover and test the provided refresh token then issue new tokens.
10        fn issuer(&mut self) -> &mut (dyn crate::primitives::Issuer + Send);
11    }
12
13    pub async fn refresh(
14        handler: &mut (dyn Endpoint + Send + Sync), request: &(dyn Request + Sync),
15    ) -> Result<BearerToken, Error> {
16        enum Requested {
17            None,
18            Refresh { token: String, grant: Box<Grant> },
19            RecoverRefresh { token: String },
20            Authenticate { client: String, pass: Option<Vec<u8>> },
21        }
22        let mut refresh = Refresh::new(request);
23        let mut requested = Requested::None;
24        loop {
25            let input = match requested {
26                Requested::None => Input::None,
27                Requested::Refresh { token, grant } => {
28                    let refreshed = handler
29                        .issuer()
30                        .refresh(&token, *grant)
31                        .await
32                        .map_err(|()| Error::Primitive)?;
33                    Input::Refreshed(refreshed)
34                }
35                Requested::RecoverRefresh { token } => {
36                    let recovered = handler
37                        .issuer()
38                        .recover_refresh(&token)
39                        .await
40                        .map_err(|()| Error::Primitive)?;
41                    Input::Recovered {
42                        scope: request.scope(),
43                        grant: recovered.map(Box::new),
44                    }
45                }
46                Requested::Authenticate { client, pass } => {
47                    handler
48                        .registrar()
49                        .check(&client, pass.as_deref())
50                        .await
51                        .map_err(|err| match err {
52                            RegistrarError::PrimitiveError => Error::Primitive,
53                            RegistrarError::Unspecified => Error::unauthorized("basic"),
54                        })?;
55                    Input::Authenticated {
56                        scope: request.scope(),
57                    }
58                }
59            };
60
61            requested = match refresh.advance(input) {
62                Output::Err(error) => return Err(error),
63                Output::Ok(token) => return Ok(token),
64                Output::Refresh { token, grant } => Requested::Refresh {
65                    token: token.to_string(),
66                    grant,
67                },
68                Output::RecoverRefresh { token } => Requested::RecoverRefresh {
69                    token: token.to_string(),
70                },
71                Output::Unauthenticated { client, pass } => Requested::Authenticate {
72                    client: client.to_string(),
73                    pass: pass.map(|p| p.to_vec()),
74                },
75            };
76        }
77    }
78}
79
80pub mod resource {
81    use oxide_auth::code_grant::resource::{Error, Input, Output, Request, Resource};
82    use oxide_auth::primitives::grant::Grant;
83    use oxide_auth::primitives::scope::Scope;
84
85    pub trait Endpoint {
86        /// The list of possible scopes required by the resource endpoint.
87        fn scopes(&mut self) -> &[Scope];
88
89        /// Recover and test the provided refresh token then issue new tokens.
90        fn issuer(&mut self) -> &mut (dyn crate::primitives::Issuer + Send);
91    }
92
93    pub async fn protect(
94        handler: &mut (dyn Endpoint + Send + Sync), req: &(dyn Request + Sync),
95    ) -> Result<Grant, Error> {
96        enum Requested {
97            None,
98            Request,
99            Scopes,
100            Grant(String),
101        }
102
103        let mut resource = Resource::new();
104        let mut requested = Requested::None;
105        loop {
106            let input = match requested {
107                Requested::None => Input::None,
108                Requested::Request => Input::Request { request: req },
109                Requested::Scopes => Input::Scopes(handler.scopes()),
110                Requested::Grant(token) => {
111                    let grant = handler
112                        .issuer()
113                        .recover_token(&token)
114                        .await
115                        .map_err(|_| Error::PrimitiveError)?;
116                    Input::Recovered(grant)
117                }
118            };
119
120            requested = match resource.advance(input) {
121                Output::Err(error) => return Err(error),
122                Output::Ok(grant) => return Ok(*grant),
123                Output::GetRequest => Requested::Request,
124                Output::DetermineScopes => Requested::Scopes,
125                Output::Recover { token } => Requested::Grant(token.to_string()),
126            };
127        }
128    }
129}
130
131pub mod client_credentials {
132    use std::borrow::Cow;
133
134    use async_trait::async_trait;
135    use chrono::{Utc, Duration};
136    use oxide_auth::{
137        code_grant::{
138            accesstoken::{PrimitiveError, BearerToken},
139            client_credentials::{ClientCredentials, Error, Input, Output, Request as TokenRequest},
140        },
141        endpoint::{PreGrant, Scope, Solicitation},
142        primitives::{
143            grant::{Extensions, Grant},
144            prelude::ClientUrl,
145            registrar::{BoundClient, RegistrarError},
146        },
147    };
148
149    #[async_trait]
150    pub trait Extension {
151        /// Inspect the request and extension data to produce extension data.
152        ///
153        /// The input data comes from the extension data produced in the handling of the
154        /// authorization code request.
155        async fn extend(
156            &mut self, request: &(dyn TokenRequest + Sync),
157        ) -> std::result::Result<Extensions, ()>;
158    }
159
160    #[async_trait]
161    impl Extension for () {
162        async fn extend(
163            &mut self, _: &(dyn TokenRequest + Sync),
164        ) -> std::result::Result<Extensions, ()> {
165            Ok(Extensions::new())
166        }
167    }
168
169    pub trait Endpoint {
170        /// Get the client corresponding to some id.
171        fn registrar(&self) -> &(dyn crate::primitives::Registrar + Sync);
172
173        /// Get the authorizer from which we can recover the authorization.
174        fn authorizer(&mut self) -> &mut (dyn crate::primitives::Authorizer + Send);
175
176        /// Return the issuer instance to create the access token.
177        fn issuer(&mut self) -> &mut (dyn crate::primitives::Issuer + Send);
178
179        /// The system of used extension, extending responses.
180        ///
181        /// It is possible to use `&mut ()`.
182        fn extension(&mut self) -> &mut (dyn Extension + Send);
183    }
184
185    /// Represents a valid, currently pending client credentials not bound to an owner.
186    ///
187    /// This will be passed along to the solicitor to obtain the owner ID, and then
188    /// a token will be issued. Since this is the client credentials flow, a pending
189    /// response is considered an internal error.
190    // Don't ever implement `Clone` here. It's to make it very
191    // hard for the user to accidentally respond to a request in two conflicting ways. This has
192    // potential security impact if it could be both denied and authorized.
193    pub struct Pending {
194        pre_grant: PreGrant,
195        extensions: Extensions,
196    }
197
198    impl Pending {
199        /// Reference this pending state as a solicitation.
200        pub fn as_solicitation(&self) -> Solicitation<'_> {
201            Solicitation::new(&self.pre_grant)
202        }
203
204        /// Inform the backend about consent from a resource owner.
205        ///
206        /// Use negotiated parameters to authorize a client for an owner. The endpoint SHOULD be the
207        /// same endpoint as was used to create the pending request.
208        pub async fn issue(
209            self, handler: &mut (dyn Endpoint + Send), owner_id: String, allow_refresh_token: bool,
210        ) -> Result<BearerToken, Error> {
211            let pre_grant = self.pre_grant.clone();
212
213            let mut token = handler
214                .issuer()
215                .issue(Grant {
216                    owner_id,
217                    client_id: pre_grant.client_id,
218                    redirect_uri: pre_grant.redirect_uri.into_url(),
219                    scope: pre_grant.scope.clone(),
220                    until: Utc::now() + Duration::minutes(10),
221                    extensions: self.extensions,
222                })
223                .await
224                .map_err(|()| Error::Primitive(Box::new(PrimitiveError::empty())))?;
225
226            if !allow_refresh_token {
227                token.refresh = None;
228            }
229
230            Ok(token.convert_bearer_token(self.pre_grant))
231        }
232    }
233
234    pub async fn client_credentials(
235        handler: &mut (dyn Endpoint + Send + Sync), request: &(dyn TokenRequest + Sync),
236    ) -> Result<Pending, Error> {
237        enum Requested {
238            None,
239            Authenticate {
240                client: String,
241                passdata: Vec<u8>,
242            },
243            Bind {
244                client_id: String,
245            },
246            Extend,
247            Negotiate {
248                bound_client: BoundClient<'static>,
249                scope: Option<Scope>,
250            },
251        }
252
253        let mut client_credentials = ClientCredentials::new(request);
254        let mut requested = Requested::None;
255
256        loop {
257            let input = match requested {
258                Requested::None => Input::None,
259                Requested::Authenticate { client, passdata } => {
260                    handler
261                        .registrar()
262                        .check(&client, Some(passdata.as_slice()))
263                        .await
264                        .map_err(|err| match err {
265                            RegistrarError::Unspecified => Error::unauthorized("basic"),
266                            RegistrarError::PrimitiveError => {
267                                Error::Primitive(Box::new(PrimitiveError {
268                                    grant: None,
269                                    extensions: None,
270                                }))
271                            }
272                        })?;
273                    Input::Authenticated
274                }
275                Requested::Bind { client_id } => {
276                    let client_url = ClientUrl {
277                        client_id: Cow::Owned(client_id),
278                        redirect_uri: None,
279                    };
280                    let bound_client = match handler.registrar().bound_redirect(client_url).await {
281                        Err(RegistrarError::Unspecified) => return Err(Error::Ignore),
282                        Err(RegistrarError::PrimitiveError) => {
283                            return Err(Error::Primitive(Box::new(PrimitiveError {
284                                grant: None,
285                                extensions: None,
286                            })));
287                        }
288                        Ok(pre_grant) => pre_grant,
289                    };
290                    Input::Bound { bound_client }
291                }
292                Requested::Extend => {
293                    let extensions = handler
294                        .extension()
295                        .extend(request)
296                        .await
297                        .map_err(|_| Error::invalid())?;
298                    Input::Extended { extensions }
299                }
300                Requested::Negotiate { bound_client, scope } => {
301                    let pre_grant = handler
302                        .registrar()
303                        .negotiate(bound_client.clone(), scope.clone())
304                        .await
305                        .map_err(|err| match err {
306                            RegistrarError::PrimitiveError => {
307                                Error::Primitive(Box::new(PrimitiveError {
308                                    grant: None,
309                                    extensions: None,
310                                }))
311                            }
312                            RegistrarError::Unspecified => Error::Ignore,
313                        })?;
314                    Input::Negotiated { pre_grant }
315                }
316            };
317
318            requested = match client_credentials.advance(input) {
319                Output::Authenticate { client, passdata } => Requested::Authenticate {
320                    client: client.to_owned(),
321                    passdata: passdata.to_vec(),
322                },
323                Output::Binding { client_id } => Requested::Bind {
324                    client_id: client_id.to_owned(),
325                },
326                Output::Extend => Requested::Extend,
327                Output::Negotiate { bound_client, scope } => Requested::Negotiate {
328                    bound_client: bound_client.clone(),
329                    scope,
330                },
331                Output::Ok {
332                    pre_grant,
333                    extensions,
334                } => {
335                    return Ok(Pending {
336                        pre_grant: pre_grant.clone(),
337                        extensions: extensions.clone(),
338                    })
339                }
340                Output::Err(e) => return Err(*e),
341            };
342        }
343    }
344}
345
346pub mod access_token {
347    use async_trait::async_trait;
348    use oxide_auth::{
349        code_grant::accesstoken::{
350            AccessToken, BearerToken, Error, Input, Output, PrimitiveError, Request as TokenRequest,
351        },
352        primitives::{
353            grant::{Extensions, Grant},
354            registrar::RegistrarError,
355        },
356    };
357    // use crate::endpoint::access_token::WrappedRequest;
358
359    #[async_trait]
360    pub trait Extension {
361        /// Inspect the request and extension data to produce extension data.
362        ///
363        /// The input data comes from the extension data produced in the handling of the
364        /// authorization code request.
365        async fn extend(
366            &mut self, request: &(dyn TokenRequest + Sync), data: Extensions,
367        ) -> std::result::Result<Extensions, ()>;
368    }
369
370    #[async_trait]
371    impl Extension for () {
372        async fn extend(
373            &mut self, _: &(dyn TokenRequest + Sync), _: Extensions,
374        ) -> std::result::Result<Extensions, ()> {
375            Ok(Extensions::new())
376        }
377    }
378
379    pub trait Endpoint {
380        /// Get the client corresponding to some id.
381        fn registrar(&self) -> &(dyn crate::primitives::Registrar + Sync);
382
383        /// Get the authorizer from which we can recover the authorization.
384        fn authorizer(&mut self) -> &mut (dyn crate::primitives::Authorizer + Send);
385
386        /// Return the issuer instance to create the access token.
387        fn issuer(&mut self) -> &mut (dyn crate::primitives::Issuer + Send);
388
389        /// The system of used extension, extending responses.
390        ///
391        /// It is possible to use `&mut ()`.
392        fn extension(&mut self) -> &mut (dyn Extension + Send);
393    }
394
395    pub async fn access_token(
396        handler: &mut (dyn Endpoint + Send + Sync), request: &(dyn TokenRequest + Sync),
397    ) -> Result<BearerToken, Error> {
398        enum Requested<'a> {
399            None,
400            Authenticate {
401                client: &'a str,
402                passdata: Option<&'a [u8]>,
403            },
404            Recover(&'a str),
405            Extend {
406                extensions: &'a mut Extensions,
407            },
408            Issue {
409                grant: &'a Grant,
410            },
411        }
412
413        let mut access_token = AccessToken::new(request);
414        let mut requested = Requested::None;
415
416        loop {
417            let input = match requested {
418                Requested::None => Input::None,
419                Requested::Authenticate { client, passdata } => {
420                    handler
421                        .registrar()
422                        .check(client, passdata)
423                        .await
424                        .map_err(|err| match err {
425                            RegistrarError::Unspecified => Error::unauthorized("basic"),
426                            RegistrarError::PrimitiveError => {
427                                Error::Primitive(Box::new(PrimitiveError {
428                                    grant: None,
429                                    extensions: None,
430                                }))
431                            }
432                        })?;
433                    Input::Authenticated
434                }
435                Requested::Recover(code) => {
436                    let opt_grant = handler.authorizer().extract(code).await.map_err(|_| {
437                        Error::Primitive(Box::new(PrimitiveError {
438                            grant: None,
439                            extensions: None,
440                        }))
441                    })?;
442                    Input::Recovered(opt_grant.map(Box::new))
443                }
444                Requested::Extend { extensions } => {
445                    let access_extensions = handler
446                        .extension()
447                        .extend(request, extensions.clone())
448                        .await
449                        .map_err(|_| Error::invalid())?;
450
451                    Input::Extended { access_extensions }
452                }
453                Requested::Issue { grant } => {
454                    let token = handler.issuer().issue(grant.clone()).await.map_err(|_| {
455                        Error::Primitive(Box::new(PrimitiveError {
456                            // FIXME: endpoint should get and handle these.
457                            grant: None,
458                            extensions: None,
459                        }))
460                    })?;
461                    Input::Issued(token)
462                }
463            };
464
465            requested = match access_token.advance(input) {
466                Output::Authenticate { client, passdata } => {
467                    Requested::Authenticate { client, passdata }
468                }
469                Output::Recover { code } => Requested::Recover(code),
470                Output::Extend { extensions, .. } => Requested::Extend { extensions },
471                Output::Issue { grant } => Requested::Issue { grant },
472                Output::Ok(token) => return Ok(token),
473                Output::Err(e) => return Err(*e),
474            };
475        }
476    }
477}
478
479pub mod authorization {
480    use async_trait::async_trait;
481    use chrono::{Duration, Utc};
482    use oxide_auth::{
483        code_grant::{
484            authorization::{Authorization, Error, ErrorUrl, Input, Output, Request},
485            error::{AuthorizationError, AuthorizationErrorType},
486        },
487        endpoint::{PreGrant, Scope, Solicitation},
488        primitives::{
489            grant::{Extensions, Grant},
490            prelude::ClientUrl,
491            registrar::{BoundClient, ExactUrl, RegistrarError},
492        },
493    };
494    use url::Url;
495
496    use std::borrow::Cow;
497
498    /// A system of addons provided additional data.
499    ///
500    /// An endpoint not having any extension may use `&mut ()` as the result of system.
501    #[async_trait]
502    pub trait Extension {
503        /// Inspect the request to produce extension data.
504        async fn extend(
505            &mut self, request: &(dyn Request + Sync),
506        ) -> std::result::Result<Extensions, ()>;
507    }
508
509    #[async_trait]
510    impl Extension for () {
511        async fn extend(&mut self, _: &(dyn Request + Sync)) -> std::result::Result<Extensions, ()> {
512            Ok(Extensions::new())
513        }
514    }
515
516    /// Required functionality to respond to authorization code requests.
517    ///
518    /// Each method will only be invoked exactly once when processing a correct and authorized request,
519    /// and potentially less than once when the request is faulty.  These methods should be implemented
520    /// by internally using `primitives`, as it is implemented in the `frontend` module.
521    pub trait Endpoint {
522        /// 'Bind' a client and redirect uri from a request to internally approved parameters.
523        fn registrar(&self) -> &(dyn crate::primitives::Registrar + Sync);
524
525        /// Generate an authorization code for a given grant.
526        fn authorizer(&mut self) -> &mut (dyn crate::primitives::Authorizer + Send);
527
528        /// An extension implementation of this endpoint.
529        ///
530        /// It is possible to use `&mut ()`.
531        fn extension(&mut self) -> &mut (dyn Extension + Send);
532    }
533
534    /// Represents a valid, currently pending authorization request not bound to an owner. The frontend
535    /// can signal a reponse using this object.
536    #[derive(Clone)]
537    pub struct Pending {
538        pre_grant: PreGrant,
539        state: Option<String>,
540        extensions: Extensions,
541    }
542
543    impl Pending {
544        /// Reference this pending state as a solicitation.
545        pub fn as_solicitation(&self) -> Solicitation<'_> {
546            let base = Solicitation::new(&self.pre_grant);
547            match self.state {
548                None => base,
549                Some(ref state) => base.with_state(state),
550            }
551        }
552
553        /// Denies the request, which redirects to the client for which the request originated.
554        pub fn deny(self) -> Result<Url, Error> {
555            let url = self.pre_grant.redirect_uri;
556            let mut error = AuthorizationError::default();
557            error.set_type(AuthorizationErrorType::AccessDenied);
558            let error = ErrorUrl::new(url.into(), self.state.as_deref(), error);
559            Err(Error::Redirect(error))
560        }
561
562        /// Inform the backend about consent from a resource owner.
563        ///
564        /// Use negotiated parameters to authorize a client for an owner. The endpoint SHOULD be the
565        /// same endpoint as was used to create the pending request.
566        pub async fn authorize(
567            self, handler: &mut (dyn Endpoint + Send), owner_id: Cow<'_, str>,
568        ) -> Result<Url, Error> {
569            let mut url = self.pre_grant.redirect_uri.to_url();
570
571            let grant = handler
572                .authorizer()
573                .authorize(Grant {
574                    owner_id: owner_id.into_owned(),
575                    client_id: self.pre_grant.client_id,
576                    redirect_uri: self.pre_grant.redirect_uri.into(),
577                    scope: self.pre_grant.scope,
578                    until: Utc::now() + Duration::minutes(10),
579                    extensions: self.extensions,
580                })
581                .await
582                .map_err(|()| Error::PrimitiveError)?;
583
584            url.query_pairs_mut()
585                .append_pair("code", grant.as_str())
586                .extend_pairs(self.state.map(|v| ("state", v)))
587                .finish();
588            Ok(url)
589        }
590
591        /// Retrieve a reference to the negotiated parameters (e.g. scope). These should be displayed
592        /// to the resource owner when asking for his authorization.
593        pub fn pre_grant(&self) -> &PreGrant {
594            &self.pre_grant
595        }
596    }
597
598    /// Retrieve allowed scope and redirect url from the registrar.
599    ///
600    /// Checks the validity of any given input as the registrar instance communicates the registrated
601    /// parameters. The registrar can also set or override the requested (default) scope of the client.
602    /// This will result in a tuple of negotiated parameters which can be used further to authorize
603    /// the client by the owner or, in case of errors, in an action to be taken.
604    /// If the client is not registered, the request will otherwise be ignored, if the request has
605    /// some other syntactical error, the client is contacted at its redirect url with an error
606    /// response.
607    pub async fn authorization_code(
608        handler: &mut (dyn Endpoint + Send + Sync), request: &(dyn Request + Sync),
609    ) -> Result<Pending, Error> {
610        enum Requested {
611            None,
612            Bind {
613                client_id: String,
614                redirect_uri: Option<ExactUrl>,
615            },
616            Extend,
617            Negotiate {
618                client_id: String,
619                redirect_uri: Url,
620                scope: Option<Scope>,
621            },
622        }
623
624        let mut authorization = Authorization::new(request);
625        let mut requested = Requested::None;
626        let mut the_redirect_uri = None;
627
628        loop {
629            let input = match requested {
630                Requested::None => Input::None,
631                Requested::Bind {
632                    client_id,
633                    redirect_uri,
634                } => {
635                    let client_url = ClientUrl {
636                        client_id: Cow::Owned(client_id),
637                        redirect_uri: redirect_uri.map(Cow::Owned),
638                    };
639                    let bound_client = match handler.registrar().bound_redirect(client_url).await {
640                        Err(RegistrarError::Unspecified) => return Err(Error::Ignore),
641                        Err(RegistrarError::PrimitiveError) => return Err(Error::PrimitiveError),
642                        Ok(pre_grant) => pre_grant,
643                    };
644                    the_redirect_uri = Some(bound_client.redirect_uri.clone().into_owned());
645                    Input::Bound {
646                        request,
647                        bound_client,
648                    }
649                }
650                Requested::Extend => {
651                    let grant_extension = match handler.extension().extend(request).await {
652                        Ok(extension_data) => extension_data,
653                        Err(()) => {
654                            let prepared_error = ErrorUrl::with_request(
655                                request,
656                                the_redirect_uri.unwrap().into_url(),
657                                AuthorizationErrorType::InvalidRequest,
658                            );
659                            return Err(Error::Redirect(prepared_error));
660                        }
661                    };
662                    Input::Extended(grant_extension)
663                }
664                Requested::Negotiate {
665                    client_id,
666                    redirect_uri,
667                    scope,
668                } => {
669                    let bound_client = BoundClient {
670                        client_id: Cow::Owned(client_id),
671                        redirect_uri: Cow::Owned(redirect_uri.clone().into()),
672                    };
673                    let pre_grant = handler.registrar().negotiate(bound_client, scope).await.map_err(
674                        |err| match err {
675                            RegistrarError::PrimitiveError => Error::PrimitiveError,
676                            RegistrarError::Unspecified => {
677                                let prepared_error = ErrorUrl::with_request(
678                                    request,
679                                    redirect_uri,
680                                    AuthorizationErrorType::InvalidScope,
681                                );
682                                Error::Redirect(prepared_error)
683                            }
684                        },
685                    )?;
686                    Input::Negotiated {
687                        pre_grant,
688                        state: request.state().map(|s| s.into_owned()),
689                    }
690                }
691            };
692
693            requested = match authorization.advance(input) {
694                Output::Bind {
695                    client_id,
696                    redirect_uri,
697                } => Requested::Bind {
698                    client_id,
699                    redirect_uri,
700                },
701                Output::Extend => Requested::Extend,
702                Output::Negotiate { bound_client, scope } => Requested::Negotiate {
703                    client_id: bound_client.client_id.clone().into_owned(),
704                    redirect_uri: bound_client.redirect_uri.to_url(),
705                    scope,
706                },
707                Output::Ok {
708                    pre_grant,
709                    state,
710                    extensions,
711                } => {
712                    return Ok(Pending {
713                        pre_grant,
714                        state,
715                        extensions,
716                    })
717                }
718                Output::Err(e) => return Err(e),
719            };
720        }
721    }
722}