karatelabs/karate · error · OAuth2Exception

Missing 'url' (token endpoint) in OAuth config

Error message

Missing 'url' (token endpoint) in OAuth config

What it means

exchangeCodeForToken() reads the token endpoint URL from the config key 'url'. Without it the authorization code cannot be exchanged for tokens, so an OAuth2Exception is thrown before any HTTP request is made. Note the key is the generic 'url', not something token-specific like 'tokenUrl'.

Solutions

  1. Add the provider's token endpoint under the exact key 'url' in the OAuth config map
  2. Check for near-miss keys like 'tokenUrl' or 'token_url' and rename to 'url'
  3. Validate the full required key set (authorizationUrl, client_id, url) before running the flow

Example fix

// before
config.put("tokenUrl", "https://idp/token");
// after
config.put("url", "https://idp/token");
Defensive patterns

Strategy: validation

Validate before calling

Object tokenUrl = config.get("url");
if (tokenUrl == null || tokenUrl.toString().isBlank()) {
    throw new IllegalArgumentException("config.url (token endpoint) is required");
}

Type guard

static String requireConfigKey(Map<String, Object> config, String key) {
    Object v = config.get(key);
    if (!(v instanceof String s) || s.isBlank()) {
        throw new IllegalArgumentException("Missing '" + key + "' in OAuth config");
    }
    return s;
}

Try / catch

try {
    Token t = handler.token(code, verifier, redirectUri);
} catch (OAuth2Exception e) {
    if (e.getMessage().contains("token endpoint")) {
        throw new ConfigurationException("Add 'url' (token endpoint) to OAuth config", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: token() -> exchangeCodeForToken() called with a config that has authorizationUrl and client_id but no 'url' key pointing at the token endpoint — common when the config was built for the authorize step only, or the key was named 'tokenUrl'.

Common situations: Splitting OAuth config across files where the token endpoint was dropped, renaming keys when migrating between auth handler implementations, or provider docs using 'token_endpoint' terminology.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/cd356003e8af7776. Report an issue: GitHub.

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/http/AuthorizationCodeAuthHandler.java:174

        // Add state for CSRF protection
        String state = generateState();
        url.append("&state=").append(urlEncode(state));

        return url.toString();
    }

    /**
     * Exchange authorization code for access token
     */
    private OAuth2Token exchangeCodeForToken(
        HttpRequestBuilder builder,
        String code,
        String codeVerifier,
        String redirectUri
    ) {
        String tokenUrl = (String) config.get("url");
        if (tokenUrl == null) {
            throw new OAuth2Exception("Missing 'url' (token endpoint) in OAuth config");
        }

        logger.debug("Exchanging authorization code for token...");

        builder.url(tokenUrl);
        builder.formField("grant_type", "authorization_code");
        builder.formField("code", code);
        builder.formField("redirect_uri", redirectUri);
        builder.formField("client_id", config.get("client_id"));
        builder.formField("code_verifier", codeVerifier);

        // Optional client_secret (for confidential clients)
        if (config.containsKey("client_secret")) {
            builder.formField("client_secret", config.get("client_secret"));
        }

        builder.header("Accept", "application/json");

View on GitHub (pinned to a22eb90246)