1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// Copyright Materialize, Inc. and contributors. All rights reserved.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0.

//! This module defines custom error types and structs related to Frontegg API.
//!
//! [`ApiError`] is an error struct that represents an error returned by the
//! Frontegg API. It contains information about the HTTP status code and a
//! vector of error messages.
//!
//! [`Error`](`enum@Error`) is a custom error type that extends the
//! [`mz_frontegg_auth::Error`] enum.
//!
//! It contains three variants:
//! * [`Error::Auth`]: represents an authentication error from the
//!   [`mz-frontegg-auth`] crate.
//! * [`Error::Transport`]: represents a transport error from the `reqwest`
//!   crate during a network request.
//! * [`Error::Api`]: represents an Frontegg API error from a request.

use std::fmt;

use reqwest::StatusCode;
use thiserror::Error;

/// An error returned by the Frontegg API.
#[derive(Debug, Clone)]
pub struct ApiError {
    /// The HTTP status code.
    pub status_code: StatusCode,
    /// A detailed message about the error conditions.
    pub messages: Vec<String>,
}

impl fmt::Display for ApiError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{} (status {})",
            self.messages.join(","),
            self.status_code
        )
    }
}

impl std::error::Error for ApiError {}

/// A custom error type that extends the `Error` enum in the `mz-frontegg-auth`
/// crate.
#[derive(Error, Debug)]
pub enum Error {
    /// An authentication error from the [`mz_frontegg_auth`] crate.
    #[error(transparent)]
    Auth(#[from] mz_frontegg_auth::Error),
    /// A transport error from the `reqwest` crate during a network request.
    #[error("frontegg error: transport: {0}")]
    Transport(#[from] reqwest::Error),
    /// An Frontegg API error from a request.
    #[error("frontegg error: api: {0}")]
    Api(#[from] ApiError),
    /// An error indicating that the JWK set contains no keys.
    #[error("JWK set contained no keys.")]
    EmptyJwks,
    /// An error thrown after trying to fetch the JWKS from well-known endpoint.
    #[error("Error fetching JWKS.")]
    FetchingJwks,
    /// An error thrown after trying to build a [jsonwebtoken::DecodingKey] using JWKS
    #[error("Converting JWK into decoding key.")]
    ConvertingJwks,
    /// An error indicating that the claims are invalid, acoording to the structure
    /// or keys provided. If the error persists,
    /// check if the token claims matches the struct.
    #[error("Error decoding JWT claims: {0}")]
    DecodingClaims(#[from] jsonwebtoken::errors::Error),
}