Saltar al contenido

Identificar usuarios

Usa Jotly('identify', …) para decirle a Jotly quién es el usuario con sesión. Una vez identificado, sus conversaciones, votos e ideas quedan a su nombre, tu equipo ve su contexto y puede entrar a tu portal público sin volver a iniciar sesión.

Hay cuatro mecanismos y todos usan el mismo secreto de identidad de tu espacio:

  • Token JWT (recomendado): identify({ token }), firmado en tu servidor. Resultado signed.
  • Firma HMAC del id: identify({ id, signature }). Resultado signed.
  • Sin firma: identify({ id }). Resultado unsigned; útil para empezar, no para datos sensibles.
  • SSO del portal (plan Pro): el botón Entrar del portal lleva a tu app y regresa con un JWT.

Identificación básica

Llama a identify después de init, cuando tu producto ya sabe quién está conectado:

Jotly('identify', {  id: 'user_123',  email: 'ana@empresa.com',  name: 'Ana López',});

Sólo id es obligatorio; el resto es opcional, aunque casi siempre vale la pena mandar email. Usa el id de usuario de tu propia app: el identificador estable que le asignas en tu sistema, no un id de sesión ni un valor que cambie entre inicios de sesión.

Además del id puedes mandar su avatar, empresa, gasto mensual y atributos libres que tu equipo verá junto a cada conversación:

