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

> Información sobre el objeto API del trigger custom-token-exchange de Actions.

# Desencadenadores de Actions: custom-token-exchange - objeto API

El objeto API del trigger custom-token-exchange de Actions incluye:

<div id="apiaccess">
  ## `api.access`
</div>

Modifica el acceso a la solicitud de intercambio de tokens, por ejemplo, rechazándola.

<div id="apiaccessdenycode-reason">
  ### `api.access.deny(code, reason)`
</div>

Marca el intercambio de tokens actual como denegado.

Si la solicitud se deniega debido a un token de sujeto no válido, recomendamos usar api.access.rejectInvalidSubjectToken en su lugar
para distinguir entre intentos de fuerza bruta sobre el token de sujeto y otros motivos para denegar la solicitud.

<ResponseField name="code" type="string">
  El código de error que justifica el rechazo del intercambio de tokens. Puede ser invalid\_request, server\_error o cualquier código personalizado.
</ResponseField>

<ResponseField name="reason" type="string">
  Una explicación en lenguaje claro de por qué se rechaza la solicitud de intercambio de tokens.
</ResponseField>

```js theme={null}
exports.onExecuteCustomTokenExchange = async (event, api) => {

  // 1. Validar subject_token
  const subject_token = await validateToken(event.transaction.subject_token, jwksUri);

  // 2. Aplicar la política de autorización al usuario
  const isAuthorized = await authorizeAccess(subject_token.sub);
  if (!isAuthorized) {
    api.access.deny('Unauthorized_login', 'User cannot login due to reason: X');
  }

  // si el usuario está autorizado, continuar según se indica aquí

};
```

<div id="apiaccessrejectinvalidsubjecttokenreason">
  ### `api.access.rejectInvalidSubjectToken(reason)`
</div>

Marca como no válido el token de sujeto proporcionado en la solicitud. Esto hará que la solicitud
se rechace con el código de error "invalid\_request".

Esto indicará a las funciones de Attack Protection que se ha proporcionado un token de sujeto no válido,
para que puedan aplicarse protecciones destinadas a evitar ataques de fuerza bruta contra el token de sujeto.

<ResponseField name="reason" type="string">
  Una explicación en lenguaje claro de por qué se rechaza la solicitud de intercambio de tokens.
</ResponseField>

```js theme={null}
exports.onExecuteCustomTokenExchange = async (event, api) => {

  try {
    // Validar subject_token
    const subject_token = await validateToken(event.transaction.subject_token, jwksUri);
    // establecer el usuario para la transacción
    api.authentication.setUserById(subject_token.id);

  } catch (error) {
    if (error.message === 'Invalid Token') {
      // Si el problema es específicamente que el subject_token no es válido
      console.error('Invalid Token error');
      api.access.rejectInvalidSubjectToken('Invalid subject_token');
    } else {
      // si hay cualquier otro error inesperado, lanzar un error de servidor
      throw error;
    }
  }

};
```

<div id="apiauthentication">
  ## `api.authentication`
</div>

Indica el resultado de la autenticación del token de sujeto para especificar el usuario para el que se emitirán los tokens.

<div id="apiauthenticationsetuserbyiduser_id">
  ### `api.authentication.setUserById(user_id)`
</div>

Indica el usuario correspondiente al subject\_token proporcionando el userId. La solicitud de intercambio de tokens emitirá tokens para este usuario.
Debe ser un usuario existente.
Nota: La acción Custom Token Exchange debe llamar a exactamente una de estas opciones: api.authentication.setUserByConnection o api.authentication.setUserById.

<ResponseField name="user_id" type="string">
  El ID del usuario; debe corresponder a un usuario existente.
</ResponseField>

```js theme={null}
exports.onExecuteCustomTokenExchange = async (event, api) => {

  // 1. Validar subject_token
  const subject_token = await validateToken(event.transaction.subject_token, jwksUri);

  // 2. Aplicar la política de autorización al usuario
  const isAuthorized = await authorizeAccess(subject_token.sub);
  if (!isAuthorized) {
    api.access.deny('Unauthorized_login', 'User cannot login due to reason: X');
  }

  // 3. Establecer el usuario para la transacción
  api.authentication.setUserById(subject_token.sub);

  return;
};
```

<div id="apiauthenticationsetuserbyconnectionconnection_name-user_attributes-options">
  ### `api.authentication.setUserByConnection(connection_name, user_attributes, options)`
</div>

Indica el usuario correspondiente al `subject_token` proporcionando una conexión y los atributos del usuario.
La solicitud de intercambio de tokens emitirá tokens para este usuario.

