# How the exchangeToken extra Parameter Works in Auth0 Auth JS: Security Risks and Implementation

> Understand the Auth0 Auth JS exchangeToken extra parameter. Learn about security risks like data leakage and injection, and how the SDK protects your application.

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

---

**The `extra` parameter in `exchangeToken` allows developers to inject custom metadata into OAuth 2.0 token exchange requests, but carries risks of data leakage and parameter injection that the SDK mitigates through a reserved parameter deny-list and strict array size limits.**

The `auth0-auth-js` library provides the `exchangeToken` method to perform RFC 8693 token exchanges and Token Vault operations. When you need to pass custom data to Auth0 Actions or downstream services, the `extra` parameter in `ExchangeProfileOptions` accepts a record of string values, though it comes with specific security guardrails implemented in the SDK source code.

## How the extra Parameter Works in exchangeToken

### Type Definition and Documentation

In [`packages/auth0-auth-js/src/types.ts`](https://github.com/auth0/auth0-auth-js/blob/main/packages/auth0-auth-js/src/types.ts) (lines 283-370), the `extra` field is defined within `ExchangeProfileOptions` as `Record<string, string | string[]>`. The JSDoc explicitly warns that this field **cannot override reserved OAuth parameters** and advises developers never to include PII or secrets because these values may appear in audit logs or network traces. Array values are limited to 20 items per key to prevent request bloat.

### The Parameter Deny-List

To prevent attackers from overriding critical OAuth parameters, the SDK maintains a `PARAM_DENYLIST` set 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) (lines 91-113). This deny-list contains reserved keys such as `grant_type`, `client_id`, `client_secret`, `scope`, `audience`, and `resource`. Any key in `extra` matching this set is silently discarded before the request is sent.

### Appending Extra Parameters

The `appendExtraParams` function 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) (lines 144-162) processes the `extra` object during `exchangeToken` execution. The function iterates over each key-value pair and applies three rules: it skips keys found in `PARAM_DENYLIST`, validates that arrays do not exceed the `MAX_ARRAY_VALUES_PER_KEY` limit of 20 items (throwing `TokenExchangeError` if exceeded), and appends valid entries to the request's `URLSearchParams`. The resulting parameters serialize as `application/x-www-form-urlencoded` data sent to the Auth0 endpoint.

### Server-Side Availability

Once the request reaches Auth0, parameters passed through `extra` become accessible in **Auth0 Actions** under `event.request.body`. This enables custom business logic such as device fingerprinting or session tracking based on the metadata you provide.

## Security Risks of the extra Parameter

### Sensitive Data Leakage

Values sent via `extra` may be written to **audit logs** or appear in network traces. The SDK documentation explicitly warns against including passwords, secrets, or personally identifiable information (PII) in this field, as there is no technical enforcement preventing such data from being transmitted.

### OAuth Parameter Injection

Without the SDK's protections, an attacker could attempt to override reserved parameters like `scope` or `grant_type` to escalate privileges. The `PARAM_DENYLIST` in [`auth-client.ts`](https://github.com/auth0/auth0-auth-js/blob/main/auth-client.ts) mitigates this by silently stripping any attempt to override these reserved keys. Unit tests in [`packages/auth0-auth-js/src/auth-client.spec.ts`](https://github.com/auth0/auth0-auth-js/blob/main/packages/auth0-auth-js/src/auth-client.spec.ts) verify that provided `scope` values in `extra` are ignored while explicitly passed parameters win.

### Denial of Service via Large Arrays

An attacker could attempt to cause memory pressure or request-size blow-up by sending massive arrays. The SDK enforces a hard limit of **20 items per array key** via `MAX_ARRAY_VALUES_PER_KEY`. Exceeding this limit throws a `TokenExchangeError`, preventing resource exhaustion attacks.

## Practical Code Examples

The following examples demonstrate safe usage, the deny-list behavior, and array limits:

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

const authClient = new AuthClient({
  domain: 'my-tenant.auth0.com',
  clientId: '<client_id>',
  clientSecret: '<client_secret>',
});

/**
 * Example 1 – Adding safe custom metadata.
 */
await authClient.exchangeToken({
  subjectTokenType: 'urn:acme:legacy-token',
  subjectToken: 'legacy-token-xyz',
  audience: 'https://api.example.com',
  scope: 'openid profile',
  extra: {
    // These will be visible in an Auth0 Action as event.request.body.device_id, etc.
    device_id: 'device-12345',
    session_id: 'sess-abcde',
  },
});

/**
 * Example 2 – Attempting to override a reserved parameter (will be ignored).
 */
await authClient.exchangeToken({
  subjectTokenType: 'urn:acme:legacy-token',
  subjectToken: 'legacy-token-xyz',
  audience: 'https://api.example.com',
  scope: 'openid profile',
  extra: {
    // `scope` is on the deny-list → the SDK discards it.
    scope: 'should_be_ignored',
    // Custom param is allowed.
    custom_param: 'allowed',
  },
});

/**
 * Example 3 – Exceeding the array limit (throws TokenExchangeError).
 */
await authClient.exchangeToken({
  subjectTokenType: 'urn:acme:legacy-token',
  subjectToken: 'legacy-token-xyz',
  audience: 'https://api.example.com',
  extra: {
    // 21 items > max 20 → error.
    large_array: Array.from({ length: 21 }, (_, i) => `value${i}`),
  },
});

```

## Summary

- The `extra` parameter in `exchangeToken` accepts custom metadata as `Record<string, string | string[]>` defined in [`types.ts`](https://github.com/auth0/auth0-auth-js/blob/main/types.ts).
- **Reserved parameters** like `scope` and `grant_type` are protected by a `PARAM_DENYLIST` in [`auth-client.ts`](https://github.com/auth0/auth0-auth-js/blob/main/auth-client.ts) that silently strips overrides.
- Arrays in `extra` are limited to **20 items** to prevent DoS attacks; exceeding this throws `TokenExchangeError`.
- Never include **PII or secrets** in `extra` values, as they may appear in Auth0 audit logs or network traces.
- Custom parameters arrive in Auth0 Actions via `event.request.body` for business logic processing.

## Frequently Asked Questions

### Can the extra parameter override standard OAuth parameters like scope or audience?

No. The SDK maintains a `PARAM_DENYLIST` 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) (lines 91-113) that explicitly prevents overriding reserved OAuth parameters. If you attempt to pass `scope` or `audience` inside `extra`, the `appendExtraParams` function silently discards these keys before sending the request to Auth0.

### What happens if I send an array with more than 20 items in the extra parameter?

The SDK throws a `TokenExchangeError`. The constant `MAX_ARRAY_VALUES_PER_KEY` is set to 20 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). When `appendExtraParams` detects an array exceeding this limit, it halts execution and raises an error to prevent request size attacks and memory exhaustion.

### Is it safe to pass sensitive data like passwords or API keys through the extra parameter?

No. According to the JSDoc in [`packages/auth0-auth-js/src/types.ts`](https://github.com/auth0/auth0-auth-js/blob/main/packages/auth0-auth-js/src/types.ts), you should **never include PII or secrets** in the `extra` parameter. These values may be logged in Auth0 audit trails, appear in network traces, or be stored in plaintext server-side. Use `extra` only for non-sensitive metadata like device IDs or session identifiers.

### How do I access extra parameters in my Auth0 Action?

Auth0 exposes custom parameters from `extra` in the `event.request.body` object within your Action code. For example, if you send `extra: { device_id: 'abc123' }`, you can retrieve it in your Action using `event.request.body.device_id` to implement custom authentication logic or risk assessments.