Biometrics SDK (Web)

Captura de selfie com prova de vida — sessão no backend, captura no SDK, JWT assinado pela Unico.

Biometrics SDK (Web)

O Biometrics SDK faz a captura de uma selfie com prova de vida
(liveness)
dentro da sua aplicação web, sem que o dado biométrico passe
pelo seu código.

O fluxo tem duas pontas suas:

  1. O seu backend cria a sessão na API da Autra com as credenciais OAuth2
    que você já tem.
  2. O seu frontend entrega essa sessão ao SDK, que conduz a captura e
    resolve com um JWT assinado pela Unico — a prova de que a captura veio
    de uma selfie legítima.
🔒

A imagem da selfie nunca chega ao seu código. O SDK não expõe, não

armazena e não transmite dado biométrico para a sua aplicação; ele entrega
apenas o JWT resultante.

O escopo do produto é captura, não verificação. A Autra entrega a você o
JWT; a decisão sobre esse JWT acontece no seu backend.


Antes de começar

A biometria é habilitada e configurada pelo time da Autra. Nenhum item
desta seção é auto-serviço: você abre uma solicitação, a Autra aplica e
confirma, e só então a integração funciona. Trate isso como um passo de
projeto, não como um detalhe de última hora.

Enquanto a liberação não acontece, POST /v1/biometrics/sessions responde
403 BIOMETRICS_FEATURE_DISABLED e o SDK nunca chega a abrir a captura.

1. O que solicitar à Autra

SolicitaçãoPor que é necessáriaO que informar
Habilitar a biometria no seu tenantSem ela, a criação de sessão é recusada com 403 BIOMETRICS_FEATURE_DISABLED.Tenant e em quais ambientes (sandbox, production ou ambos).
Cadastrar as origens (domínios) do seu appSem origem cadastrada, a captura embutida (modal) fica indisponível e o SDK só consegue operar em redirect.Um domínio por ambiente, no formato https://host[:porta]. Veja Origens autorizadas.
Liberar os IPs do seu backendPOST /v1/biometrics/sessions passa pela allowlist de IP do tenant, como os demais endpoints server-to-server.IPs ou faixas de saída do seu backend, por ambiente.
Credenciais OAuth2 (client_id / client_secret)Autenticam as chamadas do seu backend.Só se você ainda não tiver as credenciais usadas nas demais APIs da Autra. Veja Generate access token.
Ajustar TTL e tentativas (opcional)Os padrões (10 minutos, 5 tentativas) atendem a maioria dos casos.Os valores desejados, dentro das faixas em Configuração da sua conta.

Modelo de solicitação:

Assunto: Liberação de biometria — <sua empresa>

Tenant.......: <nome ou ID do tenant>
Ambientes....: sandbox e production
Origens......: sandbox    → https://app-hml.seudominio.com.br
               production → https://app.seudominio.com.br
IPs do backend: production → 200.0.0.10, 200.0.0.11
                sandbox    → 200.0.0.50
TTL/tentativas: manter o padrão (600s / 5 tentativas)
⚠️

Mudou de domínio, subiu um subdomínio novo ou trocou o ambiente de
homologação?
Solicite o cadastro da nova origem antes do deploy. A

autorização é fail-closed: uma origem não cadastrada não gera erro de
configuração no build — ela simplesmente remove a captura embutida do
conjunto de modos disponíveis em produção.

2. O que você prepara do seu lado

ItemDetalhe
Endpoint no seu backend que cria a sessãoChama POST /v1/biometrics/sessions e devolve a sessão ao seu frontend. Nunca exponha o client_secret ao browser.
Endpoint no seu backend que recebe o JWTRecebe o resultado da captura logo após o desfecho.
Páginas servidas em HTTPSO SDK recusa URLs que não sejam HTTPS.
Tela de retorno (só no modo redirect)A página do returnUrl que lê o resultado. Veja Tratando o retorno no modo redirect.
Navegador moderno com câmeraDesktop ou mobile.

Como funciona

Seu backend                  Seu app web + SDK                    Autra
     |                              |                               |
     |  POST /v1/biometrics/sessions                                 |
     |----------------------------------------------------------->  |
     |  sessionId, sessionToken, captureUrl, embedModes              |
     |  <-----------------------------------------------------------|
     |                              |                               |
     |--- repassa a sessão -------->|                               |
     |                              |  session.open()               |
     |                              |------------------------------>|
     |                              |<---------- ready -------------|
     |                              |<---- camera_requested --------|
     |                              |<---- capture_started ---------|
     |                              |<---------- jwt ---------------|
     |<-- POST /api/kyc { jwt } ----|                               |
     |                              |                               |
     |  GET /v1/biometrics/sessions/{id}  (confirmação server-side)  |
     |----------------------------------------------------------->  |

