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

> Obtén información sobre cómo llamar a tu API desde una aplicación nativa, móvil o de una sola página mediante el flujo de código de autorización con PKCE.

# Llama a tu API mediante el flujo de código de autorización con PKCE

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>;
};

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Este tutorial te ayuda a llamar a tu propia API desde una aplicación nativa, móvil o de una sola página mediante el Flujo de código de autorización con PKCE. Para saber cómo funciona el flujo y por qué deberías usarlo, consulta [Flujo de código de autorización con Proof Key for Code Exchange (PKCE)](/es/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce). Para aprender a añadir Login a tu aplicación nativa, móvil o de una sola página, consulta [Añadir Login mediante el Flujo de código de autorización con PKCE](/es/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/add-login-using-the-authorization-code-flow-with-pkce).
</Callout>

Auth0 facilita que tu aplicación implemente el Flujo de código de autorización con Proof Key for Code Exchange (PKCE) mediante:

* [SDK móviles de Auth0](/es/docs/libraries) y [SDK de aplicaciones de una sola página de Auth0](/es/docs/libraries/auth0-single-page-app-sdk): la forma más sencilla de implementar el flujo, ya que harán gran parte del trabajo por ti. Nuestros [Quickstarts para móviles](/es/docs/quickstart/native) y [Quickstarts para aplicaciones de una sola página](/es/docs/quickstart/spa) te guiarán a lo largo del proceso.
* [Authentication API](https://auth0.com/docs/api/authentication): si prefieres crear tu propia solución, sigue leyendo para aprender a llamar a nuestra API directamente.

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

**Antes de comenzar este tutorial:**

* [Registre la aplicación en Auth0](/es/docs/get-started/auth0-overview/create-applications/native-apps).

  * Seleccione **Native** o **Single-Page App** en **Tipo de aplicación**, según corresponda a su aplicación.
  * Agregue `{yourCallbackUrl}` como **URL de devolución de llamada permitida**. El formato de la URL de devolución de llamada varía según el tipo de aplicación y la plataforma. Para obtener más información sobre el formato correspondiente a su tipo de aplicación y plataforma, consulte nuestros [Quickstarts de Native/Mobile](/es/docs/quickstart/native) y [Quickstarts de Single-Page App](/es/docs/quickstart/spa).
  * Asegúrese de que los **Tipos de concesión** de la aplicación incluyan **código de autorización**. Para saber cómo hacerlo, consulte [Actualizar tipos de concesión](/es/docs/get-started/applications/update-grant-types).
  * Si quiere que su aplicación pueda usar tokens de actualización, asegúrese de que los **Tipos de concesión** de la aplicación incluyan **Token de actualización**. Para saber cómo hacerlo, consulte [Actualizar tipos de concesión](/es/docs/get-started/applications/update-grant-types). Para obtener más información sobre los tokens de actualización, consulte [Tokens de actualización](/es/docs/secure/tokens/refresh-tokens).
* [Registre su API en Auth0](/es/docs/get-started/architecture-scenarios/mobile-api/part-2#create-the-api)

  * Si quiere que su API reciba tokens de actualización para obtener tokens nuevos cuando los anteriores expiren, habilite **Permitir acceso sin conexión**.

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

1. [Crear verificador de código](#create-code-verifier):
   Genera un `code_verifier` que se enviará a Auth0 para solicitar tokens.
2. [Crear desafío de código](#create-code-challenge):
   Genera un `code_challenge` a partir del `code_verifier` que se enviará a Auth0 para solicitar un `authorization_code`.
3. [Autorizar al usuario](#authorize-user):
   Solicita la autorización del usuario y redirígelo a tu aplicación con un `authorization_code`.
4. [Solicitar tokens](#request-tokens):
   Intercambia tu `authorization_code` y `code_verifier` por tokens.
5. [Llamar a la API](#call-api):
   Usa el Token de acceso obtenido para llamar a tu API.
6. [Tokens de actualización](#refresh-tokens):
   Usa un token de actualización para solicitar nuevos tokens cuando los actuales expiren.

Opcional: [Explorar ejemplos de casos de uso](#sample-use-cases).

<div id="create-code-verifier">
  ### Crear el verificador de código
</div>

Cree un `code_verifier`, que es una clave aleatoria codificada en Base64 y criptográficamente segura, que posteriormente se enviará a Auth0 para solicitar tokens.

<div id="javascript-sample">
  #### Ejemplo de JavaScript
</div>

```javascript lines theme={null}
// Dependencia: módulo crypto de Node.js
// https://nodejs.org/api/crypto.html#crypto_crypto
function base64URLEncode(str) {
    return str.toString('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
}
var verifier = base64URLEncode(crypto.randomBytes(32));
```

<div id="java-sample">
  #### Ejemplo en Java
</div>

```java lines theme={null}
// Dependencia: Apache Commons Codec
// https://commons.apache.org/proper/commons-codec/
// Importar la clase Base64.
// import org.apache.commons.codec.binary.Base64;
SecureRandom sr = new SecureRandom();
byte[] code = new byte[32];
sr.nextBytes(code);
String verifier = Base64.getUrlEncoder().withoutPadding().encodeToString(code);
```

<div id="android-sample">
  #### Ejemplo para Android
</div>

```kotlin lines theme={null}
// Ver https://developer.android.com/reference/android/util/Base64
// Importar la clase Base64
// import android.util.Base64;
SecureRandom sr = new SecureRandom();
byte[] code = new byte[32];
sr.nextBytes(code);
String verifier = Base64.encodeToString(code, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
```

<div id="swift-5-sample">
  #### Ejemplo en Swift 5
</div>

```swift lines theme={null}
var buffer = [UInt8](repeating: 0, count: 32)
_ = SecRandomCopyBytes(kSecRandomDefault, buffer.count, &buffer)
let verifier = Data(buffer).base64EncodedString()
    .replacingOccurrences(of: "+", with: "-")
    .replacingOccurrences(of: "/", with: "_")
    .replacingOccurrences(of: "=", with: "")
```

<div id="objective-c-sample">
  #### Ejemplo en Objective-C
</div>

```objc lines theme={null}
NSMutableData *data = [NSMutableData dataWithLength:32];
int result __attribute__((unused)) = SecRandomCopyBytes(kSecRandomDefault, 32, data.mutableBytes);
NSString *verifier = [[[[data base64EncodedStringWithOptions:0]
                        stringByReplacingOccurrencesOfString:@"+" withString:@"-"]
                        stringByReplacingOccurrencesOfString:@"/" withString:@"_"]
                        stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];
```

<div id="create-code-challenge">
  ### Crear el desafío de código
</div>

Genera un `code_challenge` a partir del `code_verifier` que se enviará a Auth0 para solicitar un `authorization_code`.

#### Ejemplo de Javascript

```javascript lines theme={null}
// Dependencia: módulo crypto de Node.js
// https://nodejs.org/api/crypto.html#crypto_crypto
function sha256(buffer) {
    return crypto.createHash('sha256').update(buffer).digest();
}
var challenge = base64URLEncode(sha256(verifier));
```

<div id="java-sample">
  #### Ejemplo en Java
</div>

```java lines theme={null}
// Dependencia: Apache Commons Codec
// https://commons.apache.org/proper/commons-codec/
// Importar la clase Base64.
// import org.apache.commons.codec.binary.Base64;
byte[] bytes = verifier.getBytes("US-ASCII");
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(bytes, 0, bytes.length);
byte[] digest = md.digest();
String challenge = Base64.encodeBase64URLSafeString(digest);
```

<div id="swift-5-sample">
  #### Ejemplo en Swift 5
</div>

```swift lines theme={null}
import CommonCrypto

// ...

guard let data = verifier.data(using: .utf8) else { return nil }
var buffer = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
_ = data.withUnsafeBytes {
    CC_SHA256($0.baseAddress, CC_LONG(data.count), &buffer)
}
let hash = Data(buffer)
let challenge = hash.base64EncodedString()
    .replacingOccurrences(of: "+", with: "-")
    .replacingOccurrences(of: "/", with: "_")
    .replacingOccurrences(of: "=", with: "")
```

<div id="objective-c-sample">
  #### Ejemplo en Objective-C
</div>

```objc lines theme={null}
// Dependencia: biblioteca Apple Common Crypto
// http://opensource.apple.com//source/CommonCrypto
u_int8_t buffer[CC_SHA256_DIGEST_LENGTH * sizeof(u_int8_t)];
memset(buffer, 0x0, CC_SHA256_DIGEST_LENGTH);
NSData *data = [verifier dataUsingEncoding:NSUTF8StringEncoding];
CC_SHA256([data bytes], (CC_LONG)[data length], buffer);
NSData *hash = [NSData dataWithBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
NSString *challenge = [[[[hash base64EncodedStringWithOptions:0]
                         stringByReplacingOccurrencesOfString:@"+" withString:@"-"]
                         stringByReplacingOccurrencesOfString:@"/" withString:@"_"]
                         stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];
```

<div id="authorize-user">
  ### Autorizar al usuario
</div>

Una vez que hayas creado el `code_verifier` y el `code_challenge`, debes obtener la autorización del usuario. Técnicamente, este es el inicio del <Tooltip tip="Flujo de autorización: concesión de autorización (o flujo de trabajo) especificado en el marco de OAuth 2.0." cta="Ver glosario" href="/es/docs/glossary?term=authorization+flow">flujo de autorización</Tooltip>, y este paso puede incluir uno o más de los siguientes procesos:

* Autenticar al usuario;
* Redirigir al usuario a un <Tooltip tip="Proveedor de identidad (IdP): servicio que almacena y administra identidades digitales." cta="Ver glosario" href="/es/docs/glossary?term=Identity+Provider">Proveedor de identidad</Tooltip> para gestionar la autenticación;
* Verificar si hay sesiones activas de [inicio de sesión único (SSO)](/es/docs/authenticate/single-sign-on);
* Obtener el consentimiento del usuario para el nivel de permisos solicitado, a menos que ya se haya otorgado previamente.

Para autorizar al usuario, tu aplicación debe dirigir al usuario a la [URL de autorización](https://auth0.com/docs/api/authentication#authorization-code-grant-pkce-), incluido el `code_challenge` que generaste en el paso anterior y el método que usaste para generarlo.

<div id="example-authorization-url">
  #### Ejemplo de URL de autorización
</div>

export const codeExample1 = `https://{yourDomain}/authorize?
    response_type=code&
    code_challenge={codeChallenge}&
    code_challenge_method=S256&
    client_id={yourClientId}&
    redirect_uri={yourCallbackUrl}&
    scope=SCOPE&
    audience={apiAudience}&
    state={state}`;

<AuthCodeBlock children={codeExample1} language="http" />

<div id="parameters">
  ##### Parámetros
</div>

Ten en cuenta que, para autorizar a un usuario al llamar a una API personalizada, debes:

* incluir un parámetro <Tooltip tip="Audiencia: identificador único de la audiencia de un token emitido. Se denomina aud en un token; su valor contiene el ID de una aplicación (ID de cliente) para un ID Token o de una API (identificador de API) para un token de acceso." cta="Ver glosario" href="/es/docs/glossary?term=audience">audiencia</Tooltip>
* puedes incluir alcances adicionales admitidos por la API de destino

| Nombre del parámetro    | Descripción                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `response_type`         | Indica el tipo de credencial que devolverá Auth0 (`code` o `token`). Para este flujo, el valor debe ser `code`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `code_challenge`        | Desafío generado a partir de `code_verifier`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `code_challenge_method` | Método utilizado para generar el desafío (por ejemplo, S256). La especificación PKCE define dos métodos, `S256` y `plain`; en este ejemplo se usa el primero y es el **único** compatible con Auth0, ya que el segundo no se recomienda.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `client_id`             | El ID de cliente de tu aplicación. Puedes encontrar este valor en la [configuración de la aplicación](https://manage.auth0.com/#/Applications/\{yourClientId}/settings).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `redirect_uri`          | La URL a la que Auth0 redirigirá el navegador después de que el usuario haya otorgado la autorización. El código de autorización estará disponible en el parámetro de URL `code`. Debes especificar esta URL como una URL de devolución de llamada válida en la [configuración de la aplicación](https://manage.auth0.com/#/Applications/\{yourClientId}/settings).<br /><br />**Advertencia:** Según la [especificación de OAuth 2.0](https://tools.ietf.org/html/rfc6749#section-3.1.2), Auth0 elimina todo lo que aparece después del hash y *no* respeta ningún fragmento.                                                                                                                                                                                                                                                                                                                   |
| `scope`                 | Los [alcances](/es/docs/get-started/apis/scopes) para los que quieres solicitar autorización. Deben estar separados por espacios. Puedes solicitar cualquiera de los [alcances estándar de OpenID Connect (OIDC)](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) sobre usuarios, como `profile` y `email`, [claims personalizados](/es/docs/secure/tokens/json-web-tokens/json-web-token-claims#custom-claims) que cumplan con un [formato con espacio de nombres](/es/docs/secure/tokens/json-web-tokens/create-custom-claims), o cualquier alcance admitido por la API de destino (por ejemplo, `read:contacts`). Incluye `offline_access` para obtener un [Token de actualización](/es/docs/glossary?term=Refresh+Token) (asegúrate de que el campo **Allow Offline Access** esté habilitado en la [configuración de la aplicación](https://manage.auth0.com/#/apis)). |
| `audience`              | El identificador único de la API a la que tu aplicación móvil quiere acceder. Usa el valor **Identifier** en la pestaña [Settings](https://manage.auth0.com/#/apis) de la API que creaste como parte de los requisitos previos de este tutorial.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `state`                 | (recomendado) Una cadena alfanumérica arbitraria y opaca que tu aplicación agrega a la solicitud inicial y que Auth0 incluye al redirigir de vuelta a tu aplicación. Para ver cómo usar este valor para prevenir ataques de Cross-site Request Forgery (CSRF), consulta [Mitigar ataques CSRF con parámetros state](/es/docs/secure/attack-protection/state-parameters).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `organization`          | (opcional) ID de la organización que se usará al autenticar a un usuario. Si no se proporciona y tu aplicación está configurada para **Display Organization Prompt**, el usuario podrá introducir el nombre de la organización al autenticarse.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `invitation`            | (opcional) ID del ticket de la invitación a la organización. Al [invitar a un miembro a una Organización](/es/docs/manage-users/organizations/configure-organizations/invite-members), tu aplicación debe gestionar la aceptación de la invitación reenviando los pares clave-valor `invitation` y `organization` cuando el usuario acepte la invitación.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |

Como ejemplo, tu fragmento HTML para la URL de autorización al llamar a una API podría verse así:

export const codeExample2 = `<a href="https://{yourDomain}/authorize?
  response_type=code&
  client_id={yourClientId}&
  code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
  code_challenge_method=S256&
  redirect_uri={yourCallbackUrl}&
  scope=appointments%20contacts&
  audience=appointments:api&
  state=xyzABC123">
  Iniciar sesión
</a>`;

<AuthCodeBlock children={codeExample2} language="html" />

<div id="response">
  #### Respuesta
</div>

Si todo sale bien, recibirá una respuesta `HTTP 302`. El código de autorización se incluye al final de la URL:

```http lines theme={null}
HTTP/1.1 302 Found
Location: {yourCallbackUrl}?code={authorizationCode}&state=xyzABC123
```

<div id="request-tokens">
  ### Solicitar tokens
</div>

Ahora que ya tiene un código de autorización, debe intercambiarlo por tokens. Con el código de autorización extraído (`code`) en el paso anterior, deberá realizar un `POST` a la [URL del token](https://auth0.com/docs/api/authentication#authorization-code-pkce-) y enviar también el `code_verifier`.

<div id="example-post-to-token-url">
  #### Ejemplo de una solicitud POST a la URL del token
</div>

<AuthCodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://{yourDomain}/oauth/token' \
    --header 'content-type: application/x-www-form-urlencoded' \
    --data grant_type=authorization_code \
    --data 'client_id={yourClientId}' \
    --data 'code_verifier={yourGeneratedCodeVerifier}' \
    --data 'code={yourAuthorizationCode}' \
    --data 'redirect_uri={https://yourApp/callback}'
  ```

  ```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=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}", 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=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}")

  	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=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}")
    .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: 'authorization_code',
      client_id: '{yourClientId}',
      code_verifier: '{yourGeneratedCodeVerifier}',
      code: '{yourAuthorizationCode}',
      redirect_uri: '{https://yourApp/callback}'
    })
  };

  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=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}",
    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=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}"

  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=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}"

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

<div id="parameters">
  ##### Parámetros
</div>

| Nombre del parámetro | Descripción                                                                                                                                                                                                                                                        |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `grant_type`         | Establécelo en "authorization\_code".                                                                                                                                                                                                                              |
| `code_verifier`      | La clave criptográficamente aleatoria que se generó en el primer paso de este tutorial.                                                                                                                                                                            |
| `code`               | El `authorization_code` obtenido en el paso anterior de este tutorial.                                                                                                                                                                                             |
| `client_id`          | El ID de cliente de tu aplicación. Puedes encontrar este valor en la [configuración de la aplicación](https://manage.auth0.com/#/Applications/\{yourClientId}/settings).                                                                                           |
| `redirect_uri`       | La URL de devolución de llamada válida configurada en la configuración de tu aplicación. Debe coincidir exactamente con el `redirect_uri` enviado a la URL de autorización en el paso anterior de este tutorial. Ten en cuenta que debe estar codificada como URL. |

<div id="response">
  #### Respuesta
</div>

Si todo sale bien, recibirás una respuesta HTTP 200 con una carga útil que incluye los valores `access_token`, `refresh_token`, `id_token` y `token_type`:

```json lines theme={null}
{
  "access_token":"eyJz93a...k4laUWw",
  "refresh_token":"GEbRxBN...edjnXbL",
  "id_token":"eyJ0XAi...4faeEoQ",
  "token_type":"Bearer",
  "expires_in":86400
}
```

<Warning>
  Valide sus tokens antes de guardarlos. Para obtener más información, consulte [Validar ID Token](/es/docs/secure/tokens/id-tokens/validate-id-tokens) y [Validar tokens de acceso](/es/docs/secure/tokens/access-tokens/validate-access-tokens).
</Warning>

[ID Token](/es/docs/secure/tokens/id-tokens) contiene información del usuario que debe decodificarse y extraerse.

[Los tokens de acceso](/es/docs/secure/tokens/access-tokens) se usan para llamar al [endpoint /userinfo de la API de autenticación de Auth0](https://auth0.com/docs/api/authentication#get-user-info) o a otra API. Si está llamando a su propia API, lo primero que deberá hacer es [verificar el token de acceso](/es/docs/secure/tokens/access-tokens/validate-access-tokens).

[Los tokens de actualización](/es/docs/secure/tokens/refresh-tokens) se usan para obtener un nuevo <Tooltip tip="Token de acceso: credencial de autorización, en forma de una cadena opaca o JWT, usada para acceder a una API." cta="Ver glosario" href="/es/docs/glossary?term=access+token">token de acceso</Tooltip> o <Tooltip tip="Token de acceso: credencial de autorización, en forma de una cadena opaca o JWT, usada para acceder a una API." cta="Ver glosario" href="/es/docs/glossary?term=ID+token">token de ID</Tooltip> después de que haya expirado el anterior. El `refresh_token` solo estará presente en la respuesta si incluyó el scope `offline_access` y habilitó **Allow Offline Access** para su API en el Dashboard.

<Warning>
  Los tokens de actualización deben almacenarse de forma segura, ya que permiten que un usuario permanezca autenticado prácticamente para siempre.
</Warning>

<div id="call-api">
  ### Llamar a la API
</div>

Para llamar a la API desde una aplicación nativa o móvil, la aplicación debe enviar el Token de acceso obtenido como Bearer Token en el encabezado Authorization de la solicitud HTTP.

<AuthCodeGroup>
  ```bash cURL lines theme={null}
  curl --request GET \
    --url https://myapi.com/api \
    --header 'authorization: Bearer {accessToken}' \
    --header 'content-type: application/json'
  ```

  ```csharp C# lines theme={null}
  var client = new RestClient("https://myapi.com/api");
  var request = new RestRequest(Method.GET);
  request.AddHeader("content-type", "application/json");
  request.AddHeader("authorization", "Bearer {accessToken}");
  IRestResponse response = client.Execute(request);
  ```

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

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

  func main() {

  	url := "https://myapi.com/api"

  	req, _ := http.NewRequest("GET", url, nil)

  	req.Header.Add("content-type", "application/json")
  	req.Header.Add("authorization", "Bearer {accessToken}")

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

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

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

  }
  ```

  ```java Java lines theme={null}
  HttpResponse response = Unirest.get("https://myapi.com/api")
    .header("content-type", "application/json")
    .header("authorization", "Bearer {accessToken}")
    .asString();
  ```

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

  var options = {
    method: 'GET',
    url: 'https://myapi.com/api',
    headers: {'content-type': 'application/json', authorization: 'Bearer {accessToken}'}
  };

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

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

  curl_setopt_array($curl, [
    CURLOPT_URL => "https://myapi.com/api",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => [
      "authorization: Bearer {accessToken}",
      "content-type: application/json"
    ],
  ]);

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

  curl_close($curl);

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

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

  conn = http.client.HTTPSConnection("myapi.com")

  headers = {
      'content-type': "application/json",
      'authorization': "Bearer {accessToken}"
      }

  conn.request("GET", "/api", headers=headers)

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

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

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

  url = URI("https://myapi.com/api")

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

  request = Net::HTTP::Get.new(url)
  request["content-type"] = 'application/json'
  request["authorization"] = 'Bearer {accessToken}'

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

<div id="refresh-tokens">
  ### Tokens de actualización
</div>

Ya recibió un [token de actualización](/es/docs/secure/tokens/refresh-tokens) si ha seguido este tutorial y completó lo siguiente:

* configuró su API para permitir acceso sin conexión
* incluyó el scope `offline_access` cuando inició la solicitud de autenticación a través del [endpoint de autorización](https://auth0.com/docs/api/authentication/reference#authorize-application).

Puede usar el <Tooltip tip="Token de actualización: token utilizado para obtener un Token de acceso renovado sin obligar a los usuarios a volver a iniciar sesión." cta="Ver glosario" href="/es/docs/glossary?term=Refresh+Token">Token de actualización</Tooltip> para obtener un nuevo token de acceso. Normalmente, un usuario solo necesitará un nuevo token de acceso después de que caduque el anterior o cuando obtenga acceso a un recurso nuevo por primera vez. Es una mala práctica llamar al endpoint para obtener un nuevo token de acceso cada vez que llame a una API, y Auth0 aplica límites de frecuencia que restringen la cantidad de solicitudes al endpoint que pueden ejecutarse con el mismo token desde la misma IP.

Para renovar su token, haga una solicitud `POST` al endpoint `/oauth/token` en la Authentication API, usando `grant_type=refresh_token`.

#### Ejemplo de solicitud POST a la URL del token

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

  ```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=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D", 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=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D")

  	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=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D")
    .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: 'refresh_token',
      client_id: '{yourClientId}',
      refresh_token: '{yourRefreshToken}'
    })
  };

  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=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D",
    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=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D"

  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=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D"

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

<div id="parameters">
  ##### Parámetros
</div>

| Nombre del parámetro | Descripción                                                                                                                                                                                                                                              |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `grant_type`         | Establece este valor en `refresh_token`.                                                                                                                                                                                                                 |
| `client_id`          | El ID de cliente de tu aplicación. Puedes encontrar este valor en la [configuración de la aplicación](https://manage.auth0.com/#/Applications/\{yourClientId}/settings).                                                                                 |
| `refresh_token`      | El token de actualización que se usará.                                                                                                                                                                                                                  |
| `scope`              | (opcional) Una lista de permisos de `scope` solicitados, delimitada por espacios. Si no se envía, se usarán los alcances originales; de lo contrario, puedes solicitar un conjunto reducido de alcances. Ten en cuenta que debe estar codificado en URL. |

<div id="response">
  #### Respuesta
</div>

Si todo sale bien, recibirás una respuesta `HTTP 200` con una carga útil que incluye un nuevo `access_token`, su duración en segundos (`expires_in`), los valores de `scope` concedidos y `token_type`. Si el scope del token inicial incluía `openid`, la respuesta también incluirá un nuevo `id_token`:

```json lines theme={null}
{
  "access_token": "eyJ...MoQ",
  "expires_in": 86400,
  "scope": "openid offline_access",
  "id_token": "eyJ...0NE",
  "token_type": "Bearer"
}
```

<Warning>
  Valida tus tokens antes de guardarlos. Para obtener más información, consulta [Validar ID Tokens](/es/docs/secure/tokens/id-tokens/validate-id-tokens) y [Validar tokens de acceso](/es/docs/secure/tokens/access-tokens/validate-access-tokens).
</Warning>

<div id="sample-use-cases">
  ### Ejemplos de casos de uso
</div>

<div id="customize-tokens">
  #### Personalizar tokens
</div>

Puede usar Actions para cambiar los alcances que devuelven los tokens de acceso y/o agregar claims a los tokens de acceso y a los ID Token. (Para obtener más información sobre Actions, lea [Auth0 Actions](/es/docs/customize/actions). ) Para ello, agregue la siguiente Action, que se ejecutará después de que el usuario se autentique:

```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
  // Agregar claim personalizado al Token de acceso y al ID Token
  api.accessToken.setCustomClaim('https://foo/bar', 'value');
  api.idToken.setCustomClaim('https://fiz/baz', 'some other value');

  // Modificar el scope del Token de acceso
  api.accessToken.addScope('foo');
  api.accessToken.addScope('bar');
};
```

Los alcances estarán disponibles en el token después de que se ejecute la Action.

<Warning>
  Auth0 devuelve la información del perfil en un formato estructurado de claims, tal como lo define 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 ID Token o tokens de acceso deben [ajustarse a las pautas y restricciones](/es/docs/secure/tokens/json-web-tokens/create-custom-claims) para evitar posibles colisiones.
</Warning>

<div id="view-sample-application-mobile-app-api">
  #### Ver la aplicación de ejemplo: aplicación móvil + API
</div>

Para ver una implementación de ejemplo, consulte el escenario de arquitectura [Mobile + API](/es/docs/get-started/architecture-scenarios/mobile-api). Esta serie de tutoriales incluye un [ejemplo de código al que puede acceder en GitHub](https://github.com/auth0-samples/auth0-pnp-exampleco-timesheets).

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

* [Framework de autorización OAuth 2.0](/es/docs/authenticate/protocols/oauth)
* [Protocolo OpenID Connect](/es/docs/authenticate/protocols/openid-connect-protocol)
* [Tokens](/es/docs/secure/tokens)
