pub enum OAuthError {
Show 19 variants
Config(String),
Discovery(String),
TokenExchange(String),
IdTokenValidation(String),
UnknownProvider(String),
CsrfMismatch,
NoFlow,
Expired,
InvalidParameter,
RefreshTokenExpired,
NoRefreshToken,
NoAccessToken,
UserInfo(String),
AccessTokenExpired,
InsufficientScope,
DeviceAuthorization(String),
UnknownKid(String),
UnsupportedTokenType,
TokenEndpointTransient {
status: u16,
body: String,
},
}oauth only.Expand description
Errors returned by OAuth 2.0 / OIDC operations across discovery, token exchange, ID-token validation, and refresh.
Variants§
Config(String)
Provider configuration is missing required fields or fails validation.
Discovery(String)
Failure fetching or parsing the OIDC discovery document.
TokenExchange(String)
Token endpoint rejected the authorization code or returned an unparseable response.
IdTokenValidation(String)
ID token failed signature, issuer, audience, or claim-set validation.
UnknownProvider(String)
No provider is registered under the requested name.
CsrfMismatch
state returned by the IdP did not match the value stored at flow start.
NoFlow
Callback received but no in-progress flow was found in the session.
Expired
In-progress flow exceeded its TTL before the user completed the IdP redirect.
InvalidParameter
Required callback parameter is missing or malformed.
RefreshTokenExpired
IdP rejected the refresh token (RFC 6749 invalid_grant).
NoRefreshToken
Operation requires a refresh token but none is stored for this session.
NoAccessToken
Operation requires an access token but none is stored for this session.
UserInfo(String)
UserInfo endpoint call failed.
AccessTokenExpired
Access token expired or was rejected by the resource server.
InsufficientScope
Stored access token lacks the scopes required to call UserInfo.
DeviceAuthorization(String)
RFC 8628 device authorization endpoint returned an error.
UnknownKid(String)
JWT verification failed because the kid is not present in
the cached JWKS. Callers (e.g. back-channel logout) match on this
variant to trigger a refresh_jwks() + retry, instead of fragile
substring-matching the error message.
UnsupportedTokenType
RFC 7009 §2.2.1: the authorization server received the
revocation request but does not support the supplied token type
(e.g. it can revoke refresh_token but not access_token).
Callers should usually log + ignore: a token the AS cannot revoke
is, from its perspective, already “not a valid token”.
TokenEndpointTransient
A server-side (5xx) failure from a token endpoint
(revocation / refresh / exchange). Distinct from
TokenExchange so callers can distinguish
“AS rejected our request” from “AS is broken right now and a
retry might succeed”.
Implementations§
Source§impl OAuthError
impl OAuthError
Sourcepub fn is_transient(&self) -> bool
pub fn is_transient(&self) -> bool
Hint at whether this error is worth retrying.
Returns true for failures the application can reasonably
retry: 5xx token-endpoint responses, network-shaped discovery
failures, network-shaped userinfo failures. Returns false for
permanent semantic rejections (CSRF mismatch, expired ceremony,
invalid parameters, unknown provider, unsupported token type).
The classification is conservative: anything that might be a
permanent state error returns false. Callers building retry
loops should still apply per-call backoff and a hard attempt
cap; this is a hint, not an exponential-backoff oracle.
Config(_), IdTokenValidation(_), and UnknownKid(_) are
not transient: they indicate misconfiguration or a key
rotation that requires refresh_jwks() first, not a blind
retry of the same call.
§Consumer pattern: retry with capped exponential backoff
is_transient() is the only contract; the caller owns the
backoff schedule, attempt cap, and any jitter. The pattern
below is what axess expects consumers to implement around
any call that can return OAuthError:
use std::time::Duration;
use axess_factors::oauth::OAuthError;
async fn with_retry<T, F, Fut>(mut op: F) -> Result<T, OAuthError>
where
F: FnMut() -> Fut,
Fut: std::future::Future<Output = Result<T, OAuthError>>,
{
const MAX_ATTEMPTS: u32 = 4;
let mut delay = Duration::from_millis(250);
for attempt in 1..=MAX_ATTEMPTS {
match op().await {
Ok(v) => return Ok(v),
Err(e) if e.is_transient() && attempt < MAX_ATTEMPTS => {
tokio::time::sleep(delay).await;
delay = delay.saturating_mul(2); // 250ms, 500ms, 1s
}
Err(e) => return Err(e), // permanent OR cap exhausted
}
}
unreachable!() // loop body always returns
}Do not retry indefinitely. A permanent error like
CsrfMismatch or Expired returns false so the loop exits
immediately, but a transient classification on a misbehaving
upstream can otherwise spin forever. Always cap attempts and
emit a tracing::warn! on each backoff so SOC dashboards see
the upstream degradation.
Trait Implementations§
Source§impl Debug for OAuthError
impl Debug for OAuthError
Source§impl Display for OAuthError
impl Display for OAuthError
Source§impl Error for OAuthError
impl Error for OAuthError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Auto Trait Implementations§
impl Freeze for OAuthError
impl RefUnwindSafe for OAuthError
impl Send for OAuthError
impl Sync for OAuthError
impl Unpin for OAuthError
impl UnsafeUnpin for OAuthError
impl UnwindSafe for OAuthError
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
Source§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
Source§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
Source§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
Source§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out indicating that a T is niched.Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> ToStringFallible for Twhere
T: Display,
impl<T> ToStringFallible for Twhere
T: Display,
Source§fn try_to_string(&self) -> Result<String, TryReserveError>
fn try_to_string(&self) -> Result<String, TryReserveError>
ToString::to_string, but without panic on OOM.