Passo 1 — Backend: criar a sessão

POST /v1/biometrics/sessions

POST /v1/biometrics/sessions
Host: api.autra.io
Authorization: Bearer <access_token OAuth2>
Content-Type: application/json

{
  "referenceId": "customer-42",
  "flow": "selfie",
  "environment": "production"
}

Corpo da requisição

CampoTipoObrigatórioNotas
environment"production" | "sandbox"Qualquer outro valor → 400.
flowstringPadrão "selfie". Na v1 é o único valor aceito; outro valor → 400.
referenceIdstringSeu identificador do usuário/caso. Volta em GET /sessions/{id} para conciliação.

Resposta 201

{
  "sessionId": "0f6c2f2c-6b6b-4f0a-9c5a-2f8f3b6c1d44",
  "sessionToken": "…",
  "hostedPageUrl": "https://biometria.autra.io/sessions/0f6c2f2c-6b6b-4f0a-9c5a-2f8f3b6c1d44",
  "expiresAt": "2026-08-24T18:32:00Z",
  "maxAttempts": 5,
  "embedModes": ["iframe", "popup", "redirect"]
}
CampoDescrição
sessionIdUUID opaco da sessão.
sessionTokenEntregue uma única vez — a Autra guarda apenas o hash. Não há como recuperá-lo depois. Nunca registre em log.
hostedPageUrlEndereço opaco da captura desta sessão. Repasse ao SDK sem interpretar, sem reescrever e sem armazenar: o formato é interno e pode mudar sem aviso. Já vem sem o token.
expiresAtFim do TTL da sessão (UTC, RFC 3339).
maxAttemptsTentativas de captura permitidas nesta sessão.
embedModesModos de captura autorizados para este tenant/ambiente. Repasse sem traduzir ao SDK.
⚠️

sessionToken é uma credencial de vida curta. Entregue-a ao seu

frontend pela sua própria API, no corpo da resposta — nunca em query
string, nunca em log, nunca persistida.

embedModes é fail-closed. Se o seu tenant não tiver nenhuma origem
ativa cadastrada para aquele environment, a resposta vem sem iframe
(["popup", "redirect"]) e o SDK não tenta a captura embutida. O valor
popup ainda é devolvido por compatibilidade; o SDK aceita e ignora.

Erros

HTTPCódigoQuando
400JSON inválido, environment ausente/inválido, flow não suportado.
403BIOMETRICS_FEATURE_DISABLEDBiometria não habilitada para o tenant — solicite a liberação à Autra.
403Token sem tenant válido / IP fora da allowlist.
500Falha interna.

Passo 2 — Frontend: conduzir a captura

Instalação

npm install @autra-io/biometrics-sdk-web
  • ESM + CJS + .d.ts, tree-shakeable (sideEffects: false)
  • Sem dependência de runtime, agnóstico de framework (sem React)
  • Bundle ESM ≤ 15 KB minificado + gzip (verificado no CI)

Uso

import { AutraBiometrics, AutraBiometricsError } from '@autra-io/biometrics-sdk-web';

// 1. o seu backend cria a sessão e devolve estes campos
const { sessionId, sessionToken, hostedPageUrl, embedModes } =
  await fetch('/api/biometrics/session', { method: 'POST' }).then((r) => r.json());

// 2. instancie o SDK (nenhuma chamada de rede acontece aqui)
const biometrics = AutraBiometrics.create({
  environment: 'production', // "production" | "sandbox"
  locale: 'pt-BR',           // opcional
  debug: false,              // opcional — nunca loga sessionToken nem jwt
});

const session = biometrics.createSession({
  sessionId,
  sessionToken,
  hostedPageUrl,             // repasse direto da resposta do backend
  embedModes,                // idem
  preferredMode: 'auto',     // "auto" | "modal" | "redirect"
  timeoutMs: 300_000,
});

session.on('ready', () => console.log('captura pronta'));
session.on('mode_selected', ({ mode }) => console.log('modo', mode));
session.on('camera_requested', () => console.log('pedindo câmera'));
session.on('capture_started', ({ attempt }) => console.log('tentativa', attempt));
session.on('capture_retry', ({ attempt, code }) => console.log('retry', attempt, code));

