Skip to content

Commit de1c389

Browse files
KhayetJakob Herpelbuehler
authored
feat: log error responses returned by Zitadel (#584)
When we receive an error response on an introspection call, for example a 503, we previously returned a ParseError as the response was not valid JSON. This change adds a new error type ZitadelResponseError which handles such cases by logging the status code and body of the error response. This is a breaking change as we add a Variant to the error enum which needs to be handled by the user. Co-authored-by: Jakob Herpel <[email protected]> Co-authored-by: Christoph Bühler <[email protected]>
1 parent e550ba3 commit de1c389

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

src/oidc/introspection/mod.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ use custom_error::custom_error;
22
use openidconnect::http::Method;
33
use openidconnect::reqwest::async_http_client;
44
use openidconnect::url::{ParseError, Url};
5+
use openidconnect::HttpResponse;
56
use openidconnect::{
67
core::CoreTokenType, ExtraTokenFields, HttpRequest, StandardTokenIntrospectionResponse,
78
};
89

910
use reqwest::header::{HeaderMap, ACCEPT, AUTHORIZATION, CONTENT_TYPE};
1011
use serde::{Deserialize, Serialize};
1112
use std::collections::HashMap;
12-
use std::fmt::Debug;
13+
use std::error::Error;
14+
use std::fmt::{Debug, Display};
1315

1416
use crate::credentials::{Application, ApplicationError};
1517

@@ -25,6 +27,7 @@ custom_error! {
2527
ParseUrl{source: ParseError} = "could not parse url: {source}",
2628
ParseResponse{source: serde_json::Error} = "could not parse introspection response: {source}",
2729
DecodeResponse{source: base64::DecodeError} = "could not decode base64 metadata: {source}",
30+
ResponseError{source: ZitadelResponseError} = "received error response from Zitadel: {source}",
2831
}
2932

3033
/// Introspection response information that is returned by the ZITADEL
@@ -221,13 +224,39 @@ pub async fn introspect(
221224
.await
222225
.map_err(|source| IntrospectionError::RequestFailed { source })?;
223226

227+
if !response.status_code.is_success() {
228+
return Err(IntrospectionError::ResponseError {
229+
source: ZitadelResponseError::from_response(&response),
230+
});
231+
}
232+
224233
let mut response: ZitadelIntrospectionResponse =
225234
serde_json::from_slice(response.body.as_slice())
226235
.map_err(|source| IntrospectionError::ParseResponse { source })?;
227236
decode_metadata(&mut response)?;
228237
Ok(response)
229238
}
230239

240+
#[derive(Debug)]
241+
struct ZitadelResponseError {
242+
status_code: String,
243+
body: String,
244+
}
245+
impl ZitadelResponseError {
246+
fn from_response(response: &HttpResponse) -> Self {
247+
Self {
248+
status_code: response.status_code.to_string(),
249+
body: String::from_utf8_lossy(response.body.as_slice()).to_string(),
250+
}
251+
}
252+
}
253+
impl Display for ZitadelResponseError {
254+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
255+
write!(f, "status code: {}, body: {}", self.status_code, self.body)
256+
}
257+
}
258+
impl Error for ZitadelResponseError {}
259+
231260
// Metadata values are base64 encoded.
232261
fn decode_metadata(response: &mut ZitadelIntrospectionResponse) -> Result<(), IntrospectionError> {
233262
if let Some(h) = &response.extra_fields().metadata {

0 commit comments

Comments
 (0)