Puede tratarse de un usuario existente o de uno nuevo. Si el usuario no existe, se creará.
La propiedad `user_id` de `user_profile` se utilizará para determinar si el usuario ya existe.

Nota: La Action Custom Token Exchange debe llamar exactamente a una de estas opciones: `api.authentication.setUserByConnection` o `api.authentication.setUserById`.

<ResponseField name="connection_name" type="string">
  Nombre de la conexión en la que debe almacenarse el usuario.
</ResponseField>

<ResponseField name="user_attributes" type="customtokenexchangesetuserbyconnectionuserattributes">
  Los atributos del perfil del usuario, incluidos `user_id` y, opcionalmente, otros atributos como `email`, `name`, etc.

  El campo `user_id` es obligatorio y debe ser el identificador único del usuario dentro de la conexión;
  se utilizará para determinar si el usuario existe o si debe crearse. En el caso de usuarios existentes, este `user_id`
  puede encontrarse inspeccionando el array `identities` del perfil de usuario normalizado.

  Si el usuario ya existe, no se pueden actualizar los siguientes atributos del usuario: `email`, `email_verified`, `phone`, `phone_verified`, `username`.
  Si no coinciden con el usuario existente, se devolverá un error.

  <Expandable title="propiedades de user_attributes" defaultOpen>
    <ResponseField name="email" type="string" post={["optional"]}>
      El correo electrónico del usuario.
    </ResponseField>

    <ResponseField name="email_verified" type="boolean" post={["optional"]}>
      Indica si esta dirección de correo electrónico está verificada (`true`) o no verificada (`false`).
    </ResponseField>

    <ResponseField name="family_name" type="string" post={["optional"]}>
      Los apellidos del usuario.
    </ResponseField>

    <ResponseField name="given_name" type="string" post={["optional"]}>
      El nombre del usuario.
    </ResponseField>

    <ResponseField name="name" type="string" post={["optional"]}>
      El nombre completo del usuario.
    </ResponseField>

    <ResponseField name="nickname" type="string" post={["optional"]}>
      El apodo del usuario.
    </ResponseField>

    <ResponseField name="phone_number" type="string" post={["optional"]}>
      El número de teléfono del usuario (de acuerdo con la recomendación E.164).
    </ResponseField>

    <ResponseField name="phone_verified" type="boolean" post={["optional"]}>
      Indica si este número de teléfono ha sido verificado (`true`) o no (`false`).
    </ResponseField>

    <ResponseField name="picture" type="string" post={["optional"]}>
      Un URI que apunta a la imagen del usuario.
    </ResponseField>

    <ResponseField name="user_id" type="string">
      El identificador único del usuario dentro de la conexión.
    </ResponseField>

    <ResponseField name="username" type="string" post={["optional"]}>
      El username del usuario.
    </ResponseField>

    <ResponseField name="verify_email" type="boolean" post={["optional"]}>
      Indica si el usuario recibirá un correo electrónico de verificación después de la creación (`true`) o no recibirá ningún correo electrónico (`false`).
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="options" type="customtokenexchangesetuserbyconnectionoptions">
  Opciones para controlar el comportamiento del comando `setUserByConnection`.

  * `creationBehavior` - comportamiento que se aplicará si no existe ningún usuario con el `user_id` especificado en la conexión.
    Puede ser `create_if_not_exists`, lo que hará que se cree un nuevo usuario con los atributos de usuario proporcionados;
    o `none`, lo que hará que no se cree ningún usuario y que se devuelva un error si no existe ningún usuario.

  * `updateBehavior` - comportamiento que se aplicará si ya existe en la conexión un usuario con el `user_id` especificado.
    Puede ser `replace`, lo que hace que los atributos del usuario existente se sustituyan por los atributos de usuario
    especificados; o `none`, lo que significa que el usuario existente no se modificará.

  <Expandable title="propiedades de options" defaultOpen>
    <ResponseField name="creationBehavior" type="string">
      Comportamiento que se aplicará si no existe ningún usuario con el `user_id` especificado en la conexión.

      Valores permitidos: `create_if_not_exists`, `none`
    </ResponseField>

    <ResponseField name="updateBehavior" type="string">
      Comportamiento que se aplicará si ya existe en la conexión un usuario con el `user_id` especificado.

      Valores permitidos: `none`, `replace`
    </ResponseField>
  </Expandable>
</ResponseField>

