Error Handling
Authkestra uses the AuthError enum for all authentication-related errors.
Authkestra uses the AuthError enum for all authentication-related
errors, providing type-safe error handling throughout your application.
AuthError Enum
use thiserror::Error;
/// Errors that can occur during the authentication process.
#[derive(Debug, thiserror::Error)]
pub enum AuthError {
/// An error returned by the authentication provider
#[error("Provider error: {0}")]
Provider(String),
/// The provided credentials (email/password) are invalid
#[error("Invalid credentials")]
InvalidCredentials,
/// The authorization code is invalid or expired
#[error("Invalid code")]
InvalidCode,
/// A network error occurred during communication with the provider
#[error("Network error")]
Network,
/// An error occurred during session management
#[error("Session error: {0}")]
Session(String),
/// An error occurred during token processing
#[error("Token error: {0}")]
Token(String),
/// The CSRF state parameter does not match the expected value
#[error("CSRF state mismatch")]
CsrfMismatch,
/// An error occurred during OIDC discovery
#[error("Discovery error: {0}")]
Discovery(String),
}Error Variants
| Variant | When It Occurs | HTTP Status |
|---|---|---|
Provider | An error returned by the authentication provider | 502 Bad Gateway |
InvalidCredentials | The provided credentials (email/password) are invalid | 401 Unauthorized |
InvalidCode | The authorization code is invalid or expired | 400 Bad Request |
Network | A network error occurred during communication with the provider | 503 Service Unavailable |
Session | An error occurred during session management | 401 Unauthorized |
Token | An error occurred during token processing | 401 Unauthorized |
CsrfMismatch | The CSRF state parameter does not match the expected value | 400 Bad Request |
Discovery | An error occurred during OIDC discovery | 502 Bad Gateway |
Handling Errors
Use Rust's pattern matching to handle specific error cases:
use authkestra_core::AuthError;
async fn login(creds: LoginCredentials) -> Result<Response, AppError> {
match auth.authenticate(creds).await {
Ok(session) => Ok(create_session_response(session)),
Err(AuthError::InvalidCredentials) => {
// Log failed attempt, maybe rate limit
Ok(Response::unauthorized("Invalid username or password"))
}
Err(AuthError::Provider(msg)) => {
// Log provider error
tracing::error!("Auth provider error: {}", msg);
Err(AppError::ProviderError)
}
Err(e) => {
// Handle other errors
Ok(Response::bad_request(e.to_string()))
}
}
}Custom Error Responses
Implement IntoResponse to customize how errors are returned to clients:
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use authkestra_core::AuthError;
use serde_json::json;
impl IntoResponse for AuthError {
fn into_response(self) -> Response {
let (status, message) = match &self {
AuthError::InvalidCredentials => {
(StatusCode::UNAUTHORIZED, "Invalid credentials")
}
AuthError::Session(_) => {
(StatusCode::UNAUTHORIZED, "Session invalid or expired")
}
AuthError::Token(_) => {
(StatusCode::UNAUTHORIZED, "Token invalid or expired")
}
AuthError::CsrfMismatch | AuthError::InvalidCode => {
(StatusCode::BAD_REQUEST, "Authentication failed")
}
AuthError::Provider(_) | AuthError::Discovery(_) => {
(StatusCode::BAD_GATEWAY, "Provider error")
}
AuthError::Network => {
(StatusCode::SERVICE_UNAVAILABLE, "Network error")
}
};
let body = Json(json!({
"error": message,
"code": status.as_u16()
}));
(status, body).into_response()
}
}Error Logging
Always log internal errors with context before returning them. Use a logging
framework like tracing to capture error details for debugging.
