Overview
HoodCloud uses Clerk as the primary authentication provider. Clerk enables authentication via email, social login, wallet-based sign-in, and other identity methods. When Clerk is enabled (default):- Clerk issues JWTs that HoodCloud validates via JWKS
- User accounts are created and updated automatically via Clerk webhooks
- Users can optionally register a wallet (Ethereum or Solana) after authentication
Prerequisites
- A Clerk account with an application created
- The auth-server deployed and accessible via HTTPS (required for webhook delivery)
- Database migration
020_external_auth_idapplied
Configuration
Auth Provider Modes
TheAUTH_PROVIDER environment variable controls which JWT validators are active:
| Value | Description | Use Case |
|---|---|---|
clerk | Clerk-only (default) | All new and existing deployments |
both | Multi-validator, tries Clerk first then SIWE | Migration period — supports both token types |
siwe | SIWE-only (legacy) | Legacy deployments not yet migrated to Clerk |
Environment Variables
SetAUTH_PROVIDER, AUTH_CLERK_SECRET_KEY, AUTH_CLERK_AUTHORIZED_PARTY on both auth-server and api-server. Set AUTH_CLERK_WEBHOOK_SIGNING_SECRET on auth-server only.
Full reference with defaults and security classifications: Environment Variables
Example Configuration
Obtaining Clerk Credentials
Secret Key
- Log in to Clerk Dashboard
- Select your application
- Go to API Keys
- Copy the Secret Key (starts with
sk_live_for production orsk_test_for development) - Store as
AUTH_CLERK_SECRET_KEY
Note: For production, store secrets in Vault at secret/hoodcloud/app-credentials. See Vault Operations for details.
Authorized Party
The authorized party is the URL of your frontend application. Clerk includes this in theazp (authorized party) claim of issued JWTs. HoodCloud validates this claim to ensure tokens were issued for your application.
Set AUTH_CLERK_AUTHORIZED_PARTY to a comma-separated list of allowed frontend origins (e.g., https://hoodcloud.io,https://app.hoodcloud.io).
Webhook Signing Secret
The signing secret is generated when you create a webhook endpoint in Clerk. See the next section for webhook setup.Webhook Configuration
Clerk webhooks notify HoodCloud when users are created, updated, or deleted. The auth-server processes these events atPOST /webhooks/clerk.
Setup in Clerk Dashboard
- Go to Webhooks in the Clerk Dashboard
- Click Add Endpoint
- Set the endpoint URL to your auth-server’s public URL:
- Subscribe to these events:
user.createduser.updateduser.deleted
- Click Create
- Copy the Signing Secret (starts with
whsec_) - Store as
AUTH_CLERK_WEBHOOK_SIGNING_SECRET
Webhook Events
| Event | Action | Details |
|---|---|---|
user.created | Creates a local user account | Sets external_auth_id to Clerk user ID, syncs primary email. Idempotent — skips if user already exists. |
user.updated | Syncs email changes | Updates local email if primary email changed in Clerk. No-op if user not found locally. |
user.deleted | Audit logging | Logs the deletion event. Does not delete the local user record. |
Webhook Security
Webhooks are verified using Svix HMAC-SHA256 signature verification. The auth-server rejects any request with an invalid or missing signature. The webhook endpoint:- Does not require JWT authentication
- Does not have rate limiting (Clerk controls delivery rate)
- Is mounted conditionally — only when
AUTH_PROVIDERisclerkorboth
User Lifecycle
Clerk-Authenticated Users
- User signs up or logs in via Clerk (email, social, etc.)
- Clerk sends
user.createdwebhook → HoodCloud creates local user withexternal_auth_id - User’s frontend receives a Clerk JWT
- Frontend sends JWT to HoodCloud API → Clerk validator verifies via JWKS and resolves to local user ID
- (Optional) User registers an Ethereum wallet via
POST /api/v1/wallet/register-public-key
Wallet Registration
Clerk-authenticated users can register an Ethereum or Solana wallet: Endpoint:POST /api/v1/wallet/register-public-key
Request (Ethereum):
- The message must contain the authenticated user’s UUID
- Ethereum: The signature must be a valid EIP-191
personal_signover the message - Solana: The signature must be a valid Ed25519 signature over the message bytes
- The server auto-detects the wallet type from the address format and verifies accordingly
Migration Path: SIWE to Clerk
Phase 1: Enable Multi-Provider Mode
Deploy with both validators active:- Existing SIWE users continue authenticating with wallet signatures
- New Clerk users are created via webhooks
- The multi-validator tries Clerk first, then falls back to SIWE
- Both token types are accepted on all API endpoints
Phase 2: Migrate Frontend
- Integrate Clerk SDK into the frontend
- Update sign-in flows to use Clerk
- Existing SIWE sessions remain valid until they expire
- New sessions use Clerk JWTs
Phase 3: Switch to Clerk-Only
Once all users are migrated:/auth/nonce, /auth/verify) remain on the auth-server but issued tokens will no longer be accepted by the API server.
Database Changes
Migration020_external_auth_id makes the following schema changes:
| Change | Purpose |
|---|---|
wallet_address nullable | Allows users without Ethereum wallets (email/social login) |
external_auth_id column (VARCHAR 255) | Stores Clerk user ID (e.g., user_2abc123) |
Unique partial index on external_auth_id | Efficient lookup, allows multiple NULL values |
wallet_address and have external_auth_id = NULL.
Troubleshooting
Webhook signature verification fails
Symptom: Auth-server logsFailed to verify webhook signature
Causes:
AUTH_CLERK_WEBHOOK_SIGNING_SECRETdoes not match the signing secret in Clerk Dashboard- The webhook endpoint URL in Clerk does not match the auth-server’s actual URL
- A proxy or load balancer is modifying request headers
User not found after Clerk login
Symptom: API returns authentication errors for Clerk-authenticated users. Validator logsno local account for clerk user.
Causes:
- The
user.createdwebhook was not delivered or failed - Webhook endpoint is not reachable from Clerk’s servers
AUTH_CLERK_WEBHOOK_SIGNING_SECRETis missing (webhook handler not initialized)
- Check Clerk Dashboard → Webhooks → check delivery status for the endpoint
- Verify the auth-server is reachable at the configured webhook URL
- Check auth-server logs for webhook processing errors
- Manually trigger a re-delivery from Clerk Dashboard if needed
Authorized party mismatch
Symptom: Validator logsverify authorized party: got "X", want one of [...]
Cause: AUTH_CLERK_AUTHORIZED_PARTY does not include the azp claim origin from the Clerk JWT.
Fix: Add the missing frontend origin to AUTH_CLERK_AUTHORIZED_PARTY (comma-separated list).
Multi-provider mode — wrong validator used
Symptom: SIWE tokens fail validation, or Clerk tokens fail validation inboth mode.
Note: In both mode, the multi-validator tries Clerk first, then SIWE. If a SIWE token is passed to the Clerk validator, it will fail (expected), and the multi-validator will fall back to SIWE. This is normal behavior — no action needed unless both validators fail.