1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-08-07 17:03:01 +03:00

Use an enum for client error codes

Replace the ClientError constants with From<ClientErrorCode>.
This commit is contained in:
Kévin Commaille
2022-08-24 11:24:57 +02:00
committed by Quentin Gliech
parent 348044afdc
commit ee47c821e3
6 changed files with 421 additions and 181 deletions

73
Cargo.lock generated
View File

@@ -1176,14 +1176,37 @@ dependencies = [
"cipher 0.3.0", "cipher 0.3.0",
] ]
[[package]]
name = "darling"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
dependencies = [
"darling_core 0.13.4",
"darling_macro 0.13.4",
]
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.14.1" version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02" checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02"
dependencies = [ dependencies = [
"darling_core", "darling_core 0.14.1",
"darling_macro", "darling_macro 0.14.1",
]
[[package]]
name = "darling_core"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"syn",
] ]
[[package]] [[package]]
@@ -1200,13 +1223,24 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "darling_macro"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [
"darling_core 0.13.4",
"quote",
"syn",
]
[[package]] [[package]]
name = "darling_macro" name = "darling_macro"
version = "0.14.1" version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5" checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5"
dependencies = [ dependencies = [
"darling_core", "darling_core 0.14.1",
"quote", "quote",
"syn", "syn",
] ]
@@ -2846,6 +2880,7 @@ dependencies = [
"mas-jose", "mas-jose",
"parse-display", "parse-display",
"serde", "serde",
"serde-enum-str",
"serde_json", "serde_json",
"serde_with", "serde_with",
"sha2 0.10.2", "sha2 0.10.2",
@@ -3957,6 +3992,36 @@ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]]
name = "serde-attributes"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3aba2af3c3b9cd6f3a919056dac6005b71fceecc1cdfa65c4df3912f64e07e60"
dependencies = [
"darling_core 0.13.4",
"serde-rename-rule",
"syn",
]
[[package]]
name = "serde-enum-str"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2a41bf2fc78a58589b9a6948bfc918c9b2dc918732f2ac14eed982ffb876b39"
dependencies = [
"darling 0.13.4",
"proc-macro2",
"quote",
"serde-attributes",
"syn",
]
[[package]]
name = "serde-rename-rule"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd2930103714ccef4f1fe5b6a5f2b6fdcfe462a6c802464714bd41e5b5097c33"
[[package]] [[package]]
name = "serde_bser" name = "serde_bser"
version = "0.3.1" version = "0.3.1"
@@ -4037,7 +4102,7 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de337f322382fcdfbb21a014f7c224ee041a23785651db67b9827403178f698f" checksum = "de337f322382fcdfbb21a014f7c224ee041a23785651db67b9827403178f698f"
dependencies = [ dependencies = [
"darling", "darling 0.14.1",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",

View File

@@ -33,11 +33,7 @@ use mas_storage::oauth2::{
}; };
use mas_templates::Templates; use mas_templates::Templates;
use oauth2_types::{ use oauth2_types::{
errors::{ errors::{ClientError, ClientErrorCode},
ACCESS_DENIED, CONSENT_REQUIRED, INTERACTION_REQUIRED, INVALID_REQUEST, LOGIN_REQUIRED,
REGISTRATION_NOT_SUPPORTED, REQUEST_NOT_SUPPORTED, REQUEST_URI_NOT_SUPPORTED, SERVER_ERROR,
UNAUTHORIZED_CLIENT,
},
pkce, pkce,
prelude::*, prelude::*,
requests::{AuthorizationRequest, GrantType, Prompt, ResponseMode}, requests::{AuthorizationRequest, GrantType, Prompt, ResponseMode},
@@ -202,32 +198,49 @@ pub(crate) async fn get(
// with the right error since we don't support them. // with the right error since we don't support them.
if params.auth.request.is_some() { if params.auth.request.is_some() {
return Ok(callback_destination return Ok(callback_destination
.go(&templates, REQUEST_NOT_SUPPORTED) .go(
&templates,
ClientError::from(ClientErrorCode::RequestNotSupported),
)
.await?); .await?);
} }
if params.auth.request_uri.is_some() { if params.auth.request_uri.is_some() {
return Ok(callback_destination return Ok(callback_destination
.go(&templates, REQUEST_URI_NOT_SUPPORTED) .go(
&templates,
ClientError::from(ClientErrorCode::RequestUriNotSupported),
)
.await?); .await?);
} }
if params.auth.registration.is_some() { if params.auth.registration.is_some() {
return Ok(callback_destination return Ok(callback_destination
.go(&templates, REGISTRATION_NOT_SUPPORTED) .go(
&templates,
ClientError::from(ClientErrorCode::RegistrationNotSupported),
)
.await?); .await?);
} }
// Check if it is allowed to use this grant type // Check if it is allowed to use this grant type
if !client.grant_types.contains(&GrantType::AuthorizationCode) { if !client.grant_types.contains(&GrantType::AuthorizationCode) {
return Ok(callback_destination return Ok(callback_destination
.go(&templates, UNAUTHORIZED_CLIENT) .go(
&templates,
ClientError::from(ClientErrorCode::UnauthorizedClient),
)
.await?); .await?);
} }
// Fail early if prompt=none and there is no active session // Fail early if prompt=none and there is no active session
if params.auth.prompt == Some(Prompt::None) && maybe_session.is_none() { if params.auth.prompt == Some(Prompt::None) && maybe_session.is_none() {
return Ok(callback_destination.go(&templates, LOGIN_REQUIRED).await?); return Ok(callback_destination
.go(
&templates,
ClientError::from(ClientErrorCode::LoginRequired),
)
.await?);
} }
let code: Option<AuthorizationCode> = if response_type.has_code() { let code: Option<AuthorizationCode> = if response_type.has_code() {
@@ -248,7 +261,12 @@ pub(crate) async fn get(
// If the request had PKCE params but no code asked, it should get back with an // If the request had PKCE params but no code asked, it should get back with an
// error // error
if params.pkce.is_some() { if params.pkce.is_some() {
return Ok(callback_destination.go(&templates, INVALID_REQUEST).await?); return Ok(callback_destination
.go(
&templates,
ClientError::from(ClientErrorCode::InvalidRequest),
)
.await?);
} }
None None
@@ -315,16 +333,24 @@ pub(crate) async fn get(
Ok(params) => callback_destination.go(&templates, params).await?, Ok(params) => callback_destination.go(&templates, params).await?,
Err(GrantCompletionError::RequiresConsent) => { Err(GrantCompletionError::RequiresConsent) => {
callback_destination callback_destination
.go(&templates, CONSENT_REQUIRED) .go(
&templates,
ClientError::from(ClientErrorCode::ConsentRequired),
)
.await? .await?
} }
Err(GrantCompletionError::RequiresReauth) => { Err(GrantCompletionError::RequiresReauth) => {
callback_destination callback_destination
.go(&templates, INTERACTION_REQUIRED) .go(
&templates,
ClientError::from(ClientErrorCode::InteractionRequired),
)
.await? .await?
} }
Err(GrantCompletionError::PolicyViolation) => { Err(GrantCompletionError::PolicyViolation) => {
callback_destination.go(&templates, ACCESS_DENIED).await? callback_destination
.go(&templates, ClientError::from(ClientErrorCode::AccessDenied))
.await?
} }
Err(GrantCompletionError::Anyhow(a)) => return Err(RouteError::Anyhow(a)), Err(GrantCompletionError::Anyhow(a)) => return Err(RouteError::Anyhow(a)),
Err(GrantCompletionError::Internal(e)) => { Err(GrantCompletionError::Internal(e)) => {
@@ -378,7 +404,9 @@ pub(crate) async fn get(
Ok(r) => r, Ok(r) => r,
Err(err) => { Err(err) => {
tracing::error!(%err); tracing::error!(%err);
callback_destination.go(&templates, SERVER_ERROR).await? callback_destination
.go(&templates, ClientError::from(ClientErrorCode::ServerError))
.await?
} }
}; };

View File

@@ -19,7 +19,7 @@ use hyper::StatusCode;
use mas_policy::{PolicyFactory, Violation}; use mas_policy::{PolicyFactory, Violation};
use mas_storage::oauth2::client::insert_client; use mas_storage::oauth2::client::insert_client;
use oauth2_types::{ use oauth2_types::{
errors::{INVALID_CLIENT_METADATA, INVALID_REDIRECT_URI, SERVER_ERROR}, errors::{ClientError, ClientErrorCode},
registration::{ registration::{
ClientMetadata, ClientMetadataVerificationError, ClientRegistrationResponse, Localized, ClientMetadata, ClientMetadataVerificationError, ClientRegistrationResponse, Localized,
}, },
@@ -65,36 +65,24 @@ impl From<ClientMetadataVerificationError> for RouteError {
} }
} }
// TODO: there is probably a better way to do achieve this. ClientError only
// works for static strings
#[derive(serde::Serialize)]
struct PolicyError {
error: String,
error_description: String,
}
impl PolicyError {
#[must_use]
pub const fn new(error: String, error_description: String) -> Self {
Self {
error,
error_description,
}
}
}
impl IntoResponse for RouteError { impl IntoResponse for RouteError {
fn into_response(self) -> axum::response::Response { fn into_response(self) -> axum::response::Response {
match self { match self {
Self::Internal(_) | Self::Anyhow(_) => { Self::Internal(_) | Self::Anyhow(_) => (
(StatusCode::INTERNAL_SERVER_ERROR, Json(SERVER_ERROR)).into_response() StatusCode::INTERNAL_SERVER_ERROR,
} Json(ClientError::from(ClientErrorCode::ServerError)),
Self::InvalidRedirectUri => { )
(StatusCode::BAD_REQUEST, Json(INVALID_REDIRECT_URI)).into_response() .into_response(),
} Self::InvalidRedirectUri => (
Self::InvalidClientMetadata => { StatusCode::BAD_REQUEST,
(StatusCode::BAD_REQUEST, Json(INVALID_CLIENT_METADATA)).into_response() Json(ClientError::from(ClientErrorCode::InvalidRedirectUri)),
} )
.into_response(),
Self::InvalidClientMetadata => (
StatusCode::BAD_REQUEST,
Json(ClientError::from(ClientErrorCode::InvalidClientMetadata)),
)
.into_response(),
Self::PolicyDenied(violations) => { Self::PolicyDenied(violations) => {
let collected = &violations let collected = &violations
.iter() .iter()
@@ -104,10 +92,10 @@ impl IntoResponse for RouteError {
( (
StatusCode::UNAUTHORIZED, StatusCode::UNAUTHORIZED,
Json(PolicyError::new( Json(
"invalid_client_metadata".to_owned(), ClientError::from(ClientErrorCode::InvalidClientMetadata)
joined, .with_description(joined),
)), ),
) )
.into_response() .into_response()
} }

View File

@@ -43,7 +43,7 @@ use mas_storage::{
DatabaseInconsistencyError, PostgresqlBackend, DatabaseInconsistencyError, PostgresqlBackend,
}; };
use oauth2_types::{ use oauth2_types::{
errors::{INVALID_CLIENT, INVALID_GRANT, INVALID_REQUEST, SERVER_ERROR, UNAUTHORIZED_CLIENT}, errors::{ClientError, ClientErrorCode},
pkce::CodeChallengeError, pkce::CodeChallengeError,
requests::{ requests::{
AccessTokenRequest, AccessTokenResponse, AuthorizationCodeGrant, RefreshTokenGrant, AccessTokenRequest, AccessTokenResponse, AuthorizationCodeGrant, RefreshTokenGrant,
@@ -129,21 +129,33 @@ impl From<RefreshTokenLookupError> for RouteError {
impl IntoResponse for RouteError { impl IntoResponse for RouteError {
fn into_response(self) -> axum::response::Response { fn into_response(self) -> axum::response::Response {
match self { match self {
Self::Internal(_) | Self::Anyhow(_) => { Self::Internal(_) | Self::Anyhow(_) => (
(StatusCode::INTERNAL_SERVER_ERROR, Json(SERVER_ERROR)) StatusCode::INTERNAL_SERVER_ERROR,
} Json(ClientError::from(ClientErrorCode::ServerError)),
Self::BadRequest => (StatusCode::BAD_REQUEST, Json(INVALID_REQUEST)), ),
Self::BadRequest => (
StatusCode::BAD_REQUEST,
Json(ClientError::from(ClientErrorCode::InvalidRequest)),
),
Self::PkceVerification(err) => ( Self::PkceVerification(err) => (
StatusCode::BAD_REQUEST, StatusCode::BAD_REQUEST,
Json(INVALID_GRANT.with_description(format!("PKCE verification failed: {err}"))), Json(
ClientError::from(ClientErrorCode::InvalidGrant)
.with_description(format!("PKCE verification failed: {err}")),
),
),
Self::ClientNotFound | Self::ClientCredentialsVerification(_) => (
StatusCode::UNAUTHORIZED,
Json(ClientError::from(ClientErrorCode::InvalidClient)),
),
Self::ClientNotAllowed | Self::UnauthorizedClient => (
StatusCode::UNAUTHORIZED,
Json(ClientError::from(ClientErrorCode::UnauthorizedClient)),
),
Self::InvalidGrant => (
StatusCode::BAD_REQUEST,
Json(ClientError::from(ClientErrorCode::InvalidGrant)),
), ),
Self::ClientNotFound | Self::ClientCredentialsVerification(_) => {
(StatusCode::UNAUTHORIZED, Json(INVALID_CLIENT))
}
Self::ClientNotAllowed | Self::UnauthorizedClient => {
(StatusCode::UNAUTHORIZED, Json(UNAUTHORIZED_CLIENT))
}
Self::InvalidGrant => (StatusCode::BAD_REQUEST, Json(INVALID_GRANT)),
} }
.into_response() .into_response()
} }

View File

@@ -19,6 +19,7 @@ sha2 = "0.10.2"
data-encoding = "2.3.2" data-encoding = "2.3.2"
thiserror = "1.0.32" thiserror = "1.0.32"
itertools = "0.10.3" itertools = "0.10.3"
serde-enum-str = "0.2.5"
mas-iana = { path = "../iana" } mas-iana = { path = "../iana" }
mas-jose = { path = "../jose" } mas-jose = { path = "../jose" }

View File

@@ -14,150 +14,296 @@
use std::borrow::Cow; use std::borrow::Cow;
#[derive(serde::Serialize, Clone)] use serde::{Deserialize, Serialize};
use serde_enum_str::{Deserialize_enum_str, Serialize_enum_str};
/// A client error returned by an authorization server.
///
/// To construct this with a default description for the error code, use its
/// `From<ClientErrorCode>` implementation.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ClientError { pub struct ClientError {
pub error: &'static str, /// The error code.
pub error: ClientErrorCode,
/// A human-readable description of the error.
pub error_description: Cow<'static, str>, pub error_description: Cow<'static, str>,
} }
impl ClientError { impl ClientError {
/// Creates a new `ClientError` with the given error code and description.
#[must_use] #[must_use]
pub const fn new(error: &'static str, error_description: &'static str) -> Self { pub const fn new(error: ClientErrorCode, error_description: &'static str) -> Self {
Self { Self {
error, error,
error_description: Cow::Borrowed(error_description), error_description: Cow::Borrowed(error_description),
} }
} }
/// Changes the description of this `ClientError` with the given `String`.
#[must_use] #[must_use]
pub const fn with_description(&self, description: String) -> Self { pub fn with_description(mut self, description: String) -> Self {
Self { self.error_description = Cow::Owned(description);
error: self.error, self
error_description: Cow::Owned(description),
}
} }
} }
pub mod rfc6749 { impl From<ClientErrorCode> for ClientError {
use super::ClientError; fn from(error: ClientErrorCode) -> Self {
let desc = error.default_description();
pub const INVALID_REQUEST: ClientError = ClientError::new( Self::new(error, desc)
"invalid_request", }
"The request is missing a required parameter, \
includes an invalid parameter value, \
includes a parameter more than once, \
or is otherwise malformed.",
);
pub const INVALID_CLIENT: ClientError =
ClientError::new("invalid_client", "Client authentication failed.");
pub const INVALID_GRANT: ClientError = ClientError::new(
"invalid_grant",
"The provided access grant is invalid, expired, or revoked.",
);
pub const UNAUTHORIZED_CLIENT: ClientError = ClientError::new(
"unauthorized_client",
"The client is not authorized to request an access token using this method.",
);
pub const UNSUPPORTED_GRANT_TYPE: ClientError = ClientError::new(
"unsupported_grant_type",
"The authorization grant type is not supported by the authorization server.",
);
pub const ACCESS_DENIED: ClientError = ClientError::new(
"access_denied",
"The resource owner or authorization server denied the request.",
);
pub const UNSUPPORTED_RESPONSE_TYPE: ClientError = ClientError::new(
"unsupported_response_type",
"The authorization server does not support obtaining an access token using this method.",
);
pub const INVALID_SCOPE: ClientError = ClientError::new(
"invalid_scope",
"The requested scope is invalid, unknown, or malformed.",
);
pub const SERVER_ERROR: ClientError = ClientError::new(
"server_error",
"The authorization server encountered an unexpected condition \
that prevented it from fulfilling the request.",
);
pub const TEMPORARILY_UNAVAILABLE: ClientError = ClientError::new(
"temporarily_unavailable",
"The authorization server is currently unable to handle the request \
due to a temporary overloading or maintenance of the server.",
);
} }
pub mod oidc_core { #[derive(Debug, Clone, PartialEq, Eq, Serialize_enum_str, Deserialize_enum_str)]
use super::ClientError; #[serde(rename_all = "snake_case")]
pub enum ClientErrorCode {
/// `invalid_request`
///
/// The request is missing a required parameter, includes an invalid
/// parameter value, includes a parameter more than once, or is otherwise
/// malformed.
///
/// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).
InvalidRequest,
pub const INTERACTION_REQUIRED: ClientError = ClientError::new( /// `invalid_client`
"interaction_required", ///
"The Authorization Server requires End-User interaction of some form to proceed.", /// Client authentication failed (e.g., unknown client, no client
); /// authentication included, or unsupported authentication method).
///
/// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).
InvalidClient,
pub const LOGIN_REQUIRED: ClientError = ClientError::new( /// `invalid_grant`
"login_required", ///
"The Authorization Server requires End-User authentication.", /// The provided authorization grant (e.g., authorization code, resource
); /// owner credentials) or refresh token is invalid, expired, revoked, does
/// not match the redirection URI used in the authorization request, or was
/// issued to another client.
///
/// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).
InvalidGrant,
pub const ACCOUNT_SELECTION_REQUIRED: ClientError = ClientError::new( /// `unauthorized_client`
"account_selection_required", ///
"The End-User is REQUIRED to select a session at the Authorization Server.", /// The authenticated client is not authorized to use this authorization
); /// grant type.
///
/// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).
UnauthorizedClient,
pub const CONSENT_REQUIRED: ClientError = ClientError::new( /// `unsupported_grant_type`
"consent_required", ///
"The Authorization Server requires End-User consent.", /// The authorization grant type is not supported by the authorization
); /// server.
///
/// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-5.2).
UnsupportedGrantType,
pub const INVALID_REQUEST_URI: ClientError = ClientError::new( /// `access_denied`
"invalid_request_uri", ///
"The request_uri in the Authorization Request returns an error or contains invalid data. ", /// The resource owner or authorization server denied the request.
); ///
/// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1).
AccessDenied,
pub const INVALID_REQUEST_OBJECT: ClientError = ClientError::new( /// `unsupported_response_type`
"invalid_request_object", ///
"The request parameter contains an invalid Request Object.", /// The authorization server does not support obtaining an authorization
); /// code using this method.
///
/// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1).
UnsupportedResponseType,
pub const REQUEST_NOT_SUPPORTED: ClientError = ClientError::new( /// `invalid_scope`
"request_not_supported", ///
"The provider does not support use of the request parameter.", /// The requested scope is invalid, unknown, malformed, or exceeds the scope
); /// granted by the resource owner.
///
/// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1).
InvalidScope,
pub const REQUEST_URI_NOT_SUPPORTED: ClientError = ClientError::new( /// `server_error`
"request_uri_not_supported", ///
"The provider does not support use of the request_uri parameter.", /// The authorization server encountered an unexpected condition that
); /// prevented it from fulfilling the request.
///
/// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1).
ServerError,
pub const REGISTRATION_NOT_SUPPORTED: ClientError = ClientError::new( /// `temporarily_unavailable`
"registration_not_supported", ///
"The provider does not support use of the registration parameter.", /// The authorization server is currently unable to handle the request due
); /// to a temporary overloading or maintenance of the server.
///
/// From [RFC6749](https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1).
TemporarilyUnavailable,
/// `interaction_required`
///
/// The authorization server requires end-user interaction of some form to
/// proceed.
///
/// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
InteractionRequired,
/// `login_required`
///
/// The authorization server requires end-user authentication.
///
/// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
LoginRequired,
/// `account_selection_required`
///
/// The end-user is required to select a session at the authorization
/// server.
///
/// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
AccountSelectionRequired,
/// `consent_required`
///
/// The authorization server requires end-user consent.
///
/// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
ConsentRequired,
/// `invalid_request_uri`
///
/// The `request_uri` in the authorization request returns an error or
/// contains invalid data.
///
/// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
InvalidRequestUri,
/// `invalid_request_object`
///
/// The request parameter contains an invalid request object.
///
/// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
InvalidRequestObject,
/// `request_not_supported`
///
/// The authorization server does not support use of the `request`
/// parameter.
///
/// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
RequestNotSupported,
/// `request_uri_not_supported`
///
/// The authorization server does not support use of the `request_uri`
/// parameter.
///
/// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
RequestUriNotSupported,
/// `registration_not_supported`
///
/// The authorization server does not support use of the `registration`
/// parameter.
///
/// From [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthError).
RegistrationNotSupported,
/// `invalid_redirect_uri`
///
/// The value of one or more redirection URIs is invalid.
///
/// From [RFC7591](https://www.rfc-editor.org/rfc/rfc7591#section-3.2.2).
InvalidRedirectUri,
/// `invalid_client_metadata`
///
/// The value of one of the client metadata fields is invalid and the server
/// has rejected this request.
///
/// From [RFC7591](https://www.rfc-editor.org/rfc/rfc7591#section-3.2.2).
InvalidClientMetadata,
/// Another error code.
#[serde(other)]
Unknown(String),
} }
mod rfc7591 { impl ClientErrorCode {
use super::ClientError; /// Get the default description for this `ClientErrorCode`.
///
pub const INVALID_REDIRECT_URI: ClientError = ClientError::new( /// Note that [`ClientErrorCode::Unknown`] returns an empty string.
"invalid_redirect_uri", #[must_use]
"The value of one or more redirection URIs is invalid.", pub fn default_description(&self) -> &'static str {
); match self {
ClientErrorCode::InvalidRequest => {
pub const INVALID_CLIENT_METADATA: ClientError = ClientError::new( "The request is missing a required parameter, includes an \
"invalid_client_metadata", invalid parameter value, includes a parameter more than once, \
"The value of one of the client metadata fields is invalid", or is otherwise malformed."
); }
ClientErrorCode::InvalidClient => "Client authentication failed.",
ClientErrorCode::InvalidGrant => {
"The provided access grant is invalid, expired, or revoked."
}
ClientErrorCode::UnauthorizedClient => {
"The client is not authorized to request an access token using this method."
}
ClientErrorCode::UnsupportedGrantType => {
"The authorization grant type is not supported by the authorization server."
}
ClientErrorCode::AccessDenied => {
"The resource owner or authorization server denied the request."
}
ClientErrorCode::UnsupportedResponseType => {
"The authorization server does not support obtaining an access \
token using this method."
}
ClientErrorCode::InvalidScope => {
"The requested scope is invalid, unknown, or malformed."
}
ClientErrorCode::ServerError => {
"The authorization server encountered an unexpected condition \
that prevented it from fulfilling the request."
}
ClientErrorCode::TemporarilyUnavailable => {
"The authorization server is currently unable to handle the request \
due to a temporary overloading or maintenance of the server."
}
ClientErrorCode::InteractionRequired => {
"The Authorization Server requires End-User interaction of some form to proceed."
}
ClientErrorCode::LoginRequired => {
"The Authorization Server requires End-User authentication."
}
ClientErrorCode::AccountSelectionRequired => {
"The End-User is required to select a session at the Authorization Server."
}
ClientErrorCode::ConsentRequired => {
"The Authorization Server requires End-User consent."
}
ClientErrorCode::InvalidRequestUri => {
"The request_uri in the Authorization Request returns an error \
or contains invalid data."
}
ClientErrorCode::InvalidRequestObject => {
"The request parameter contains an invalid Request Object."
}
ClientErrorCode::RequestNotSupported => {
"The provider does not support use of the request parameter."
}
ClientErrorCode::RequestUriNotSupported => {
"The provider does not support use of the request_uri parameter."
}
ClientErrorCode::RegistrationNotSupported => {
"The provider does not support use of the registration parameter."
}
ClientErrorCode::InvalidRedirectUri => {
"The value of one or more redirection URIs is invalid."
}
ClientErrorCode::InvalidClientMetadata => {
"The value of one of the client metadata fields is invalid"
}
ClientErrorCode::Unknown(_) => "",
}
}
} }
pub use oidc_core::*;
pub use rfc6749::*;
pub use rfc7591::*;