---
title: "Como funciona"
description: "Como uma assinatura em nuvem passa pelo CloudHub: sessões e tipos de sessão, descoberta de provedores, regras das URIs de redirecionamento, como levar seus próprios dados na ida e volta e uma lista de verificação de segurança."
canonical: "https://docs.lacunasoftware.com/articles/cloudhub/how-it-works"
locale: "pt-BR"
product: "CloudHub"
last_updated: "2026-10-12"
---

# Como funciona

Esta página acompanha uma assinatura pelo CloudHub e explica o que você escolhe no caminho: o tipo
de sessão, como o CloudHub descobre os provedores, quais URIs de redirecionamento ele aceita e como
levar os seus próprios dados até o retorno do usuário. [Primeiros passos](https://docs.lacunasoftware.com/articles/cloudhub/get-started) transforma
tudo isso em código.

## Provedores e certificados em nuvem

Um **provedor** (PSC, Prestador de Serviço de Confiança) guarda certificados e as chaves privadas
deles em um HSM e permite que o titular os use remotamente. A interface dele segue o DOC-ICP-17.01
do ITI, que é OAuth 2.0: a aplicação envia o usuário à página de autorização do provedor, o usuário
entra e aprova, e a aplicação recebe um token que permite assinar com a chave desse usuário.

Uma pessoa pode ter certificados em vários provedores, e mais de um certificado no mesmo provedor.
O CloudHub esconde o protocolo, mas não essa escolha: quem decide o provedor é o usuário.

## O fluxo, passo a passo

![Como uma assinatura em nuvem passa pelo CloudHub](https://docs.lacunasoftware.com/images/cloudhub/cloudhub-signature-flow.pt-br.svg)

### 1. Criar uma sessão

O seu backend chama `POST /api/sessions` com o CPF (ou CNPJ) do signatário, a **URI de
redirecionamento** para onde o CloudHub deve devolver o usuário e o [tipo de sessão](https://docs.lacunasoftware.com/articles/cloudhub/how-it-works#tipos-de-sessão).
O CloudHub pergunta a cada provedor se ele tem um certificado para esse identificador e responde com
uma entrada para cada provedor que tem:

```json
{
  "services": [
    {
      "serviceInfo": {
        "serviceName": "BirdID",
        "provider": "SOLUTI",
        "endpoint": "https://api.birdid.com.br/",
        "badgeUrl": "https://cdn.lacunasoftware.com/img/psc/birdid.png"
      },
      "authUrl": "https://api.birdid.com.br/oauth/authorize?client_id=…"
    }
  ]
}
```

Nada foi autorizado ainda. Uma lista `services` vazia significa que nenhum provedor tem um
certificado para esse identificador, ou que nenhum dos que têm respondeu a tempo.

### 2. Enviar o usuário a um provedor

Mostre os provedores, por exemplo com `badgeUrl` como logotipo e `provider` como legenda, e leve o
navegador para a `authUrl` da opção escolhida. O usuário entra no provedor e aprova a solicitação,
normalmente no aplicativo móvel do provedor, com um PIN ou lendo um QR code.

### 3. O usuário volta com uma sessão

O provedor redireciona o navegador para o CloudHub, o CloudHub troca o código de autorização pelo
token do provedor e o guarda, e então redireciona o navegador para a sua URI de redirecionamento com
o parâmetro `session` acrescentado. Os parâmetros que você colocou na URI de redirecionamento são
mantidos:

```text
https://app.example.com/sign/complete?fileId=42&session=9f2c…e81a
```

Se o usuário cancelar, se o provedor recusar ou se a troca falhar, o CloudHub também redireciona
para a sua URI de redirecionamento, mas **sem** o parâmetro `session`. O CloudHub não informa o
motivo. Trate a falta de `session` como "não autorizado" e deixe o usuário tentar de novo.

### 4. Ler o certificado

Com a sessão, `GET /api/sessions/certificate` devolve o certificado do signatário, em base64.
`GET /api/v2/sessions/certificate` devolve o mesmo certificado junto com o `alias` dele e o
`serviceName` do provedor.

Quando o provedor tem mais de um certificado para o usuário, o CloudHub escolhe um: um certificado
dentro da validade tem preferência sobre um que não esteja e, entre eles, vale aquele cuja validade
começou mais recentemente. Para garantir que o hash seja assinado exatamente com o certificado que
você leu, passe o `alias` dele na próxima chamada.

### 5. Assinar o hash

A sua biblioteca de assinatura calcula o hash a assinar a partir do documento e do certificado. O
seu backend o envia para `POST /api/sessions/sign-hash` com a sessão e o algoritmo de hash, e o
CloudHub devolve o valor da assinatura, em base64. A biblioteca de assinatura então insere a
assinatura e o certificado no documento assinado.

## Sessões

### O valor da sessão

O valor `session` que a sua URI de redirecionamento recebe é uma string hexadecimal de 64
caracteres. O CloudHub guarda o token do provedor; a sua aplicação guarda só esse valor e o envia em
toda chamada que usa a sessão.

Sem a sua chave de API, uma sessão não serve para nada, mas, juntas, elas permitem assinar com a
chave do usuário. Por isso, trate o valor da sessão como uma credencial: use-o logo, mantenha-o fora
dos seus logs e não o guarde por mais tempo do que precisa. Ele chega em uma query string, então
pode parar no histórico do navegador e no log de acesso do seu servidor web; use HTTPS e configure os
logs de acesso de acordo.

### Tipos de sessão

O tipo de sessão, enviado em `type` ao criar a sessão, diz o que o usuário autoriza.

| Tipo | O usuário autoriza | Use para |
|---|---|---|
| `SingleSignature` | Uma assinatura. É o padrão. | Assinar um documento. Assinar um desafio para [autenticar o usuário](https://docs.lacunasoftware.com/articles/cloudhub/authentication). |
| `SignatureSession` | Qualquer número de assinaturas até a sessão expirar. | Assinar vários documentos com uma única autorização. |
| `MultiSignature` | Uma operação de assinatura que cobre um ou mais hashes. | Depende do provedor. O CloudHub assina um hash por chamada a `sign-hash`, então, para vários documentos, prefira `SignatureSession`. |
| `AuthenticationSession` | Nenhuma assinatura: só a leitura do certificado. | Não recomendado. A maioria dos provedores não oferece esse tipo; para autenticar usuários, use `SingleSignature`. |

Ler o certificado não conta como assinatura: uma sessão `SingleSignature` pode ler o certificado e
depois assinar uma vez.

### Tempo de vida

`lifetimeInSeconds` pede ao provedor uma sessão com essa duração. Quem decide é o provedor: ele pode
conceder menos e, quando o valor é omitido, aplica o próprio padrão. Peça o que a operação precisa:
alguns minutos para uma assinatura, mais para uma `SignatureSession` que assina um lote.

Depois que uma sessão expira, o CloudHub responde com o erro `SessionExpired` a uma chamada que leia
o certificado dela ou assine com ela. Isso pode acontecer já na primeira chamada, se o usuário
demorou a autorizar. Crie
uma nova sessão e envie o usuário ao provedor de novo.

## Descoberta

A **descoberta** é como o CloudHub encontra os provedores que têm um certificado para o signatário.
Ao criar uma sessão:

- **Com um identificador**, o CloudHub consulta todos os provedores em paralelo e devolve só os que
  têm um certificado para ele. Um provedor que não responde fica de fora, em vez de fazer a chamada
  falhar. Envie o CPF ou o CNPJ só com os dígitos.
- **`identifierType`** diz se o identificador é um `CPF` ou um `CNPJ`. Quando omitido, um
  identificador com mais de 11 dígitos é tratado como CNPJ.
- **`discover: false`** pula as consultas e devolve todos os provedores, passando o identificador a
  cada um como dica de login (*login hint*).
- **Sem identificador**, o CloudHub devolve todos os provedores, e o usuário se identifica no
  provedor, por exemplo lendo um QR code. `discover: true` sem identificador é recusado com
  `IdentifierRequiredToDiscover`.

Outras três operações ajudam quando você precisa de mais controle:

- `GET /api/sessions/services?identifier=…` faz a descoberta sem criar uma sessão. Devolve os
  provedores, mas sem `authUrl`.
- `GET /api/sessions/services/{name}/availability?identifier=…` consulta um único provedor.
  `discoveryAvailable: false` significa que o provedor não conseguiu responder; caso contrário,
  `certificateFound` diz se ele tem um certificado para o identificador.
- `POST /api/sessions/services/{name}` cria uma sessão em um único provedor, quando o usuário já o
  escolheu. `name` é o `serviceName` que o CloudHub devolveu, como `BirdID`.

A página [API REST](https://docs.lacunasoftware.com/articles/cloudhub/rest-api) detalha cada uma.

## URIs de redirecionamento

O CloudHub só devolve usuários a URIs de redirecionamento cadastradas para a sua chave de API. Ele
confere a URI quando você cria a sessão e recusa uma URI não cadastrada com
`UnauthorizedRedirectUri`. A Lacuna cadastra as URIs ao emitir a chave; uma chave pode ter várias.
Cada entrada tem uma destas formas:

| Entrada cadastrada | Aceita |
|---|---|
| `https://app.example.com/sign/complete` | Exatamente essa URI, sem diferenciar maiúsculas de minúsculas. A query string entra na comparação. |
| `https://app.example.com` | Qualquer URI que comece com esse esquema, host e porta. |
| `https://*.example.com` | Qualquer subdomínio de `example.com` (mas não o próprio `example.com`), com o mesmo esquema. Inclua a porta quando não for a padrão: `https://*.example.com:8443`. |
| `https://*.example.com/callback` | Qualquer subdomínio, mas só quando o caminho for exatamente `/callback`. |

Se você acrescenta os seus próprios parâmetros à URI de redirecionamento (veja a próxima seção),
cadastre uma entrada de host ou com curinga: uma entrada exata deixa de corresponder assim que a
query string muda.

Para desenvolvimento local, peça uma entrada como `https://localhost:5001` além das de produção.

## Como levar os seus dados até o retorno

O usuário sai da sua aplicação para autorizar, então a requisição que volta à sua URI de
redirecionamento precisa saber a que ela se refere: qual documento assinar, qual pedido aprovar. Há
duas formas de levar essa informação:

- **Parâmetros na URI de redirecionamento**, como `?fileId=42`. Eles voltam inalterados, ao lado de
  `session`, e todas as bibliotecas cliente os suportam. O usuário consegue vê-los e alterá-los.
- **`customState`**, uma string que você envia ao criar a sessão. O CloudHub a guarda dentro do
  estado OAuth criptografado dele, então o usuário não consegue lê-la nem alterá-la, e a devolve em
  `GET /api/sessions/custom-state?session=…`. A API REST, o cliente PHP e o cliente Node.js a enviam;
  os clientes .NET e Java publicados hoje não têm o campo.

De um jeito ou de outro, confira se o que volta se refere a algo que o usuário atual pode assinar.

## Lista de verificação de segurança

- **Mantenha a chave de API no seu servidor.** Nunca a envie a um navegador nem a inclua em um
  aplicativo móvel. Se ela vazar, peça uma nova ao suporte da Lacuna.
- **Confira quem assinou.** O usuário pode entrar no provedor com uma conta diferente da esperada.
  Depois de ler o certificado, compare o CPF (ou CNPJ) dele com o que você pediu.
- **Valide o certificado com a sua biblioteca de assinatura.** O CloudHub devolve o que o provedor
  devolve. É o *trust arbitrator* (PKI SDK) ou o contexto de segurança (Rest PKI) da sua biblioteca
  de assinatura que decide se o certificado é confiável.
- **Trate o valor da sessão como uma credencial**, e só o aceite na URI de redirecionamento com a
  qual você criou a sessão.
- **Use HTTPS** em toda URI de redirecionamento fora do desenvolvimento local.
