Praxsuite

Proveedores de Plataformas de Juego

Proveedores de Plataformas de Juego

Un navegador puede redirigir a algún lado y mostrar un campo de contraseña. Un servidor de juego no puede: no hay popup dentro de una experiencia de Roblox, no hay barra de direcciones en un plugin de Paper. Esta página trata sobre cómo el API Gateway igual convierte "hay un jugador sentado frente a este juego" en una sesión de end user real y firmada — del mismo tipo que le da a una app web /auth/login — sin nada de eso.

Los proveedores se manejan en API Gateway → Identity Providers (la pantalla de configuración también responde en su ruta anterior, /oidc-providers — nada se rompió cuando le agregamos un segundo tipo).


Cuatro tipos de proveedor, un solo registro

Cada identidad externa que un workspace acepta — una cuenta de Google, un login de Discord, un servidor de juego de Roblox, un cliente de Steam — es una fila de la misma tabla, distinguida por su tipo (kind). Agregar una plataforma es completar configuración, no desplegar código nuevo.

Tipo

Cómo prueba la identidad

Techo

Oidc

Documento de discovery, redirección del navegador, id_token firmado

PlatformVerified

OAuth2

El mismo ida y vuelta por navegador, para proveedores sin discovery OIDC — Discord, Twitch, Roblox Open Cloud

PlatformVerified

ServerAssertion

Un servidor de confianza responde por el jugador — no existe navegador al que redirigir

ServerAsserted

Ticket

El cliente obtiene un ticket firmado de la plataforma; el backend lo valida contra la propia API de la plataforma — tickets de sesión de Steam, y las redes de consolas

PlatformVerified

Esta página es sobre ServerAssertion — el tipo que usa de verdad el SDK de cada motor de juego (las llamadas Identify/assertPlayer/LoginPlayer de los SDKs de Lua, Unity, TypeScript y Java terminan todas acá). Es el único tipo que funciona desde dentro de un motor sin navegador al que pasarle el control, y también es el más débil en el papel — que es exactamente por qué el resto de esta página trata sobre los chequeos que lo hacen seguro de todas formas.


Server Assertion: la palabra del servidor es la credencial

No hay ningún paso de cara al jugador. Tu servidor de juego llama a un endpoint, en nombre de un jugador que nunca ve que esto pasa:

POST /{workspaceId}/auth/{providerSlug}/assert
Authorization: Bearer sk_live_...

{
  "platformPlayerId": "123456789",
  "displayName": "Ana",
  "avatarUrl": null,
  "metadata": { "accountAge": 842 }
}

platformPlayerId tiene que ser algo que el jugador no pueda falsificar — leído del lado del servidor, nunca tomado de un paquete del cliente:

Plataforma

Qué mandar como platformPlayerId

Roblox

tostring(player.UserId)

Minecraft (online-mode:true)

player.getUniqueId().toString()

Unity, FiveM, Unreal, una plataforma custom

el id que tu propio servidor ya confía como identidad de jugador de esa plataforma

displayName, avatarUrl y metadata son cosméticos — se cachean para leaderboards y vistas de admin, nunca se chequean contra nada y nunca se usan para decidir acceso.

Una llamada exitosa devuelve exactamente lo mismo que devuelve /auth/login: un access token, un refresh token, y el mismo conjunto de claims (sub, role, role_id, …) que produce cualquier otro login. Los row filters, __SELF__, el Event Bus — todo lo que viene después trata a este jugador como a cualquier otro end user, porque para el resto de la plataforma, eso es exactamente lo que ahora es. Mirá Autenticación de Usuarios Finales para saber qué hacer con los tokens una vez que los tenés.

El filtro: por qué la palabra de un servidor alcanza como confianza