try {
  const result = await session.open();
  // { sessionId, jwt, attempts, capturedAt }

  // 3. envie o JWT ao SEU backend imediatamente
  await fetch('/api/kyc', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ sessionId: result.sessionId, jwt: result.jwt }),
  });
} catch (err) {
  if (err instanceof AutraBiometricsError) {
    if (err.code === 'cancelled_by_user') return; // usuário fechou, não é erro
    showError(err.code, err.retryable);
  }
} finally {
  session.destroy();
}
⚠️

O jwt é uma credencial de TTL curto (minutos). Envie ao seu backend

imediatamente, não persista e não registre em log.


Passo 3 — Backend: confirmar o resultado

Nunca trate o resultado do browser como a fonte de verdade sozinho. Confirme
o estado da sessão pela API antes de liberar qualquer coisa de valor.

GET /v1/biometrics/sessions/{sessionId}

GET /v1/biometrics/sessions/0f6c2f2c-6b6b-4f0a-9c5a-2f8f3b6c1d44
Authorization: Bearer <access_token OAuth2>
{
  "sessionId": "0f6c2f2c-6b6b-4f0a-9c5a-2f8f3b6c1d44",
  "status": "CAPTURED",
  "referenceId": "customer-42",
  "attempts": 2,
  "maxAttempts": 5,
  "createdAt": "2026-08-24T18:22:00Z",
  "expiresAt": "2026-08-24T18:32:00Z",
  "terminatedAt": "2026-08-24T18:24:11Z",
  "lastFailureCode": null
}

A sessão é sempre escopada ao tenant do token: uma sessão de outro tenant
responde 404, nunca 403 — a API não revela a existência do recurso.

POST /v1/biometrics/sessions/{sessionId}/cancel

{ "status": "CANCELLED" }

Idempotente: cancelar uma sessão já terminada devolve 200 com o
estado atual. O 409 BIOMETRICS_SESSION_CONFLICT fica reservado para
corrida real (o estado mudou entre a leitura e a escrita).


Ciclo de vida da sessão

EstadoSignificado
CREATEDSessão criada; o SDK ainda não abriu a captura.
AUTHORIZEDO SDK abriu a captura e o sessionToken foi validado.
CAPTURINGUma tentativa de captura está em andamento.
CAPTURED✅ Terminal — captura concluída, JWT emitido.
FAILED❌ Terminal — tentativas esgotadas ou falha definitiva.
CANCELLED❌ Terminal — cancelada pelo usuário ou pelo seu backend.
EXPIRED❌ Terminal — TTL vencido.

Regras:

  • Estado terminal é absorvente: uma sessão terminada nunca volta atrás.
    Para uma nova tentativa, crie uma nova sessão.
  • Recarregar a página não consome tentativa — a autorização é
    idempotente, inclusive quando a aba volta do segundo plano no meio da
    captura (CAPTURING → AUTHORIZED).
  • maxAttempts e o TTL são congelados na criação da sessão: um ajuste
    aplicado pela Autra depois vale só para as sessões criadas dali em diante.

Modos de captura

ModoO que o usuário vêQuando usar
modal (iframe no vocabulário da API)A captura abre em um overlay sobre a sua página; o usuário nunca sai do seu app.Modo primário. Exige a origem do seu app cadastrada.
redirectO navegador leva o usuário para a captura e volta ao seu returnUrl com o resultado.Quando o seu app não pode embutir conteúdo externo (CSP, webview, política interna).

preferredMode: 'auto' (padrão) tenta modal e cai para redirect
apenas se você passou returnUrl. Um modo explícito ('modal' ou
'redirect') desliga o fallback automático.

Se você passar embedModes vindo do backend, a sequência resolvida é
filtrada por ele — mesmo que contrarie o preferredMode. É o comportamento
fail-closed: sem iframe autorizado, o modal nunca é tentado.

Tratando o retorno no modo redirect

No modo redirect, open() não resolve — o navegador sai da sua página. O
resultado chega na página do returnUrl, no fragmento da URL (fragmento, e
não query string: assim o valor não vaza para logs de servidor nem para o
header Referer). Leia-o com readRedirectResult():

import { readRedirectResult } from '@autra-io/biometrics-sdk-web';

const outcome = readRedirectResult(); // lê e limpa o fragmento de window.location

if (outcome?.type === 'result') {
  await fetch('/api/kyc', {
    method: 'POST',
    body: JSON.stringify({ jwt: outcome.result.jwt }),
  });
} else if (outcome?.type === 'error') {
  showError(outcome.error.code);
}
// undefined = carregamento normal da página, não um retorno de captura

