Error Handling
All guardo errors extend Error and set .name for easy instanceof checks.
AuthError and TokenTypeError also carry a machine-readable .code.
import { AuthError, RateLimitError } from "guardo";
try {
await auth.auth.loginWithOtp({ identifier, otp });
} catch (err) {
if (err instanceof RateLimitError) {
res.status(429).json({ error: `Retry in ${err.retryAfterSeconds}s` });
} else if (err instanceof AuthError) {
res.status(401).json({ error: err.message, code: err.code });
}
}Error classes
| Class | Thrown by | Extra property |
|---|---|---|
AuthError | auth.auth.* - bad OTP, revoked session, user not found, refresh-token reuse | .code?: GuardoErrorCode |
RateLimitError | auth.otp.send() - too many requests | .retryAfterSeconds |
TokenTypeError | auth.jwt.verify*() - wrong token type | .code?: GuardoErrorCode |
OAuthError | auth.oauth.* - unknown provider, bad state, exchange/profile failure | .code?: GuardoErrorCode |
JsonWebTokenError | auth.jwt.verify*() - invalid signature (from jsonwebtoken) | - |
TokenExpiredError | auth.jwt.verify*() - expired token (from jsonwebtoken) | - |
AuthError, RateLimitError, TokenTypeError, and OAuthError are exported
from the package root. JsonWebTokenError / TokenExpiredError come from the jsonwebtoken
dependency.
auth.otp.verify() does not throw on a bad code - it returns
{ success: false, verified: false, error, code }. Only loginWithOtp turns
a failed verification into a thrown AuthError.
GuardoErrorCode
Machine-readable codes attached to AuthError.code, TokenTypeError.code, and
VerifyOtpResult.code. Middleware 401/403 JSON responses also include a
code field.
| Code | Meaning |
|---|---|
OTP_EXPIRED | No valid OTP found for the identifier. |
OTP_INVALID | OTP didnāt match. |
OTP_MAX_ATTEMPTS | Too many failed attempts; OTP invalidated. |
OTP_RATE_LIMITED | OTP verify rate limit hit. |
SESSION_REVOKED | The session backing the token was revoked. |
SESSION_NOT_FOUND | No authenticated user / session. |
TOKEN_EXPIRED | Token has expired. |
TOKEN_INVALID | Token missing or malformed. |
TOKEN_TYPE_MISMATCH | Access token used where a refresh token was expected, or vice-versa. |
USER_NOT_FOUND | resolveUser returned null and no onNewUser was set. |
REFRESH_TOKEN_REUSE | A revoked refresh token was replayed - all sessions revoked. |
INVALID_ARGUMENT | A method was called with the wrong argument type (e.g. logout({ sessionId }) instead of logout(sessionId)). |
FORBIDDEN | Role check failed. |
OAUTH_NOT_CONFIGURED | No redirectUri configured or passed to oauth.start(). |
OAUTH_PROVIDER_NOT_FOUND | No provider registered under the given id. |
OAUTH_STATE_INVALID | Missing, expired, replayed, or mismatched OAuth state (CSRF). |
OAUTH_EXCHANGE_FAILED | The providerās token endpoint rejected the code exchange. |
OAUTH_PROFILE_FAILED | Fetching the user profile from the provider failed. |