```js Set user by connection with full profile attributes theme={null}
exports.onExecuteCustomTokenExchange = async (event, api) => {

  // 1. Validar subject_token
  const subject_token = await validateToken(event.transaction.subject_token, jwksUri);

  // 2. Aplicar la política de autorización al usuario
  const isAuthorized = await authorizeAccess(subject_token.sub);
  if (!isAuthorized) {
    api.access.deny('Unauthorized_login', 'User cannot login due to reason: X');
  }

  // 3. Establecer el usuario para la transacción
  api.authentication.setUserByConnection(
    'My Connection',
    {
      user_id: subject_token.sub,
      email: subject_token.email,
      email_verified: subject_token.email_verified,
      phone_number: subject_token.phone_number,
      phone_verified: subject_token.phone_number_verified,
      username: subject_token.preferred_username,
      name: subject_token.name,
      given_name: subject_token.given_name,
      family_name: subject_token.family_name,
      nickname: subject_token.nickname,
      verify_email: false
    },
    {
      creationBehavior: 'create_if_not_exists',
      updateBehavior: 'none'
    }
  );

  return;
};
```

```js Create a user without verifying email theme={null}
exports.onExecuteCustomTokenExchange = async (event, api) => {

  // Validar subject_token
  const subject_token = await validateToken(event.transaction.subject_token, jwksUri);

  // Crear un usuario sin verificar el correo electrónico
  api.authentication.setUserByConnection(
    'My Connection',
    {
      user_id: subject_token.sub,
      email: subject_token.email,
      email_verified: false,
      verify_email: false
    },
    {
      creationBehavior: 'create_if_not_exists',
      updateBehavior: 'none'
    }
  );

  return;
};
```

<div id="apiauthenticationsetorganizationorganization_id_or_name">
  ### `api.authentication.setOrganization(organization_id_or_name)`
</div>

Establece la organización del usuario asociado al intercambio de tokens.

<ResponseField name="organization_id_or_name" type="string">
  El id o el nombre de la organización que se establecerá para el usuario.
</ResponseField>

```js theme={null}
exports.onExecuteCustomTokenExchange = async (event, api) => {

  // 1. Validar subject_token
  const subject_token = await validateToken(event.transaction.subject_token, jwksUri);

  // 2. Aplicar la política de autorización al usuario
  const isAuthorized = await authorizeAccess(subject_token.sub);
  if (!isAuthorized) {
    api.access.deny('Unauthorized_login', 'User cannot login due to reason: X');
  }

  // 3. Establecer la organización para la transacción
  api.authentication.setOrganization('org_xS525r979AS33MSf');

  // 4. Establecer el usuario para la transacción. También puede usar setUserByConnection()
  api.authentication.setUserById(subject_token.sub);

  return;
};
```

<div id="apiauthenticationsetactoractor">
  ### `api.authentication.setActor(actor)`
</div>

Establece el actor para el intercambio de tokens a fin de representar a la entidad que actúa en nombre del sujeto.
Debe usarse junto con los comandos setUserById o SetUserByConnection. Llamar a setActor es opcional.
Recibir un actor\_token en la solicitud no genera automáticamente un claim `act`; la Action debe llamar explícitamente a este método.
No se emiten Tokens de actualización cuando se establece un actor para la transacción.

<ResponseField name="actor" type="actorparams">
  Un objeto anidado que representa una cadena de delegación. Se permiten hasta 4 niveles adicionales de `act`
  (5 actores en total, incluido el actor raíz). Para cada nivel, el campo `sub` es obligatorio; se pueden proporcionar hasta 5 propiedades
  personalizadas adicionales (valores de tipo cadena, booleano o numérico).

  <Expandable title="propiedades del actor" defaultOpen>
    <ResponseField name="sub" type="string" />

    <ResponseField name="act" type="dictionary" post={["optional"]}>
      <Expandable title="propiedades de `act`" defaultOpen>
        <ResponseField name="sub" type="string" />

        <ResponseField name="act" type="dictionary" post={["optional"]}>
          <Expandable title="propiedades de `act`" defaultOpen>
            <ResponseField name="sub" type="string" />

            <ResponseField name="act" type="dictionary" post={["optional"]}>
              <Expandable title="propiedades de `act`">
                <ResponseField name="sub" type="string" />

                <ResponseField name="act" type="dictionary" post={["optional"]}>
                  <Expandable title="propiedades de `act`">
                    <ResponseField name="sub" type="string" />

                    <ResponseField name="act" type="undefined" post={["optional"]} />
                  </Expandable>
                </ResponseField>
              </Expandable>
            </ResponseField>
          </Expandable>
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

```js theme={null}
exports.onExecuteCustomTokenExchange = async (event, api) => {

  // 1. Validar subject_token
  const subject_token = await validateToken(event.transaction.subject_token, jwksUri);
  const actor_token = await validateToken(event.transaction.actor_token, jwksUri);

  // 2. Establecer el actor para la transacción
  api.authentication.setActor({ sub: actor_token.sub });

  // 3. Establecer el usuario para la transacción
  api.authentication.setUserById(subject_token.sub);

  return;
};
```