readRedirectResult(href) aceita uma URL explícita para SSR/testes; nesse
caso window.location não é tocado. A função nunca lança — um fragmento
malformado vira { type: 'error', error: message_invalid }.


Referência do SDK

AutraBiometrics.create(options)

OpçãoTipoObrigatórioNotas
environment"production" | "sandbox"Outro valor → configuration_error.
localestringIdioma da captura. Valor não suportado cai para pt-BR, sem erro.
debugbooleanLoga apenas transições de estado. Nunca loga sessionToken nem jwt.

Não faz nenhuma chamada de rede.

biometrics.createSession(options)

OpçãoTipoObrigatórioNotas
sessionIdstringVindo do seu backend.
sessionTokenstringVindo do seu backend. Nunca logado, nunca persistido.
hostedPageUrlstringVindo do seu backend, repassado sem alteração. Precisa ser HTTPS absoluto.
embedModesArray<"modal" | "iframe" | "popup" | "redirect">Repasse direto de embedModes da API. Omitir = não filtrar.
preferredMode"auto" | "modal" | "redirect"Padrão "auto".
returnUrlstringobrigatório se preferredMode: "redirect"Precisa ser HTTPS.
timeoutMsnumberTeto local de UI; padrão 300000. O servidor continua sendo a autoridade sobre o TTL.

Não faz nenhuma chamada de rede. Entrada inválida lança
AutraBiometricsError com código configuration_error de forma
síncrona
.

session.open(): Promise<AutraBiometricsResult>

type AutraBiometricsResult = {
  sessionId: string;
  jwt: string;        // credencial de TTL curto — envie ao backend, não persista, não logue
  attempts: number;
  capturedAt: string; // RFC 3339
};
  • Chamar open() duas vezes na mesma sessão rejeita a segunda com
    invalid_session.
  • Apenas uma captura embutida por instância de AutraBiometrics pode
    estar aberta por vez; a segunda sessão que tentar rejeita com
    configuration_error.

session.on(event, listener): Unsubscribe

EventoPayloadQuando
readyA captura terminou de carregar e está pronta.
mode_selected{ mode: "modal" | "redirect" }O SDK escolheu o modo de captura.
camera_requestedO SDK pediu permissão de câmera ao usuário.
capture_started{ attempt: number }Início de uma tentativa.
capture_retry{ attempt: number; code: string }Tentativa falhou e haverá nova.
closedA captura foi fechada.

O retorno de on() é a função de unsubscribe.

session.close() / session.destroy()

  • close() fecha a captura ativa; o open() pendente rejeita com
    cancelled_by_host.
  • destroy() remove listeners, a UI e os timers. É idempotente e seguro
    chamar múltiplas vezes — chame sempre no finally.

AUTRA_BIOMETRICS_SDK_VERSION

Constante com a versão publicada do pacote, injetada em tempo de build.


Códigos de erro

Toda falha do SDK chega como AutraBiometricsError:

class AutraBiometricsError extends Error {
  readonly code: AutraBiometricsErrorCode;
  readonly sessionId?: string;
  readonly retryable: boolean;
}
CódigoretryableSignificado
configuration_errornãoParâmetro inválido, URL não-HTTPS, ou outra captura já aberta.
invalid_sessionnãoopen() chamado duas vezes, ou sessão já destruída.
session_expirednãoTTL da sessão venceu.
session_already_usednãoSessão já terminada.
origin_not_allowednãoA origem do seu app não está cadastrada para este ambiente — solicite o cadastro à Autra.
feature_disablednãoBiometria não habilitada para o tenant.
camera_permission_deniednãoUsuário negou a câmera.
camera_unavailablesimSem câmera disponível ou em uso por outro app.
browser_unsupportednãoNavegador sem as APIs necessárias, ou execução fora do browser (SSR).
capture_failedsimA captura falhou (liveness não aprovado, imagem inválida).
attempts_exhaustednãomaxAttempts consumidas.
cancelled_by_usernãoUsuário fechou a captura. Trate como fluxo normal, não como erro.
cancelled_by_hostnãoclose()/destroy() chamados pela sua aplicação.
timeoutsimEstourou o timeoutMs local.
network_errorsimFalha de rede ao carregar a captura.
message_origin_rejectednãoO SDK recebeu uma mensagem de origem inesperada e a descartou.
message_invalidnãoMensagem malformada ou fragmento de retorno corrompido.

retryable indica se repetir a captura faz sentido — na prática, criar
uma nova sessão e abrir de novo.


Configuração da sua conta

