Q31 of 40 · Karate
How would you handle complex OAuth 2.0 / OIDC flows in Karate?
Short answer
Short answer: Write a login.feature that POSTs to the token endpoint for client credentials, extracts access_token, and returns it. Call it with karate.callSingle in karate-config.js so every scenario gets the token automatically. For PKCE flows requiring a browser redirect, stub the callback with Karate Mock Server and drive the exchange with embedded JavaScript.
Detail
Client credentials flow — straightforward:
# helpers/get-token-cc.feature
Scenario:
* url tokenUrl
Given path '/oauth/token'
And form field grant_type = 'client_credentials'
And form field client_id = clientId
And form field client_secret = clientSecret
And form field scope = 'api:read api:write'
When method POST
Then status 200
* def accessToken = response.access_token
* def expiresIn = response.expires_in
In karate-config.js — fetch once per suite:
var auth = karate.callSingle('classpath:helpers/get-token-cc.feature', config);
config.bearerToken = auth.accessToken;
Resource Owner Password Credentials (test-only grant):
And form field grant_type = 'password'
And form field username = testUsername
And form field password = testPassword
PKCE / Authorization Code — harder without a browser: Karate can't automate the browser redirect natively. Two options:
- Use a Karate Mock Server to capture the redirect and exchange the code programmatically
- Use a dedicated library (Playwright for the auth flow) and hand the token to Karate via a system property or shared file
Token refresh: use a JavaScript helper that checks expiresAt - 60s before each feature and re-calls the token feature if needed, injecting the new token via karate.set('bearerToken', newToken).
// EXAMPLE
helpers/get-token.feature
Feature: Fetch OAuth 2.0 access token (client credentials)
Scenario:
# These come from karate-config.js / environment variables
* def tokenEndpoint = karate.properties['oauth.token.url']
* def clientId = karate.properties['oauth.client.id']
* def clientSecret = karate.properties['oauth.client.secret']
Given url tokenEndpoint
And form field grant_type = 'client_credentials'
And form field client_id = clientId
And form field client_secret = clientSecret
And form field scope = 'api:read api:write'
When method POST
Then status 200
And match response.access_token == '#string'
And match response.token_type == 'Bearer'
And match response.expires_in == '#number'
# Export — caller gets accessToken
* def accessToken = response.access_token
* def expiresIn = response.expires_in