JevalID — OAuth + OpenID Connect (OIDC)

Tutorial oficial: implementación, configuración, validación y troubleshooting (pensado para humanos y para IA).
🔐 OAuth (code) 🪪 OIDC (id_token) 🧱 RS256 + JWKS

Índice

Compatibilidad: OIDC es opcional. Si tu app NO pide scope=openid, todo funciona como OAuth normal (no se rompe nada).

1) Qué es OAuth y qué agrega OIDC

OAuth (Authorization Code) sirve para obtener un access_token y llamar APIs. En JevalID esto te permite: canjear un code por un token y luego llamar /api/userinfo.php.

OpenID Connect (OIDC) es una capa encima de OAuth. Si tu app pide scope=openid, JevalID te devuelve además un id_token: un JWT firmado que prueba identidad (estilo Google).

Resumen rápido:
OAuth = autorización (token para APIs).
OIDC = identidad estándar (JWT firmado: id_token).

2) Para qué sirve (casos reales)

  • “Iniciar sesión con JevalID” en cualquier web o servicio (igual que Google).
  • SSO dentro de tu infraestructura: un login para varios paneles.
  • Proxmox (realm OIDC) y otras herramientas que aceptan proveedores OIDC.
  • Apps de terceros: integración fácil usando librerías estándar OIDC.
  • Menos llamadas: con OIDC puedes validar identidad con id_token sin llamar siempre a userinfo.
Importante: El access_token es para APIs. El id_token es para identidad. No mezcles roles: no uses id_token como “token de API”.

3) Endpoints oficiales JevalID

  • Authorization: https://id.jeval.cl/oauth/authorize.php
  • Token: https://id.jeval.cl/oauth/token.php
  • UserInfo: https://id.jeval.cl/api/userinfo.php
  • JWKS: https://id.jeval.cl/oauth/jwks.json
  • Discovery: https://id.jeval.cl/.well-known/openid-configuration

OIDC usa openid-configuration (discovery) para que herramientas (como Proxmox) se configuren solas.

4) Flujo completo (paso a paso)

4.1 Paso 1: botón “Iniciar sesión con JevalID”

Tu app redirige al usuario a /oauth/authorize.php:

// Parámetros recomendados:
client_id=TU_CLIENT_ID
redirect_uri=TU_REDIRECT_URI (exacta, igual a la registrada)
response_type=code
state=RANDOM_ANTI_CSRF
scope=openid email profile   (si quieres OIDC)
nonce=RANDOM_ANTI_REPLAY     (recomendado si usas openid)
state protege contra CSRF. Debes guardarlo en sesión y compararlo al volver.
nonce previene replay en OIDC. Se devuelve dentro del id_token.

4.2 Paso 2: JevalID autentica

  • Si el usuario ya tiene sesión en JevalID: vuelve inmediato.
  • Si no tiene sesión: se le muestra login, y luego vuelve al authorize.

4.3 Paso 3: tu app recibe el code

JevalID redirige a tu redirect_uri con: ?code=...&state=...

4.4 Paso 4: canje del code por token

Tu backend hace POST a /oauth/token.php:

POST https://id.jeval.cl/oauth/token.php
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=EL_CODE
&redirect_uri=TU_REDIRECT_URI
&client_id=TU_CLIENT_ID
&client_secret=TU_CLIENT_SECRET

Respuesta:

{
  "access_token": "....",
  "token_type": "Bearer",
  "expires_in": 3600,
  "id_token": "JWT_FIRMADO_RS256 (solo si scope incluye openid)"
}

4.5 Paso 5: obtener usuario

Opción A (clásica): usar userinfo:

GET https://id.jeval.cl/api/userinfo.php
Authorization: Bearer ACCESS_TOKEN

Opción B (OIDC): validar id_token localmente (ver sección 6).

5) Cómo configurar una app (Developer Dashboard)

  1. Entra a /dashboard/developer.php (rol developer_api o admin).
  2. Crea una app OAuth:
    • Nombre
    • Redirect URI EXACTA (mismo https, misma ruta)
  3. Guarda:
    • client_id
    • client_secret (solo backend, nunca frontend)
