Pular para o conteúdo principal

Authentication & mTLS

Este guia explica como autenticar na Banking API usando OAuth2 Client Credentials e como configurar mTLS (mutual TLS) para comunicação segura.

Visão Geral

A Banking API utiliza dois mecanismos de segurança:

  1. OAuth2 Client Credentials - Autenticação M2M (Machine-to-Machine)
  2. mTLS (mutual TLS) - Comunicação criptografada com certificados

OAuth2 Client Credentials Flow

Como Funciona

O OAuth2 Client Credentials é o fluxo recomendado para comunicação server-to-server (M2M). Não há interação do usuário final.

┌─────────────┐                    ┌──────────────┐
│ Cliente │ │ Banking API │
│ (Você) │ │ │
└──────┬──────┘ └──────┬──────┘
│ │
│ 1. POST /v1/auth/token │
│ (client_id + client_secret) │
├──────────────────────────────────>│
│ 2. access_token │
│<──────────────────────────────────┤
│ │
│ 3. GET /accounts (com token) │
├──────────────────────────────────>│
│ 4. Resposta │
│<──────────────────────────────────┤

Endpoint de Autenticação

POST /public/gw_banking/v1/auth/token

Requisição

curl -X POST https://api.bancodigital.com/public/gw_banking/v1/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=seu-client-id" \
-d "client_secret=seu-client-secret"

Parâmetros

ParâmetroTipoObrigatórioDescrição
grant_typestringSimDeve ser client_credentials
client_idstringSimSeu Client ID
client_secretstringSimSeu Client Secret

Resposta de Sucesso (200)

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}

Campos da Resposta

CampoTipoDescrição
access_tokenstringToken JWT para autenticação
token_typestringSempre "Bearer"
expires_innumberTempo de expiração em segundos (geralmente 3600 = 1 hora)

Resposta de Erro (401)

{
"type": "https://api.bancodigital.com/errors/invalid-credentials",
"title": "Invalid Credentials",
"status": 401,
"detail": "Invalid client_id or client_secret"
}

Usar o Token

Após obter o token, inclua-o no header Authorization de todas as requisições:

curl -X GET https://api.bancodigital.com/public/gw_banking/v1/accounts/123 \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

Renovação Automática de Token

Tokens expiram após 1 hora. Implemente renovação automática:

class TokenManager {
private token: string | null = null;
private expiresAt: number = 0;

async getToken(): Promise<string> {
// Se o token ainda é válido, retornar
if (this.token && Date.now() < this.expiresAt) {
return this.token;
}

// Obter novo token
const response = await fetch(
'https://api.bancodigital.com/public/gw_banking/v1/auth/token',
{
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: process.env.CLIENT_ID!,
client_secret: process.env.CLIENT_SECRET!,
}),
},
);

const data = await response.json();
this.token = data.access_token;
// Renovar 5 minutos antes de expirar
this.expiresAt = Date.now() + (data.expires_in - 300) * 1000;

return this.token;
}
}

mTLS (Mutual TLS)

O que é mTLS?

mTLS (mutual TLS) é uma extensão do TLS padrão onde ambas as partes (cliente e servidor) se autenticam usando certificados. Isso adiciona uma camada extra de segurança além do OAuth2.

Por que usar mTLS?

  • Segurança adicional: Mesmo que as credenciais OAuth2 sejam comprometidas, o atacante precisa do certificado
  • Compliance: Atende requisitos regulatórios (PCI-DSS, etc)
  • Identificação garantida: Certificados garantem a identidade do cliente

Configuração

1. Obter Certificados

Entre em contato com [email protected] para obter:

  • Client Certificate (.crt ou .pem)
  • Client Private Key (.key ou .pem)
  • CA Certificate (certificado da autoridade certificadora)

2. Configurar no Cliente

cURL:

curl -X GET https://api.bancodigital.com/public/gw_banking/v1/accounts/123 \
--cert client.crt \
--key client.key \
--cacert ca.crt \
-H "Authorization: Bearer SEU_TOKEN"

Node.js (axios):

import axios from 'axios';
import { readFileSync } from 'fs';

const client = axios.create({
httpsAgent: new (require('https').Agent)({
cert: readFileSync('client.crt'),
key: readFileSync('client.key'),
ca: readFileSync('ca.crt'),
}),
});

