> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vu-one.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Autenticación con OAuth 2.0 y OIDC

> Obtenga tokens de VU ONE FREE con OAuth 2.0 y OpenID Connect, valide su firma con JWKS y lea los claims que trae cada token de su tenant.

Esta página explica cómo obtener, renovar y validar tokens de acceso para la API de su tenant de VU ONE FREE. Al terminar, usted tiene un token en la variable `$TOKEN`, listo para los ejemplos de las demás páginas de la API. Verá dos flujos. El primero inicia sesión a un usuario en el navegador. El segundo autentica un proceso del lado del servidor.

> [!WARNING]
>
> **VU ONE FREE es una versión limitada, en vista previa.** Solo la usan las cuentas de Identity Link que VU seleccionó hasta la disponibilidad general. Algunas funciones son del plan pago y las funciones, los límites y esta documentación pueden cambiar. [Vea qué incluye](https://docs.vu-one.com/vu-one/plan-free.md).

## Antes de empezar

Necesita lo siguiente:

* El nombre de su tenant. VU ONE genera ese nombre con la forma `<adjetivo>-<sustantivo>-<4 dígitos>`, por ejemplo `wispy-waterfall-3912`.
* Un cliente OAuth para cada flujo. Cree los clientes en [Clientes OAuth](https://docs.vu-one.com/vu-one/admin/clientes-oauth.md):
  * Para el flujo de usuario: deje **Código de Autorización** en **Tipos de Concesión**. En **URIs de Redirección**, agregue la URI exacta de su aplicación. La consola solo acepta URIs que empiezan con `http://` o `https://`. En una app móvil nativa, use una URI `https://` que abra su app, como un enlace universal de iOS o un App Link de Android, en lugar de un esquema propio. En **Alcances**, elija **OpenID Connect**, **Perfil** y **Correo Electrónico** (`openid`, `profile` y `email`). Una aplicación de una sola página o móvil no puede guardar un secreto: elija el método **Ninguno** y active **Requerir PKCE (Proof Key for Code Exchange)**.
  * Para el flujo de servidor: **Credenciales de Cliente**. El cliente del [inicio rápido](https://docs.vu-one.com/vu-one/inicio-rapido.md) ya sirve para este flujo, pero no para el de usuario.
* Para probar el flujo de usuario, un usuario de prueba con contraseña. El **Ámbito de Acceso** del cliente define qué cuentas pueden iniciar sesión:

  * Un cliente fijado a un negocio abre la página de inicio de sesión de ese negocio. El usuario necesita una cuenta en ese negocio, del mismo **Tipo de Cuenta** que el cliente.
  * Un cliente con **Global (Tenant)** abre la pestaña **Global**. Esa pestaña solo acepta cuentas sin negocio de tipo **LABORAL**, como las de administrador del tenant.

  Cree el usuario con la API, según el [flujo típico de cuentas](https://docs.vu-one.com/vu-one/desarrolladores/cuentas.md), o en la consola, en [Identidades](https://docs.vu-one.com/vu-one/admin/identidades.md). El flujo típico crea una cuenta `CUSTOMER` en un negocio: para esa cuenta, fije el cliente a ese negocio con el tipo de cuenta **CLIENTE**.
* `curl` y `jq` instalados en su equipo.

> [!NOTE]
>
> Durante la vista previa, los SDK no se distribuyen públicamente. Esta página cubre la API.

## URL base y endpoints

Todas las rutas usan el mismo host de su tenant.

| Recurso | URL |
| - | - |
| Base de la API | `https://<tenant>.prod.vu-one.com/middleware` |
| Descubrimiento OIDC | `https://<tenant>.prod.vu-one.com/middleware/.well-known/openid-configuration` |
| Token | `https://<tenant>.prod.vu-one.com/middleware/oauth2/token` |
| Claves públicas (JWKS) | `https://<tenant>.prod.vu-one.com/middleware/oauth2/jwks` |
| Perfil del usuario | `https://<tenant>.prod.vu-one.com/middleware/userinfo` |

Lea el documento de descubrimiento en tiempo de ejecución. No copie su contenido en su código. Para iniciar sesión, use el `authorization_endpoint` que publica ese documento.

Defina estas variables antes de seguir los ejemplos. `TENANT_HOST` es la misma variable que usa el [inicio rápido](https://docs.vu-one.com/vu-one/inicio-rapido.md):

```bash theme={null}
export TENANT_HOST="wispy-waterfall-3912.prod.vu-one.com"  # reemplace por el host de su tenant
export CLIENT_ID="<client-id>"
export CLIENT_SECRET="<client-secret>"
export REDIRECT_URI="<redirect-uri-registrada-en-el-cliente>"
```

Guarde el secreto del cliente al crearlo. Trátelo como una contraseña.

## Elija el flujo

| Su caso | Flujo |
| - | - |
| Un usuario inicia sesión desde una aplicación web o móvil | Código de autorización con PKCE |
| Un proceso sin usuario, como una integración entre sistemas | `client_credentials` |

## Flujo de usuario: código de autorización con PKCE

Use este flujo cuando un usuario inicia sesión desde una aplicación web o móvil. Su aplicación no recibe la contraseña del usuario. El usuario la escribe en la pantalla de inicio de sesión de VU ONE.

**1. Lea el endpoint de inicio de sesión**

```bash theme={null}
export AUTHORIZATION_ENDPOINT=$(curl -s "https://$TENANT_HOST/middleware/.well-known/openid-configuration" | jq -r .authorization_endpoint)
echo "$AUTHORIZATION_ENDPOINT"
```

Use el valor que devuelve el documento de descubrimiento. No escriba esta ruta a mano.

**2. Cree el verificador y el desafío PKCE**

```bash theme={null}
export CODE_VERIFIER=$(openssl rand -base64 64 | tr -d '=+/' | cut -c1-64)
export CODE_CHALLENGE=$(printf '%s' "$CODE_VERIFIER" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')
export STATE=$(openssl rand -hex 16)
export REDIRECT_ENC=$(printf '%s' "$REDIRECT_URI" | jq -sRr @uri)
```

Guarde `CODE_VERIFIER` y `STATE`. Los necesita en los pasos siguientes.

**3. Abra la pantalla de inicio de sesión**

```bash theme={null}
echo "$AUTHORIZATION_ENDPOINT?response_type=code&client_id=$CLIENT_ID&redirect_uri=$REDIRECT_ENC&scope=openid%20profile%20email&state=$STATE&code_challenge=$CODE_CHALLENGE&code_challenge_method=S256"
```

Abra la URL impresa en un navegador. El usuario escribe sus credenciales en la pantalla de VU ONE.

**4. Reciba el código de autorización**

Tras el inicio de sesión, el navegador vuelve a `redirect_uri` con los parámetros `code` y `state`. Compare `state` con el valor que guardó. Si no coincide, rechace la respuesta.

Copie el valor de `code` en una variable:

```bash theme={null}
export AUTH_CODE="<valor-de-code>"
```

**5. Intercambie el código por tokens**

```bash theme={null}
RESPONSE=$(curl -s -X POST "https://$TENANT_HOST/middleware/oauth2/token" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  --data-urlencode "grant_type=authorization_code" \
  --data-urlencode "code=$AUTH_CODE" \
  --data-urlencode "redirect_uri=$REDIRECT_URI" \
  --data-urlencode "code_verifier=$CODE_VERIFIER")

echo "$RESPONSE" | jq .
export TOKEN=$(echo "$RESPONSE" | jq -r .access_token)
export REFRESH_TOKEN=$(echo "$RESPONSE" | jq -r .refresh_token)
```

Este ejemplo usa `client_secret_basic`, el método de autenticación por defecto de la consola. Si su cliente usa otro método, autentíquelo con ese método. Un cliente público, con el método **Ninguno**, no envía secreto: quite `-u` y envíe `client_id` en el cuerpo. El `code_verifier` protege el intercambio.

**6. Lea el perfil del usuario**

```bash theme={null}
curl -s "https://$TENANT_HOST/middleware/userinfo" -H "Authorization: Bearer $TOKEN" | jq .
```

Vea los campos del perfil en la sección [Perfil con /userinfo](#perfil-con-userinfo).

> [!NOTE]
>
> La pantalla de inicio de sesión que publica `authorization_endpoint` es la de la consola de VU ONE. Esa pantalla recibe `client_id`, `redirect_uri`, `scope`, `state`, `code_challenge` y `code_challenge_method`, y devuelve el código a su `redirect_uri`. Antes de salir a producción, pruebe el flujo completo con un usuario de prueba. Revise que el cliente tenga el grant `authorization_code`, la `redirect_uri` exacta y los scopes que pide (`openid`, `profile`, `email`).

> [!WARNING]
>
> El código de autorización vence pronto y solo sirve una vez. Si el intercambio falla con `invalid_grant`, inicie el flujo de nuevo desde el paso 2.

La respuesta del endpoint `/oauth2/token` sigue el estándar de OAuth 2.0 y OpenID Connect:

**access\_token** `string`

Token de acceso. Envíelo en el encabezado `Authorization: Bearer`.

**token\_type** `string`

Tipo del token. Es `Bearer` en las integraciones web.

**expires\_in** `integer`

Vida del token de acceso, en segundos.

**refresh\_token** `string`

Token para renovar el acceso. Aparece cuando el cliente tiene permitido renovar tokens.

**id\_token** `string`

Token de identidad OIDC. Aparece cuando la solicitud incluye el scope `openid`.

**scope** `string`

Scopes que el servidor concedió.

## Flujo de servidor: client\_credentials

Use este flujo para un proceso sin usuario, como una integración entre sistemas. No hay pantalla de inicio de sesión en este flujo.

Antes de pedir un token, revise la configuración del cliente:

* Un cliente sin configuración de negocio no recibe token. La API responde `invalid_scope`.
* El cliente necesita el tipo de concesión **Credenciales de Cliente**. La consola marca **Código de Autorización** por defecto.
* Un cliente con **Global (Tenant)** como negocio recibe tokens de alcance `TENANT`. Un cliente fijado a un negocio recibe tokens de alcance `BUSINESS`, con `business_id`. Si además está fijado a un canal, el token trae `channel_id`.
* El scope `role_admin` concede todos los permisos, pero solo dentro del negocio y el canal del cliente. Pida solo los scopes que necesita cuando pueda.

```bash theme={null}
curl -s -X POST "https://$TENANT_HOST/middleware/oauth2/token" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  -d "scope=role_admin" | jq .
```

Para usar el token en los ejemplos de las demás páginas, guárdelo en `$TOKEN`:

```bash theme={null}
export TOKEN=$(curl -s -X POST "https://$TENANT_HOST/middleware/oauth2/token" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d "grant_type=client_credentials" \
  -d "scope=role_admin" | jq -r .access_token)
```

Un cliente con `role_admin` puede pedir un permiso concreto, como `sys_account:read`, para reducir el alcance del token. Un cliente sin `role_admin` solo puede pedir los scopes que tiene registrados.

Este flujo no devuelve `refresh_token`. Cuando el token vence, pida uno nuevo con las mismas credenciales.

## Renovar el token

Use el `refresh_token` para obtener un nuevo `access_token` sin pedir al usuario que inicie sesión de nuevo.

```bash theme={null}
curl -s -X POST "https://$TENANT_HOST/middleware/oauth2/token" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  --data-urlencode "grant_type=refresh_token" \
  --data-urlencode "refresh_token=$REFRESH_TOKEN" | jq .
```

Si la respuesta trae un `refresh_token` nuevo, guárdelo y descarte el anterior.

## El grant password no es para integraciones

No use el grant `password` en integraciones web ni de servidor. Solo lo usa el SDK móvil, con una clave de dispositivo. Para cualquier otra integración, use el flujo de código de autorización o `client_credentials`.

## Claims del token

Cada token de acceso trae claims que describen el contexto de la sesión. Los claims de perfil, como el nombre o el correo, no van en el token. Consúltelos en [/userinfo](#perfil-con-userinfo).

| Claim | Cuándo aparece | Significado |
| - | - | - |
| `tenant_id` | Siempre | Identificador del tenant. |
| `iss` | Siempre | Emisor: `https://<tenant>.prod.vu-one.com/middleware`. |
| `identity_id` | Tokens de usuario | Identidad del usuario que inició sesión. |
| `account_id` | Tokens de usuario | Cuenta del usuario que inició sesión. |
| `active_scope` | Siempre | `TENANT` o `BUSINESS`. En los tokens de usuario, sigue el alcance de la cuenta. |
| `business_id` | Cuando `active_scope` es `BUSINESS` | Negocio activo del token. |
| `channel_id` | Cuando el token está fijado a un canal | Canal activo del token. |
| `sid` | Cuando la autorización tiene identificador de sesión | Identificador de la sesión. |

Los tokens de `client_credentials` no traen `identity_id` ni `account_id`. Traen `active_scope` según la configuración de negocio del cliente.

## Perfil con /userinfo

Llame a `/userinfo` con el token de acceso. El servidor devuelve los campos estándar solo para los scopes que pidió. Pida `profile` para el nombre, `email` para el correo y `phone` para el teléfono.

```bash theme={null}
curl -s "https://$TENANT_HOST/middleware/userinfo" -H "Authorization: Bearer $TOKEN" | jq .
```

**sub** `string`

Identificador de la cuenta del usuario.

**authorities** `array`

Autoridades del usuario.

**given\_name** `string`

Nombre. Requiere el scope `profile`.

**family\_name** `string`

Apellido. Requiere el scope `profile`.

**preferred\_username** `string`

Nombre de usuario. Requiere el scope `profile`.

**email** `string`

Correo de la cuenta. Requiere el scope `email`.

**phone\_number** `string`

Teléfono de la cuenta. Requiere el scope `phone`.

**phone\_verified** `boolean`

Indica si el teléfono está verificado. Requiere el scope `phone`. La respuesta usa este nombre, no `phone_number_verified`.

Además, `/userinfo` devuelve campos propios de VU ONE: `active_scope`, `business_id`, `login_slug`, `identity_id`, `account_type`, `account_state`, `identity_provider_id`, `is_tenant_admin` y `metadata`.

## Encabezados de contexto

Use estos encabezados para elegir el negocio o el canal de una llamada. Un encabezado nunca cambia el alcance que el token ya tiene.

| Encabezado | Valores | Efecto |
| - | - | - |
| `X-Business-Id` | UUID del negocio | Elige el negocio de la llamada. Solo un token de alcance tenant elige negocio con libertad. |
| `X-Channel-Id` | UUID del canal | Elige el canal de la llamada. Un token fijado a un canal no cambia de canal. |
| `X-Account-Scope` | `BUSINESS` o `TENANT` | Elige el alcance de la llamada. Un token de `BUSINESS` no sube a `TENANT`. |

> [!WARNING]
>
> Si un encabezado contradice el token, la API responde **403** con el código `GOVERNANCE.BUSINESS_SCOPE_ACCESS_DENIED`. Revise que el encabezado coincida con el negocio o el canal del token.

Un encabezado que solo indica el canal recibe, del token, el negocio y el alcance que faltan.

## Validar un token en su servicio

Si su servicio recibe tokens de acceso, valídelos antes de confiar en ellos:

**1. Descargue las claves públicas del tenant**

```bash theme={null}
curl -s "https://$TENANT_HOST/middleware/oauth2/jwks" | jq .
```

**2. Verifique la firma**

Verifique la firma RS256 con la clave JWKS que corresponde al token.

**3. Compruebe los claims**

* Compruebe que `iss` sea `https://<tenant>.prod.vu-one.com/middleware`.
* Compruebe que `exp` no haya pasado.
* Compruebe `aud` solo si su librería lo exige. Esta vista previa no documenta un valor fijo para `aud`.
* Compruebe `tenant_id` si su servicio atiende más de un tenant.

> [!TIP]
>
> Guarde las claves JWKS en caché y actualícelas cuando aparezca una clave que no conoce. No descargue las claves en cada solicitud.

## Cerrar sesión

Hay dos formas de cerrar la sesión de un usuario.

**Cierre de sesión OIDC.** Redirija el navegador al endpoint de cierre de sesión. Use `end_session_endpoint` del documento de descubrimiento. Si ese documento no lo publica, use `https://$TENANT_HOST/middleware/connect/logout`.

**Revocar el refresh token.** Este paso invalida el token para renovar el acceso. El token de la llamada necesita el permiso `sys_oauth2_authorization:delete` o el scope `role_admin`. Por ejemplo, haga la llamada desde su backend con un token de `client_credentials`:

```bash theme={null}
curl -s -X POST "https://$TENANT_HOST/middleware/api/v1/oauth2/authorizations/logout" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"refreshToken\": \"$REFRESH_TOKEN\"}" \
  -i
```

La API responde `204` sin cuerpo, también cuando el refresh token no existe. Después de revocar el token, el cliente no puede usarlo para renovar el acceso.

## Qué sigue

> [card] [Cuentas, identidades y contraseñas](https://docs.vu-one.com/vu-one/desarrolladores/cuentas.md)
>
> Cree identidades y cuentas, y administre contraseñas con la API.

> [card] [Factores de autenticación en la API](https://docs.vu-one.com/vu-one/desarrolladores/factores.md)
>
> Enrole y verifique OTP por correo, TOTP y enlace mágico.

> [card] [Errores de la API de VU ONE FREE](https://docs.vu-one.com/vu-one/desarrolladores/errores.md)
>
> Entienda cada forma de error y cuándo reintentar.

> [card] [Clientes OAuth](https://docs.vu-one.com/vu-one/admin/clientes-oauth.md)
>
> Revise los valores por defecto y las buenas prácticas del cliente.


## Related topics

- [Aprovisionamiento con SCIM 2.0](https://docs.vu-one.com/vu-one/desarrolladores/scim.md)
- [Factores de autenticación en la API](https://docs.vu-one.com/vu-one/desarrolladores/factores.md)
- [Cuentas, identidades y contraseñas](https://docs.vu-one.com/vu-one/desarrolladores/cuentas.md)
- [Errores de la API de VU ONE FREE](https://docs.vu-one.com/vu-one/desarrolladores/errores.md)
- [Crear un cliente OAuth en la consola](https://docs.vu-one.com/vu-one/admin/clientes-oauth.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.