Os parâmetros abaixo pertencem ao seu tenant e são aplicados pelo time da
Autra
. Não há endpoint público nem tela de auto-serviço para eles: para
criar, alterar ou remover qualquer um, abra uma solicitação com a Autra. Toda
alteração é auditada.

Parâmetros da sessão

ParâmetroPadrãoFaixa aceitaEfeito
TTL da sessão600 segundos (10 min)60 – 600Prazo entre a criação da sessão e o desfecho da captura. Vencido, a sessão vai para EXPIRED.
Tentativas por sessão51 – 6Quantas capturas o usuário pode tentar antes de a sessão ir para FAILED.

Os dois valores são congelados na criação de cada sessão: uma alteração
combinada com a Autra passa a valer para as sessões criadas dali em diante,
nunca para as que já estão em andamento.

Origens autorizadas

Necessárias para o modo modal: a Autra só autoriza a captura embutida em
origens previamente cadastradas.

Formato da origem: https://host[:porta]sem caminho, sem barra final,
sem http://
.

✅ https://app.seudominio.com.br
✅ https://checkout.seudominio.com.br:8443
❌ https://app.seudominio.com.br/
❌ https://app.seudominio.com.br/checkout
❌ http://app.seudominio.com.br

As origens são por ambiente: cadastrar em sandbox não libera production
informe as duas listas na solicitação.

Para conferir o que está ativo hoje, olhe o embedModes da resposta de
POST /v1/biometrics/sessions: a presença de iframe confirma que a origem
daquele ambiente está cadastrada. Se iframe não aparecer, é sinal de origem
faltando — solicite o cadastro à Autra.


Segurança

  • O SDK nunca recebe uma credencial da API da Autra. Ele recebe apenas o
    sessionToken de vida curta emitido pelo seu backend.
  • O sessionToken é entregue uma única vez e guardado apenas como hash,
    comparado em tempo constante. Não é recuperável.
  • O token nunca trafega em URL que o seu servidor possa registrar: a API
    devolve hostedPageUrl limpa e o SDK acopla o token no browser, em um
    ponto da URL que não chega ao servidor nem ao header Referer.
  • Canal de mensagens endurecido: o SDK valida a origem e a janela de
    cada mensagem que recebe, usa envelope versionado e ignora qualquer
    mensagem após o desfecho da sessão.
  • Todas as URLs precisam ser HTTPS (hostedPageUrl, returnUrl).
  • jwt é credencial: envie ao seu backend imediatamente, nunca persista,
    nunca logue.
  • Não confie apenas no cliente: confirme o desfecho com
    GET /v1/biometrics/sessions/{sessionId} antes de liberar qualquer coisa
    de valor.

Solução de problemas

SintomaCausa provável
configuration_error em createSession()hostedPageUrl/returnUrl não é HTTPS ou não é URL absoluta; falta campo obrigatório; preferredMode: "redirect" sem returnUrl.
configuration_error em open()Outra sessão da mesma instância já tem uma captura aberta.
A captura nunca abre em modalembedModes veio sem iframe — a origem do seu app não está cadastrada para esse ambiente. Solicite o cadastro à Autra.
open() nunca resolve no modo redirectEsperado: o navegador sai da sua página. Trate o resultado no returnUrl com readRedirectResult().
browser_unsupportedChamado fora do browser (SSR) ou sem as APIs de DOM/câmera que o modo exige.
camera_permission_denied mesmo com o usuário aceitandoA sua página está dentro de outro iframe ou tem Permissions-Policy restritiva, bloqueando o acesso à câmera.
message_origin_rejected no consoleO SDK descartou uma mensagem de origem inesperada — não vem da captura legítima.
403 BIOMETRICS_FEATURE_DISABLEDBiometria não habilitada para o tenant. Solicite a liberação à Autra.
404 em GET /sessions/{id}A sessão não existe ou pertence a outro tenant.
409 BIOMETRICS_SESSION_CONFLICT no cancelO estado mudou concorrentemente. Releia com GET /sessions/{id}.

Referência rápida de endpoints

MétodoRotaAuthUso
POST/v1/biometrics/sessionsOAuth2 Bearer + IP allowlistCria a sessão
GET/v1/biometrics/sessions/{sessionId}OAuth2 BearerConsulta o estado
POST/v1/biometrics/sessions/{sessionId}/cancelOAuth2 BearerCancela (idempotente)

São os três endpoints da integração — não há endpoint de configuração: TTL,
tentativas, origens autorizadas e habilitação da feature são aplicados pela
Autra mediante solicitação. Veja Configuração da sua
conta
.


Licença

@autra-io/biometrics-sdk-web é distribuído sob Apache-2.0.