OG Framework
OG Framework Documentação
Voltar para Documentação

Criptografia

Security Module

O módulo de Security centraliza operações críticas de segurança do framework, fornecendo encriptação simétrica para dados sensíveis e gestão de tokens JWT para autenticação entre serviços.

O Que Faz Este Módulo?

O Security Module é a "caixa-forte" do framework. Sempre que precisas de proteger dados que vão ser armazenados (como tokens de terceiros, dados pessoais, ou credenciais de APIs externas), usas o Encrypter. Quando precisas de trocar informação autenticada entre serviços (como provar que um pedido veio realmente do ERP), usas o JwtManager.

Vamos ver cada um em detalhe.

Encrypter (Encriptação Simétrica)

Imagina que tens de guardar o token de acesso à API de um banco na base de dados. Se alguém aceder à base de dados, esse token não pode estar em texto limpo. O Encrypter resolve isto — encripta os dados com AES-256 antes de os guardar, e desencripta quando precisas de os usar.

A encriptação é "simétrica" porque usa a mesma chave (APP_KEY) para encriptar e desencriptar. É rápida e eficiente para dados que só a tua aplicação precisa de ler.

Uso Básico

A Facade Crypt torna isto muito simples. Podes encriptar strings, arrays, ou objectos — o Encrypter serializa tudo automaticamente.

use Og\Modules\Common\Facades\Crypt;

// Encriptar dados simples
$encrypted = Crypt::encrypt('token-secreto-do-banco');

// Encriptar arrays (serializados automaticamente)
$encrypted = Crypt::encrypt([
    'access_token' => 'xxx',
    'refresh_token' => 'yyy',
    'expires_at' => now()->addHours(2)
]);

// Desencriptar
$data = Crypt::decrypt($encrypted);
echo $data['access_token']; // 'xxx'

Quando Usar?

Usa o Encrypter para proteger dados que a tua aplicação precisa de ler mais tarde. Exemplos típicos:

  • Tokens de APIs externas: OAuth tokens, API keys de parceiros.
  • Dados pessoais sensíveis: NIFs, números de conta, dados de saúde (dependendo do contexto legal).
  • Configurações secretas por tenant: Credenciais de email, keys de SMS.

Nota: Para passwords de utilizadores, continua a usar hashing (bcrypt). O Encrypter é para dados que precisas de recuperar, não para validar.

JwtManager (JSON Web Tokens)

Os JWTs são usados para provar identidade entre sistemas. Ao contrário do Encrypter, um JWT não esconde o conteúdo — qualquer pessoa pode ler o payload. O que garante é que o conteúdo não foi alterado e que foi emitido por quem diz ter sido.

No OfficeGest, usamos JWTs principalmente para comunicação com a Autoridade Tributária e outros sistemas externos que exigem assinaturas digitais.

Algoritmos Disponíveis

O algoritmo determina como a assinatura é criada. Os mais comuns:

  • HS256 (simétrico): Usa uma "secret" partilhada entre as duas partes. Bom para comunicação interna onde ambos os sistemas são teus.
  • RS256 (assimétrico): Usa um par de chaves (privada para assinar, pública para verificar). Essencial quando o verificador não pode conhecer a chave de assinatura — como no caso da AT.

Uso Básico

use Og\Modules\Common\Facades\Jwt;

// Criar um JWT assinado com RS256
$payload = [
                                        'iss' => 'officegest.com',     // Quem emitiu
    'sub' => $user->getId(),        // Sujeito (utilizador)
    'iat' => time(),                // Issued at
    'exp' => time() + 3600,         // Expira em 1 hora
    'data' => ['nif' => '123456789']
];

$token = Jwt::encode($payload, $privateKey, 'RS256');

// Verificar e decodificar um JWT recebido
try {
    $decoded = Jwt::decode($token, $publicKey, 'RS256');
    echo $decoded->sub; // ID do utilizador
} catch (ExpiredException $e) {
    // Token expirou
} catch (SignatureInvalidException $e) {
    // Assinatura inválida — alguém alterou o token
}

Gestão de Chaves

Trabalhar com chaves RSA pode ser frustrante. Ficheiros exportados de diferentes sistemas vêm com formatações diferentes — alguns têm BOMs invisíveis, outros usam \r\n em vez de \n, e por aí fora. O JwtManager actua como um "médico de chaves" que corrige estes problemas automaticamente.

Normalização Automática

Quando passas uma chave ao encode() ou decode(), o JwtManager detecta e corrige automaticamente:

  • BOM (Byte Order Mark): Caracteres invisíveis no início do ficheiro — removidos.
  • Linhas literais: Se a chave tem \n como texto em vez de quebras de linha reais — convertido.
  • CRLF do Windows: \r\n convertido para \n.

Ofuscação de Chaves

Para alguns cenários (como integração com a AT), precisamos de guardar chaves RSA na base de dados. Em vez de as guardar em texto limpo, podemos ofuscá-las.

// Ofuscar uma chave antes de guardar na BD
$obfuscated = Jwt::encodeRsaKey($privateKey);
// Guardar $obfuscated na base de dados...

// Restaurar quando precisar de usar
$privateKey = Jwt::decodeRsaKey($obfuscated);
$token = Jwt::encode($payload, $privateKey);

Configuração da APP_KEY

A APP_KEY é a chave mestra do Encrypter. Sem ela, nada funciona. Deve ser uma string de 32 bytes codificada em base64, começando com base64:.

Gerar uma Nova Chave

Usa o comando CLI. A chave é gerada e automaticamente guardada no ficheiro de configuração.

docker compose exec app php og key:generate

⚠️ Nunca Partilhes a APP_KEY

A APP_KEY é como a chave mestra de um cofre. Se alguém a obtiver, pode desencriptar todos os dados protegidos. Nunca a comitas em repositórios git, nunca a partilhes em logs ou mensagens. Cada ambiente (local, staging, produção) deve ter a sua própria chave.

Resolução de Problemas

"Unsupported cipher or incorrect key length"

Este erro significa que a APP_KEY está mal formatada. Verifica que:

  • • Começa com base64:
  • • O conteúdo após base64: tem exactamente 44 caracteres (que decodificam para 32 bytes)
  • • Não tem espaços ou quebras de linha no meio

"JWT Signature Verification Failed"

Estás a usar a chave errada para verificar. Lembra-te:

  • encode() usa a chave Privada
  • decode() usa a chave Pública
  • • Se usares a chave errada, a verificação falha