Confiar en un simple reclamo de "soy el UserId 123" no valdría nada — cualquiera podría mandar cualquier id. Lo que en realidad hace esto seguro es todo lo que se chequea antes de creerle a ese reclamo, en orden:

  1. Quien llama tiene que estar autenticado con una server key (`sk_live_`), no una publicable. Una clave pk_live_ vive en un build de cliente, donde un jugador podría leerla y hacerse pasar por cualquiera. AssertPlayerSession se niega directamente si no: "Se requiere una server key (sklive). Una clave publicable no puede abrir una sesión en nombre de un jugador: vive en el cliente, donde el jugador podría usarla para convertirse en otra persona."

  2. Esa clave tiene que estar marcada para una plataforma de juego. Una credencial tiene un campo Platform — roblox, minecraft, steam, fivem, unity, unreal, custom, o vacío para una clave web/mobile común. Una clave sin marcar no puede afirmar a nadie.

  3. La plataforma de la clave tiene que coincidir con el proveedor contra el que se afirma. Una clave marcada roblox no puede abrir una sesión minecraft, a propósito — esto es lo que evita que una clave filtrada de un juego se reuse contra otras plataformas del mismo workspace.

  4. El propio `MinVerificationLevel` del proveedor no puede superar `ServerAsserted`. Un workspace puede decidir que la identidad de cierta plataforma necesita ser más fuerte que "un servidor lo dijo" — ver niveles de verificación abajo. Si es así, la afirmación se rechaza y el jugador tiene que conectar la cuenta de esa plataforma a través del propio flujo OAuth del portal.

Recién cuando se cumplen los cuatro puntos, el id de la plataforma se resuelve en una cuenta.

Niveles de verificación: cuánto vale confiar en una identidad de plataforma

Esto reemplaza lo que antes era un simple booleano de "¿es real?". Existe porque un UserId de Roblox afirmado por un servidor de juego y un id de Discord que un jugador probó con un OAuth real no son el mismo tipo de confianza, aunque los dos terminen siendo un end user normal después:

Nivel

Significado

Unverified

Una etiqueta que mandó el cliente. Nada la firmó, nada la chequeó — sirve para analítica o mostrarla, nunca para acceso.

ServerAsserted

Un servidor de confianza respondió por ella. El jugador no puede falsificarla, pero quien tenga la clave de ese servidor sí puede — la clave es la credencial real, no el jugador.

PlatformVerified

El jugador la probó él mismo ante la plataforma, en un ida y vuelta que controló. El único nivel que sobrevive a un cliente de juego robado o copiado.

Los proveedores ServerAssertion nunca pueden producir más que ServerAsserted — no hay ningún paso controlado por el jugador que lo suba. Poner el MinVerificationLevel de un proveedor en PlatformVerified es la forma en que un workspace dice, a propósito, "la afirmación in-game no me alcanza acá."

Opcional: chequear el id de verdad contra la plataforma

Dos plataformas — Roblox y Steam — tienen un validador real registrado: algo que puede llamar a la propia API de la plataforma y confirmar que un id determinado existe de verdad ahí. Cualquier otra plataforma (minecraft, unity, fivem, unreal, custom) todavía no tiene ninguno, así que sus ids se confían tal cual una vez que pasan el filtro de arriba.

Donde existe un validador, el PlayerValidationMode de la credencial decide si se llega a llamar:

Modo

Comportamiento

TrustServer (default)

Nunca llama a la plataforma. El filtro de arriba es el único chequeo.

ValidateOnFirstSeen

Llama a la API de la plataforma la primera vez que aparece ese id puntual en el workspace, y de ahí en más confía en él.

ValidateAlways

Lo llama en cada afirmación.

Qué previene esto y qué no: confirmar que un `UserId` de Roblox existe no dice nada sobre quién está llamando — atrapa errores de tipeo e ids viejos, no suplantación. El filtro de la sección anterior es lo que en realidad previene la suplantación; esto es un chequeo de calidad de datos encima, para las dos plataformas que ofrecen uno.


Registrar un proveedor

Campo

Notas

providerSlug

Minúsculas, alfanumérico y guiones. Permanente una vez creado — es lo que referencian las llamadas de tu SDK y a lo que apunta cada identidad ya registrada, así que renombrarlo las dejaría huérfanas.

displayName / icon

Cosmético — no significan nada para ServerAssertion ya que no hay ningún botón de login que dibujar.

kind

ServerAssertion para una plataforma de juego.

isEnabled

Un proveedor deshabilitado no acepta afirmaciones nuevas, pero conserva su configuración y cada identidad ya registrada a través de él.

allowSignup

Si afirmar un id no reconocido puede crear una cuenta nueva, o solo puede adjuntarse a una que ya existe.

allowLink