<div id="apiuser">
  ## `api.user`
</div>

Solicita cambios en el usuario correspondiente al token de sujeto.

<div id="apiusersetappmetadatakey-value">
  ### `api.user.setAppMetadata(key, value)`
</div>

Establece metadatos específicos de la aplicación para el usuario asociado al token de sujeto.

<ResponseField name="key" type="string">
  La propiedad de metadatos que se va a establecer.
</ResponseField>

<ResponseField name="value" type="unknown">
  El valor de la propiedad de metadatos. Se puede establecer en `null` para eliminar la
  propiedad de metadatos.
</ResponseField>

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

  // establecer el usuario para la transacción
  api.authentication.setUserById(subject_token.id);

  // establecer el grupo de usuario según la información contenida en subject_token
  api.user.setAppMetadata('group', subject_token.group);

  return;
};
```

<div id="apiusersetusermetadatakey-value">
  ### `api.user.setUserMetadata(key, value)`
</div>

Establece metadatos generales para el usuario correspondiente al token de sujeto.

<ResponseField name="key" type="string">
  La propiedad de metadatos que se va a establecer.
</ResponseField>

<ResponseField name="value" type="unknown">
  El valor de la propiedad de metadatos. Puede establecerse en `null` para eliminar la
  propiedad de metadatos.
</ResponseField>

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

  // establecer el usuario para la transacción
  api.authentication.setUserById(subject_token.id);

  // establecer preferred_locale del usuario según la información contenida en subject_token
  api.user.setUserMetadata('preferred_locale', subject_token.locale);

  return;
};
```

<div id="apicache">
  ## `api.cache`
</div>

Permite almacenar y recuperar datos que persisten entre ejecuciones.

<div id="apicachedeletekey">
  ### `api.cache.delete(key)`
</div>

Elimina el registro que describe un valor almacenado en caché en la
clave proporcionada, si existe.

<ResponseField name="key" type="string">
  La clave del registro de caché que se eliminará.
</ResponseField>

<div id="apicachegetkey">
  ### `api.cache.get(key)`
</div>

Recupera un registro que describe un valor almacenado en caché en la clave proporcionada,
si existe. Si se encuentra un registro, el valor almacenado en caché está disponible
en la propiedad `value` del objeto devuelto.

<ResponseField name="key" type="string">
  La clave del registro almacenado en la caché.
</ResponseField>

<div id="apicachesetkey-value-options">
  ### `api.cache.set(key, value, options)`
</div>

Almacena o actualiza un valor de tipo cadena en la caché con la clave especificada.

Los valores almacenados en esta caché se limitan al Trigger en el que
se establecen. Están sujetos a los [límites de caché de Actions](https://auth0.com/docs/customize/actions/limitations).

Los valores almacenados de esta forma tendrán una duración de *hasta* los valores
`ttl` o `expires_at` especificados. Si no se especifica ninguna duración, se usará
una duración predeterminada de 15 minutos. La duración no puede superar el máximo
indicado en [límites de caché de Actions](https://auth0.com/docs/customize/actions/limitations).

**Importante**: Esta caché está diseñada para datos efímeros y de corta duración. Es posible que los elementos no estén
disponibles en transacciones posteriores, aunque sigan dentro de la duración especificada.

<ResponseField name="key" type="string">
  La clave del registro que se almacenará.
</ResponseField>

<ResponseField name="value" type="string">
  El valor del registro que se almacenará.
</ResponseField>

<ResponseField name="options" type="cachesetoptions" post={["optional"]}>
  Opciones para ajustar el comportamiento de la caché.

  <Expandable title="propiedades de options" defaultOpen>
    <ResponseField name="expires_at" type="number" post={["optional"]}>
      La hora absoluta de vencimiento, en milisegundos desde la época Unix.
      Aunque los registros en caché pueden eliminarse antes, nunca
      permanecerán más allá del valor `expires_at` proporcionado.

      *Nota*: No debe proporcionarse este valor si también se proporcionó
      un valor para `ttl`. Si se proporcionan ambas opciones, se
      usará el vencimiento más próximo de las dos.
    </ResponseField>

    <ResponseField name="ttl" type="number" post={["optional"]}>
      El valor de tiempo de vida de esta entrada de caché, en milisegundos.
      Aunque los valores en caché pueden eliminarse antes, nunca
      permanecerán más allá del valor `ttl` proporcionado.

      *Nota*: No debe proporcionarse este valor si también se proporcionó
      un valor para `expires_at`. Si se proporcionan ambas opciones, se
      usará el vencimiento más próximo de las dos.
    </ResponseField>
  </Expandable>
</ResponseField>
