Visão Geral
A API Avista utiliza autenticação baseada em OAuth 2.0 com certificados X.509 (mTLS) . Este modelo de segurança em camadas garante que apenas clientes autorizados com certificados válidos possam acessar a API.
Por que mTLS?
O mTLS (mutual TLS) oferece segurança superior comparado a tokens simples:
Autenticação mútua : Tanto o cliente quanto o servidor se autenticam
Não-repúdio : Certificados vinculados à conta garantem rastreabilidade
Proteção contra roubo de credenciais : Mesmo com clientId/clientSecret vazados, o atacante precisaria do certificado
Pré-requisitos
Antes de iniciar, você precisará:
Certificado Digital X.509
Obtenha seu certificado cliente através do portal Avista. O certificado deve estar no formato PEM e será vinculado à sua conta .
Credenciais OAuth
Solicite suas credenciais (clientId e clientSecret) no painel administrativo.
Configuração do Ambiente
Configure seu ambiente para enviar o certificado no header X-SSL-Client-Cert.
O certificado X.509 deve estar vinculado à sua conta antes de ser utilizado. Certificados não vinculados serão rejeitados mesmo que válidos.
Endpoint de Autenticação
POST /api/auth/token
Gera um token JWT de acesso válido por 30 minutos (1800 segundos).
O certificado X.509 deve ser enviado URL-encoded no header X-SSL-Client-Cert. O sistema valida o fingerprint SHA256 do certificado contra os registros vinculados à conta.
Request
curl -X POST https://api.avista.global/api/auth/token \
-H "Content-Type: application/json" \
-H "X-SSL-Client-Cert: -----BEGIN%20CERTIFICATE-----%0AMIIB..." \
-d '{
"clientId": "account-93-550e8400",
"clientSecret": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
}'
Response (201 Created)
{
"access_token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ,
"token_type" : "Bearer" ,
"expires_in" : 1800
}
Exemplo Prático: Node.js
Instalação
Código Completo
const axios = require ( 'axios' );
const fs = require ( 'fs' );
// Carregar certificado X.509
const certificate = fs . readFileSync ( './client-cert.pem' , 'utf8' );
const encodedCert = encodeURIComponent ( certificate );
// Configuração da requisição
const config = {
method: 'post' ,
url: 'https://api.avista.global/api/auth/token' ,
headers: {
'Content-Type' : 'application/json' ,
'X-SSL-Client-Cert' : encodedCert
},
data: {
clientId: process . env . AVISTA_CLIENT_ID ,
clientSecret: process . env . AVISTA_CLIENT_SECRET
}
};
// Fazer requisição
async function getToken () {
try {
const response = await axios ( config );
console . log ( 'Token obtido com sucesso!' );
console . log ( 'Expira em:' , response . data . expires_in , 'segundos' );
return response . data . access_token ;
} catch ( error ) {
console . error ( 'Erro ao obter token:' , error . response ?. data || error . message );
throw error ;
}
}
getToken ();
Exemplo Prático: Python
Instalação
Código Completo
import os
import requests
import urllib.parse
# Carregar e codificar certificado
with open ( 'client-cert.pem' , 'r' ) as f:
certificate = f.read()
encoded_cert = urllib.parse.quote(certificate)
# Configuração da requisição
url = 'https://api.avista.global/api/auth/token'
headers = {
'Content-Type' : 'application/json' ,
'X-SSL-Client-Cert' : encoded_cert
}
payload = {
'clientId' : os.environ.get( 'AVISTA_CLIENT_ID' ),
'clientSecret' : os.environ.get( 'AVISTA_CLIENT_SECRET' )
}
# Fazer requisição
try :
response = requests.post(url, json = payload, headers = headers)
response.raise_for_status()
data = response.json()
print ( 'Token obtido com sucesso!' )
print ( f "Expira em: { data[ 'expires_in' ] } segundos" )
except requests.exceptions.RequestException as e:
print ( f 'Erro ao obter token: { e } ' )
if hasattr (e.response, 'text' ):
print ( f 'Resposta: { e.response.text } ' )
Utilizando o Token
Após obter o token, inclua-o no header Authorization de todas as requisições:
curl -X GET https://api.avista.global/api/balance \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Renovação de Token
Tokens expiram após 30 minutos . Implemente lógica de renovação automática em sua aplicação para evitar interrupções.
Estratégia Recomendada
class TokenManager {
constructor ( clientId , clientSecret , certificatePath ) {
this . clientId = clientId ;
this . clientSecret = clientSecret ;
this . certificatePath = certificatePath ;
this . token = null ;
this . expiresAt = null ;
}
async getValidToken () {
// Verifica se o token ainda é válido (com margem de 30 segundos)
if ( this . token && this . expiresAt && Date . now () < this . expiresAt - 30000 ) {
return this . token ;
}
// Renova o token
return await this . refreshToken ();
}
async refreshToken () {
const response = await this . requestNewToken ();
this . token = response . access_token ;
this . expiresAt = Date . now () + ( response . expires_in * 1000 );
return this . token ;
}
async requestNewToken () {
const fs = require ( 'fs' );
const axios = require ( 'axios' );
const certificate = fs . readFileSync ( this . certificatePath , 'utf8' );
const encodedCert = encodeURIComponent ( certificate );
const response = await axios . post ( 'https://api.avista.global/api/auth/token' , {
clientId: this . clientId ,
clientSecret: this . clientSecret
}, {
headers: {
'Content-Type' : 'application/json' ,
'X-SSL-Client-Cert' : encodedCert
}
});
return response . data ;
}
}
// Uso
const tokenManager = new TokenManager (
process . env . AVISTA_CLIENT_ID ,
process . env . AVISTA_CLIENT_SECRET ,
'./client-cert.pem'
);
// Em qualquer requisição
const token = await tokenManager . getValidToken ();
Validação do Certificado
O sistema realiza as seguintes validações no certificado:
Formato PEM válido : O certificado deve estar no formato PEM e URL-encoded
Vinculação à conta : O fingerprint SHA256 do certificado deve estar registrado e vinculado à sua conta
Correspondência de credenciais : O certificado deve pertencer à mesma conta das credenciais OAuth
Certificados não vinculados ou vinculados a outra conta serão rejeitados, mesmo que tecnicamente válidos.
Erros Comuns
400 Bad Request
Causa: Certificado ausente ou mal formatado
{
"statusCode" : 400 ,
"message" : "Certificado ausente no header X-SSL-Client-Cert"
}
Solução: Verifique se:
O certificado está no formato PEM
O certificado está URL-encoded (use encodeURIComponent())
O header X-SSL-Client-Cert está presente na requisição
401 Unauthorized
Causa: Credenciais inválidas ou certificado não autorizado
{
"statusCode" : 401 ,
"message" : "Credenciais inválidas ou certificado inválido"
}
Solução: Verifique se:
O clientId e clientSecret estão corretos
O certificado está vinculado à sua conta no portal Avista
O certificado corresponde às credenciais OAuth utilizadas
403 Forbidden
Causa: Certificado não vinculado à conta
{
"statusCode" : 403 ,
"message" : "Certificado não vinculado à conta"
}
Solução: Entre em contato com o suporte Avista para vincular o certificado à sua conta.
Boas Práticas
Armazene credenciais de forma segura
Implemente cache de tokens
Evite requisições desnecessárias armazenando tokens válidos em cache (Redis, memória, etc.).
Configure alertas para detectar falhas de autenticação recorrentes, que podem indicar problemas com renovação de tokens.
Sempre utilize conexões HTTPS para proteger credenciais em trânsito.
Próximos Passos