#[non_exhaustive]pub enum TokenRejection {
Missing,
Invalid(InvalidToken),
InsufficientScope,
}Expand description
Why a bearer credential was refused, and — crucially — with which HTTP status.
The split is the whole point: RFC 6750 distinguishes “this token is not good”
(401 invalid_token, go get a new one) from “this token is fine but not
sufficient” (403 insufficient_scope). A client that gets 401 for an
insufficient-scope token will loop through the authorization flow forever and
land back on the same refusal.
| Variant | Status | WWW-Authenticate (with OAuth configured) |
|---|---|---|
Missing | 401 | crate::OAuthValidator::invalid_token_challenge |
Invalid | 401 | crate::OAuthValidator::invalid_token_challenge |
InsufficientScope | 403 | crate::OAuthValidator::insufficient_scope_challenge |
#[non_exhaustive]: treat a variant this code does not know as a 401.
It implements std::error::Error, so ? carries it into
Box<dyn Error> or anyhow. Display deliberately renders the category
only — missing credential, invalid token, insufficient scope — and
never Invalid’s reason, so a careless format!("{e}")
in a response body cannot tell a caller which check failed. The reason is
reachable through the variant itself (InvalidToken) and through
Debug, for logs.
use oauth_resource_server::{InvalidToken, InvalidTokenKind, TokenRejection};
let e = TokenRejection::Invalid(InvalidToken::new(
InvalidTokenKind::WrongAudience,
"token rejected: InvalidAudience",
));
assert_eq!(e.to_string(), "invalid token");
assert!(format!("{e:?}").contains("InvalidAudience"));Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Missing
401: the request carried no credential at all. Separate from Invalid so
a server can log it quietly — every OAuth client’s first request looks
like this — not because the response differs (it should not: a missing
credential gets the same invalid_token challenge as a bad one).
Invalid(InvalidToken)
401 invalid_token: malformed, unsigned, wrong issuer/audience/type,
expired, or signed by a key we could not obtain. The
InvalidToken says which check failed: its
kind is stable and matchable (a metrics label
via InvalidTokenKind::as_str), its detail
is for logs only — never return it to the caller, since telling an
unauthenticated client exactly which check failed is a free oracle.
InsufficientScope
403 insufficient_scope: signature, issuer, audience and expiry all
passed, but the token does not carry every required scope.
Trait Implementations§
Source§impl Clone for TokenRejection
impl Clone for TokenRejection
Source§impl Debug for TokenRejection
impl Debug for TokenRejection
Source§impl Display for TokenRejection
impl Display for TokenRejection
impl Eq for TokenRejection
Source§impl Error for TokenRejection
impl Error for TokenRejection
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()