Captcha
Endpoints for generating and verifying captcha challenges.
GET /api/captcha
Generate a captcha image.
Authentication: Not required
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
theme | string | light | Theme: light or dark |
Response:
SVG image (Content-Type: image/svg+xml)
Cookie Set:
Sets an encrypted captcha cookie containing the expected answer.
Example Request:
curl https://app.example.com/api/captcha?theme=dark
Response:
<svg xmlns="http://www.w3.org/2000/svg" width="160" height="55">
<!-- SVG captcha image -->
</svg>
Captcha Configuration:
- Size: 4 characters
- Ignored Characters:
0oO1iIlLqQgG9S5sZz2(to avoid confusion) - Noise: Level 1
- Color: Yes (colored characters)
- Background:
- Light theme:
#fff - Dark theme:
#202125
- Light theme:
- Font Size: 45px
- Dimensions: 160x55 pixels
POST /api/captcha/_verify
Verify a captcha response.
Authentication: Not required
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
response | string | Yes | User's captcha answer |
Example Request:
{
"response": "ABC7"
}
Response (Success):
{
"valid": true
}
Response (Failure):
{
"valid": false
}
Validation:
- Compares user input against decrypted cookie value
- Case-insensitive comparison
- Clears the captcha cookie after verification
Captcha Flow
1. Request Captcha Image
GET /api/captcha?theme=light
Response: SVG image + encrypted cookie
2. Display Image to User
Render the SVG image in the UI and provide an input field.
3. Submit User Response
POST /api/captcha/_verify
{
"response": "ABC7"
}
Response:
{
"valid": true
}
4. Handle Result
- If
valid: true, proceed with protected action (e.g., login, registration) - If
valid: false, request a new captcha and ask user to try again
Integration Examples
Login Form with Captcha
// 1. Load captcha on page load
async function loadCaptcha() {
const response = await fetch('/api/captcha?theme=dark');
const svg = await response.text();
document.getElementById('captcha-image').innerHTML = svg;
}
// 2. Verify captcha before login
async function login(username, password, captchaResponse) {
// First verify captcha
const verification = await fetch('/api/captcha/_verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ response: captchaResponse })
}).then(r => r.json());
if (!verification.valid) {
alert('Invalid captcha');
loadCaptcha(); // Reload captcha
return;
}
// Proceed with login
const loginResponse = await fetch('/api/login/local', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
// Handle login response...
}
Registration Form
async function register(userData, captchaResponse) {
// Verify captcha first
const { valid } = await fetch('/api/captcha/_verify', {
method: 'POST',
body: JSON.stringify({ response: captchaResponse })
}).then(r => r.json());
if (!valid) {
throw new Error('Invalid captcha');
}
// Proceed with registration...
}
Use Cases
Prevent Automated Attacks
- Brute Force Login - Rate limit login attempts with captcha
- Account Enumeration - Prevent automated user discovery
- Spam Registration - Block automated account creation
Security Triggers
Captcha can be selectively required:
- After N failed login attempts
- For registration from untrusted IPs
- For password reset requests
- When unusual activity is detected
Security Considerations
Cookie Encryption
The captcha answer is encrypted before being stored in the cookie to prevent:
- Client-side tampering
- Cookie inspection revealing the answer
Single-Use
Captcha verification consumes the cookie. Each captcha image can only be verified once.
Case Insensitivity
Verification is case-insensitive to improve usability while maintaining security.
Accessibility
Consider providing:
- Audio captcha alternative
- Option to refresh captcha
- Clear error messages
Only require captcha when necessary (e.g., after failed attempts) to maintain good UX while preventing abuse.
The character set excludes commonly confused characters (0oO1iIlLqQgG9S5sZz2) to reduce user frustration.