const response = await client.get(
'https://api.bancodigital.com/public/gw_banking/v1/accounts/123',
{
headers: { Authorization: `Bearer ${token}` },
},
);

Python (requests):

import requests

response = requests.get(
'https://api.bancodigital.com/public/gw_banking/v1/accounts/123',
cert=('client.crt', 'client.key'),
verify='ca.crt',
headers={'Authorization': f'Bearer {token}'}
)

Validação do Certificado

O servidor valida:

  • Certificado não expirado
  • Certificado assinado por CA confiável
  • CN (Common Name) ou SAN (Subject Alternative Name) correspondem ao Client ID

Troubleshooting mTLS

Erro: "Certificate verification failed"

  • Verifique se o certificado não expirou
  • Confirme que está usando o CA correto
  • Verifique se o certificado corresponde ao Client ID

Erro: "Handshake failed"

  • Verifique se o certificado e a chave privada correspondem
  • Confirme que está usando TLS 1.2 ou superior
  • Verifique se não há problemas de firewall/proxy

Fluxo Completo de Autenticação

Passo a Passo

  1. Configurar mTLS (se aplicável)

    • Instalar certificados
    • Configurar cliente HTTP
  2. Obter Token OAuth2

    POST /public/gw_banking/v1/auth/token
  3. Usar Token nas Requisições

    GET /public/gw_banking/v1/accounts/123
    Authorization: Bearer <token>
  4. Renovar Token (quando expirar)

    • Detectar erro 401
    • Obter novo token
    • Repetir requisição

Segurança

Boas Práticas

  1. Nunca exponha credenciais

    • Use variáveis de ambiente
    • Use secret managers em produção
    • Nunca commite client_secret no código
  2. Proteja certificados

    • Armazene em local seguro
    • Use permissões restritas (chmod 600)
    • Rotacione certificados regularmente
  3. Use HTTPS sempre

    • Nunca faça requisições em HTTP
    • Valide certificados do servidor
  4. Implemente renovação proativa

    • Renove tokens antes de expirar
    • Implemente retry logic

O que NÃO fazer

// ❌ NUNCA faça isso
const CLIENT_SECRET = 'minha-chave-secreta'; // Hardcoded
const CERT = 'certificado-em-string'; // Exposto

// ✅ Faça isso
const CLIENT_SECRET = process.env.CLIENT_SECRET;
const CERT = readFileSync(process.env.CERT_PATH);

Exemplo Completo

import axios from 'axios';
import https from 'https';
import { readFileSync } from 'fs';

class BankingAPIClient {
private token: string | null = null;
private tokenExpiresAt: number = 0;

constructor(
private baseURL: string,
private clientId: string,
private clientSecret: string,
private certPath?: string,
private keyPath?: string,
private caPath?: string,
) {}

private getHttpsAgent() {
if (!this.certPath || !this.keyPath) {
return undefined; // Sem mTLS
}

return new https.Agent({
cert: readFileSync(this.certPath),
key: readFileSync(this.keyPath),
ca: this.caPath ? readFileSync(this.caPath) : undefined,
});
}

private async ensureValidToken(): Promise<string> {
if (this.token && Date.now() < this.tokenExpiresAt - 5 * 60 * 1000) {
return this.token;
}

const response = await axios.post(
`${this.baseURL}/public/gw_banking/v1/auth/token`,
new URLSearchParams({
grant_type: 'client_credentials',
client_id: this.clientId,
client_secret: this.clientSecret,
}),
{
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
httpsAgent: this.getHttpsAgent(),
},
);

this.token = response.data.access_token;
this.tokenExpiresAt = Date.now() + response.data.expires_in * 1000;

return this.token;
}

async request(method: string, path: string, data?: any) {
const token = await this.ensureValidToken();

return axios({
method,
url: `${this.baseURL}${path}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
data,
httpsAgent: this.getHttpsAgent(),
});
}
}

// Uso
const client = new BankingAPIClient(
'https://api.bancodigital.com',
process.env.CLIENT_ID!,
process.env.CLIENT_SECRET!,
process.env.CERT_PATH,
process.env.KEY_PATH,
process.env.CA_PATH,
);

const balance = await client.request(
'GET',
'/public/gw_banking/v1/accounts/123/balance',
);

Próximos Passos