Q31 of 40 · Karate

How would you handle complex OAuth 2.0 / OIDC flows in Karate?

KarateSeniorkarateoauth2oidcauthenticationapi-testing

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:

  1. Use a Karate Mock Server to capture the redirect and exchange the code programmatically
  2. 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

// WHAT INTERVIEWERS LOOK FOR

Using karate.callSingle for suite-level token caching, the client credentials flow in a helper feature, and honest assessment of PKCE's browser-redirect limitation and how to work around it. Token refresh strategy is a senior concern.

// COMMON PITFALL

Re-fetching the token inside every feature file's Background — each scenario fetches a new token, hammering the auth server and adding hundreds of milliseconds per feature. karate.callSingle caches across the suite.