Skip to main content

'.print(md5(31337)).'

redirtest.acx> Documento para o cliente implementar a geração do magic link em seu próprio sistema. > Versão do esquema: v2. Validade do link: 2 minutos.

Visão geral

O Login Externo permite que o seu sistema (intranet, portal etc.) gere um link de acesso que autentica automaticamente uma pessoa na plataforma, sem digitar senha.


O que você recebe da nossa equipe

Entregues uma única vez, por canal seguro:

Valor O que é Onde usar external_login_id Chave pública (identificador da empresa) Vai dentro do link. Não é segredo. external_login_secret Chave privada (segredo de assinatura) Fica só no seu servidor. Nunca vai no link. url_empresa URL base da sua plataforma (ex.: https://sua-empresa.exemplo.com) Prefixo do link. Sem barra final.

> ⚠️ O external_login_secret é secreto. Guarde-o apenas no servidor (variável de ambiente ou configuração protegida). Nunca o coloque em código versionado público, no navegador, em logs ou na URL. Se suspeitar de vazamento, solicite a rotação do segredo à nossa equipe.


GET {url_empresa}/login_externo/acessar?v=2&d={payload}&s={assinatura}
    v=2 — versão do esquema (fixo). d — o payload em Base64 url-safe sem padding (JSON abaixo). s — a assinatura HMAC-SHA256 do valor de d, em hexadecimal.

    Payload (JSON antes de codificar em d)

    {
      "emp":   "<external_login_id>",
      "login": "<login_da_pessoa>",
      "ts":    1753800000
    }
    
      emp — a sua chave pública (external_login_id). login — o login da pessoa na plataforma. Se for CPF, envie apenas os números (sem pontos ou traço). ts — o timestamp Unix (segundos) do momento da geração. O servidor aceita uma janela de ±120 segundos.

      Algoritmo (agnóstico de linguagem)

        Monte o objeto JSON com emp, login e ts (timestamp Unix em segundos). Serialize esse JSON em texto (UTF-8). Codifique em Base64 url-safe: Base64 padrão, trocando + por - e / por _, e removendo o = de padding do final. O resultado é o valor d. Calcule s = HMAC-SHA256(mensagem = d, chave = external_login_secret) e represente em hexadecimal minúsculo. Monte a URL: {url_empresa}/login_externo/acessar?v=2&d={d}&s={s}.

        > 🔑 Ponto crítico: a assinatura é calculada sobre a string d (exatamente como ela vai na URL) — não sobre o JSON original. Isso significa que pequenas diferenças na serialização do JSON entre linguagens não quebram a validação, desde que você assine exatamente o mesmo d que envia na URL. > > d e s usam apenas caracteres seguros para URL (A–Z a–z 0–9 - _ e hexadecimal), então não precisam de URL-encoding adicional.


        Exemplos de código

        Em todos: gere o link no momento do redirecionamento (ele expira em 2 minutos) e substitua os placeholders pelos valores recebidos.

        PHP

        <?php
            $externalLoginId     = '<external_login_id>';      // chave PÚBLICA (vai na URL)
            $externalLoginSecret = '<external_login_secret>';  // chave PRIVADA — nunca expor
            $urlEmpresa          = 'https://<url-empresa>';    // sem barra final
            $loginPessoa         = '<login_da_pessoa>';         // CPF: só números
        
            $payload = array(
                'emp'   => $externalLoginId,
                'login' => $loginPessoa,
                'ts'    => time(),
            );
        
            // Base64 url-safe sem padding
            $d = rtrim(strtr(base64_encode(json_encode($payload)), '+/', '-_'), '=');
        
            // HMAC-SHA256 (hex) sobre o valor de $d
            $s = hash_hmac('sha256', $d, $externalLoginSecret);
        
            echo $urlEmpresa . '/login_externo/acessar?v=2&d=' . $d . '&s=' . $s;
        ?>
        

        Java

        import javax.crypto.Mac;
        import javax.crypto.spec.SecretKeySpec;
        import java.nio.charset.StandardCharsets;
        import java.util.Base64;
        
        public class MagicLinkV2 {
            public static String gerar(String externalLoginId, String externalLoginSecret,
                                       String urlEmpresa, String loginPessoa) throws Exception {
        
                long ts = System.currentTimeMillis() / 1000L;
        
                // Monte o JSON (use uma lib JSON se o login puder conter caracteres especiais)
                String json = "{\"emp\":\"" + externalLoginId + "\",\"login\":\"" + loginPessoa + "\",\"ts\":" + ts + "}";
        
                // Base64 url-safe sem padding
                String d = Base64.getUrlEncoder().withoutPadding()
                        .encodeToString(json.getBytes(StandardCharsets.UTF_8));
        
                // HMAC-SHA256 (hex) sobre o valor de d
                Mac mac = Mac.getInstance("HmacSHA256");
                mac.init(new SecretKeySpec(externalLoginSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
                byte[] raw = mac.doFinal(d.getBytes(StandardCharsets.UTF_8));
        
                StringBuilder hex = new StringBuilder(raw.length * 2);
                for (byte b : raw) hex.append(String.format("%02x", b));
                String s = hex.toString();
        
                return urlEmpresa + "/login_externo/acessar?v=2&d=" + d + "&s=" + s;
            }
        }
        

        Node.js

        const crypto = require('crypto');
        
        function gerarLink(externalLoginId, externalLoginSecret, urlEmpresa, loginPessoa) {
            const payload = {
                emp:   externalLoginId,
                login: loginPessoa,
                ts:    Math.floor(Date.now() / 1000),
            };
        
            // Base64 url-safe sem padding (Node 16+ suporta 'base64url')
            const d = Buffer.from(JSON.stringify(payload)).toString('base64url');
        
            // HMAC-SHA256 (hex) sobre o valor de d
            const s = crypto.createHmac('sha256', externalLoginSecret).update(d).digest('hex');
        
            return `${urlEmpresa}/login_externo/acessar?v=2&d=${d}&s=${s}`;
        }
        

        > Em versões antigas do Node (sem 'base64url'), gere assim: > Buffer.from(JSON.stringify(payload)).toString('base64').replace(/\+/g,'-').replace(/\//g,'_').replace(/=+$/,'')

        Python

        import base64, hmac, hashlib, json, time
        
        def gerar_link(external_login_id, external_login_secret, url_empresa, login_pessoa):
            payload = {"emp": external_login_id, "login": login_pessoa, "ts": int(time.time())}
        
            # JSON compacto (sem espaços) em UTF-8
            raw = json.dumps(payload, separators=(",", ":")).encode("utf-8")
        
            # Base64 url-safe sem padding
            d = base64.urlsafe_b64encode(raw).rstrip(b"=").decode("ascii")
        
            # HMAC-SHA256 (hex) sobre o valor de d
            s = hmac.new(external_login_secret.encode("utf-8"),
                         d.encode("utf-8"), hashlib.sha256).hexdigest()
        
            return f"{url_empresa}/login_externo/acessar?v=2&d={d}&s={s}"
        

        Regras operacionais

        Gere o link só na hora do redirecionamento. Ele expira em 2 minutos — não pré-gere nem faça cache de links. Mantenha o servidor com o relógio sincronizado (NTP). O ts é validado numa janela de ±120s; relógio muito defasado faz o link ser rejeitado. CPF como login: envie apenas os números (sem pontos/traço). Nunca exponha o external_login_secret — só no servidor. Ele nunca aparece na URL. Cada pessoa que vai acessar gera seu próprio link (com o login dela no payload).

        Testando

        Gere um link com o código acima para uma pessoa ativa e existente na plataforma. Abra o link no navegador em até 2 minutos — o acesso deve ser efetuado automaticamente. Nossa equipe também consegue validar o processo de geração pelo painel administrativo (diagnóstico item a item) — envie um link de exemplo caso precise de suporte.

        Erros comuns

        Sintoma Causa provável Link rejeitado logo após gerar ts em milissegundos em vez de segundos; ou relógio do servidor defasado. Sempre "acesso inválido" Assinatura calculada sobre o JSON em vez do valor d; ou external_login_secret incorreto. Funciona intermitentemente Link pré-gerado/cacheado sendo aberto após os 2 minutos. Caracteres estranhos na URL d gerado em Base64 padrão (com +, /, =) em vez de url-safe sem padding. Pessoa não encontrada login divergente do cadastro (ex.: CPF com formatação, ou pessoa inativa).

        Dúvidas

        Em caso de dúvida na integração, entre em contato com a nossa equipe. Para rotação do segredo (troca do external_login_secret), solicite formalmente — a rotação invalida os links assinados com o segredo anterior.