> ## 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.

> Aprenda a usar Hooks para cambiar alcances y agregar claims personalizados al token de acceso obtenido mediante el flujo de credenciales del cliente.

# Personalizar tokens con Hooks mediante el flujo de credenciales del cliente

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****ENMASCARADO*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

<Warning>
  La fecha de fin de vida (EOL) de Rules y Hooks será el **18 de noviembre de 2026**, y ya no están disponibles para los nuevos inquilinos creados a partir del **16 de octubre de 2023**. Los inquilinos existentes con Hooks activos conservarán el acceso al producto Hooks hasta su fin de vida.

  Recomendamos encarecidamente que uses Actions para extender Auth0. Con Actions, tienes acceso a información de tipos avanzada, documentación integrada y paquetes públicos de `npm`, y puedes conectar integraciones externas que mejoran tu experiencia general de extensibilidad. Para obtener más información sobre lo que ofrece Actions, consulta [Understand How Auth0 Actions Work](/es/docs/customize/actions/actions-overview).

  Para ayudarte con la migración, ofrecemos guías que te ayudarán a [migrar de Rules a Actions](/es/docs/customize/actions/migrate/migrate-from-rules-to-actions) y [migrar de Hooks a Actions](/es/docs/customize/actions/migrate/migrate-from-hooks-to-actions). También contamos con una página dedicada, [Move to Actions](https://auth0.com/extensibility/movetoactions), que destaca comparaciones de funcionalidades, [una demostración de Actions](https://www.youtube.com/watch?v=UesFSY1klrI) y otros recursos para acompañarte en tu proceso de migración.

  Para obtener más información sobre la desaprobación de Rules y Hooks, lee nuestra entrada del blog: [Preparing for Rules and Hooks End of Life](https://auth0.com/blog/preparing-for-rules-and-hooks-end-of-life/).
</Warning>

<Warning>
  Como tenemos previsto eliminar las funciones de Rules y Hooks en 2026, debes crear nuevos Rules o Hooks solo en tu entorno de desarrollo y únicamente para probar la migración a Actions.

  Para aprender a migrar tus Rules a Actions, consulta [Migrate from Rules to Actions](/es/docs/customize/actions/migrate/migrate-from-rules-to-actions). Para aprender a migrar tus Hooks a Actions, consulta [Migrate from Hooks to Actions](/es/docs/customize/actions/migrate/migrate-from-hooks-to-actions).
</Warning>

Puedes cambiar alcances y agregar claims personalizados en los tokens emitidos mediante el [flujo de credenciales del cliente](/es/docs/get-started/authentication-and-authorization-flow/client-credentials-flow) agregando [Hooks](/es/docs/customize/hooks).

Hooks te permiten personalizar el comportamiento de Auth0 con código de Node.js. Son funciones seguras y autocontenidas asociadas a puntos de extensibilidad específicos de la plataforma Auth0 (como el flujo de credenciales del cliente). Auth0 invoca los Hooks en tiempo de ejecución para ejecutar tu lógica personalizada.

Puedes administrar Hooks mediante el <Tooltip tip="Auth0 Dashboard: el producto principal de Auth0 para configurar tus servicios." cta="Ver glosario" href="/es/docs/glossary?term=Auth0+Dashboard">Auth0 Dashboard</Tooltip> o la <Tooltip tip="Auth0 Dashboard: el producto principal de Auth0 para configurar tus servicios." cta="Ver glosario" href="/es/docs/glossary?term=Management+API">Management API</Tooltip>.

<Warning>
  Aunque puedes crear varios hooks para un punto de extensibilidad determinado, cada punto de extensibilidad solo puede tener un hook habilitado a la vez. Cualquier hook adicional que crees para ese punto de extensibilidad se deshabilitará automáticamente, por lo que debes habilitarlo explícitamente. El hook habilitado se ejecutará para todas las aplicaciones y API.
</Warning>

<div id="prerequisites">
  ## Requisitos previos
</div>

Antes de comenzar este tutorial, debe:

* [Registrar su API en Auth0](/es/docs/get-started/auth0-overview/set-up-apis)

  * [Agregar los permisos adecuados para la API](/es/docs/get-started/apis/add-api-permissions)
* [Registrar la aplicación M2M en Auth0](/es/docs/get-started/auth0-overview/create-applications/machine-to-machine-apps).

  * Seleccione **Application Type** como **Machine to Machine Applications**.
  * Elija la API que registró previamente.
  * Autorice la aplicación M2M para llamar a su API.

<div id="steps">
  ## Pasos
</div>

1. **Crear Hook**: Crea un Hook para personalizar tu token.
2. **Probar Hook**: Prueba tu nuevo Hook ejecutando un flujo de credenciales del cliente y decodificando el token de acceso.

<div id="create-a-hook">
  ### Crear un Hook
</div>

En este ejemplo, harás lo siguiente:

* agregar un claim arbitrario (`https://foo.com/claim`) al [Token de acceso](/es/docs/secure/tokens/access-tokens)
* agregar un permiso adicional a la API que configuraste

Crea un Hook para personalizar el token. Cuando se te pida elegir un punto de extensibilidad, selecciona `Client Credentials Exchange` y agrega el siguiente código en el editor:

```js lines theme={null}
module.exports = function(client, scope, audience, context, cb) {
  var access_token = {};
  access_token['https://foo.com/claim'] = 'bar';
  access_token.scope = scope;
  access_token.scope.push('extra');
  cb(null, access_token);
};
```

<Warning>
  Auth0 devuelve la información del perfil en un formato estructurado de claims, tal como se define en la [especificación de OpenID Connect (OIDC)](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). Esto significa que los claims personalizados agregados a los ID Tokens o a los tokens de acceso deben [ajustarse a las directrices y restricciones](/es/docs/secure/tokens/json-web-tokens/create-custom-claims) para evitar posibles colisiones.
</Warning>

<div id="test-your-hook">
  ### Prueba tu Hook
</div>

Para probar el hook que acabas de crear, debes ejecutar un intercambio de credenciales de cliente, obtener el <Tooltip tip="Token de acceso: credencial de autorización, en forma de una cadena opaca o de un JWT, que se utiliza para acceder a una API." cta="Ver glosario" href="/es/docs/glossary?term=Access+Token">Token de acceso</Tooltip>, decodificarlo y revisar su contenido.

<div id="get-token">
  #### Obtener un token
</div>

Para obtener un token, realice una solicitud `POST` al [endpoint del flujo de credenciales del cliente](https://auth0.com/docs/api/authentication#client-credentials-flow). Asegúrese de reemplazar los marcadores de posición CLIENT\_ID, CLIENT\_SECRET y API\_IDENTIFIER por el <Tooltip tip="ID de cliente: Valor de identificación otorgado por Auth0 a su recurso registrado." cta="Ver glosario" href="/es/docs/glossary?term=Client+ID">ID de cliente</Tooltip> de su aplicación, el <Tooltip tip="Secreto del cliente: Secreto utilizado por un cliente (aplicación) para autenticarse ante el Servidor de autorización; solo deben conocerlo el cliente y el Servidor de autorización, y debe ser lo suficientemente aleatorio como para que no pueda adivinarse." cta="Ver glosario" href="/es/docs/glossary?term=Client+Secret">Secreto del cliente</Tooltip> de su aplicación y el Identificador de su API, respectivamente. Puede encontrar el ID de cliente y el Secreto del cliente en la configuración de su [Aplicación](https://manage.auth0.com/#/applications) y el Identificador de la API en la configuración de su [API](https://manage.auth0.com/#/apis).

<AuthCodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://{yourDomain}/oauth/token' \
    --header 'content-type: application/x-www-form-urlencoded' \
    --data grant_type=client_credentials \
    --data 'client_id={yourClientId}' \
    --data client_secret={yourClientSecret} \
    --data audience=YOUR_API_IDENTIFIER
  ```

  ```csharp C# theme={null}
  var client = new RestClient("https://{yourDomain}/oauth/token");
  var request = new RestRequest(Method.POST);
  request.AddHeader("content-type", "application/x-www-form-urlencoded");
  request.AddParameter("application/x-www-form-urlencoded", "grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER", ParameterType.RequestBody);
  IRestResponse response = client.Execute(request);
  ```

  ```go Go theme={null}
  package main

  import (
  	"fmt"
  	"strings"
  	"net/http"
  	"io/ioutil"
  )

  func main() {

  	url := "https://{yourDomain}/oauth/token"

  	payload := strings.NewReader("grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER")

  	req, _ := http.NewRequest("POST", url, payload)

  	req.Header.Add("content-type", "application/x-www-form-urlencoded")

  	res, _ := http.DefaultClient.Do(req)

  	defer res.Body.Close()
  	body, _ := ioutil.ReadAll(res.Body)

  	fmt.Println(res)
  	fmt.Println(string(body))

  }
  ```

  ```java Java theme={null}
  HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
    .header("content-type", "application/x-www-form-urlencoded")
    .body("grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER")
    .asString();
  ```

  ```javascript Node.JS theme={null}
  var axios = require("axios").default;

  var options = {
    method: 'POST',
    url: 'https://{yourDomain}/oauth/token',
    headers: {'content-type': 'application/x-www-form-urlencoded'},
    data: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: '{yourClientId}',
      client_secret: '{yourClientSecret}',
      audience: 'YOUR_API_IDENTIFIER'
    })
  };

  axios.request(options).then(function (response) {
    console.log(response.data);
  }).catch(function (error) {
    console.error(error);
  });
  ```

  ```php PHP theme={null}
  $curl = curl_init();

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://{yourDomain}/oauth/token",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => "grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER",
    CURLOPT_HTTPHEADER => [
      "content-type: application/x-www-form-urlencoded"
    ],
  ]);

  $response = curl_exec($curl);
  $err = curl_error($curl);

  curl_close($curl);

  if ($err) {
    echo "cURL Error #:" . $err;
  } else {
    echo $response;
  }
  ```

  ```python Python theme={null}
  import http.client

  conn = http.client.HTTPSConnection("")

  payload = "grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER"

  headers = { 'content-type': "application/x-www-form-urlencoded" }

  conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)

  res = conn.getresponse()
  data = res.read()

  print(data.decode("utf-8"))
  ```

  ```ruby Ruby theme={null}
  require 'uri'
  require 'net/http'
  require 'openssl'

  url = URI("https://{yourDomain}/oauth/token")

  http = Net::HTTP.new(url.host, url.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE

  request = Net::HTTP::Post.new(url)
  request["content-type"] = 'application/x-www-form-urlencoded'
  request.body = "grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER"

  response = http.request(request)
  puts response.read_body
  ```
</AuthCodeGroup>

Una respuesta exitosa incluirá:

* un `access_token`,
* su tiempo de expiración en segundos (`expires_in`),
* el tipo de token establecido en `Bearer` (`token_type`), y
* un permiso `extra` (`scope`) (que agregó tu Hook)

```json lines theme={null}
HTTP/1.1 200 OK
Content-Type: application/json
{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5ESTFNa05DTVRGQlJrVTRORVF6UXpFMk1qZEVNVVEzT1VORk5ESTVSVU5GUXpnM1FrRTFNdyJ9.eyJpc3MiOiJodHRwczovL2RlbW8tYWNjb3VudC5hdXRoMC3jb20vIiwic3ViIjoic0FRSlFpQmYxREw0c2lqSVZCb2pFRUZvcmRoa0o4WUNAY2xpZW50cyIsImF1ZCI6ImRlbW8tYWNjb3VudC5hcGkiLCJleHAiOjE0ODc3NjU8NjYsImlhdCI6MTQ4NzY3OTI2Niwic2NvcGUiOiJyZWFkOmRhdGEgZXh0cmEiLCJodHRwczovL2Zvby5jb20vY2xhaW0iOiKoPXIifQ.da-48mHY_7esfLZpvHWWL8sIH1j_2mUYAB49c-B472lCdsNFvpaLoq6OKQyhnqk9_aW_Xhfkusos3FECTrLFvf-qwQK70QtwbkbVye_IuPSTAYdQ2T-XTzGDm9Nmmy5Iwl9rNYLxVs2OoCdfpVMyda0OaI0AfHBgEdKWluTP67OOnV_dF3KpuwtK3dPKWTCo2j9VCa7X1I4h0CNuM79DHhY2wO7sL8WBej7BSNA3N2TUsp_YTWWfrvsr_vVhJf-32G7w_12ms_PNFUwj2C30ZZIPWc-uEkDztyMLdI-lu9q9TLrLdr0dOhfrtfkdeJx4pUSiHdJHf42kg7UAVK6JcA",
  "expires_in": 86400,
  "scope": "extra",
  "token_type": "Bearer"
}
```

<div id="decode-token">
  #### Decodificar el token
</div>

La forma más sencilla de decodificar el token de acceso y revisar su contenido es usar el [depurador de JWT.io](https://jwt.io/#debugger-io).

Copia tu token de acceso y pégalo en el editor. El <Tooltip tip="JSON Web Token (JWT): formato estándar de ID Token (y, a menudo, de Token de acceso) que se usa para representar claims de forma segura entre dos partes." cta="Ver glosario" href="/es/docs/glossary?term=JWT">JWT</Tooltip> se decodifica automáticamente y se muestra su contenido.

Ten en cuenta que tu Hook ha establecido los dos últimos elementos de la **Carga útil**:

* `"scope": "extra"`
* `"https://foo.com/claim": "bar"`

<div id="learn-more">
  ## Más información
</div>

* [Auth0 Hooks](/es/docs/customize/hooks)
* [Flujo de credenciales del cliente](/es/docs/get-started/authentication-and-authorization-flow/client-credentials-flow)
* [Llame a su API mediante el flujo de credenciales del cliente](/es/docs/get-started/authentication-and-authorization-flow/client-credentials-flow/call-your-api-using-the-client-credentials-flow)
