Appearance
Errors & Rate Limiting
Error Response Format
OAuth Endpoints
OAuth endpoints (/oauth/*) follow the standard RFC 6749 error format:
json
{
"error": "invalid_grant",
"error_description": "The authorization code has expired"
}Common OAuth error codes:
| Code | Description |
|---|---|
invalid_request | Missing or malformed parameter |
invalid_client | Client authentication failed |
invalid_grant | Authorization code, refresh token, or device code is invalid/expired |
unauthorized_client | Client is not authorized for this grant type |
unsupported_grant_type | The grant type is not supported |
invalid_scope | Requested scope is invalid or exceeds what was granted |
access_denied | User denied the authorization request |
authorization_pending | Device code flow: user has not yet authorized |
slow_down | Device code flow: polling too frequently |
expired_token | Device code flow: the device code has expired |
Admin & API Endpoints
All admin and resource API endpoints return a consistent envelope:
json
{
"didSucceed": false,
"data": null,
"message": "Human-readable error description",
"status": 400
}Validation errors include an errors array with field-level details:
json
{
"didSucceed": false,
"data": null,
"message": "Validation error",
"errors": [
{
"code": "too_small",
"minimum": 1,
"path": ["client_name"],
"message": "String must contain at least 1 character(s)"
}
],
"status": 400
}HTTP Status Codes
| Status | Meaning |
|---|---|
200 | Success |
201 | Resource created |
400 | Bad request or validation error |
401 | Authentication required or token invalid |
404 | Resource not found |
409 | Conflict (e.g. duplicate email) |
429 | Rate limit exceeded |
500 | Internal server error |
Rate Limiting
Auth endpoints are rate-limited to prevent brute-force attacks.
Limits
| Endpoints | Limit | Window |
|---|---|---|
POST /admin/auth/login | 10 requests | 15 minutes |
POST /admin/auth/register | 10 requests | 15 minutes |
POST /admin/auth/forgot-password | 10 requests | 15 minutes |
POST /admin/auth/reset-password | 10 requests | 15 minutes |
POST /admin/auth/verify-email | 10 requests | 15 minutes |
Limits are applied per IP address.
Rate Limit Response
When the limit is exceeded, the API returns HTTP 429 with a Retry-After header:
HTTP/1.1 429 Too Many Requests
Retry-After: 847
Content-Type: application/jsonjson
{
"didSucceed": false,
"data": null,
"message": "Too many attempts. Please try again later.",
"status": 429
}The Retry-After value is the number of seconds until the rate limit window resets.
Best Practices
- Implement exponential backoff on
429responses - Cache tokens and reuse them until they expire rather than requesting new ones
- Use the
Retry-Afterheader to determine when to retry - For the device code flow, respect the
intervalvalue in the device authorization response