66
77//! The error types used in this crate.
88
9+ use async_trait:: async_trait;
910use mas_jose:: {
1011 claims:: ClaimError ,
1112 jwa:: InvalidAlgorithm ,
1213 jwt:: { JwtDecodeError , JwtSignatureError , NoKeyWorked } ,
1314} ;
1415use oauth2_types:: { oidc:: ProviderMetadataVerificationError , pkce:: CodeChallengeError } ;
16+ use serde:: Deserialize ;
1517use thiserror:: Error ;
1618
1719/// All possible errors when using this crate.
@@ -42,17 +44,15 @@ pub enum Error {
4244
4345/// All possible errors when fetching provider metadata.
4446#[ derive( Debug , Error ) ]
47+ #[ error( "Fetching provider metadata failed" ) ]
4548pub enum DiscoveryError {
4649 /// An error occurred building the request's URL.
47- #[ error( transparent) ]
4850 IntoUrl ( #[ from] url:: ParseError ) ,
4951
5052 /// The server returned an HTTP error status code.
51- #[ error( transparent) ]
5253 Http ( #[ from] reqwest:: Error ) ,
5354
5455 /// An error occurred validating the metadata.
55- #[ error( transparent) ]
5656 Validation ( #[ from] ProviderMetadataVerificationError ) ,
5757
5858 /// Discovery is disabled for this provider.
@@ -62,25 +62,26 @@ pub enum DiscoveryError {
6262
6363/// All possible errors when authorizing the client.
6464#[ derive( Debug , Error ) ]
65+ #[ error( "Building the authorization URL failed" ) ]
6566pub enum AuthorizationError {
6667 /// An error occurred constructing the PKCE code challenge.
67- #[ error( transparent) ]
6868 Pkce ( #[ from] CodeChallengeError ) ,
6969
7070 /// An error occurred serializing the request.
71- #[ error( transparent) ]
7271 UrlEncoded ( #[ from] serde_urlencoded:: ser:: Error ) ,
7372}
7473
7574/// All possible errors when requesting an access token.
7675#[ derive( Debug , Error ) ]
76+ #[ error( "Request to the token endpoint failed" ) ]
7777pub enum TokenRequestError {
7878 /// The HTTP client returned an error.
79- #[ error( transparent) ]
8079 Http ( #[ from] reqwest:: Error ) ,
8180
81+ /// The server returned an error
82+ OAuth2 ( #[ from] OAuth2Error ) ,
83+
8284 /// Error while injecting the client credentials into the request.
83- #[ error( transparent) ]
8485 Credentials ( #[ from] CredentialsError ) ,
8586}
8687
@@ -92,7 +93,7 @@ pub enum TokenAuthorizationCodeError {
9293 Token ( #[ from] TokenRequestError ) ,
9394
9495 /// An error occurred validating the ID Token.
95- #[ error( transparent ) ]
96+ #[ error( "Verifying the 'id_token' returned by the provider failed" ) ]
9697 IdToken ( #[ from] IdTokenError ) ,
9798}
9899
@@ -104,7 +105,7 @@ pub enum TokenRefreshError {
104105 Token ( #[ from] TokenRequestError ) ,
105106
106107 /// An error occurred validating the ID Token.
107- #[ error( transparent ) ]
108+ #[ error( "Verifying the 'id_token' returned by the provider failed" ) ]
108109 IdToken ( #[ from] IdTokenError ) ,
109110}
110111
@@ -129,12 +130,16 @@ pub enum UserInfoError {
129130 } ,
130131
131132 /// An error occurred verifying the Id Token.
132- #[ error( transparent ) ]
133+ #[ error( "Verifying the 'id_token' returned by the provider failed" ) ]
133134 IdToken ( #[ from] IdTokenError ) ,
134135
135136 /// An error occurred sending the request.
136137 #[ error( transparent) ]
137138 Http ( #[ from] reqwest:: Error ) ,
139+
140+ /// The server returned an error
141+ #[ error( transparent) ]
142+ OAuth2 ( #[ from] OAuth2Error ) ,
138143}
139144
140145/// All possible errors when requesting a JWKS.
@@ -178,12 +183,12 @@ pub enum IdTokenError {
178183 #[ error( "Authorization ID token is missing" ) ]
179184 MissingAuthIdToken ,
180185
181- /// An error occurred validating the ID Token's signature and basic claims.
182186 #[ error( transparent) ]
187+ /// An error occurred validating the ID Token's signature and basic claims.
183188 Jwt ( #[ from] JwtVerificationError ) ,
184189
185- /// An error occurred extracting a claim.
186190 #[ error( transparent) ]
191+ /// An error occurred extracting a claim.
187192 Claim ( #[ from] ClaimError ) ,
188193
189194 /// The subject identifier returned by the issuer is not the same as the one
@@ -225,3 +230,78 @@ pub enum CredentialsError {
225230 #[ error( transparent) ]
226231 JwtSignature ( #[ from] JwtSignatureError ) ,
227232}
233+
234+ #[ derive( Debug , Deserialize ) ]
235+ struct OAuth2ErrorResponse {
236+ error : String ,
237+ error_description : Option < String > ,
238+ error_uri : Option < String > ,
239+ }
240+
241+ impl std:: fmt:: Display for OAuth2ErrorResponse {
242+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
243+ write ! ( f, "{:?}" , self . error) ?;
244+
245+ if let Some ( error_uri) = & self . error_uri {
246+ write ! ( f, " (See {error_uri})" ) ?;
247+ }
248+
249+ if let Some ( error_description) = & self . error_description {
250+ write ! ( f, ": {error_description}" ) ?;
251+ }
252+
253+ Ok ( ( ) )
254+ }
255+ }
256+
257+ /// An error returned by the OAuth 2.0 provider
258+ #[ derive( Debug , Error ) ]
259+ pub struct OAuth2Error {
260+ error : Option < OAuth2ErrorResponse > ,
261+
262+ #[ source]
263+ inner : reqwest:: Error ,
264+ }
265+
266+ impl std:: fmt:: Display for OAuth2Error {
267+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
268+ if let Some ( error) = & self . error {
269+ write ! (
270+ f,
271+ "Request to the provider failed with the following error: {error}"
272+ )
273+ } else {
274+ write ! ( f, "Request to the provider failed" )
275+ }
276+ }
277+ }
278+
279+ impl From < reqwest:: Error > for OAuth2Error {
280+ fn from ( inner : reqwest:: Error ) -> Self {
281+ Self { error : None , inner }
282+ }
283+ }
284+
285+ /// An extension trait to deal with error responses from the OAuth 2.0 provider
286+ #[ async_trait]
287+ pub ( crate ) trait ResponseExt {
288+ async fn error_from_oauth2_error_response ( self ) -> Result < Self , OAuth2Error >
289+ where
290+ Self : Sized ;
291+ }
292+
293+ #[ async_trait]
294+ impl ResponseExt for reqwest:: Response {
295+ async fn error_from_oauth2_error_response ( self ) -> Result < Self , OAuth2Error > {
296+ let Err ( inner) = self . error_for_status_ref ( ) else {
297+ return Ok ( self ) ;
298+ } ;
299+
300+ let error: OAuth2ErrorResponse = self . json ( ) . await ?;
301+
302+ Err ( OAuth2Error {
303+ error : Some ( error) ,
304+ inner,
305+ } )
306+ }
307+ }
0 commit comments