fraiseql_error/auth.rs
1/// Errors that arise during authentication and authorisation flows.
2#[derive(Debug, thiserror::Error)]
3pub enum AuthError {
4 /// The supplied username/password (or API key) did not match any account.
5 #[error("Invalid credentials")]
6 InvalidCredentials,
7
8 /// The access token has passed its expiry time and must be refreshed.
9 #[error("Token expired")]
10 TokenExpired,
11
12 /// The access token is structurally invalid or has been tampered with.
13 #[error("Invalid token: {reason}")]
14 InvalidToken {
15 /// Reason the token was rejected (kept server-side; not forwarded to clients).
16 reason: String,
17 },
18
19 /// An upstream OAuth / OIDC provider returned an error during the flow.
20 #[error("Provider error: {provider} - {message}")]
21 ProviderError {
22 /// Name of the provider (e.g. `"google"`, `"github"`).
23 provider: String,
24 /// Provider-supplied error message (kept server-side; not forwarded to clients).
25 message: String,
26 },
27
28 /// The OAuth `state` parameter did not match the stored value, indicating a
29 /// possible CSRF attack or a stale/replayed authorisation request.
30 #[error("Invalid OAuth state")]
31 InvalidState,
32
33 /// The resource owner explicitly declined the authorisation request at the
34 /// provider's consent screen.
35 #[error("User denied authorization")]
36 UserDenied,
37
38 /// No active session exists for the supplied session identifier.
39 #[error("Session not found")]
40 SessionNotFound,
41
42 /// The session existed but has expired and can no longer be used.
43 #[error("Session expired")]
44 SessionExpired,
45
46 /// The authenticated principal does not have the scopes or roles required
47 /// to perform the requested operation.
48 #[error("Insufficient permissions: requires {required}")]
49 InsufficientPermissions {
50 /// The permission or scope that was required but not granted.
51 required: String,
52 },
53
54 /// The refresh token has been revoked, used more than once, or has expired.
55 #[error("Refresh token invalid or expired")]
56 RefreshTokenInvalid,
57
58 /// The account has been administratively locked and cannot be used.
59 #[error("Account locked: {reason}")]
60 AccountLocked {
61 /// Reason the account was locked.
62 reason: String,
63 },
64}
65
66impl AuthError {
67 /// Returns a short, stable error code string suitable for API responses and
68 /// structured logging.
69 pub const fn error_code(&self) -> &'static str {
70 match self {
71 Self::InvalidCredentials => "invalid_credentials",
72 Self::TokenExpired => "token_expired",
73 Self::InvalidToken { .. } => "invalid_token",
74 Self::ProviderError { .. } => "auth_provider_error",
75 Self::InvalidState => "invalid_oauth_state",
76 Self::UserDenied => "user_denied",
77 Self::SessionNotFound => "session_not_found",
78 Self::SessionExpired => "session_expired",
79 Self::InsufficientPermissions { .. } => "insufficient_permissions",
80 Self::RefreshTokenInvalid => "refresh_token_invalid",
81 Self::AccountLocked { .. } => "account_locked",
82 }
83 }
84}