Pangeia ID - Guia Completo de Integracao (v2)
Esta pagina e o guia oficial para integrar login Pangeia ID em qualquer site/app, com foco em onboarding rapido e sem ambiguidade.
Contrato usado aqui: frontend sem apiKey obrigatoria, exchange server-to-server com Authorization: Bearer.
TL;DR (em 30 segundos)
- Adicione o script
pangeia-id.jsna sua pagina. - Crie um botao com classe
.pangeiaid-loginedata-exchange-url. - Implemente no seu backend o endpoint
POST /auth/exchange-hash. - Seu backend chama
POST /api/auth/exchange-hashno Pangeia com bearer token. - Com
pid + user, crie sessao local e pronto.
Passo a Passo (modo newbie)
Passo 1 - Frontend: botao pronto
<button class="pangeiaid-login" data-exchange-url="/auth/exchange-hash">
Entrar com Pangeia ID
</button>
<script defer src="https://id.pangeialabs.com/static/pangeia-id.js"></script>
<script defer src="/static/js/pangeia-auth.js"></script>
Exemplo de /static/js/pangeia-auth.js (arquivo externo, sem inline):
document.addEventListener("pangeia:authenticated", function () {
window.location.reload();
});
document.addEventListener("pangeia:error", function (ev) {
console.error("Erro Pangeia:", ev.detail);
alert("Nao foi possivel autenticar agora.");
});
CSP recomendada (sem unsafe-inline)
Para evitar bloqueios de Content Security Policy, nao use onclick/onload no HTML e nao use <script>...</script> inline.
Content-Security-Policy:
default-src 'self';
script-src 'self' https://id.pangeialabs.com;
connect-src 'self' https://id.pangeialabs.com;
frame-ancestors 'self';
base-uri 'self';
Se voce realmente precisar de script inline, use nonce no seu backend e script-src 'nonce-...'. O recomendado para integracao do Pangeia ID continua sendo script externo com defer.
Passo 2 - Backend: endpoint local de exchange
Esse endpoint recebe login_hash do frontend e troca no Pangeia ID.
Exemplo Python (Flask)
import os
import requests
from flask import Flask, request, jsonify, session
app = Flask(__name__)
app.secret_key = "troque-isto"
PANGEIA_BASE = "https://id.pangeialabs.com"
PANGEIA_TOKEN = os.environ["PANGEIA_INTEGRATOR_TOKEN"]
@app.post("/auth/exchange-hash")
def auth_exchange_hash():
data = request.get_json() or {}
login_hash = (data.get("login_hash") or "").strip()
if not login_hash:
return jsonify({"ok": False, "error": "login_hash obrigatoria"}), 400
resp = requests.post(
f"{PANGEIA_BASE}/api/auth/exchange-hash",
headers={
"Authorization": f"Bearer {PANGEIA_TOKEN}",
"Content-Type": "application/json",
},
json={"login_hash": login_hash},
timeout=15,
)
out = resp.json()
if not resp.ok or not out.get("ok"):
return jsonify(out), resp.status_code
# Sessao local do seu app
session["pid"] = out["pid"]
session["user_email"] = out["user"]["email"]
return jsonify(out), 200
Exemplo Node.js (Express)
import express from "express";
const app = express();
app.use(express.json());
const PANGEIA_BASE = "https://id.pangeialabs.com";
const PANGEIA_TOKEN = process.env.PANGEIA_INTEGRATOR_TOKEN;
app.post("/auth/exchange-hash", async (req, res) => {
const login_hash = (req.body?.login_hash || "").trim();
if (!login_hash) {
return res.status(400).json({ ok: false, error: "login_hash obrigatoria" });
}
const r = await fetch(`${PANGEIA_BASE}/api/auth/exchange-hash`, {
method: "POST",
headers: {
"Authorization": `Bearer ${PANGEIA_TOKEN}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ login_hash })
});
const out = await r.json();
return res.status(r.status).json(out);
});
Passo 3 - Consultar dados pelo PID
curl -X POST https://id.pangeialabs.com/api/user/by-pid \
-H "Authorization: Bearer SEU_TOKEN_DE_INTEGRADOR" \
-H "Content-Type: application/json" \
-d '{"pid":"pid_xxx"}'
Contrato HTTP oficial (v2)
POST /api/auth/exchange-hash
Headers obrigatorios
Authorization: Bearer <integrator_token>
Content-Type: application/json
Body
{ "login_hash": "temp_..." }
Resposta de sucesso
{
"ok": true,
"pid": "pid_...",
"user": {
"id": "...",
"name": "...",
"email": "...",
"phone": "...",
"taxid": "...",
"birth_date": "...",
"avatar_url": "...",
"created_at": "...",
"updated_at": "..."
}
}
Erros padronizados
401 INVALID_INTEGRATOR_TOKEN400 INVALID_LOGIN_HASH401 EXPIRED_LOGIN_HASH409 LOGIN_HASH_ALREADY_CONSUMED500 INTERNAL_ERROR
POST /api/user/by-pid
Authorization: Bearer <integrator_token>
Content-Type: application/json
{ "pid": "pid_..." }
Webhook v2 (seguranca e consumo)
Configure sua webhook_url. O Pangeia enviara eventos assinados.
Headers
X-Pangeia-Signature: sha256=<hmac_hex>X-Pangeia-Timestamp: <unix_seconds>X-Pangeia-Event-Id: evt_...
Webhook secret no seu backend: use o webhook_secret configurado na integração no dashboard Pangeia ID (ou rotacione em "API Keys e integrações").
Exemplo de env no app integrador: PANGEIA_ID_WEBHOOK_SECRET=ws_live_...
Payload
{
"version": "2",
"event_id": "evt_...",
"event_type": "user.updated",
"timestamp": "2026-02-14T00:00:00Z",
"pid": "pid_...",
"user": {}
}
Tipos de evento
user.updated: usuario alterou dados de perfil.user.revoked: usuario revogou o app/integracao.
Validacao de assinatura (Python)
import hmac, hashlib
from flask import request
def verify_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
# signature_header esperado: "sha256=..."
if not signature_header or not signature_header.startswith("sha256="):
return False
sent = signature_header.split("=", 1)[1]
expected = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(sent, expected)
@app.post("/webhook/pangeia-id")
def webhook():
raw = request.get_data()
sig = request.headers.get("X-Pangeia-Signature", "")
if not verify_signature(raw, sig, secret="SEU_WEBHOOK_SECRET"):
return {"ok": False, "error": "invalid signature"}, 401
event = request.get_json() or {}
# idempotencia recomendada por event_id
# processar user.updated / user.revoked
return {"ok": True}, 200
Configuracao por data-* (auto-bind)
Voce pode configurar o SDK diretamente no HTML:
<button
class="pangeiaid-login"
data-exchange-url="/auth/exchange-hash"
data-exchange-method="POST"
data-exchange-credentials="include"
data-exchange-timeout-ms="15000"
data-exchange-payload-key="login_hash"
>
Entrar
</button>
FAQ rapido
Preciso enviar apiKey no frontend?
Não. No v2, o app e identificado pelo bearer token no backend.
Posso continuar usando modo programatico?
Sim. PangeiaID.openLogin(...) continua disponivel.
Quando usar pid?
Sempre como identificador do usuario no seu app e para conciliar webhooks.
Checklist final (go-live)
- Botao de login com
.pangeiaid-loginfuncionando. /auth/exchange-hashlocal criado e testado.- Bearer token configurado no backend (nunca no browser).
- Sessao local criada apos exchange com sucesso.
- Webhook recebendo, validando assinatura e tratando idempotencia.