Skip to content

fernandodilland/cloudflare-workers-turnstile-kv-rust-auth-argon2id-api

Repository files navigation

Cloudflare Workers Rust Auth API

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

πŸ” Security Features

Per-User JWT Secrets

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

Enhanced Token Security

  • JWT version tracking prevents token reuse after rotation
  • Automatic token invalidation on security-sensitive operations
  • No global JWT secret configuration needed

πŸš€ Setup and Installation

πŸ“‹ Prerequisites

Before starting, make sure you have:

⚑ Quick Installation

Step 1: Clone the Repository

# 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

Step 2: Install Wrangler CLI

# Install Wrangler globally
npm install -g wrangler

# Authenticate with Cloudflare
wrangler login

Step 3: Create KV Namespaces

Create 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" --preview

Copy 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

Step 4: Configure Turnstile (Bot Protection)

  1. Go to Cloudflare Dashboard:

  2. Configure the site:

    Site name: My Auth API (or your preference)
    Domain: your-domain.com (or localhost for testing)
    Widget Mode: Managed (recommended)
    
  3. πŸ“ SAVE THESE KEYS (you'll need them in the next step):

    • πŸ”‘ Site Key: 0x4AAAAAAAxxxxxxxxxxxxxxxx (for frontend)
    • πŸ” Secret Key: 0x4AAAAAAAxxxxxxxxxxxxxxxx (for Worker - KEEP PRIVATE!)

Step 5: Generate JWT Secret

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)

Step 6: Configure Local Development

  1. Create local environment file:
# Copy the example file
cp .dev.vars.example .dev.vars
  1. Edit .dev.vars with 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_chars

Step 7: Set Production Secrets

Configure 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 secret

Step 8: Deploy the Worker

Now you're ready to deploy:

# Build and deploy to production
npm run build
npm run deploy

# Or deploy to staging first
npm run deploy:staging

Step 9: Test Your Deployment

Verify 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"}

πŸ› οΈ Development

πŸ§ͺ Test Your Deployment (Recommended)

Update the test scripts with your Worker URL:

  1. 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
  1. 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:

🌐 Production Recommendations

πŸ”’ 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:

  1. Go to Workers & Pages β†’ Your Worker β†’ Metrics
  2. Set up alerts for error rates or high usage
  3. Monitor KV operations in the KV section

πŸ”„ Update Turnstile Configuration

After deployment, update your Turnstile site settings:

  1. Go back to Cloudflare Dashboard β†’ Turnstile
  2. Edit your site
  3. Add your Worker URL to the Domain field:
    your-worker-name.your-subdomain.workers.dev
    
  4. Save changes

πŸŽ‰ Congratulations!

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.


πŸ› οΈ Manual Setup

Option 1: Automated Setup (Recommended)

  1. 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
  1. Run setup script:
# Windows
.\setup.ps1

# Linux/macOS
chmod +x setup.sh
./setup.sh
  1. Configure your secrets:
    • Edit .dev.vars with your actual keys
    • Set production secrets: wrangler secret put TURNSTILE_SECRET_KEY

Option 2: Manual Setup

Click to expand manual setup instructions

1. Prerequisites

  • Wrangler CLI installed
  • Cloudflare account with Workers enabled
  • Rust toolchain (for local builds)

2. Create KV Namespaces

# Create production namespace
wrangler kv:namespace create "USERS_KV"

# Create preview namespace
wrangler kv:namespace create "USERS_KV" --preview

Copy the generated IDs and update wrangler.toml:

[[kv_namespaces]]
binding = "USERS_KV"
id = "your_production_namespace_id"
preview_id = "your_preview_namespace_id"

3. Setup Turnstile

  1. Go to Cloudflare Dashboard > Turnstile
  2. Create a new site
  3. Note down your Site Key (for frontend) and Secret Key (for backend)

4. Configure Secrets

For local development:

cp .dev.vars.example .dev.vars
# Edit .dev.vars with your actual values

