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.
flowstring—Padrão "selfie". Na v1 é o único valor aceito; outro valor → 400.
referenceIdstring—Seu 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
400—JSON inválido, environment ausente/inválido, flow não suportado.
403BIOMETRICS_FEATURE_DISABLEDBiometria não habilitada para o tenant — solicite a liberação à Autra.
403—Token sem tenant válido / IP fora da allowlist.
500—Falha 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.
localestring—Idioma da captura. Valor não suportado cai para pt-BR, sem erro.
debugboolean—Loga apenas transições de estado. Nunca loga sessionToken nem jwt.

Não faz nenhuma chamada de rede.

biometrics.createSession(options)

OpçãoTipoObrigatórioNotas
sessionIdstring✓Vindo do seu backend.
sessionTokenstring✓Vindo do seu backend. Nunca logado, nunca persistido.
hostedPageUrlstring✓Vindo 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.
timeoutMsnumber—Teto 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
ready—A captura terminou de carregar e está pronta.
mode_selected{ mode: "modal" | "redirect" }O SDK escolheu o modo de captura.
camera_requested—O 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.
closed—A 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.