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

> Discover why Auth0 Auth.js PARAM_DENYLIST blocks critical OAuth parameters like grant_type during token exchange. Learn how this prevents credential leakage and security risks.

- Repository: [Auth0/auth0-auth-js](https://github.com/auth0/auth0-auth-js)
- Tags: deep-dive
- Published: 2026-02-25

---

**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`](https://github.com/auth0/auth0-auth-js/blob/main/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`](https://github.com/auth0/auth0-auth-js/blob/main/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`](https://github.com/auth0/auth0-auth-js/blob/main/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.

```typescript
// 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

```typescript
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:

```typescript
// 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`](https://github.com/auth0/auth0-auth-js/blob/main/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`](https://github.com/auth0/auth0-auth-js/blob/main/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`](https://github.com/auth0/auth0-auth-js/blob/main/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.