Autenticação com certificado digital ICP-Brasil no seu sistema web. Dois métodos — Popup ou XHR — com retorno em JSON pronto para o seu login.
// inclua ihubauth.js e chame:
ihubauth(TOKEN, function (erro, resultado) {
if (erro) return tratarErro(erro);
// envie resultado.ticket ao seu backend → /verificar
enviarAoBackend(resultado.ticket);
});
Antes de ir para produção, você pode validar a integração em ambiente de desenvolvimento ou homologação na sua rede local.
Autenticações originadas de redes locais não descontam créditos do seu plano — valide a integração à vontade, sem afetar seu saldo. Valem as faixas privadas padrão:
Para evitar abuso, cada ambiente de homologação em rede local é limitado a 7 autenticações por dia — suficiente para validar a integração ponta a ponta.
Você inclui a integração na sua página de login e configura o token de licença. O serviço valida a cadeia ICP-Brasil e devolve ao navegador apenas um ticket de uso único; o seu backend troca esse ticket pela identidade do titular — que nunca passa pelo navegador.
O Popup é o caminho recomendado e seguro: devolve um ticket que o seu backend troca pela identidade. O XHR entrega o JSON direto no navegador e existe só para compatibilidade com sistemas legados — será desativado em 1º de outubro de 2026.
Inclui a biblioteca ihubauth.js e chama uma função. A janela é isolada e devolve um ticket de uso único — a identidade é resgatada no seu backend, nunca exposta ao navegador.
Chamada direta ao endpoint, com o certificado apresentado na requisição (mTLS). Retorna o JSON direto no navegador — sem etapa de backend, com menor garantia.
Inclua o arquivo ihubauth.js (fornecido pela iHub) e chame ihubauth(TOKEN, callback). No sucesso, o callback recebe um ticket de uso único — não os dados. Envie esse ticket ao seu backend, que o troca pela identidade em /certificado/verificar.
<!-- 1. Inclua a biblioteca fornecida pela iHub -->
<script src="/js/ihubauth.js"></script>
<!-- 2. Botão de login -->
<button onclick="autenticar()">Autenticar com certificado digital</button>
<script>
// Cole aqui o token de licença fornecido pela iHub:
var TOKEN = 'SEU_TOKEN_AQUI';
function autenticar() {
ihubauth(TOKEN, function (erro, resultado) {
if (erro) {
// erro = { codigo, etapa, mensagem } — ver "Códigos de erro"
alert(erro.mensagem);
return;
}
// resultado.ticket — opaco, uso único (~120s). Envie ao SEU backend:
fetch('/sessao/certificado', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ticket: resultado.ticket })
}).then(function (r) {
if (r.ok) location.href = '/painel'; // sessão criada no backend
else alert('Falha ao validar o login.');
});
});
}
</script>
A biblioteca já aponta para a API de produção. Se precisar, dá para informar a base por opção: ihubauth(TOKEN, callback, { baseUrl: 'https://api.ihub.com.br' }). Para o Popup funcionar, o navegador precisa permitir popups para o domínio da sua aplicação.
Faça uma requisição GET ao endpoint com credentials: 'include' — isso faz o navegador apresentar o certificado do cliente (mTLS). A resposta vem com HTTP 200 e o JSON no corpo, ou um dos códigos de erro.
// Cole aqui o token de licença fornecido pela iHub:
var TOKEN = 'SEU_TOKEN_AQUI';
var API_URL = 'https://api.ihub.com.br/certificado/login?token=' + encodeURIComponent(TOKEN);
function autenticar() {
fetch(API_URL, {
method: 'GET',
credentials: 'include' // apresenta o certificado do cliente (mTLS)
})
.then(function (res) {
return res.text().then(function (body) {
return { status: res.status, body: body };
});
})
.then(function (r) {
if (r.status === 200) {
var dados = JSON.parse(r.body);
// dados.Nome, dados.CPF, dados.Validade, dados.DiasValidade,
// dados.Verificado, dados.TipoCertificado
realizarLogin(dados);
} else {
tratarErro(r.status); // ver "Códigos de erro"
}
});
}
O frontend recebe um ticket; o seu backend o troca pela identidade autoritativa do titular. Assim a identidade nunca é confiada a partir do navegador — só o ticket, opaco e de uso único, trafega no cliente.
Do seu backend, faça um POST para o endpoint abaixo com o token de licença e o ticket recebido. A resposta traz os dados do titular (mesmo objeto da seção Retorno).
POST https://api.ihub.com.br/certificado/verificar
Content-Type: application/json
{ "token": "SEU_TOKEN_AQUI", "ticket": "<ticket recebido do frontend>" }
→ 200 OK
{
"Nome": "JOAO DA SILVA",
"CPF": "12345678909",
"Validade": "22/07/2026",
"DiasValidade": 425,
"Verificado": true,
"TipoCertificado": "A1"
}
<?php
// Endpoint do SEU backend que recebe o ticket do frontend.
// Ex.: POST /sessao/certificado · corpo JSON: { "ticket": "..." }
const IHUB_TOKEN = 'SEU_TOKEN_AQUI'; // token de licença (config no servidor)
const IHUB_VERIFICAR = 'https://api.ihub.com.br/certificado/verificar';
session_start();
// 1) Proteja contra CSRF como qualquer POST que cria sessão
// (token anti-CSRF do seu framework, ou um nonce/state ligado à sessão).
$entrada = json_decode(file_get_contents('php://input'), true);
$ticket = $entrada['ticket'] ?? null;
if (!$ticket) {
http_response_code(400);
exit(json_encode(['erro' => 'ticket ausente']));
}
// 2) Resgata o ticket na iHub (servidor-a-servidor)
$ch = curl_init(IHUB_VERIFICAR);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['token' => IHUB_TOKEN, 'ticket' => $ticket]),
CURLOPT_TIMEOUT => 10,
]);
$resposta = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
http_response_code(401);
exit(json_encode(['erro' => 'ticket inválido ou expirado']));
}
$dados = json_decode($resposta, true);
// 3) Confere a validação da cadeia ICP-Brasil
if (($dados['Verificado'] ?? false) !== true) {
http_response_code(401);
exit(json_encode(['erro' => 'certificado não verificado']));
}
// 4) Localize o usuário pelo CPF/CNPJ na SUA base (find-or-create)
$usuario = encontrarUsuarioPorDocumento($dados['CPF']); // implemente na sua app
if (!$usuario) {
http_response_code(403);
exit(json_encode(['erro' => 'usuário não cadastrado']));
}
// 5) Cria a sessão com os dados da iHub (NUNCA com algo vindo do frontend)
$_SESSION['usuario_id'] = $usuario['id'];
$_SESSION['nome'] = $dados['Nome'];
echo json_encode(['ok' => true]);
import requests
from flask import Flask, request, session, jsonify
app = Flask(__name__)
app.secret_key = "..." # chave de sessão do Flask
IHUB_TOKEN = "SEU_TOKEN_AQUI" # token de licença (config no servidor)
IHUB_VERIFICAR = "https://api.ihub.com.br/certificado/verificar"
@app.post("/sessao/certificado")
def sessao_certificado():
# 1) Proteja contra CSRF como qualquer POST que cria sessão
# (Flask-WTF/CSRF, ou um nonce/state ligado à sessão).
ticket = (request.get_json(silent=True) or {}).get("ticket")
if not ticket:
return jsonify(erro="ticket ausente"), 400
# 2) Resgata o ticket na iHub (servidor-a-servidor)
r = requests.post(
IHUB_VERIFICAR,
json={"token": IHUB_TOKEN, "ticket": ticket},
timeout=10,
)
if r.status_code != 200:
return jsonify(erro="ticket inválido ou expirado"), 401
dados = r.json()
# 3) Confere a validação da cadeia ICP-Brasil
if dados.get("Verificado") is not True:
return jsonify(erro="certificado não verificado"), 401
# 4) Localize o usuário pelo CPF/CNPJ na SUA base (find-or-create)
usuario = encontrar_usuario_por_documento(dados["CPF"]) # implemente na sua app
if not usuario:
return jsonify(erro="usuário não cadastrado"), 403
# 5) Cria a sessão com os dados da iHub (NUNCA com algo vindo do frontend)
session["usuario_id"] = usuario["id"]
session["nome"] = dados["Nome"]
return jsonify(ok=True)
Um cliente reutilizável que encapsula o resgate do ticket — use-o em qualquer app .NET.
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json.Serialization;
// Cliente reutilizável que troca o ticket pela identidade na iHub.
public sealed class IHubAuthClient
{
private const string Verificar = "https://api.ihub.com.br/certificado/verificar";
private readonly HttpClient _http;
private readonly string _token; // token de licença (config no servidor)
public IHubAuthClient(HttpClient http, string token)
{
_http = http;
_token = token;
}
// Resgata o ticket. Lança se inválido/expirado ou não verificado.
public async Task<CertificadoDados> VerifyAsync(string ticket, CancellationToken ct = default)
{
var resp = await _http.PostAsJsonAsync(
Verificar, new { token = _token, ticket }, ct);
if (!resp.IsSuccessStatusCode)
throw new InvalidOperationException("Ticket inválido ou expirado.");
var dados = await resp.Content.ReadFromJsonAsync<CertificadoDados>(cancellationToken: ct)
?? throw new InvalidOperationException("Resposta vazia.");
if (!dados.Verificado)
throw new InvalidOperationException("Certificado não verificado.");
return dados;
}
}
public sealed record CertificadoDados(
[property: JsonPropertyName("Nome")] string Nome,
[property: JsonPropertyName("CPF")] string Cpf,
[property: JsonPropertyName("Validade")] string Validade,
[property: JsonPropertyName("DiasValidade")] int DiasValidade,
[property: JsonPropertyName("Verificado")] bool Verificado,
[property: JsonPropertyName("TipoCertificado")] string TipoCertificado);
O controller que recebe o ticket do frontend, usa o cliente acima e cria a sessão por cookie.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
[ApiController]
[Route("sessao")]
public class SessaoController : ControllerBase
{
private readonly IHubAuthClient _ihub;
private readonly IUsuarioRepo _usuarios;
public SessaoController(IHubAuthClient ihub, IUsuarioRepo usuarios)
{
_ihub = ihub;
_usuarios = usuarios;
}
public record Entrada(string Ticket);
[HttpPost("certificado")]
[ValidateAntiForgeryToken] // protege o POST de login contra CSRF
public async Task<IActionResult> Certificado([FromBody] Entrada entrada)
{
if (string.IsNullOrEmpty(entrada.Ticket))
return BadRequest(new { erro = "ticket ausente" });
// 1) Resgata o ticket na iHub (servidor-a-servidor)
CertificadoDados dados;
try { dados = await _ihub.VerifyAsync(entrada.Ticket); }
catch { return Unauthorized(new { erro = "ticket inválido ou expirado" }); }
// 2) Localize o usuário pelo CPF/CNPJ na SUA base
var usuario = await _usuarios.PorDocumentoAsync(dados.Cpf);
if (usuario is null)
return StatusCode(403, new { erro = "usuário não cadastrado" });
// 3) Cria a sessão (cookie) com os dados da iHub
var claims = new List<Claim>
{
new(ClaimTypes.NameIdentifier, usuario.Id.ToString()),
new(ClaimTypes.Name, dados.Nome),
};
var id = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(id));
return Ok(new { ok = true });
}
}
O /certificado/verificar devolve ao seu backend o objeto com os dados do titular. (No XHR legado, o mesmo objeto vem direto no corpo.)
{
"Nome": "JOAO DA SILVA",
"CPF": "12345678909", // CPF (11 díg) ou CNPJ (14 díg)
"Validade": "22/07/2026",
"DiasValidade": 425,
"Verificado": true,
"TipoCertificado": "A1" // "A1" ou "A3"
}
Os códigos variam um pouco entre os métodos. Trate cada um com uma mensagem clara para o usuário.
O callback recebe { codigo, etapa, mensagem } como primeiro parâmetro.
O código vem em res.status; o corpo pode trazer detalhes.
ihubauth(TOKEN, function (erro, resultado) {
if (erro) {
switch (erro.codigo) {
case 456:
alert('Seu certificado foi revogado. Renove-o na sua certificadora.');
break;
case 457:
alert('Certificado não encontrado. Verifique se está instalado.');
break;
default:
alert(erro.mensagem);
}
return;
}
enviarAoBackend(resultado.ticket); // envie o ticket ao seu backend
});