Acapadev

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()`).
Enter para selecionar ESC para sair