Integração Avançada
Webhooks e Sincronização de Dados
Para manter as suas aplicações satélite perfeitamente sincronizadas com o ACAPADEV ID, disponibilizamos um sistema de Webhooks em tempo real. Sempre que um evento importante ocorre no perfil de um utilizador (ou na sua aplicação), enviamos um pedido POST para o seu servidor.
Eventos Disponíveis
Atualmente, o nosso sistema suporta os seguintes eventos:
user.updated- Quando um utilizador atualiza o seu perfil (nome, email, avatar).user.logout- Quando um utilizador termina a sessão globalmente (Single Sign-Out).user.role_updated- Quando o cargo (role) de um utilizador é alterado no portal do desenvolvedor.
Aviso de Segurança: O Segredo do Webhook (Webhook Secret)
Muitos desenvolvedores cometem o erro de tentar validar as assinaturas dos Webhooks utilizando o Client Secret do OAuth. No ACAPADEV ID, por motivos de segurança, os Webhooks utilizam uma chave independente chamada Webhook Secret (ou Signing Secret).
Como Validar a Assinatura (HMAC)
Para garantir que o pedido POST veio efetivamente do ACAPADEV ID e não de um atacante, incluímos um cabeçalho X-Acapadev-Signature em cada webhook. Esta assinatura é um HMAC-SHA256 gerado a partir do payload JSON exato enviado no corpo do pedido.
1. Obter o Webhook Secret
Vá ao Portal do Desenvolvedor, abra a sua App e aceda ao separador Webhooks. Copie o valor do Webhook Secret (geralmente tem 40 caracteres). Coloque este valor no seu ficheiro .env local:
ACAPADEV_WEBHOOK_SECRET=o_seu_webhook_secret_aqui
2. Código de Validação no seu Servidor (Exemplo Laravel)
No seu controlador que recebe o webhook, utilize o seguinte código para validar a assinatura antes de processar o evento:
use Illuminate\Http\Request;
public function handleWebhook(Request $request)
{
// 1. Obter a assinatura enviada pelo ACAPADEV
$signature = $request->header('X-Acapadev-Signature');
// 2. Obter o corpo exato (cru) do pedido JSON
$payloadRaw = $request->getContent();
// 3. Obter o Webhook Secret do seu .env
$secret = env('ACAPADEV_WEBHOOK_SECRET');
// 4. Calcular o HMAC-SHA256
$expectedSignature = hash_hmac('sha256', $payloadRaw, $secret);
// 5. Comparar de forma segura
if (!hash_equals($expectedSignature, $signature)) {
abort(401, 'Assinatura Inválida!');
}
// Assinatura válida! Processar o evento...
$payload = json_decode($payloadRaw, true);
$event = $payload['event'];
if ($event === 'user.updated') {
// Atualizar utilizador na sua base de dados local
}
if ($event === 'user.role_updated') {
// Obter o novo cargo (ex: 'admin', 'editor' ou null se revogado)
$newRole = $payload['new_role'];
$userId = $payload['user_id'];
// Exemplo: Atualizar flag de administrador
$localUser = User::where('sso_id', $userId)->first();
if ($localUser) {
$localUser->is_admin = ($newRole === 'admin');
$localUser->save();
}
}
return response()->json(['status' => 'success']);
}
Estrutura do Payload: user.role_updated
Para o evento de atribuição de cargos RBAC, o payload JSON que a sua aplicação receberá será semelhante a este:
{
"event": "user.role_updated",
"app_id": "99a8b7c6-...",
"timestamp": "2026-06-20T12:34:56+00:00",
"user_id": 123,
"email": "[email protected]",
"new_role": "admin"
}
Nota: Se o acesso for revogado pelo desenvolvedor através do portal, o campo new_role será enviado com o valor null.
Dicas de Resolução de Problemas
- As assinaturas não coincidem de forma alguma? Certifique-se de que não está a usar o `Client Secret` em vez do `Webhook Secret`.
- Ainda não coincidem? Verifique se não está a modificar ou a recodificar o JSON com `json_encode()` antes de calcular o Hash. O HMAC deve ser calculado sobre a string crua (`$request->getContent()`).