HTTP REQUESTS
Request Signing
Sign outgoing HTTP requests with HMAC, AWS SigV4, or any custom scheme. Karate evaluates a JavaScript function just before each request leaves the wire, giving the signer access to the final method, path, headers, and body — everything you need to compute a signature over a canonical string.
The Mechanism
Assign a function (not a map) to configure headers. The function is called once per request, receives the built HttpRequest, and returns the headers to add:
* configure headers =
"""
function(req) {
// compute headers using req.method, req.path, req.body, etc.
return { 'X-Signature': '...' }
}
"""
The returned map is merged into the request's headers (case-insensitive).
What's on req
| Property | Type | Example |
|---|---|---|
req.method | String | 'POST' |
req.url / req.urlAndPath | String | 'https://api.example.com/v1/orders' |
req.path | String | '/v1/orders' |
req.params | Map | { region: ['us-east-1'] } |
req.headers | Map | { 'Content-Type': ['application/json'] } |
req.body | byte[] | the raw bytes that will be sent (may be null for GET) |
req.bodyString | String | UTF-8 view of req.body |
The body is the final, fully-assembled body — including form fields, multipart parts, and JSON serialisation. The function runs after the request is built, so what you sign is what gets sent.
Example: HMAC-SHA256
A common pattern: sign a canonical string (METHOD\nPATH\nTIMESTAMP\nBODY) with HMAC-SHA256, send the result in an X-Signature header alongside the timestamp.
Feature: HMAC-signed API calls
Background:
* def secret = karate.sysenv('API_SECRET')
* def signRequest =
"""
function(req) {
var Mac = Java.type('javax.crypto.Mac')
var Spec = Java.type('javax.crypto.spec.SecretKeySpec')
var Base64 = Java.type('java.util.Base64')
var ts = '' + java.lang.System.currentTimeMillis()
var body = req.bodyString || ''
var canonical = req.method + '\n' + req.path + '\n' + ts + '\n' + body
var mac = Mac.getInstance('HmacSHA256')
mac.init(new Spec(secret.getBytes('UTF-8'), 'HmacSHA256'))
var sig = Base64.getEncoder().encodeToString(mac.doFinal(canonical.getBytes('UTF-8')))
return { 'X-Timestamp': ts, 'X-Signature': sig }
}
"""
* configure headers = signRequest
* url 'https://api.example.com'
Scenario: signed GET
Given path 'orders'
When method get
Then status 200
Scenario: signed POST with JSON body
Given path 'orders'
And request { item: 'widget', qty: 3 }
When method post
Then status 201
The same signRequest works for both GET (no body) and POST (with body) — req.method and req.body reflect whatever the scenario built.
AWS SigV4
Karate does not ship a built-in SigV4 signer. Rather than implement SigV4 in JavaScript (CanonicalRequest, StringToSign, HMAC chain, signed-headers list, X-Amz-Date format — each easy to get subtly wrong), call the AWS SDK for Java v2 from the headers function via Karate's Java interop.
Add the SDK dependency to your pom.xml:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>auth</artifactId>
</dependency>
Then call Aws4Signer from the headers function with the same (req) => headersMap shape as the HMAC example above. References:
- AWS SigV4 reference — what the algorithm produces.
Aws4SignerJavadoc — the SDK entry point.
For short-lived pre-signed URLs (S3 object access, etc.) use the SDK's S3Presigner to produce a complete URL you can pass straight to url — no headers-function needed.
When Not to Use This
The headers function is for headers that genuinely depend on the request. For everything else, prefer the simpler tools:
| Need | Use |
|---|---|
| Static headers for every request | configure headers = { ... } (map, not function) |
| Bearer token from a login call | configure auth = { type: 'bearer', token: '#(...)' } |
| OAuth 2.0 client credentials | configure auth = { type: 'oauth2', ... } |
| Basic auth | configure auth = { type: 'basic', username: '...', password: '...' } |
| Per-call header override | header X-Foo = 'bar' on the request itself |
Next Steps
- Headers and Authentication — built-in auth handlers (basic, bearer, OAuth 2.0).
- Headers and Cookies — static and dynamic header assignment.
- Java API — calling Java from feature files for richer integrations.