Pular para o conteúdo principal

Autenticação e Segurança

O acesso à Web API Aéreo é protegido por uma camada dupla de credenciais: Segurança de Desenvolvedor (via cabeçalhos HTTP) e Identificação de Agência (no corpo das requisições).


1. Cabeçalhos HTTP Obrigatórios​

Todas as chamadas à API devem incluir os seguintes headers:

HeaderTipoDescrição
developer-tokenString (GUID)Identificador único do desenvolvedor fornecido pela Wooba.
developer-access-codeString (Base64)Código de acesso diário criptografado em RSA (PKCS#1 v1.5) com a data atual.
Content-TypeStringapplication/json
AcceptStringapplication/json

2. Como Gerar o developer-access-code​

O developer-access-code deve ser recalculado diariamente para garantir a segurança da chamada:

  1. Mensagem original: Combine sua chave secreta com a data atual (formato DD/MM/AAAA), separadas por pipe |:
    {CHAVE_SECRETA_DO_DESENVOLVEDOR}|{DD/MM/AAAA}
    Exemplo: MINHA_CHAVE_SECRETA_123|15/10/2026
  2. Criptografia RSA: Criptografe essa string utilizando a Chave Pública RSA fornecida pela Wooba, obrigatoriamente no modo de preenchimento PKCS#1 v1.5.
  3. Conversão Base64: Converta o array de bytes criptografado para uma string em Base64.

3. Implementação da Criptografia em Diferentes Linguagens​

A chave pública é fornecida no formato XML padrão da Wooba:

<RSAKeyValue>
<Modulus>m3Kx...==</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>

3.1 Exemplo em C# (.NET)​

using System;
using System.Security.Cryptography;
using System.Text;

public static class WoobaAuth
{
public static string GerarDeveloperAccessCode(string secretKey, string publicKeyXml)
{
string dataHoje = DateTime.UtcNow.ToString("dd/MM/yyyy");
string texto = $"{secretKey}|{dataHoje}";

using (var rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(publicKeyXml);
byte[] dados = Encoding.UTF8.GetBytes(texto);
// Segundo parâmetro = false ativa o modo PKCS#1 v1.5
byte[] criptografado = rsa.Encrypt(dados, false);
return Convert.ToBase64String(criptografado);
}
}
}

3.2 Exemplo em Node.js (JavaScript / TypeScript)​

const crypto = require('crypto');

function xmlKeyToPem(xmlKey) {
const modulusMatch = xmlKey.match(/<Modulus>(.*?)<\/Modulus>/);
const exponentMatch = xmlKey.match(/<Exponent>(.*?)<\/Exponent>/);
if (!modulusMatch || !exponentMatch) throw new Error('Chave XML inválida');

const modulus = Buffer.from(modulusMatch[1], 'base64');
const exponent = Buffer.from(exponentMatch[1], 'base64');

return crypto.createPublicKey({
key: {
kty: 'RSA',
n: modulus.toString('base64url'),
e: exponent.toString('base64url'),
},
format: 'jwk',
});
}

function gerarDeveloperAccessCode(secretKey, publicKeyXml) {
const hoje = new Date();
const dia = String(hoje.getUTCDate()).padStart(2, '0');
const mes = String(hoje.getUTCMonth() + 1).padStart(2, '0');
const ano = hoje.getUTCFullYear();
const texto = `${secretKey}|${dia}/${mes}/${ano}`;

const publicKey = xmlKeyToPem(publicKeyXml);
const buffer = Buffer.from(texto, 'utf8');

const encrypted = crypto.publicEncrypt(
{
key: publicKey,
padding: crypto.constants.RSA_PKCS1_PADDING,
},
buffer
);

return encrypted.toString('base64');
}

module.exports = { gerarDeveloperAccessCode };

3.3 Exemplo em Python (3.x)​

from datetime import datetime
import base64
import xml.etree.ElementTree as ET
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers

def xml_to_rsa_key(xml_str):
root = ET.fromstring(xml_str)
modulus = int.from_bytes(base64.b64decode(root.find('Modulus').text), 'big')
exponent = int.from_bytes(base64.b64decode(root.find('Exponent').text), 'big')
return RSAPublicNumbers(exponent, modulus).public_key()

def gerar_developer_access_code(secret_key: str, xml_public_key: str) -> str:
data_hoje = datetime.utcnow().strftime('%d/%m/%Y')
mensagem = f"{secret_key}|{data_hoje}".encode('utf-8')

public_key = xml_to_rsa_key(xml_public_key)
criptografado = public_key.encrypt(mensagem, padding.PKCS1v15())
return base64.b64encode(criptografado).decode('utf-8')

4. Credenciais Operacionais da Agência (No Request Body)​

Cada chamada à API é independente (stateless) e deve identificar a agência/usuário responsável pela transação dentro do JSON:

{
"Login": "AGENCIA_OPERACIONAL_LOGIN",
"Senha": "SENHA_OPERACIONAL",
"ClienteId": null,
"transacaoId": "guid-opcional-para-rastreabilidade"
}
  • Login (Obrigatório, String): Identificador da agência/usuário cadastrado no Travellink.
  • Senha (Obrigatório, String): Senha da agência.
  • ClienteId (Opcional, Int): ID de subcliente/empresa corporativa (para agências corporativas com múltiplos clientes).
  • transacaoId (Opcional, String): Identificador único gerado pelo seu sistema para rastreamento de logs e auditoria ponta a ponta.