Which Parameters Are Blocked by PARAM_DENYLIST in Auth0 Token Exchange and Why

The PARAM_DENYLIST constant in the Auth0 Auth.js SDK blocks 15+ critical OAuth parameters—including grant_type, client_id, scope, and audience—from being overridden via the extras object during token exchange to prevent credential leakage, protocol violations, and unauthorized scope escalation.

The auth0-auth-js repository uses a strict allowlist approach for custom parameters in token exchange requests. The PARAM_DENYLIST constant, defined in packages/auth0-auth-js/src/auth-client.ts, explicitly enumerates which OAuth 2.0 fields cannot be manipulated through user-supplied extras, ensuring the security and integrity of the token exchange flow while maintaining clear API contracts.

The Complete PARAM_DENYLIST Breakdown

The denylist contains parameters that are fundamental to OAuth 2.0 token exchange semantics, client authentication, or routing logic. According to the source code comment in packages/auth0-auth-js/src/auth-client.ts, these restrictions “prevent security issues and maintain API contract clarity”.

Core Protocol and Authentication Parameters

These fields define the token exchange mechanism itself and client identity:

  • grant_type — The core OAuth protocol field specifying the exchange mechanism (e.g., urn:ietf:params:oauth:grant-type:token-exchange). Changing this could invoke unsupported grant types or break the flow.
  • client_id, client_secret, client_assertion, client_assertion_type — Client authentication credentials must be supplied through SDK configuration, never through user-controlled parameters, to prevent credential leakage or hijacking.

Token Identification Parameters

These identify which token is being exchanged and what type is requested:

  • subject_token and subject_token_type — Fundamental parts of the token-exchange request; overriding them would create ambiguity about which token is being exchanged.
  • requested_token_type — Determines what kind of token the server should return (e.g., access token, refresh token, or ID token); must remain explicit in the SDK API.

Delegation and Context Parameters

These affect authorization context and delegation chains:

  • actor_token and actor_token_type — Delegation-related fields that define the acting party in a token exchange; allowing overrides could alter the intended delegation chain.
  • assertion — SAML assertion payload; handled separately for security and format validation reasons.

Routing and Target Parameters

These determine where the token is valid and which resources it can access:

  • audience, aud, resource, resources, resource_indicator — Target API identifiers that must be supplied via dedicated SDK options so routing and audience validation remain deterministic.
  • connection — Indicates which Auth0 connection (e.g., a Token Vault) should be used; must be set explicitly to avoid routing to the wrong identity source.
  • organization — Determines tenant context; must be explicit to prevent cross-tenant token issuance.

Authorization and Identity Parameters

These influence permissions and user resolution:

  • scope — Overriding scope via extras could bypass the explicit scope argument and unintentionally grant broader permissions than intended.
  • login_hint — Influences user identity resolution; allowing arbitrary overrides could cause identity confusion or targeting the wrong user.

How the Denylist is Enforced in the SDK

The SDK enforces PARAM_DENYLIST in the helper function appendExtraParams, located in packages/auth0-auth-js/src/auth-client.ts. This function iterates over the user-supplied extras object and skips any key that appears in the denylist before appending parameters to the request.

When you call exchangeToken(), the SDK passes your extras through this sanitization layer. Blocked parameters are silently dropped rather than sent to the authorization server, ensuring that critical OAuth semantics remain under the SDK's control.

// Conceptual implementation based on auth-client.ts lines 44-50
function appendExtraParams(params: URLSearchParams, extras?: Record<string, unknown>) {
  if (!extras) return;
  
  for (const [key, value] of Object.entries(extras)) {
    if (PARAM_DENYLIST.includes(key)) {
      continue; // Silently skip blocked parameters
    }
    // Append allowed parameters...
  }
}

Correct Usage of Extras in Token Exchange

The extras parameter is designed for custom, non-standard parameters your backend might require. Valid use cases include passing custom flags, correlation IDs, or vendor-specific extensions that are not part of the core OAuth specification.

Allowed Parameters Example

import { AuthClient } from '@auth0/auth0-auth-js';

const client = new AuthClient({
  domain: 'tenant.auth0.com',
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret' // Provided via config, not extras
});

// Correct: Using permitted extra parameters
const response = await client.exchangeToken({
  subjectToken: 'eyJhbGciOiJ...',
  subjectTokenType: 'urn:ietf:params:oauth:token-type:access_token',
  audience: 'https://api.example.com', // Set via explicit option, not extras
  scope: 'read:messages',              // Set via explicit option, not extras
  extras: {
    custom_tracking_id: 'uuid-1234',
    deployment_stage: 'production',
    feature_flags: ['flag1', 'flag2']
  }
});

Blocked Parameters Example

The following demonstrates parameters that will be silently ignored:

// Incorrect: Attempting to override blocked parameters
const response = await client.exchangeToken({
  subjectToken: 'eyJhbGciOiJ...',
  subjectTokenType: 'urn:ietf:params:oauth:token-type:access_token',
  extras: {
    grant_type: 'client_credentials',    // ❌ Ignored - core protocol field
    client_id: 'attacker-client-id',     // ❌ Ignored - security risk
    client_secret: 'stolen-secret',      // ❌ Ignored - credential leakage risk
    scope: 'admin:*',                    // ❌ Ignored - prevents scope escalation
    audience: 'https://victim-api.com',  // ❌ Ignored - routing control
    connection: 'hijacked-connection'    // ❌ Ignored - routing integrity
  }
});

In this case, appendExtraParams filters out all six blocked keys, and the request proceeds with only the SDK-controlled values for these critical fields.

Summary

  • PARAM_DENYLIST is defined in packages/auth0-auth-js/src/auth-client.ts and contains 15+ blocked OAuth parameters.
  • Blocked categories include authentication credentials (client_id, client_secret), protocol fields (grant_type), token identifiers (subject_token), routing directives (audience, connection), and authorization boundaries (scope).
  • Enforcement mechanism occurs in appendExtraParams, which silently drops any denylisted keys from the extras object.
  • Security rationale prevents credential leakage, protocol violations, and unauthorized scope escalation while maintaining deterministic API contracts.
  • Correct usage requires passing sensitive parameters through dedicated SDK options (audience, scope, organization) rather than the generic extras object.

Frequently Asked Questions

What happens if I try to include a blocked parameter in the extras object?

The SDK silently drops the parameter. During request construction, appendExtraParams checks each key against PARAM_DENYLIST and skips any matches. Your code will not throw an error, but the blocked parameters will not reach the Auth0 authorization server, as verified in packages/auth0-auth-js/src/token.spec.ts.

Why is the scope parameter blocked from being overridden via extras?

Blocking scope prevents privilege escalation attacks. If users could override scope through extras, they could bypass the explicit scope argument validation and potentially request broader permissions (e.g., admin:*) than the application intended to grant. The SDK requires scope to be set explicitly in the method arguments to ensure intentional permission grants.

Where exactly is PARAM_DENYLIST defined in the source code?

The constant is defined in packages/auth0-auth-js/src/auth-client.ts at approximately lines 67-88, immediately preceded by a detailed comment block explaining the security rationale for each blocked parameter. The enforcement logic resides in the appendExtraParams helper function at lines 44-50 of the same file.

Can I modify PARAM_DENYLIST to allow custom grant types?

No. The denylist is a hardcoded constant designed to protect the integrity of the OAuth 2.0 token exchange flow. If you require a different grant type, you should use the appropriate SDK method designed for that flow (e.g., clientCredentialsGrant for client_credentials) rather than attempting to override grant_type in a token exchange request.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →