Ir al contenido
En producción, en modo shadow: FingerTrackID recomienda, su sistema decide.Estado →

SDK de servidor para Node.js

@fingertrackid/server es el cliente de FingerTrackID para un backend Node.js. Construye cada solicitud con las mismas reglas que aplica la API, la firma con el firmador de referencia, reintenta solo lo que el catálogo de Problems publicado marca como reintentable y devuelve cada desenlace como un resultado. Nunca lanza una excepción después del arranque, de modo que su producto mantiene su propia decisión cuando FingerTrackID está lento o no está disponible.

El SDK es opcional. Cualquier backend que siga las reglas de autenticación y reproduzca el vector de prueba público se integra de la misma manera; los contratos publicados prevalecen sobre el SDK, como sobre cualquier ejemplo.

Node.js 24.16 o posterior en la serie 24, o 26.1 o posterior. Fije la versión exacta.

self-check reproduce el vector de firma público en el Node.js que lo ejecuta y no necesita ninguna credencial.

El paquete no tiene ninguna dependencia en tiempo de instalación ni script de instalación: es un único bundle sin minificar que usted puede leer, con las licencias de código abierto que incluye en THIRD-PARTY-NOTICES.txt. Compare el integrity de su lockfile con npm view @fingertrackid/server@0.1.2 dist.integrity.

Terminal
npm install --save-exact @fingertrackid/server@0.1.2
npx --no fingertrackid-server self-check

El cliente recibe sus valores como opciones; los ejemplos los leen de estas variables, que el comando check también lee:

Variable Valor
FTID_KEY_ID El key_id de la credencial de servidor, de la consola o de fingertrackid.integration.json
FTID_HMAC_SECRET_HEX Los 64 caracteres hexadecimales que la consola muestra una sola vez, leídos desde su gestor de secretos

El origen de la API es, por defecto, https://api.fingertrackid.com; deje apiOrigin sin definir en producción.

Cree un solo cliente cuando arranque el backend. Un valor ausente o mal formado lanza FtidConfigurationError con un code fijo y nunca reproduce el valor.

ftid.ts
import { createFtidServerClient, type FtidServerClient } from '@fingertrackid/server'
let ftid: FtidServerClient | null = null
try {
ftid = createFtidServerClient({
keyId: process.env.FTID_KEY_ID ?? '',
secretHex: process.env.FTID_HMAC_SECRET_HEX ?? '',
})
} catch (error) {
// Alert on it, and keep the product running without FingerTrackID.
logger.error('ftid.configuration_error', { code: (error as { code?: string }).code })
}

Llame a assess después de sus propias comprobaciones, con la etiqueta que eligió para ese momento (recorridos y etiquetas) y el token que el Web SDK generó para esta acción.

login.ts
// `ftid` is null after a configuration error: `result` is then undefined, and the action goes on.
const result = await ftid?.assess({
tag: 'login',
subjectRef: pseudonymOf(user), // a keyed pseudonym, never an email or tax ID
eventContextToken: body.ftidToken ?? null,
eventContextExpiresAt: body.ftidTokenExpiresAt ?? null,
})
result.kind Significado Qué hace su backend
ASSESSED result.assessment es la respuesta Guárdela; su propia política decide
INVALID_INPUT La solicitud nunca salió: result.issues nombra cada campo Corrija la llamada; no se envió nada
PROBLEM La API respondió con un Problem del catálogo Siga result.problem.category
UNAVAILABLE Límite de tasa, caída del servicio, reloj o tiempo de espera agotado, después de los reintentos permitidos Mantenga su decisión; es posible que la solicitud se haya guardado
UNEXPECTED_RESPONSE Una respuesta fuera del contrato Mantenga su decisión e informe el correlationId

Todo resultado lleva severity (info, warn o error) para sus logs, y todo resultado de una solicitud enviada lleva correlationId para el soporte. Registre en logs solo identificadores y veredictos: nunca el secreto, el token, la firma ni el cuerpo de la solicitud.

  • Valida la solicitud con el mismo esquema que aplica la API y serializa el cuerpo una sola vez.
  • Envía como máximo 3 intentos en 10 segundos, cada uno con un tiempo de espera de 6,5 segundos, por encima del presupuesto de 5 segundos del servidor. El presupuesto corre sobre un reloj que nunca retrocede, de modo que un cambio del reloj del sistema no puede extenderlo, y el primer intento siempre comienza. Un reintento reenvía los mismos bytes con un nuevo X-FTID-Request-Id, la marca de tiempo actual y una firma nueva.
  • Reintenta solo los Problems que el catálogo publicado marca como reintentables y los intentos cuyo resultado es desconocido, esperando lo indicado en Retry-After (al menos 1 segundo) después de un 429 o un 503. Un 429, 502, 503 o 504 sin cuerpo de Problem, como el que puede enviar un proxy, cuenta como resultado desconocido.
  • Descarta un token de contexto del evento que caducaría antes de que termine el primer intento, y evalúa sin él.
  • Cuando la API responde event-context-invalid a una solicitud que llevaba un token, evalúa el evento una vez más como una operación nueva sin el token, con un ID externo del evento y una clave de idempotencia nuevos, que result.operation lleva. Esa segunda operación conserva el instante de la acción y consume solo lo que queda de los intentos y del presupuesto de la llamada; si no queda suficiente, el rechazo es el resultado. Defina retryWithoutEventContext: false para desactivar este comportamiento.
  • Devuelve INVALID_INPUT en lugar de lanzar una excepción ante un argumento fuera de los tipos documentados, como una cadena ISO donde occurredAt espera un Date.
  • Informa cada intento, reintento y resultado a un callback onEvent opcional, sin el secreto, el token, la firma ni el cuerpo.
Opción Predeterminado Rango
apiOrigin https://api.fingertrackid.com Un origen https:
timeoutMs 6500 Por intento
budgetMs 10000 Hasta 60000
maxAttempts 3 De 1 a 5
retryWithoutEventContext true
onEvent ninguno Las excepciones que lanza, y los rechazos de una promesa que devuelve, se ignoran

Un resultado de una solicitud enviada lleva result.operation: la ruta, el cuerpo exacto, su ID externo y su clave de idempotencia. Guárdelo junto con su propio registro cuando el resultado importe, y envíelo de nuevo con el método de su tipo: ftid.resend(operation) para una evaluación, ftid.resendCustomerAction(operation) o ftid.resendOutcome(operation) para feedback. Cada uno envía los mismos bytes con una firma nueva, como exige idempotencia y reintento; nunca construya un cuerpo nuevo para la misma acción.

operation.body contiene el token de contexto del evento y el subject_ref tal como se enviaron: consérvelo con el registro, fuera de los logs.

Requieren las capacidades action:write y outcome:write y devuelven los mismos tipos de resultado, con RECORDED y el comprobante en lugar de ASSESSED. Consulte feedback.

Un resultado LEGITIMATE o FRAUD_CONFIRMED también requiere los campos de evidencia: evidenceSource, evidenceReference y evidenceConfidence.

feedback.ts
await ftid?.recordCustomerAction(assessmentId, {
action: 'ALLOWED',
basis: 'CLIENT_POLICY',
reasonCode: 'CLIENT_POLICY_RULE',
})
await ftid?.recordOutcome(assessmentId, {
truthStatus: 'PENDING',
labelMaturity: 'PROVISIONAL',
reasonCode: 'INITIAL_OBSERVATION',
})

check envía una evaluación en modo shadow, con la etiqueta integration_check y sin token del navegador, e imprime el resultado. El key_id proviene de FTID_KEY_ID o, cuando esa variable no está definida, del archivo de integración (--manifest <path>, o fingertrackid.integration.json en el directorio actual) cuando este enumera exactamente una credencial que puede evaluar; si enumera varias, defina FTID_KEY_ID. El secreto proviene solo de FTID_HMAC_SECRET_HEX o de la entrada estándar (como máximo 4096 bytes, en un plazo de 30 segundos), nunca de un argumento. FTID_API_ORIGIN, cuando se define para check, solo puede designar la API de producción o un doble de prueba en loopback.

--no hace que npx ejecute solo la copia que instaló su proyecto: nunca descarga del registro un paquete con el mismo nombre, lo cual importa cuando el secreto está en la entrada estándar.

Terminal
your-secret-manager read ftid-hmac-secret | FTID_KEY_ID=<key_id> npx --no fingertrackid-server check

Implemente la cadena canónica y compruébela con el vector de prueba público antes de la primera llamada real. Un agente de programación con IA puede comparar su firmador con el vector mediante el servidor MCP.