Prohibido: poner el client_secret en JavaScript público o en Unity directo. Siempre va en backend. Si se filtra, se revoca la app.

6) Cómo validar id_token (JWT RS256 + JWKS)

Si pediste scope=openid, JevalID devuelve id_token firmado (RS256). Para validar:

  1. Decodifica JWT header y toma kid.
  2. Descarga JWKS: https://id.jeval.cl/oauth/jwks.json.
  3. Selecciona la key cuyo kid coincide.
  4. Verifica firma RS256.
  5. Valida claims:
    • iss debe ser https://id.jeval.cl
    • aud debe ser tu client_id
    • exp no debe estar expirado
    • nonce debe coincidir (si lo usaste)
Nota: Si no quieres validar JWT en tu app, puedes seguir usando /api/userinfo.php con access_token.

7) Ejemplo: Proxmox (OIDC Realm)

Proxmox puede usar JevalID como proveedor OIDC si: /.well-known/openid-configuration y /oauth/jwks.json están disponibles y el id_token es RS256.

Configuración típica (conceptual):

  • Issuer: https://id.jeval.cl
  • Client ID: el de tu app OAuth creada en JevalID
  • Client Secret: el de tu app OAuth
  • Scopes: openid email profile
  • Redirect URI: la que Proxmox te indica (debe estar registrada en JevalID)
Si Proxmox dice “OpenID login failed”, casi siempre es: issuer mal, redirect_uri distinta, jwks inaccesible, o firma/claims no válidos.

8) Ejemplo: Unity (recomendación práctica)

En Unity lo sano es: Unity NO guarda client_secret. Unity abre el navegador (o webview), recibe un code en tu backend, y tu backend hace el canje.

  • Unity abre: authorize URL
  • Tu backend recibe callback y canjea code
  • Tu backend crea “sesión de juego” propia (cookie/token de tu juego)
No recomendado: meter client_secret dentro del juego. Eso es filtrar credenciales.

9) Errores típicos y soluciones

Errores OAuth/Token comunes

  • {"error":"Método no permitido, usa POST"}
  • {"error":"grant_type inválido"}
  • {"error":"Faltan parámetros obligatorios"}
  • {"error":"client_id inválido"}
  • {"error":"client_secret incorrecto"}
  • {"error":"redirect_uri no coincide con el registrado"}
  • {"error":"Código de autorización inválido"}
  • {"error":"Código ya utilizado"}
  • {"error":"Código expirado"}
  • {"error":"client_revoked"}
  • {"error":"oidc_key_missing"}

Causa → Solución

  • redirect_uri no coincide → tu app usa una URI distinta a la registrada (hasta un “/” cambia). Usa coincidencia exacta.
  • client_secret incorrecto → secret equivocado o filtrado (rota/recrea app).
  • código inválido → code no existe, client_id/redirect_uri no coinciden, o lo alteraste.
  • código ya utilizado → el code solo se canjea una vez. No reintentes con el mismo.
  • código expirado → tardaste demasiado; genera uno nuevo.
  • client_revoked → el owner revocó la app en Developer Dashboard.
  • oidc_key_missing → faltan las llaves RS256 en el server (no puede emitir id_token).
Error ultra típico: “state inválido”. Eso es tu app fallando: guarda state en sesión antes de redirigir y compáralo al volver.

10) Reglas de seguridad y buenas prácticas

  • client_secret siempre backend. Nunca en frontend, Unity, JS público.
  • Usa HTTPS en producción. Solo http://localhost para pruebas.
  • Usa state siempre (anti-CSRF).
  • Si usas OIDC, usa nonce y valídalo.
  • Valida id_token con JWKS y claims (iss/aud/exp).
  • Si una app se filtra o abusa → revoca en Developer Dashboard.
  • Tu sistema puede mantener logs técnicos para seguridad (IP, user-agent, timestamps).
Developer_api no es juguete: abuso de OAuth/APIs puede afectar a toda la infraestructura. Tokens y apps pueden ser revocados sin aviso si hay riesgo real.