A secure authentication API built with Cloudflare Workers and Rust featuring:
- β Bot Protection: Cloudflare Turnstile verification
- β Secure Storage: User data stored in Cloudflare KV
- β Password Security: Argon2id password hashing
- β Enhanced JWT Security: Unique 512-bit JWT secrets per user
- β Automatic Token Invalidation: Tokens expire when passwords change
- β Global Scale: Leverages Cloudflare's edge network
Each user has their own unique 512-bit (64 bytes) JWT secret key that:
- Automatically rotates when password or username changes
- Invalidates all existing tokens on credential changes
- Eliminates global JWT compromise risk - no single point of failure
- Provides true token isolation between users
- JWT version tracking prevents token reuse after rotation
- Automatic token invalidation on security-sensitive operations
- No global JWT secret configuration needed
Before starting, make sure you have:
- Cloudflare Account (Sign up for free)
- Workers Plan enabled (Free tier included)
- Node.js (version 18 or higher) - Download
- Rust installed - Install
- LLVM installed - Download or install via package manager
- Git installed - Download
# Clone the repository
git clone https://github.com/YOUR_USERNAME/cloudflare-workers-turnstile-kv-rust-auth-argon2id-api.git
cd cloudflare-workers-turnstile-kv-rust-auth-argon2id-api
# Install dependencies
npm install# Install Wrangler globally
npm install -g wrangler
# Authenticate with Cloudflare
wrangler loginCreate the required KV storage namespaces:
# Create production namespace
wrangler kv:namespace create "USERS_KV"
# Create preview namespace for development
wrangler kv:namespace create "USERS_KV" --previewCopy the generated namespace IDs and update wrangler.toml:
[[kv_namespaces]]
binding = "USERS_KV"
id = "your_production_namespace_id" # Replace with your production ID
preview_id = "your_preview_namespace_id" # Replace with your preview ID-
Go to Cloudflare Dashboard:
- Navigate to Cloudflare Dashboard β Turnstile
- Click "Add Site"
-
Configure the site:
Site name: My Auth API (or your preference) Domain: your-domain.com (or localhost for testing) Widget Mode: Managed (recommended) -
π SAVE THESE KEYS (you'll need them in the next step):
- π Site Key:
0x4AAAAAAAxxxxxxxxxxxxxxxx(for frontend) - π Secret Key:
0x4AAAAAAAxxxxxxxxxxxxxxxx(for Worker - KEEP PRIVATE!)
- π Site Key:
Generate a strong JWT secret for token signing:
# PowerShell
[Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))
# Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
# OpenSSL
openssl rand -base64 32π Keep these ready:
- Turnstile Secret Key (from Step 4)
- JWT Secret (generated above)
- Create local environment file:
# Copy the example file
cp .dev.vars.example .dev.vars- Edit
.dev.varswith your actual values:
# Cloudflare Turnstile Secret Key
TURNSTILE_SECRET_KEY=your_turnstile_secret_key_here
# JWT Secret Key for signing tokens
JWT_SECRET=your_very_secure_jwt_secret_key_here_at_least_32_charsConfigure the secrets for production deployment:
# Set Turnstile secret key
wrangler secret put TURNSTILE_SECRET_KEY
# When prompted, paste your Turnstile Secret Key
# Set JWT secret
wrangler secret put JWT_SECRET
# When prompted, paste your generated JWT secretNow you're ready to deploy:
# Build and deploy to production
npm run build
npm run deploy
# Or deploy to staging first
npm run deploy:stagingVerify your API is working:
# Test health endpoint (replace with your worker URL)
curl https://your-worker-name.your-subdomain.workers.dev/health
# Expected response:
# {"status": "healthy", "message": "API is running"}Update the test scripts with your Worker URL:
- Edit test scripts:
# Update test_api.ps1 or test_api.sh
# Replace $API_URL with your actual Worker URL
# Replace $TURNSTILE_TOKEN with a valid token from your frontend- Run tests:
# Windows
.\test_api.ps1
# Linux/macOS
chmod +x test_api.sh
./test_api.shπ¨ Want to test with a real frontend? Check out our example implementations:
π Security Enhancements:
- Set up a custom domain for production use
- Enable Cloudflare's security features (Bot Fight Mode, Rate Limiting)
- Use different secrets for staging/production environments
- Monitor your Worker logs regularly
β‘ Performance Optimization:
# Optional: Set up multiple environments
wrangler secret put TURNSTILE_SECRET_KEY --env production
wrangler secret put JWT_SECRET --env productionπ Monitoring Setup:
- Go to Workers & Pages β Your Worker β Metrics
- Set up alerts for error rates or high usage
- Monitor KV operations in the KV section
After deployment, update your Turnstile site settings:
- Go back to Cloudflare Dashboard β Turnstile
- Edit your site
- Add your Worker URL to the Domain field:
your-worker-name.your-subdomain.workers.dev - Save changes
Your secure authentication API is now live! Here's what you've achieved:
β
Deployed a production-ready Rust API to Cloudflare's edge network
β
Secured with Turnstile bot protection and Argon2id password hashing
β
Configured with proper secrets management
β
Ready for frontend integration
π Next Steps:
- Integrate with your frontend application
- Customize the API for your specific needs
- Set up monitoring and alerts
- Consider adding rate limiting for additional security
π Need help? Check out the detailed API documentation below or visit our Setup Guide.
- Clone and install:
git clone https://github.com/YOUR_USERNAME/cloudflare-workers-turnstile-kv-rust-auth-argon2id-api
cd cloudflare-workers-turnstile-kv-rust-auth-argon2id-api
npm install- Run setup script:
# Windows
.\setup.ps1
# Linux/macOS
chmod +x setup.sh
./setup.sh- Configure your secrets:
- Edit
.dev.varswith your actual keys - Set production secrets:
wrangler secret put TURNSTILE_SECRET_KEY
- Edit
Click to expand manual setup instructions
- Wrangler CLI installed
- Cloudflare account with Workers enabled
- Rust toolchain (for local builds)
# Create production namespace
wrangler kv:namespace create "USERS_KV"
# Create preview namespace
wrangler kv:namespace create "USERS_KV" --previewCopy the generated IDs and update wrangler.toml:
[[kv_namespaces]]
binding = "USERS_KV"
id = "your_production_namespace_id"
preview_id = "your_preview_namespace_id"- Go to Cloudflare Dashboard > Turnstile
- Create a new site
- Note down your Site Key (for frontend) and Secret Key (for backend)
For local development:
cp .dev.vars.example .dev.vars
# Edit .dev.vars with your actual valuesFor production:
wrangler secret put TURNSTILE_SECRET_KEY
wrangler secret put JWT_SECRETGenerate a secure JWT secret:
# PowerShell
$bytes = New-Object byte[] 32; [Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($bytes); [Convert]::ToBase64String($bytes)
# Or use OpenSSL
openssl rand -base64 32Register a new user account.
Headers:
Content-Type: application/jsoncf-turnstile-response: <turnstile_token>
Request Body:
{
"user": "username",
"password": "password123"
}Response:
{
"success": true,
"message": "User registered successfully"
}Authenticate an existing user.
Headers:
Content-Type: application/jsoncf-turnstile-response: <turnstile_token>
Request Body:
{
"user": "username",
"password": "password123"
}Response:
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"message": "Login successful",
"expires_in": 900
}Delete the authenticated user's account.
Headers:
Authorization: Bearer <jwt_token>
Response:
{
"success": true,
"message": "User 'username' deleted successfully"
}Update user account information (username and/or password).
Headers:
Content-Type: application/jsonAuthorization: Bearer <jwt_token>
Request Body:
{
"new_username": "newusername", // Optional: new username
"new_password": "newpassword123" // Optional: new password
}Note: At least one field (new_username or new_password) must be provided.
Response (Password change only):
{
"success": true,
"message": "Password updated successfully",
"new_token": null,
"expires_in": null
}Response (Username change):
{
"success": true,
"message": "Username updated successfully",
"new_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 900
}Response (Both username and password change):
{
"success": true,
"message": "Username and password updated successfully",
"new_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 900
}Important: When changing username, a new JWT token is issued. You must update your stored token with the new_token value.
Check API health status.
Response:
{
"status": "healthy",
"message": "API is running"
}| Variable | Description | Where to get it |
|---|---|---|
TURNSTILE_SECRET_KEY |
Cloudflare Turnstile secret key | Dashboard > Turnstile > Settings |
JWT_SECRET |
JWT signing key (min. 32 chars) | Generate with openssl rand -base64 32 |
JWT_EXPIRATION_MINUTES |
JWT token expiration (optional, default: 15) | Any number in minutes |
src/
βββ lib.rs # Main entry point and request routing
βββ auth.rs # Authentication types and structures
βββ kv_store.rs # KV storage operations
βββ turnstile.rs # Turnstile verification logic
test_api.ps1 # PowerShell API testing script
test_api.sh # Bash API testing script
setup.ps1 # Windows setup automation
setup.sh # Unix setup automation
SETUP.md # Detailed setup documentation
# Local development (uses .dev.vars)
npm run dev
# Remote development
npm run dev:remote
# Build the project
npm run build
# Deploy to staging
npm run deploy:staging
# Deploy to production
npm run deploy:production
# View logs
npm run logsThe project supports multiple environments:
- Purpose: Local development and testing
- JWT Expiration: 60 minutes
- Secrets: From
.dev.varsfile
- Purpose: Pre-production testing
- JWT Expiration: 30 minutes
- Deploy:
npm run deploy:staging
- Purpose: Live production environment
- JWT Expiration: 15 minutes
- Deploy:
npm run deploy:production
# Deploy to production
wrangler deploy --env production
# Deploy to staging
wrangler deploy --env staging
# Deploy with custom name
wrangler deploy --name my-custom-worker-name- KV namespaces created and configured
- Turnstile site configured
- Production secrets set (
TURNSTILE_SECRET_KEY,JWT_SECRET) -
wrangler.tomlupdated with correct namespace IDs - Custom domain configured (optional)
# View real-time logs
npm run logs
# View logs for specific environment
npm run logs:staging
npm run logs:production
# View KV storage usage
wrangler kv:namespace listUpdate the JWT_EXPIRATION_MINUTES variable in wrangler.toml or set it as an environment variable:
[vars]
JWT_EXPIRATION_MINUTES = "30" # 30 minutes- Add your handler in
src/lib.rs - Update the routing logic in the
mainfunction - Redeploy with
wrangler deploy
Modify the password validation logic in your frontend application. The API accepts any password and hashes it securely with Argon2id.
β "Invalid turnstile token" responses
- Verify your Turnstile Site Key is correct in your frontend
- Ensure your Turnstile site domain matches your Worker URL
- Check that
TURNSTILE_SECRET_KEYsecret is set correctly - Test with a fresh Turnstile token (they expire quickly)
β "Internal server error" responses
# Check Worker logs for detailed error messages
wrangler tail your-worker-name
# Common causes:
# 1. Missing secrets (JWT_SECRET or TURNSTILE_SECRET_KEY)
# 2. KV namespace not properly configured
# 3. Invalid JSON in request bodyβ CORS errors in browser
- The Worker includes CORS headers, but check your request format
- Ensure you're sending
Content-Type: application/jsonheader - Try the request with curl first to isolate browser issues
β "Missing .dev.vars file" errors
# Copy the example file and edit it
cp .dev.vars.example .dev.vars
# Edit .dev.vars with your actual secretsβ "KV namespace not found" in development
- Ensure your
wrangler.tomlhas the correct namespace IDs - Run
wrangler kv:namespace listto verify namespaces exist - For local dev, you can use
--localflag:wrangler dev --local
β Rust build errors
- Ensure you have the Rust toolchain installed
- Run
rustup target add wasm32-unknown-unknown - Clear cache:
cargo cleanthenwrangler deploy
β Slow response times
- Check your Worker's metrics in Cloudflare Dashboard
- Monitor KV operations (they have small latency)
- Consider using a custom domain for better performance
β "Script exceeded CPU time limit"
- This usually indicates an issue with Argon2id hashing settings
- Check if you're using reasonable password lengths (<1000 characters)
- Contact support if this persists with normal usage
| Error | Cause | Solution |
|---|---|---|
Missing required header: cf-turnstile-response |
Frontend not sending Turnstile token | Add Turnstile widget to your frontend |
Invalid JSON body |
Malformed request | Check request format matches API docs |
User already exists |
Attempting to register existing username | Use a different username or implement login |
Invalid credentials |
Wrong username/password in login | Verify credentials or register new user |
Token verification failed |
Invalid JWT in Authorization header | Check token format: Bearer <token> |
If you're still having issues:
- Check the logs:
wrangler tail your-worker-name - Verify your setup: Compare with SETUP.md
- Test with curl: Use the provided curl commands to isolate issues
- Create an issue: Include:
- Error message or behavior
- Steps to reproduce
- Your
wrangler.toml(remove sensitive data) - Worker logs if available
π Debug mode: Set LOG_LEVEL=debug in your environment variables for verbose logging.
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
This project is open source and available under the MIT License.
- π Documentation: SETUP.md for detailed setup
- π Issues: GitHub Issues
- π¬ Discussions: GitHub Discussions
β If this project helped you, please give it a star!