Jotly('identify', {  id: 'user_123',                 // obligatorio: tu id de usuario  email: 'ana@empresa.com',  name: 'Ana López',  avatar: 'https://…/ana.png',  company: 'Empresa SA',  monthlySpend: 49,  attributes: { plan: 'pro', pais: 'MX' },  signature: 'HMAC_DEL_ID',      // ver "Firmar el id con HMAC-SHA256"});

En la mayoría de las apps, identifica al usuario cuando:

  • inicia sesión
  • tu app recupera una sesión que ya existía
  • cambia su perfil y quieres que Jotly refleje los datos nuevos

Identidad firmada con un token JWT

Sin firma, cualquiera podría escribir otro id en la consola del navegador. Con un token, Jotly comprueba que la identidad viene de tu servidor. Genera un JWT HS256 con el secreto de Ajustes → Inicio de sesión y pásalo en token. identify devuelve una promesa con el resultado:

// El token lo genera tu servidor y lo entrega a la página.const { viewer, identityTrust, warnings } = await Jotly('identify', {  token: tokenDeTuServidor,}); console.log(identityTrust); // 'signed'

Claims del token

ClaimObligatorioQué es
subSíTu id de usuario (texto).
issSíEl slug o el id de tu espacio en Jotly.
audSí"jotly"
iatSíSegundos Unix en que lo firmaste.
expSíVencimiento; máximo 1 hora después de iat. Toleramos 60 s de diferencia de reloj.
emailNoCorreo del usuario.
firstName, lastNameNoNombre y apellido.
avatarNoURL https de su foto.
traitsNoAtributos con valores de texto, número, booleano o null.
companiesNoLista de { id, name?, domain?, traits? }.

Los datos dentro del token están verificados. Si además mandas campos sueltos (email, name…), son información extra sin verificar y el token gana cuando no coinciden.

import crypto from "node:crypto"; // En TU servidor, nunca en el navegador.const SECRETO = process.env.JOTLY_SECRET;const ESPACIO = "tu-espacio"; // slug de tu espacio en Jotlyconst b64 = (v) => Buffer.from(JSON.stringify(v)).toString("base64url"); export function tokenJotly(user) {  const ahora = Math.floor(Date.now() / 1000);  const datos =    b64({ alg: "HS256", typ: "JWT" }) +    "." +    b64({      sub: String(user.id),   // tu id de usuario      iss: ESPACIO,           // slug o id del espacio      aud: "jotly",      iat: ahora,      exp: ahora + 10 * 60,   // máximo 1 hora después de iat      email: user.email,      firstName: user.firstName,      lastName: user.lastName,      avatar: user.avatarUrl,      traits: { plan: user.plan },      companies: [{ id: String(user.companyId), name: user.companyName }],    });  const firma = crypto.createHmac("sha256", SECRETO).update(datos).digest("base64url");  return datos + "." + firma;}
Un token inválido, vencido o con aud o iss incorrectos nunca se acepta como identidad sin firma: identify rechaza la promesa con IDENTIFY_FAILED y la API responde 401 con un código como TOKEN_EXPIRED, TOKEN_SIGNATURE, TOKEN_AUDIENCE o TOKEN_ISSUER. Genera un token nuevo en cada carga de página.

Firmar el id con HMAC-SHA256

La alternativa al token es firmar sólo el id: HMAC-SHA256(id, secreto) en hexadecimal, en el mismo identify. El resultado también es signed, pero sólo el id queda verificado, no el resto de los campos.

Jotly('identify', {  id: 'user_123',  email: 'ana@empresa.com',  signature: 'HMAC_DEL_ID', // calculada en tu servidor});
import crypto from "node:crypto"; // En TU servidor, nunca en el navegador.const SECRETO = process.env.JOTLY_SECRET; export function firmaJotly(userId) {  return crypto.createHmac("sha256", SECRETO).update(String(userId)).digest("hex");}
Si mandas una firma que no coincide, Jotly rechaza la identificación. Revisa que firmes exactamente el mismo id, como texto, que pasas en identify.

Exigir identidad firmada

En Ajustes → Inicio de sesión puedes activar Exigir identidad firmada. Con eso encendido, cualquier identify sin token o firma válidos se rechaza con SIGNED_IDENTITY_REQUIRED, y el inicio automático al portal sólo acepta tokens JWT. Un usuario que ya se verificó una vez tampoco puede volver a entrar sin firma.

Entrar al portal público

Tu portal de feedback tiene tres formas de iniciar sesión, en Ajustes → Inicio de sesión → Inicio de sesión del portal:

  • Enlace por correo (predeterminado): el usuario escribe su correo y recibe un enlace mágico y un código de 6 dígitos. Ambos sirven una sola vez y vencen en 15 minutos. Escribir el correo de otra persona no da acceso a nada.
  • SSO de tu app (plan Pro): el botón Entrar lleva a tu app, que firma un JWT.
  • Deshabilitado (plan Pro): no hay botón Entrar. Participan los invitados, si los permites, y quien llega con inicio automático.

Con Publicar como invitado activo, el visitante también puede publicar, votar y comentar sin cuenta. Cada invitado es una identidad nueva que sólo ve y edita lo suyo mientras dure su sesión en ese navegador.

SSO del portal

El flujo, como en cualquier SSO con redirección:

  • El usuario pulsa Entrar y Jotly lo manda a tu URL de inicio de sesión con ?state=…. El state es de un solo uso y vence en 15 minutos.
  • Tu app lo autentica como siempre (o lo reconoce si ya tenía sesión).
  • Tu servidor firma un JWT con los mismos claims de arriba (aquí iat es opcional; sugerimos que dure de 5 a 15 minutos) y redirige a /api/portal/tu-espacio/sso?jwt=…&state=… con el mismo state. La URL exacta está en Ajustes.
import express from "express";import { tokenJotly } from "./jotly.js"; // la función de arriba const app = express(); // URL de inicio de sesión que pegaste en Jotly: https://tuapp.com/jotly/ssoapp.get("/jotly/sso", requireLogin, (req, res) => {  const state = String(req.query.state ?? "");  const jwt = tokenJotly(req.user);  const regreso = new URL("https://jotly.si/api/portal/tu-espacio/sso");  regreso.searchParams.set("jwt", jwt);  regreso.searchParams.set("state", state); // el mismo state, sin cambios  res.redirect(regreso.toString());});

Si algo falla, el usuario regresa al portal con ?sso_error= y uno de estos valores: invalid_state (el state no existe, ya se usó o venció), invalid_token (firma, aud, iss o vencimiento del JWT) o auth_failed (el SSO está apagado o la cuenta no puede participar).

Inicio automático desde tu app

Si tu app tiene el widget con un usuario identificado, cualquier enlace de tu app que apunte a tu portal sale con ?clientToken= y el usuario llega ya con su sesión. No tienes que hacer nada más: el widget reescribe el enlace justo cuando el usuario lo abre.

// clientToken = base64 de este JSON (no es secreto: la confianza viene del token de dentro){  "version": 2,  "id": "tu-espacio",  "token": "eyJhbGciOiJIUzI1NiJ9…"   // o "user": { "id", "email", "name", "signature" }}

Con Exigir identidad firmada sólo se aceptan los clientToken que traen un JWT. El inicio automático no aplica a las cuentas de tu equipo.

Cerrar sesión

Al salir de tu app, olvida al usuario para que el siguiente que use el navegador no vea su historial:

// Cuando el usuario cierra sesión en tu appJotly('logout');

Si todavía no instalas el widget, empieza por Instalación.

Ver también Widget de feedback en tu app