> ## Documentation Index
> Fetch the complete documentation index at: https://docs-dev-actions-triggers-prototype.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Learn about the custom-token-exchange Action trigger's API object.

# API Object

The API object for the custom-token-exchange Actions trigger exposes methods for controlling access, authenticating users, managing metadata, and caching data.

## `api.access`

Modify the access of the token exchange request, such as rejecting the request.

<ParamField body="api.access.deny(code, reason)" type="void">
  Mark the current token exchange as denied.

  If the request is being denied due to an invalid subject token, use `api.access.rejectInvalidSubjectToken` instead to distinguish brute force attempts from other denial reasons.

  ```js Example theme={null}
  exports.onExecuteCustomTokenExchange = async (event, api) => {
    const subject_token = await validateToken(event.transaction.subject_token, jwksUri);
    const isAuthorized = await authorizeAccess(subject_token.sub);
    if (!isAuthorized) {
      api.access.deny('Unauthorized_login', 'User cannot login due to reason: X');
    }
  };
  ```

  **Parameters**

  <Expandable title="Parameters">
    <ParamField body="code" type="string">
      The error code justifying the rejection. Can be `invalid_request`, `server_error`, or any custom code.
    </ParamField>

    <ParamField body="reason" type="string">
      A human-readable explanation for rejecting the token exchange request.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="api.access.rejectInvalidSubjectToken(reason)" type="void">
  Mark the provided subject token as invalid. This rejects the request with an `invalid_request` error and signals Attack Protection features to apply brute force protections.

  ```js Example theme={null}
  exports.onExecuteCustomTokenExchange = async (event, api) => {
    try {
      const subject_token = await validateToken(event.transaction.subject_token, jwksUri);
      api.authentication.setUserById(subject_token.id);
    } catch (error) {
      if (error.message === 'Invalid Token') {
        api.access.rejectInvalidSubjectToken('Invalid subject_token');
      } else {
        throw error;
      }
    }
  };
  ```

  **Parameters**

  <Expandable title="Parameters">
    <ParamField body="reason" type="string">
      A human-readable explanation for rejecting the token exchange request.
    </ParamField>
  </Expandable>
</ParamField>

## `api.authentication`

Indicate the result of the authentication of the subject token, specifying the user for whom tokens will be issued.

<ParamField body="api.authentication.setUserById(user_id)" type="void">
  Indicate the user corresponding to the subject token by providing their user ID. Exactly one of `setUserById` or `setUserByConnection` must be called.

  ```js Example theme={null}
  exports.onExecuteCustomTokenExchange = async (event, api) => {
    const subject_token = await validateToken(event.transaction.subject_token, jwksUri);
    api.authentication.setUserById(subject_token.sub);
  };
  ```

  **Parameters**

  <Expandable title="Parameters">
    <ParamField body="user_id" type="string">
      The ID of the user; must be an existing user.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="api.authentication.setUserByConnection(connection_name, user_attributes, options)" type="void">
  Indicate the user corresponding to the subject token by providing a connection and user attributes. Creates the user if they don't exist. Exactly one of `setUserById` or `setUserByConnection` must be called.

  ```js Example theme={null}
  exports.onExecuteCustomTokenExchange = async (event, api) => {
    const subject_token = await validateToken(event.transaction.subject_token, jwksUri);
    api.authentication.setUserByConnection(
      'My Connection',
      { user_id: subject_token.sub, email: subject_token.email, email_verified: true },
      { creationBehavior: 'create_if_not_exists', updateBehavior: 'none' }
    );
  };
  ```

  **Parameters**

  <Expandable title="Parameters">
    <ParamField body="connection_name" type="string">
      Name of the connection the user should be stored in.
    </ParamField>

    <ParamField body="user_attributes" type="object">
      The user's profile attributes. The `user_id` field is required and used to determine if the user exists.

      <Expandable title="user_attributes properties">
        <ParamField body="user_id" type="string">
          The user's unique identifier within the connection. Required.
        </ParamField>

        <ParamField body="email" type="string">Optional. The user's email.</ParamField>
        <ParamField body="email_verified" type="boolean">Optional. Whether the email address is verified.</ParamField>
        <ParamField body="family_name" type="string">Optional. The user's family name.</ParamField>
        <ParamField body="given_name" type="string">Optional. The user's given name.</ParamField>
        <ParamField body="name" type="string">Optional. The user's full name.</ParamField>
        <ParamField body="nickname" type="string">Optional. The user's nickname.</ParamField>
        <ParamField body="phone_number" type="string">Optional. The user's phone number (E.164 format).</ParamField>
        <ParamField body="phone_verified" type="boolean">Optional. Whether the phone number is verified.</ParamField>
        <ParamField body="picture" type="string">Optional. A URI pointing to the user's picture.</ParamField>
        <ParamField body="username" type="string">Optional. The user's username.</ParamField>
        <ParamField body="verify_email" type="boolean">Optional. Whether to send a verification email after creation.</ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="options" type="object">
      Options to control behavior of the command.

      <Expandable title="options properties">
        <ParamField body="creationBehavior" type="string">
          Behavior when the user does not exist. Allowed values: `create_if_not_exists`, `none`.
        </ParamField>

        <ParamField body="updateBehavior" type="string">
          Behavior when the user already exists. Allowed values: `none`, `replace`.
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="api.authentication.setOrganization(organization_id_or_name)" type="void">
  Set the organization for the user associated with the token exchange.

  ```js Example theme={null}
  exports.onExecuteCustomTokenExchange = async (event, api) => {
    api.authentication.setOrganization('org_xS525r979AS33MSf');
    api.authentication.setUserById(subject_token.sub);
  };
  ```

  **Parameters**

  <Expandable title="Parameters">
    <ParamField body="organization_id_or_name" type="string">
      The ID or name of the organization to set for the user.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="api.authentication.setActor(actor)" type="void">
  Set the actor for the token exchange to represent the entity acting on behalf of the subject. Calling `setActor` is optional. Refresh tokens are not issued when an actor is set.

  ```js Example theme={null}
  exports.onExecuteCustomTokenExchange = async (event, api) => {
    const actor_token = await validateToken(event.transaction.actor_token, jwksUri);
    api.authentication.setActor({ sub: actor_token.sub });
    api.authentication.setUserById(subject_token.sub);
  };
  ```

  **Parameters**

  <Expandable title="Parameters">
    <ParamField body="actor" type="object">
      A nested object representing a delegation chain. The `sub` field is required; up to 5 additional custom properties may be provided per level, up to 4 additional `act` levels.

      <Expandable title="actor properties">
        <ParamField body="sub" type="string">The subject of the actor. Required.</ParamField>
        <ParamField body="act" type="object">Optional nested actor for delegation chains.</ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