Si esta plataforma puede agregarse como una conexión adicional a una cuenta que ya tiene otra (solo se consulta cuando el modo de vinculación del workspace es Linked, abajo).

minVerificationLevel

Ver arriba. Dejalo en Unverified a menos que específicamente quieras exigir más que la palabra de un servidor.

defaultRoleIds

Roles con los que nace una cuenta recién creada. Vacío cae al default del propio workspace.

Una cuenta nueva sin ningún rol se autentica bien y no llega a ninguna tabla — la plataforma lo registra como warning porque, del lado del jugador, se ve exactamente como un login roto, cuando en realidad es una configuración faltante. Poné un rol default acá, en el workspace, o asigná roles vía una Automation en su lugar (el patrón que usan las guías de Caso de Uso de los SDK: una automation Endpoint Trigger → Validate End User Token → Manage End User Roles que el cliente de cualquier plataforma puede llamar de la misma forma justo después de afirmar — ver la guía de Caso de Uso de cualquier SDK para la versión concreta). La vía de la Automation es la que escala más allá de un solo default estático por proveedor.


Un jugador, varias plataformas: vinculación

Una configuración a nivel workspace decide si un jugador que inicia sesión a través de dos plataformas distintas es una cuenta o dos:

Modo

Comportamiento

Linked (default)

Crossplay. Una cuenta puede tener una conexión de Roblox, una de Steam y una de Discord a la vez, y el progreso sigue al jugador sin importar con cuál inició sesión.

Isolated

Una cuenta por conexión. Iniciar sesión con Roblox y con Steam produce dos end users sin relación, cada uno con sus propios datos — reforzado por un índice único de workspace + proveedor + subject, no solo por una configuración.

Cambiar de Isolated a Linked más adelante no fusiona retroactivamente las cuentas duplicadas que Isolated ya creó — fusionar identidades después del hecho es un problema aparte y más difícil. Un workspace que en algún momento pueda querer crossplay debería arrancar en Linked.


Errores Comunes y Cómo Evitarlos

Error

Causa

Solución

Se requiere una server key (sk_live_)...

La llamada se autenticó con una clave publicable, o con un JWT de end user.

Usá la secret key del workspace, guardada solo del lado del servidor — nunca la mandes desde un build de cliente.

Esta clave no está marcada para una plataforma de juego...

El campo Platform de la credencial está vacío.

Marcá la plataforma de la clave con el proveedor para el que debería afirmar jugadores, en Gateway → Credentials.

Esta clave es de 'X' y no puede afirmar jugadores de 'Y'.

La plataforma de la clave no coincide con el slug del proveedor en la URL.

Usá la clave que se marcó para esa plataforma específica, o corregí la marca de plataforma.

'X' requiere identidades PlatformVerified, y un servidor de juego solo puede afirmar.

El MinVerificationLevel del proveedor está por encima de ServerAsserted.

Bajá el requisito, o hacé que el jugador conecte esa plataforma a través del propio flujo OAuth del portal en vez de afirmar desde el servidor de juego.

'X' no es un id de jugador de <plataforma> válido.

Hay un validador registrado para esa plataforma (Roblox o Steam) y el id no pasa su chequeo de formato.

Confirmá que estás leyendo el campo correcto del lado del servidor (por ejemplo player.UserId, no un nombre para mostrar).

<plataforma> no reconoció al jugador 'X'.

El PlayerValidationMode llamó a la API de la plataforma y rechazó el id.

El id está viejo, mal tipeado, o de verdad no existe en esa plataforma.

Un jugador nuevo inicia sesión bien pero cualquier consulta devuelve vacío o 403

Ningún rol llegó a la cuenta — sin defaultRoleIds en el proveedor, ninguno en el workspace, y ninguna Automation de asignación de roles fue llamada.

Configurá uno de los tres. Las guías de Caso de Uso de los SDK muestran el patrón con Automation.


Próximos pasos

  • Autenticación de Usuarios Finales — el token que te devuelve una afirmación tiene la misma forma que devuelve /auth/login; esto es qué hacer con él.

  • Roles de Gateway — cómo los roles que reparte un proveedor deciden en realidad qué puede ver un jugador.

  • Las guías de Implementation y Use Case de cualquier SDK (Lua/Roblox, Unity, TypeScript, Java/Minecraft) — la versión concreta, por motor, de todo lo de esta página.