RFC-compliant OAuth 2.0 JWT generator for testing authorization servers. Runs on Cloudflare Workers.
Generate RFC-compliant test JWTs for:
- CI pipeline testing
- Local development
- Integration testing of authorization servers
- OAuth Client ID Metadata Document testing
- ✅ RFC 7523 compliant JWT generation (private_key_jwt)
- ✅ RFC 7517 compliant JWKS endpoint
- ✅ RFC 7591 compliant OAuth client metadata
- ✅ OAuth Client ID Metadata Document support
- ✅ Dynamic redirect_uris and metadata via base64url-encoded client_id URLs
- ✅ Support for authorization_code, refresh_token, and client_credentials flows
- ✅ TypeScript
- ✅ Zero production dependencies (uses
josefor development) - ✅ Comprehensive test suite with Vitest
GET / - Interactive UI for testing
GET /health - Service health check
GET /oauth-client - OAuth client metadata (RFC 7591)
GET /oauth-client/{base64url} - OAuth client metadata with custom overrides
GET /jwks - JSON Web Key Set (RFC 7517)
POST /client-id-document-token - Generate JWT using client_id URL
POST /private-key-jwt-token - Generate JWT with custom claims
- Node.js 20+
- npm
# Install dependencies
npm install
# Run tests
npm test
# Start development server
npm run devThe dev server will start at http://127.0.0.1:8787
Tests use @cloudflare/vitest-pool-workers and run directly in the Workers runtime:
npm testTests verify RFC compliance:
- RFC 7591: OAuth client metadata structure
- RFC 7517: JWKS document format
- RFC 7523: JWT claims and structure
- CORS behavior
- Client ID Metadata Document integration
-
Get Cloudflare API Token
- Go to Cloudflare Dashboard
- Navigate to: My Profile > API Tokens
- Click "Create Token"
- Use template: "Edit Cloudflare Workers"
- Copy the token
-
Configure GitHub Secrets
- Go to your GitHub repository settings
- Navigate to: Settings > Secrets and variables > Actions
- Add secret:
CLOUDFLARE_API_TOKENwith your API token
-
Deploy
The GitHub Actions workflow will automatically deploy on push to
main:# .github/workflows/ci.yml runs: # 1. Tests on all pushes and PRs # 2. Deploys to Cloudflare Workers on push to main
-
Manual Deploy
npm run deploy
Configure in wrangler.toml:
JWT_AUDIENCE- Comma-separated audience values (optional)DEFAULT_REDIRECT_URIS- Comma-separated redirect URIs (optional, default:http://localhost:8080/callback)DEFAULT_GRANT_TYPES- Comma-separated grant types (optional, default:authorization_code,refresh_token,client_credentials)
The worker automatically infers its public URL from the incoming request hostname, so no configuration is needed for different deployment environments.
Example configuration:
[vars]
JWT_AUDIENCE = "https://auth-server.com/token"
DEFAULT_REDIRECT_URIS = "https://myapp.com/callback,http://localhost:3000/auth/callback"
DEFAULT_GRANT_TYPES = "authorization_code,refresh_token"Configure client metadata without redeployment. The API handles base64url encoding automatically.
UI:
- Navigate to
/ - Configure redirect URIs, scope, grant types in "Client ID Document Token" section
- Click "Generate Token" - returns custom client_id URL and JWT
API:
curl -X POST https://your-worker.dev/client-id-document-token \
-H "Content-Type: application/json" \
-d '{
"metadata": {
"redirect_uris": ["https://myapp.com/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"scope": "read write"
},
"aud": "https://auth-server.com/token"
}'
# Response
{
"access_token": "eyJhbGc...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read write",
"client_id": "https://your-worker.dev/oauth-client/eyJyZWRpcmVjdF91cmlz..."
}The client_id URL contains base64url-encoded metadata and can be dereferenced to get full client metadata.
Metadata Fields:
redirect_uris- Array of redirect URIsgrant_types- Array of grant typesscope- Space-separated scope valuesclient_name- Display name
# Generate JWT for authorization server testing
CLIENT_ASSERTION=$(curl -s -X POST https://oauth-jwt-provider.example.workers.dev/client-id-document-token \
-H "Content-Type: application/json" \
-d '{"aud": "https://auth-server.com/token"}' \
| jq -r .access_token)
# Use JWT to test authorization server
curl -X POST https://auth-server.com/token \
-d "grant_type=client_credentials" \
-d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
-d "client_assertion=$CLIENT_ASSERTION"curl -X POST https://oauth-jwt-provider.example.workers.dev/private-key-jwt-token \
-H "Content-Type: application/json" \
-d '{"client_id": "test-client", "aud": "https://auth-server.com/token"}' \
| jq -r .access_token# 1. Authorization server discovers client metadata
curl https://oauth-jwt-provider.example.workers.dev/oauth-client
# 2. Authorization server retrieves public keys
curl https://oauth-jwt-provider.example.workers.dev/jwks
# 3. Generate JWT for token request
CLIENT_ASSERTION=$(curl -s -X POST https://oauth-jwt-provider.example.workers.dev/client-id-document-token \
-H "Content-Type: application/json" \
-d '{"aud": "https://auth-server.com/token"}' \
| jq -r .access_token)
# 4. Test authorization server token endpoint
curl -X POST https://auth-server.com/token \
-d "grant_type=client_credentials" \
-d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
-d "client_assertion=$CLIENT_ASSERTION"The service automatically infers its public URL from the incoming request hostname. This means:
- No configuration needed for deployment
- Works on
localhost,*.workers.dev, and custom domains automatically client_idandjwks_uriadapt to the actual hostname
The service returns the incoming Origin header in Access-Control-Allow-Origin. If no Origin header is present, it defaults to http://127.0.0.1:8787.
This allows the service to be used from any origin in CI/testing environments.
This service is designed for testing authorization servers and is NOT secure for production:
- Ephemeral keys regenerate on cold start (no persistence)
- No key rotation mechanisms
- No rate limiting
- CORS allows all origins
- Public keys are visible via /jwks endpoint (by design)
Intended Use: Testing authorization servers in CI/CD pipelines and local development.
oauth-jwt-provider/
├── src/
│ ├── index.ts # Main worker entry point
│ └── config.ts # Configuration
├── test/
│ └── index.test.ts # RFC compliance tests
├── .github/
│ └── workflows/
│ └── ci.yml # GitHub Actions CI/CD
├── package.json
├── wrangler.toml # Cloudflare Workers config
├── vitest.config.ts # Vitest configuration
└── tsconfig.json # TypeScript config
- RFC 6749 - OAuth 2.0 Authorization Framework
- RFC 7517 - JSON Web Key (JWK)
- RFC 7519 - JSON Web Token (JWT)
- RFC 7523 - JWT Profile for OAuth 2.0 Client Authentication
- RFC 7591 - OAuth 2.0 Dynamic Client Registration
Apache-2.0
Issues and pull requests welcome!