## `api.user`

Request changes to the user corresponding to the subject token.

<ParamField body="api.user.setAppMetadata(key, value)" type="void">
  Set application-specific metadata for the user corresponding to the subject token.

  ```js Example theme={null}
  exports.onExecuteCustomTokenExchange = async (event, api) => {
    api.user.setAppMetadata('group', subject_token.group);
  };
  ```

  **Parameters**

  <Expandable title="Parameters">
    <ParamField body="key" type="string">
      The metadata property to be set.
    </ParamField>

    <ParamField body="value" type="unknown">
      The value of the metadata property. This may be set to `null` to remove the metadata property.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="api.user.setUserMetadata(key, value)" type="void">
  Set general metadata for the user corresponding to the subject token.

  ```js Example theme={null}
  exports.onExecuteCustomTokenExchange = async (event, api) => {
    api.user.setUserMetadata('preferred_locale', subject_token.locale);
  };
  ```

  **Parameters**

  <Expandable title="Parameters">
    <ParamField body="key" type="string">
      The metadata property to be set.
    </ParamField>

    <ParamField body="value" type="unknown">
      The value of the metadata property. This may be set to `null` to remove the metadata property.
    </ParamField>
  </Expandable>
</ParamField>

## `api.cache`

Store and retrieve data that persists across executions.

<ParamField body="api.cache.delete(key)" type="void">
  Delete a cached record at the supplied key if it exists.

  ```js Example theme={null}
  exports.onExecuteCustomTokenExchange = async (event, api) => {
    api.cache.delete('my-key');
  };
  ```

  **Parameters**

  <Expandable title="Parameters">
    <ParamField body="key" type="string">
      The key of the cache record to delete.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="api.cache.get(key)" type="object | undefined">
  Retrieve a cached record at the supplied key. If found, access the value via `record.value`.

  ```js Example theme={null}
  exports.onExecuteCustomTokenExchange = async (event, api) => {
    const record = api.cache.get('my-key');
    if (record) console.log(record.value);
  };
  ```

  **Parameters**

  <Expandable title="Parameters">
    <ParamField body="key" type="string">
      The key of the record stored in the cache.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="api.cache.set(key, value, options)" type="void">
  Store or update a string value in the cache at the specified key. Values are scoped to the Trigger and subject to the [Actions Cache Limits](https://auth0.com/docs/customize/actions/limitations). If no lifetime is specified, a default lifetime of 15 minutes will be used.

  **Important**: This cache is designed for short-lived, ephemeral data. Items may not be available in later transactions even if they are within their supplied lifetime.

  ```js Example theme={null}
  exports.onExecuteCustomTokenExchange = async (event, api) => {
    api.cache.set('my-key', 'my-value', { ttl: 60000 });
  };
  ```

  **Parameters**

  <Expandable title="Parameters">
    <ParamField body="key" type="string">
      The key of the record to be stored.
    </ParamField>

    <ParamField body="value" type="string">
      The value of the record to be stored.
    </ParamField>

    <ParamField body="options" type="CacheSetOptions">
      Options for adjusting cache behavior. Optional.

      <Expandable title="options properties">
        <ParamField body="expires_at" type="number">
          The absolute expiry time in milliseconds since the unix epoch. *Note*: Do not supply if `ttl` is also provided; the earlier expiry will be used.
        </ParamField>

        <ParamField body="ttl" type="number">
          The time-to-live in milliseconds. *Note*: Do not supply if `expires_at` is also provided; the earlier expiry will be used.
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>
