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

# Guía técnica del cliente

> Implementación OAuth 2.1 + PKCE: cliente remoto, loopback, DCR, refresh rotativo.

<Tip>
  RFC en la práctica — remoto, loopback, PKCE. Camino rápido: [Quick Start](/es/oauth-api/como-funciona/quick-start).
</Tip>

Para implementar el flujo **desde cero** o con librería OAuth. Resumen: [Construir un cliente](/es/oauth-api/como-funciona/construir-cliente).

Notifique implementa **OAuth 2.1** con **PKCE obligatorio** y **DCR** en `POST /oauth/register`. Issuer: `https://api.notifique.dev`.

Login y consentimiento están en el **panel Notifique**. Tu app abre la URL de autorización en el navegador y maneja el callback — **no** construyes UI de consentimiento.

## Tipos de cliente

| Tipo             | Secret | Cuándo                | Auth en `/oauth/token`       |
| ---------------- | :----: | --------------------- | ---------------------------- |
| **Público**      |   No   | SPA, mobile, CLI, MCP | PKCE + `none`                |
| **Confidencial** |   Sí   | Web con backend       | PKCE + `client_secret_basic` |

PKCE es **siempre** obligatorio.

## Caminos recomendados

1. **Registro fijo vs DCR** — pre-registrar apps conocidas; DCR en runtime para MCP/CLI.
2. **Remoto vs local** — callback HTTPS con sesión en servidor vs loopback `http://127.0.0.1:<puerto>/callback`.

## Escopos

Declara el **mínimo** en registro y authorize. Ver [Escopos](/es/oauth-api/como-funciona/escopos).

## Encoding

| Endpoint               | Content-Type                        |
| ---------------------- | ----------------------------------- |
| `POST /oauth/register` | `application/json`                  |
| `POST /oauth/token`    | `application/x-www-form-urlencoded` |
| `POST /oauth/revoke`   | `application/x-www-form-urlencoded` |

Clientes confidenciales usan **HTTP Basic** en token/revoke.

## Generar PKCE y state

```javascript theme={null}
import { createHash, randomBytes } from 'node:crypto';

function base64url(input) {
  return Buffer.from(input).toString('base64url');
}

const codeVerifier = base64url(randomBytes(64));
const codeChallenge = base64url(
  createHash('sha256').update(codeVerifier).digest(),
);
const state = base64url(randomBytes(24));
```

**Remoto:** persiste `state` y `codeVerifier` en la sesión.

**Local:** en memoria mientras corre el servidor loopback.

***

## Cliente remoto pre-registrado

Redirect **HTTPS** fijo. Registro confidencial. Guarda `client_secret` de forma segura — se muestra una sola vez.

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant C as Backend
    participant B as Navegador
    participant AS as api.notifique.dev
    participant D as Panel Notifique

    C->>B: 302 a /oauth/authorize
    B->>D: Usuario aprueba
    B->>C: Callback code + state
    C->>AS: POST /oauth/token
    AS-->>C: tokens
```

Falla si falta `code`, `state` no coincide o hay `error` en la query.

```bash theme={null}
curl -X POST 'https://api.notifique.dev/oauth/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -u 'CLIENT_ID:CLIENT_SECRET' \
  -d 'grant_type=authorization_code&code=AUTH_CODE&redirect_uri=https%3A%2F%2Fexample.com%2Foauth%2Fcallback&code_verifier=CODE_VERIFIER'
```

***

## Cliente local (loopback)

Cliente **público**, bind en `127.0.0.1` — nunca `0.0.0.0`.

<Warning>
  No hagas prefetch de `/oauth/authorize` server-side. El **usuario** debe ver la pantalla de consentimiento.
</Warning>

```bash theme={null}
curl -X POST 'https://api.notifique.dev/oauth/register' \
  -H 'Content-Type: application/json' \
  -d '{
    "client_name": "Mi CLI",
    "redirect_uris": ["http://127.0.0.1/oauth/callback"],
    "grant_types": ["authorization_code", "refresh_token"],
    "response_types": ["code"],
    "token_endpoint_auth_method": "none",
    "scope": "email:send"
  }'
```

Cierra el servidor loopback tras éxito o timeout.

***

## Refresh rotativo

Cada refresh devuelve un **nuevo** `refresh_token`. Serializa refresh por grant y persiste el nuevo token **atómicamente**.

***

## Revocar

Revoca el **refresh token** — los JWT de access no se revocan individualmente.

Workspace: **Configuración → Equipo → Apps conectadas**.

## Próximos pasos

* [Quick Start](/es/oauth-api/como-funciona/quick-start)
* [MCP](/es/oauth-api/como-funciona/mcp)
* [OpenAPI](/es/oauth-api/api-reference/openapi-oauth.json)