For production:

wrangler secret put TURNSTILE_SECRET_KEY
wrangler secret put JWT_SECRET

Generate 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 32

πŸ“‹ API Endpoints

POST /register

Register a new user account.

Headers:

  • Content-Type: application/json
  • cf-turnstile-response: <turnstile_token>

Request Body:

{
    "user": "username",
    "password": "password123"
}

Response:

{
    "success": true,
    "message": "User registered successfully"
}

POST /login

Authenticate an existing user.

Headers:

  • Content-Type: application/json
  • cf-turnstile-response: <turnstile_token>

Request Body:

{
    "user": "username",
    "password": "password123"
}

Response:

{
    "success": true,
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "message": "Login successful",
    "expires_in": 900
}

DELETE /user

Delete the authenticated user's account.

Headers:

  • Authorization: Bearer <jwt_token>

Response:

{
    "success": true,
    "message": "User 'username' deleted successfully"
}

PATCH /user

Update user account information (username and/or password).

Headers:

  • Content-Type: application/json
  • Authorization: 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.

GET /health

Check API health status.

Response:

{
    "status": "healthy",
    "message": "API is running"
}

πŸ“¦ Environment Variables

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

πŸ—οΈ Project Structure

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

πŸ’» Development Commands

# 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 logs

🌍 Environment Configuration

The project supports multiple environments:

Development

  • Purpose: Local development and testing
  • JWT Expiration: 60 minutes
  • Secrets: From .dev.vars file

Staging

  • Purpose: Pre-production testing
  • JWT Expiration: 30 minutes
  • Deploy: npm run deploy:staging

Production

  • Purpose: Live production environment
  • JWT Expiration: 15 minutes
  • Deploy: npm run deploy:production

πŸš€ Deployment

Deploy with CLI

# 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

Deployment Checklist

  • KV namespaces created and configured
  • Turnstile site configured
  • Production secrets set (TURNSTILE_SECRET_KEY, JWT_SECRET)
  • wrangler.toml updated with correct namespace IDs
  • Custom domain configured (optional)

πŸ“Š Monitoring

# 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 list

πŸ› οΈ Customization

Adjusting JWT Expiration

Update the JWT_EXPIRATION_MINUTES variable in wrangler.toml or set it as an environment variable:

[vars]
JWT_EXPIRATION_MINUTES = "30"  # 30 minutes

Adding Custom Endpoints

  1. Add your handler in src/lib.rs
  2. Update the routing logic in the main function
  3. Redeploy with wrangler deploy

Custom Password Requirements

Modify the password validation logic in your frontend application. The API accepts any password and hashes it securely with Argon2id.

🚨 Troubleshooting

API Response Issues

❌ "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_KEY secret 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/json header
  • Try the request with curl first to isolate browser issues

Local Development 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.toml has the correct namespace IDs
  • Run wrangler kv:namespace list to verify namespaces exist
  • For local dev, you can use --local flag: wrangler dev --local

❌ Rust build errors

  • Ensure you have the Rust toolchain installed
  • Run rustup target add wasm32-unknown-unknown
  • Clear cache: cargo clean then wrangler deploy

Performance Issues

❌ 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

Common Error Messages

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>

Getting Help

If you're still having issues:

  1. Check the logs: wrangler tail your-worker-name
  2. Verify your setup: Compare with SETUP.md
  3. Test with curl: Use the provided curl commands to isolate issues
  4. 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.

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'Add amazing feature'
  4. Push to the branch: git push origin feature/amazing-feature
  5. Open a Pull Request

πŸ“„ License

This project is open source and available under the MIT License.

πŸ†˜ Support

πŸ”— Related Resources


⭐ If this project helped you, please give it a star!

About

A Cloudflare Workers project leveraging to power a secure authentication API. It stores user credentials in Cloudflare KV using Argon2id for robust hashing and integrates Cloudflare Turnstile for bot protection.

Topics

Resources

License

Stars

Watchers

Forks

Contributors