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, |
|
OAuth2 | El mismo ida y vuelta por navegador, para proveedores sin discovery OIDC — Discord, Twitch, Roblox Open Cloud |
|
ServerAssertion | Un servidor de confianza responde por el jugador — no existe navegador al que redirigir |
|
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 |
|
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 |
Roblox |
|
Minecraft ( |
|
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:
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.AssertPlayerSessionse 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."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.La plataforma de la clave tiene que coincidir con el proveedor contra el que se afirma. Una clave marcada
robloxno puede abrir una sesiónminecraft, a propósito — esto es lo que evita que una clave filtrada de un juego se reuse contra otras plataformas del mismo workspace.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 |
| 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. |
| Cosmético — no significan nada para |
|
|
| Un proveedor deshabilitado no acepta afirmaciones nuevas, pero conserva su configuración y cada identidad ya registrada a través de él. |
| Si afirmar un id no reconocido puede crear una cuenta nueva, o solo puede adjuntarse a una que ya existe. |
| 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 |
| Ver arriba. Dejalo en |
| 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 |
| 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. |
| El campo | Marcá la plataforma de la clave con el proveedor para el que debería afirmar jugadores, en Gateway → Credentials. |
| 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. |
| El | 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. |
| 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 |
| El | 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 | Ningún rol llegó a la cuenta — sin | 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.