HttpBin is a microservice designed for testing HTTP-related scenarios, network resilience, and simulating various service conditions. It provides endpoints that help developers test error handling, latency, and dependency interactions.
- Java JDK 17+
- Gradle
./gradlew buildjava -jar build/libs/httpbin-0.0.1-SNAPSHOT.jar- /api-docs -> Public API documentation without authentication
- /api-docs/secured -> Bearer token required `**Bearer test-token-123**`
- /api-docs/multi-server -> 4 servers (dev/staging/prod/local)
- /api-docs/staging - 2 servers (staging/local)
- /yaml/api-docs.yaml -> Public API documentation in YAML format
- /yaml/api-docs/secured.yaml -> Bearer token required `**Bearer test-token-123**` (YAML format)
- /yaml/api-docs/multi-server.yaml -> 4 servers (dev/staging/prod/local) (YAML format)
- /yaml/api-docs/staging.yaml -> 2 servers (staging/local) (YAML format)
- GET /api/hello?name=Alice
- GET /api/hello/with-delay?name=Alice
- GET /api/hello/intermittent-failures?name=Alice
- GET /api/hello/service-down?name=Alice
- GET /api/hello/overloaded?name=Alice
- GET /api/hello/failure-types?name=Alice
- GET /api/hello/external-dependency?name=Alice
GET /api/auth/basic - Main basic auth test endpoint
GET /api/auth/userinfo - User information
POST /api/auth/data - POST endpoint with auth
GET /api/auth/protected - Another protected resource
GET /api/oauth/protected - Main OAuth2 protected endpoint (returns token details)
GET /api/oauth/userinfo - OAuth2 user information and JWT claims
POST /api/oauth/data - POST endpoint with OAuth2 authentication
GET /api/oauth/validate - Simple token validation endpoint
- Issuer: https://trial-5299397.okta.com/oauth2/default
- Token Endpoint: https://trial-5299397.okta.com/oauth2/default/v1/token
- Required Header:
Authorization: Bearer <JWT_TOKEN>
curl -X POST https://trial-5299397.okta.com/oauth2/default/v1/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=0oavy0g8zojZWpY3X697" \
-d "client_secret=jHIhlwWz0uOWhpJGzOc1hukJF1s2RpLVtpC8bIyL8lzG6xxChtPeXMunazyCQvdt" \
-d "scope=openid"# Get token
TOKEN=$(curl -X POST https://trial-5299397.okta.com/oauth2/default/v1/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=0oavy0g8zojZWpY3X697&client_secret=jHIhlwWz0uOWhpJGzOc1hukJF1s2RpLVtpC8bIyL8lzG6xxChtPeXMunazyCQvdt&scope=openid" \
| jq -r '.access_token')
# Call protected endpoint
curl -H "Authorization: Bearer $TOKEN" http://localhost:8081/api/oauth/protectedThe service provides production-like HMAC-SHA256 authentication endpoints that simulate real-world API authentication patterns similar to AWS Signature v4. These endpoints are useful for testing HMAC-based authentication in Orkes Conductor workflows.
GET /api/auth/hmac/validate - Validate HMAC signature (GET request)
POST /api/auth/hmac/validate - Validate HMAC signature with request body (POST request)
GET /api/auth/hmac/credentials - Get test credentials
GET /api/auth/hmac/helper - Helper to generate signatures for testing
- Algorithm: HMAC-SHA256
- Signing Key:
test-signing-key-12345 - Access Key:
test-access-key-123 - Timestamp Tolerance: 300 seconds (5 minutes)
- Required Headers:
Authorization: HMAC-SHA256 AccessKey=<key>, Signature=<signature>X-Timestamp: <unix-timestamp-seconds>Content-Type: application/jsonHost: localhost:8081
The signature is calculated using a canonical request that includes:
- HTTP Method (GET, POST, etc.)
- Request URI (the path)
- Canonical Query String (sorted query parameters)
- Canonical Headers (content-type and host, lowercase, sorted)
- Signed Headers (list of header names: "content-type;host")
- Payload Hash (SHA-256 hash of request body, empty string for GET)
String to Sign Format:
AccessKey + Timestamp + CanonicalRequest
curl http://localhost:8081/api/auth/hmac/credentials# For GET request
curl "http://localhost:8081/api/auth/hmac/helper?method=GET&path=/api/auth/hmac/validate"
# For GET request with query parameters
curl "http://localhost:8081/api/auth/hmac/helper?method=GET&path=/api/auth/hmac/validate&queryParams=param1=value1%26param2=value2"
# For POST request with body
curl "http://localhost:8081/api/auth/hmac/helper?method=POST&path=/api/auth/hmac/validate&body=%7B%22test%22:%22data%22%7D"# Example GET request (copy the example_curl from helper response)
TIMESTAMP=$(date +%s)
# Use the signature generated by helper endpoint
curl -H "Authorization: HMAC-SHA256 AccessKey=test-access-key-123, Signature=<your-signature>" \
-H "X-Timestamp: $TIMESTAMP" \
-H "Content-Type: application/json" \
-H "Host: localhost:8081" \
http://localhost:8081/api/auth/hmac/validate
# Example POST request with body
curl -X POST \
-H "Authorization: HMAC-SHA256 AccessKey=test-access-key-123, Signature=<your-signature>" \
-H "X-Timestamp: $TIMESTAMP" \
-H "Content-Type: application/json" \
-H "Host: localhost:8081" \
-d '{"test":"data"}' \
http://localhost:8081/api/auth/hmac/validateThe HMAC implementation follows production patterns similar to AWS Signature v4:
- Actual request data: Uses real request path, headers, query parameters, and body
- Query parameter sorting: Parameters are sorted alphabetically before signing
- Body hashing: Request body is hashed with SHA-256 for POST/PUT requests
- Replay protection: Timestamp validation prevents replay attacks (5-minute window)
- Detailed error messages: Returns expected vs received signatures for debugging
import hmac
import hashlib
import base64
import time
# Credentials
access_key = "test-access-key-123"
signing_key = "test-signing-key-12345"
# Request details
method = "GET"
path = "/api/auth/hmac/validate"
query_string = "" # Empty for no query params
timestamp = str(int(time.time()))
# Build canonical request
canonical_request = f"{method}\n{path}\n{query_string}\ncontent-type:application/json\nhost:localhost:8081\n\ncontent-type;host\n{base64.b64encode(hashlib.sha256(b'').digest()).decode()}"
# Build string to sign
string_to_sign = access_key + timestamp + canonical_request
# Calculate signature
signature = base64.b64encode(
hmac.new(
signing_key.encode(),
string_to_sign.encode(),
hashlib.sha256
).digest()
).decode()
print(f"Authorization: HMAC-SHA256 AccessKey={access_key}, Signature={signature}")
print(f"X-Timestamp: {timestamp}")Production-like implementation of AWS Signature Version 4 (AWS SigV4) authentication, similar to AWS API authentication. Perfect for testing AWS-style authentication in Orkes Conductor workflows.
GET /api/auth/aws/validate - Validate AWS Signature v4 (GET request)
POST /api/auth/aws/validate - Validate AWS Signature v4 with request body (POST request)
GET /api/auth/aws/credentials - Get test credentials
GET /api/auth/aws/helper - Helper to generate AWS signatures for testing
- Algorithm: AWS4-HMAC-SHA256
- Access Key ID:
AKIAIOSFODNN7EXAMPLE - Secret Access Key:
wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - Region:
us-east-1 - Service:
httpbin - Timestamp Tolerance: 900 seconds (15 minutes)
- Required Headers:
Authorization: AWS4-HMAC-SHA256 Credential=<access-key>/<date>/<region>/<service>/aws4_request, SignedHeaders=<headers>, Signature=<signature>X-Amz-Date: <ISO8601-timestamp>(format: YYYYMMDDTHHMMSSZ)
The signature follows AWS Signature Version 4 signing process:
- Canonical Request: Method + URI + Query String + Headers + Signed Headers + Payload Hash
- String to Sign: Algorithm + Timestamp + Credential Scope + Hash(Canonical Request)
- Signing Key: Derived from secret key, date, region, and service
- Signature: HMAC-SHA256(String to Sign, Signing Key)
Credential Scope Format: YYYYMMDD/region/service/aws4_request
curl http://localhost:8081/api/auth/aws/credentials# For GET request
curl "http://localhost:8081/api/auth/aws/helper?method=GET&path=/api/auth/aws/validate"
# For POST request with body
curl "http://localhost:8081/api/auth/aws/helper?method=POST&path=/api/auth/aws/validate&body=%7B%22test%22:%22data%22%7D"# Copy the example_curl from helper response
# Example:
curl -X GET \
-H "Authorization: AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20241016/us-east-1/httpbin/aws4_request, SignedHeaders=host;x-amz-date, Signature=<signature>" \
-H "X-Amz-Date: 20241016T120000Z" \
-H "Host: localhost:8081" \
http://localhost:8081/api/auth/aws/validateimport hmac
import hashlib
from datetime import datetime
# Credentials
access_key_id = "AKIAIOSFODNN7EXAMPLE"
secret_access_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
region = "us-east-1"
service = "httpbin"
# Request details
method = "GET"
uri = "/api/auth/aws/validate"
amz_date = datetime.utcnow().strftime('%Y%m%dT%H%M%SZ')
date_stamp = amz_date[:8]
# Step 1: Create canonical request
canonical_request = f"{method}\n{uri}\n\nhost:localhost:8081\nx-amz-date:{amz_date}\n\nhost;x-amz-date\n{hashlib.sha256(b'').hexdigest()}"
# Step 2: Create string to sign
credential_scope = f"{date_stamp}/{region}/{service}/aws4_request"
string_to_sign = f"AWS4-HMAC-SHA256\n{amz_date}\n{credential_scope}\n{hashlib.sha256(canonical_request.encode()).hexdigest()}"
# Step 3: Calculate signing key
def sign(key, msg):
return hmac.new(key, msg.encode(), hashlib.sha256).digest()
k_date = sign(("AWS4" + secret_access_key).encode(), date_stamp)
k_region = sign(k_date, region)
k_service = sign(k_region, service)
k_signing = sign(k_service, "aws4_request")
# Step 4: Calculate signature
signature = hmac.new(k_signing, string_to_sign.encode(), hashlib.sha256).hexdigest()
print(f"Authorization: AWS4-HMAC-SHA256 Credential={access_key_id}/{credential_scope}, SignedHeaders=host;x-amz-date, Signature={signature}")
print(f"X-Amz-Date: {amz_date}")Production-like implementation of RSA signature authentication (SHA256withRSA), commonly used in webhooks, API callbacks, and JWT. Perfect for testing asymmetric cryptography-based authentication.
GET /api/auth/rsa/validate - Validate RSA signature (GET request)
POST /api/auth/rsa/validate - Validate RSA signature with request body (POST request)
GET /api/auth/rsa/keys - Get public key for verification
GET /api/auth/rsa/helper - Helper to generate RSA signatures for testing
- Algorithm: SHA256withRSA
- Key Size: 2048 bits
- Timestamp Tolerance: 300 seconds (5 minutes)
- Required Headers:
X-Signature: <base64-encoded-rsa-signature>X-Timestamp: <unix-timestamp-seconds>
The signature is calculated over: METHOD + URI + TIMESTAMP + BODY
- Concatenate: HTTP method + request URI + timestamp + request body (if any)
- Sign with RSA private key using SHA256withRSA
- Base64 encode the signature
- Send in
X-Signatureheader
curl http://localhost:8081/api/auth/rsa/keys# For GET request
curl "http://localhost:8081/api/auth/rsa/helper?method=GET&path=/api/auth/rsa/validate"
# For POST request with body
curl "http://localhost:8081/api/auth/rsa/helper?method=POST&path=/api/auth/rsa/validate&body=%7B%22test%22:%22data%22%7D"# Copy the example_curl from helper response
# Example:
TIMESTAMP=$(date +%s)
curl -X GET \
-H "X-Signature: <base64-signature>" \
-H "X-Timestamp: $TIMESTAMP" \
http://localhost:8081/api/auth/rsa/validatefrom Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from Crypto.Hash import SHA256
import base64
import time
# Load keys (get public key from /api/auth/rsa/keys endpoint)
# Private key is kept on server, use /helper endpoint for testing
# For signing (server-side or testing):
method = "GET"
path = "/api/auth/rsa/validate"
timestamp = str(int(time.time()))
body = "" # Empty for GET
# Build data to sign
data_to_sign = method + path + timestamp + body
# Sign with private key (use helper endpoint in practice)
# signature = sign_with_private_key(data_to_sign)
# signature_base64 = base64.b64encode(signature).decode()
# For verification (client-side):
# public_key = RSA.import_key(public_key_pem)
# h = SHA256.new(data_to_sign.encode())
# pkcs1_15.new(public_key).verify(h, base64.b64decode(signature_base64))RSA signature authentication is commonly used for:
- Webhook Verification: Validate incoming webhooks (GitHub, Stripe, etc.)
- API Callbacks: Verify callbacks from external services
- JWT Alternatives: Non-JWT token-based authentication
- Service-to-Service: Secure service communication without shared secrets
The /api/degradation endpoint simulates a time-based service lifecycle that demonstrates the complete circuit breaker pattern, including the recovery phase. This endpoint is ideal for testing resilience patterns like circuit breakers in a realistic environment.
The endpoint simulates a service that cycles through four distinct phases:
- NORMAL Phase: Service operates with minimal delay
- DEGRADING Phase: Service gradually slows down (response times increase)
- FAILING Phase: Service consistently fails with 500 errors (triggers circuit breaker open)
- RECOVERING Phase: Service gradually returns to normal (allows circuit breaker to transition from open to half-open to closed)
The service automatically cycles through these phases based on configured time periods, regardless of request frequency.
GET /api/degradation?normalPeriod=30°radationPeriod=60&failurePeriod=30&recoveryPeriod=60
| Parameter | Description | Default |
|---|---|---|
| normalPeriod | Duration of normal operation (seconds) | 30 |
| degradationPeriod | Duration of progressive degradation (seconds) | 60 |
| failurePeriod | Duration of failure state (seconds) | 30 |
| recoveryPeriod | Duration of recovery phase (seconds) | 60 |
| initialDelay | Starting response time (milliseconds) | 50 |
| degradationRate | Rate at which delay increases during degradation | 100 |
| failureThreshold | Delay threshold at which service fails (ms) | 2000 |
Feel free to extend this service with more failure scenarios or testing endpoints.
The service provides Bearer Token authentication with refresh capability, simulating OAuth2-style token management for testing Orkes authentication configurations.
POST /api/auth/bearer/token - Request a new bearer token
POST /api/auth/bearer/refresh - Refresh an existing bearer token
GET /api/auth/bearer/validate - Validate a bearer token
GET /api/auth/bearer/protected - Protected endpoint requiring bearer token
GET /api/auth/bearer/stats - Token statistics (for testing)
- Client ID:
test_client - Client Secret:
test_secret - Token TTL: 3600 seconds (1 hour)
- Token Format:
bearer_<uuid> - Refresh Token Format:
refresh_<uuid>
curl -X POST http://localhost:8081/api/auth/bearer/token \
-H "Content-Type: application/json" \
-d '{
"client_id": "test_client",
"client_secret": "test_secret"
}'
# Response:
{
"access_token": "bearer_<uuid>",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "refresh_<uuid>",
"scope": "read write"
}curl -X POST http://localhost:8081/api/auth/bearer/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "refresh_<uuid>",
"client_secret": "test_secret"
}'
# Response (if token not expired):
{
"access_token": "bearer_<same_uuid>", # Same token returned
"token_type": "Bearer",
"expires_in": 2400, # Remaining TTL
"refresh_token": "refresh_<uuid>",
"scope": "read write",
"refresh_count": 0
}# Validate token
curl http://localhost:8081/api/auth/bearer/validate \
-H "Authorization: Bearer bearer_<uuid>"
# Access protected endpoint
curl http://localhost:8081/api/auth/bearer/protected \
-H "Authorization: Bearer bearer_<uuid>"{
"secretName": "httpbin_bearer_auth_secret",
"version": 1,
"secretConfig": {
"type": "BEARER_TOKEN",
"accessToken": "<bearer_token_from_response>",
"refreshToken": "<refresh_token_from_response>",
"clientSecret": "test_secret",
"clientId": "test_client",
"refreshEndpoint": "http://localhost:8081/api/auth/bearer/refresh",
"refreshMethod": "POST",
"refreshHeaders": {
"Content-Type": "application/json"
},
"refreshBodyTemplate": "{\"refresh_token\":\"{{refresh_token}}\",\"client_secret\":\"{{client_secret}}\"}",
"accessTokenPath": "$.access_token",
"refreshTokenPath": "$.refresh_token",
"expiresInPath": "$.expires_in",
"autoRefresh": true,
"refreshThresholdSec": 300
}
}The service provides API Key authentication with refresh capability, simulating services like Stripe that support API key rotation.
POST /api/auth/apikey/create - Create a new API key
POST /api/auth/apikey/refresh - Refresh an existing API key
GET /api/auth/apikey/validate - Validate an API key
GET /api/auth/apikey/protected - Protected endpoint requiring API key
POST /api/auth/apikey/protected/data - POST endpoint requiring API key
GET /api/auth/apikey/stats - API key statistics (for testing)
- Account ID:
test_account - Account Secret:
test_account_secret - Key TTL: 2592000 seconds (30 days)
- Key Format:
sk_test_<uuid> - Refresh Secret Format:
refresh_<uuid> - Supports multiple header formats:
X-API-Key,Authorization,Authorization: Bearer,Authorization: ApiKey
curl -X POST http://localhost:8081/api/auth/apikey/create \
-H "Content-Type: application/json" \
-d '{
"account_id": "test_account",
"account_secret": "test_account_secret",
"header_name": "Authorization",
"header_prefix": "Bearer "
}'
# Response:
{
"api_key": "sk_test_<uuid>",
"refresh_secret": "refresh_<uuid>",
"expires_in": 2592000,
"expires_at": "2025-11-19T...",
"header_name": "Authorization",
"header_prefix": "Bearer "
}curl -X POST http://localhost:8081/api/auth/apikey/refresh \
-H "Content-Type: application/json" \
-d '{
"api_key": "sk_test_<uuid>",
"refresh_secret": "refresh_<uuid>"
}'
# Response (if key not expired):
{
"api_key": "sk_test_<same_uuid>", # Same key returned
"expires_in": 2000000, # Remaining TTL
"expires_at": "2025-11-19T...",
"refresh_count": 0,
"message": "API key is still valid"
}# Validate with X-API-Key header
curl http://localhost:8081/api/auth/apikey/validate \
-H "X-API-Key: sk_test_<uuid>"
# Validate with Authorization header (Bearer prefix)
curl http://localhost:8081/api/auth/apikey/validate \
-H "Authorization: Bearer sk_test_<uuid>"
# Access protected endpoint
curl http://localhost:8081/api/auth/apikey/protected \
-H "Authorization: Bearer sk_test_<uuid>"
# POST to protected endpoint
curl -X POST http://localhost:8081/api/auth/apikey/protected/data \
-H "Authorization: Bearer sk_test_<uuid>" \
-H "Content-Type: application/json" \
-d '{"data": "test payload"}'{
"secretName": "httpbin_apikey_auth_secret",
"version": 1,
"secretConfig": {
"type": "API_KEY",
"apiKey": "<api_key_from_response>",
"refreshSecret": "<refresh_secret_from_response>",
"headerName": "Authorization",
"headerPrefix": "Bearer ",
"refreshEndpoint": "http://localhost:8081/api/auth/apikey/refresh",
"refreshMethod": "POST",
"refreshBodyTemplate": "{\"api_key\":\"{{current_api_key}}\",\"refresh_secret\":\"{{refresh_secret}}\"}",
"accessTokenPath": "$.api_key",
"expiresInPath": "$.expires_in",
"autoRefresh": true,
"refreshThresholdSec": 600
}
}Both Bearer Token and API Key implementations follow the Orkes specification:
- Token Not Expired: When refresh is called before expiry, the same token is returned with updated TTL
- Token Expired: When refresh is called after expiry, a new token is generated
- Refresh Count: Tracks how many times a token has been refreshed (useful for testing)
- Auto-Refresh: Orkes can use
refreshThresholdSecto refresh tokens proactively before they expire
# 1. Create a token/key with short TTL for testing
# 2. Check remaining TTL
curl http://localhost:8081/api/auth/bearer/validate -H "Authorization: Bearer <token>"
# 3. Wait until close to expiry (within refreshThresholdSec)
# 4. Refresh - should get same token if not expired
# 5. Wait until after expiry
# 6. Refresh - should get new token
# Check stats to see active tokens
curl http://localhost:8081/api/auth/bearer/stats
curl http://localhost:8081/api/auth/apikey/statsFeel free to extend this service with more failure scenarios or testing endpoints.