HttpBin Service
Overview
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.
Prerequisites
- Java JDK 17+
- Gradle
Build & Run
Build Command
Run Service
java -jar build/libs/httpbin-0.0.1-SNAPSHOT.jar
Swagger Documentation
JSON Format (Default)
- /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 Format
- /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)
Endpoints
- 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
Protected Endpoints (Require Basic Auth with testuser/testpass):
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
OAuth2 Protected Endpoints (Require Okta JWT Bearer Token):
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
OAuth2 Configuration
- 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>
Getting an OAuth2 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"
Testing OAuth2 Endpoint
# 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/protected
HMAC Authentication Endpoints
The 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.
HMAC Endpoints
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
HMAC Configuration
- 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
Canonical Request Format
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
Testing HMAC Authentication
Step 1: Get Test Credentials
curl http://localhost:8081/api/auth/hmac/credentials
Step 2: Use Helper Endpoint to Generate Signature
# 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"
Step 3: Test HMAC Validation
# 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/validate
HMAC Implementation Details
The 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
Example: Calculating HMAC Signature Manually
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}")
AWS Signature v4 Authentication Endpoints
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.
AWS Signature v4 Endpoints
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
AWS Signature v4 Configuration
- 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)
AWS Signature v4 Format
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
Testing AWS Signature v4
Step 1: Get Test Credentials
curl http://localhost:8081/api/auth/aws/credentials
Step 2: Use Helper Endpoint to Generate Signature
# 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"
Step 3: Test AWS Signature Validation
# 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/validate
Example: AWS Signature v4 Calculation
import 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}")
RSA Signature Authentication Endpoints
Production-like implementation of RSA signature authentication (SHA256withRSA), commonly used in webhooks, API callbacks, and JWT. Perfect for testing asymmetric cryptography-based authentication.
RSA Signature Endpoints
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
RSA Signature Configuration
- 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>
RSA Signature Format
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
Testing RSA Signature
Step 1: Get Public Key
curl http://localhost:8081/api/auth/rsa/keys
Step 2: Use Helper Endpoint to Generate Signature
# 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"
Step 3: Test RSA Signature Validation
# 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/validate
Example: RSA Signature Calculation
from 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 Use Cases
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
Circuit Breaker Testing Endpoint
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.
How It Works
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.
Usage
GET /api/degradation?normalPeriod=30°radationPeriod=60&failurePeriod=30&recoveryPeriod=60
Parameters
| 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 |
Contribution
Feel free to extend this service with more failure scenarios or testing endpoints.
Bearer Token Authentication Endpoints
The service provides Bearer Token authentication with refresh capability, simulating OAuth2-style token management for testing Orkes authentication configurations.
Bearer Token Endpoints
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)
Bearer Token Configuration
- Client ID:
test_client - Client Secret:
test_secret - Token TTL: 3600 seconds (1 hour)
- Token Format:
bearer_<uuid> - Refresh Token Format:
refresh_<uuid>
Getting a Bearer Token
Step 1: Request Initial Token
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" }
Step 2: Refresh Token (Before Expiry - Returns Same Token)
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 }
Step 3: Use Bearer Token
# 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>"
Orkes Authentication Config for Bearer Token
{
"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
}
}API Key Authentication Endpoints
The service provides API Key authentication with refresh capability, simulating services like Stripe that support API key rotation.
API Key Endpoints
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)
API Key Configuration
- 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
Getting an API Key
Step 1: Create Initial API Key
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 " }
Step 2: Refresh API Key (Before Expiry - Returns Same Key)
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" }
Step 3: Use API Key
# 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"}'
Orkes Authentication Config for API Key
{
"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
}
}Token Lifecycle Behavior
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
Testing Token Refresh Behavior
# 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/stats
Contribution
Feel free to extend this service with more failure scenarios or testing endpoints.