389389//! .set_device_authorization_url(device_auth_url);
390390//!
391391//! let details: StandardDeviceAuthorizationResponse = client
392- //! .exchange_device_code()
392+ //! .exchange_device_code()?
393393//! .add_scope(Scope::new("read".to_string()))
394394//! .request(http_client)?;
395395//!
@@ -513,6 +513,24 @@ pub use crate::revocation::RevocableToken;
513513const CONTENT_TYPE_JSON : & str = "application/json" ;
514514const CONTENT_TYPE_FORMENCODED : & str = "application/x-www-form-urlencoded" ;
515515
516+ ///
517+ /// There was a problem configuring the request.
518+ ///
519+ #[ non_exhaustive]
520+ #[ derive( Debug , thiserror:: Error ) ]
521+ pub enum ConfigurationError {
522+ ///
523+ /// The endpoint URL tp be contacted is missing.
524+ ///
525+ #[ error( "No {0} endpoint URL specified" ) ]
526+ MissingUrl ( & ' static str ) ,
527+ ///
528+ /// The endpoint URL to be contacted MUST be HTTPS.
529+ ///
530+ #[ error( "Scheme for {0} endpoint URL must be HTTPS" ) ]
531+ InsecureUrl ( & ' static str ) ,
532+ }
533+
516534///
517535/// Indicates whether requests to the authorization server should use basic authentication or
518536/// include the parameters in the request body for requests in which either is valid.
@@ -813,16 +831,21 @@ where
813831 /// Perform a device authorization request as per
814832 /// https://tools.ietf.org/html/rfc8628#section-3.1
815833 ///
816- pub fn exchange_device_code ( & self ) -> DeviceAuthorizationRequest < TE > {
817- DeviceAuthorizationRequest {
834+ pub fn exchange_device_code (
835+ & self ,
836+ ) -> Result < DeviceAuthorizationRequest < TE > , ConfigurationError > {
837+ Ok ( DeviceAuthorizationRequest {
818838 auth_type : & self . auth_type ,
819839 client_id : & self . client_id ,
820840 client_secret : self . client_secret . as_ref ( ) ,
821841 extra_params : Vec :: new ( ) ,
822842 scopes : Vec :: new ( ) ,
823- device_authorization_url : self . device_authorization_url . as_ref ( ) ,
843+ device_authorization_url : self
844+ . device_authorization_url
845+ . as_ref ( )
846+ . ok_or ( ConfigurationError :: MissingUrl ( "device authorization_url" ) ) ?,
824847 _phantom : PhantomData ,
825- }
848+ } )
826849 }
827850
828851 ///
@@ -856,17 +879,20 @@ where
856879 pub fn introspect < ' a > (
857880 & ' a self ,
858881 token : & ' a AccessToken ,
859- ) -> IntrospectionRequest < ' a , TE , TIR , TT > {
860- IntrospectionRequest {
882+ ) -> Result < IntrospectionRequest < ' a , TE , TIR , TT > , ConfigurationError > {
883+ Ok ( IntrospectionRequest {
861884 auth_type : & self . auth_type ,
862885 client_id : & self . client_id ,
863886 client_secret : self . client_secret . as_ref ( ) ,
864887 extra_params : Vec :: new ( ) ,
865- introspection_url : self . introspection_url . as_ref ( ) ,
888+ introspection_url : self
889+ . introspection_url
890+ . as_ref ( )
891+ . ok_or ( ConfigurationError :: MissingUrl ( "introspection" ) ) ?,
866892 token,
867893 token_type_hint : None ,
868894 _phantom : PhantomData ,
869- }
895+ } )
870896 }
871897
872898 ///
@@ -878,16 +904,30 @@ where
878904 /// Attempting to submit the generated request without calling [`set_revocation_url()`](Self::set_revocation_url())
879905 /// first will result in an error.
880906 ///
881- pub fn revoke_token ( & self , token : RT ) -> RevocationRequest < RT , TRE > {
882- RevocationRequest {
907+ pub fn revoke_token (
908+ & self ,
909+ token : RT ,
910+ ) -> Result < RevocationRequest < RT , TRE > , ConfigurationError > {
911+ // https://tools.ietf.org/html/rfc7009#section-2 states:
912+ // "The client requests the revocation of a particular token by making an
913+ // HTTP POST request to the token revocation endpoint URL. This URL
914+ // MUST conform to the rules given in [RFC6749], Section 3.1. Clients
915+ // MUST verify that the URL is an HTTPS URL."
916+ let revocation_url = match self . revocation_url . as_ref ( ) {
917+ Some ( url) if url. url ( ) . scheme ( ) == "https" => Ok ( url) ,
918+ Some ( _) => Err ( ConfigurationError :: InsecureUrl ( "revocation" ) ) ,
919+ None => Err ( ConfigurationError :: MissingUrl ( "revocation" ) ) ,
920+ } ?;
921+
922+ Ok ( RevocationRequest {
883923 auth_type : & self . auth_type ,
884924 client_id : & self . client_id ,
885925 client_secret : self . client_secret . as_ref ( ) ,
886926 extra_params : Vec :: new ( ) ,
887- revocation_url : self . revocation_url . as_ref ( ) ,
927+ revocation_url,
888928 token,
889929 _phantom : PhantomData ,
890- }
930+ } )
891931 }
892932}
893933
@@ -1529,7 +1569,7 @@ where
15291569 client_id : & ' a ClientId ,
15301570 client_secret : Option < & ' a ClientSecret > ,
15311571 extra_params : Vec < ( Cow < ' a , str > , Cow < ' a , str > ) > ,
1532- introspection_url : Option < & ' a IntrospectionUrl > ,
1572+ introspection_url : & ' a IntrospectionUrl ,
15331573
15341574 _phantom : PhantomData < ( TE , TIR , TT ) > ,
15351575}
@@ -1604,11 +1644,7 @@ where
16041644 & self . extra_params ,
16051645 None ,
16061646 None ,
1607- self . introspection_url
1608- . ok_or_else ( || {
1609- RequestTokenError :: Other ( "no introspection_url provided" . to_string ( ) )
1610- } ) ?
1611- . url ( ) ,
1647+ self . introspection_url . url ( ) ,
16121648 params,
16131649 ) )
16141650 }
@@ -1662,7 +1698,7 @@ where
16621698 client_id : & ' a ClientId ,
16631699 client_secret : Option < & ' a ClientSecret > ,
16641700 extra_params : Vec < ( Cow < ' a , str > , Cow < ' a , str > ) > ,
1665- revocation_url : Option < & ' a RevocationUrl > ,
1701+ revocation_url : & ' a RevocationUrl ,
16661702
16671703 _phantom : PhantomData < ( RT , TE ) > ,
16681704}
@@ -1700,21 +1736,6 @@ where
17001736 where
17011737 RE : Error + ' static ,
17021738 {
1703- // https://tools.ietf.org/html/rfc7009#section-2 states:
1704- // "The client requests the revocation of a particular token by making an
1705- // HTTP POST request to the token revocation endpoint URL. This URL
1706- // MUST conform to the rules given in [RFC6749], Section 3.1. Clients
1707- // MUST verify that the URL is an HTTPS URL."
1708- let revocation_url = match self . revocation_url {
1709- Some ( url) if url. url ( ) . scheme ( ) == "https" => Ok ( url. url ( ) ) ,
1710- Some ( _) => Err ( RequestTokenError :: Other (
1711- "revocation_url is not HTTPS" . to_string ( ) ,
1712- ) ) ,
1713- None => Err ( RequestTokenError :: Other (
1714- "no revocation_url provided" . to_string ( ) ,
1715- ) ) ,
1716- } ?;
1717-
17181739 let mut params: Vec < ( & str , & str ) > = vec ! [ ( "token" , self . token. secret( ) ) ] ;
17191740 if let Some ( type_hint) = self . token . type_hint ( ) {
17201741 params. push ( ( "token_type_hint" , type_hint) ) ;
@@ -1727,7 +1748,7 @@ where
17271748 & self . extra_params ,
17281749 None ,
17291750 None ,
1730- revocation_url,
1751+ self . revocation_url . url ( ) ,
17311752 params,
17321753 ) )
17331754 }
@@ -1972,7 +1993,7 @@ where
19721993 client_secret : Option < & ' a ClientSecret > ,
19731994 extra_params : Vec < ( Cow < ' a , str > , Cow < ' a , str > ) > ,
19741995 scopes : Vec < Cow < ' a , Scope > > ,
1975- device_authorization_url : Option < & ' a DeviceAuthorizationUrl > ,
1996+ device_authorization_url : & ' a DeviceAuthorizationUrl ,
19761997 _phantom : PhantomData < TE > ,
19771998}
19781999
@@ -2023,11 +2044,7 @@ where
20232044 & self . extra_params ,
20242045 None ,
20252046 Some ( & self . scopes ) ,
2026- self . device_authorization_url
2027- . ok_or_else ( || {
2028- RequestTokenError :: Other ( "no device authorization_url provided" . to_string ( ) )
2029- } ) ?
2030- . url ( ) ,
2047+ self . device_authorization_url . url ( ) ,
20312048 vec ! [ ] ,
20322049 ) )
20332050 }
0 commit comments