#[derive(Debug, thiserror::Error)]
pub enum XrpcGatewayError {
#[error("xrpc_gateway disabled — request should not have been routed here")]
GatewayDisabled,
#[error("NSID not on v1.7 allowlist: {0}")]
UnknownNsid(String),
#[error("HTTP method {method} not allowed for NSID {nsid}")]
MethodNotAllowed {
nsid: &'static str,
method: String,
},
#[error("invalid request: {0}")]
InvalidRequest(String),
#[error("internal server error")]
InternalServerError,
}
#[derive(Debug, thiserror::Error)]
pub enum XrpcAuthError {
#[error("missing or malformed Authorization header")]
MissingOrMalformedAuthHeader,
#[error("invalid JWT structure: {0}")]
InvalidJwtStructure(String),
#[error("unsupported JWT algorithm: {0}; only ES256K is accepted")]
UnsupportedAlgorithm(String),
#[error("failed to resolve issuer DID {iss}: {reason}")]
DidResolutionFailed {
iss: String,
reason: String,
},
#[error("issuer DID {iss} has no usable #atproto verification method: {reason}")]
NoVerificationMethod {
iss: String,
reason: String,
},
#[error("JWT signature verification failed for issuer {iss}")]
SignatureVerificationFailed {
iss: String,
},
#[error("audience mismatch: expected {expected}, got {actual}")]
AudienceMismatch {
expected: String,
actual: String,
},
#[error("method mismatch: lxm claim {lxm} does not match request NSID {nsid}")]
MethodMismatch {
lxm: String,
nsid: String,
},
#[error("lxm claim {lxm} is not on the v1.7 NSID allowlist")]
LxmNotAllowlisted {
lxm: String,
},
#[error("JWT expired at {exp}; now is {now}")]
Expired {
exp: i64,
now: i64,
},
}
impl XrpcAuthError {
pub fn http_status(&self) -> axum::http::StatusCode {
use axum::http::StatusCode;
match self {
Self::MissingOrMalformedAuthHeader
| Self::InvalidJwtStructure(_)
| Self::UnsupportedAlgorithm(_)
| Self::DidResolutionFailed { .. }
| Self::NoVerificationMethod { .. }
| Self::SignatureVerificationFailed { .. } => StatusCode::UNAUTHORIZED,
Self::AudienceMismatch { .. }
| Self::MethodMismatch { .. }
| Self::LxmNotAllowlisted { .. }
| Self::Expired { .. } => StatusCode::FORBIDDEN,
}
}
pub fn xrpc_error_code(&self) -> &'static str {
match self {
Self::MissingOrMalformedAuthHeader => "AuthRequired",
Self::Expired { .. } => "ExpiredToken",
Self::InvalidJwtStructure(_)
| Self::UnsupportedAlgorithm(_)
| Self::DidResolutionFailed { .. }
| Self::NoVerificationMethod { .. }
| Self::SignatureVerificationFailed { .. }
| Self::AudienceMismatch { .. }
| Self::MethodMismatch { .. }
| Self::LxmNotAllowlisted { .. } => "InvalidToken",
}
}
}