Para validar CPF em aplicações Nuxt.js sem expor a chave de API no cliente, crie uma server route em server/api/cpf/[cpf].ts que recebe o CPF do front-end, faz a chamada à API CPFHub.io com o header x-api-key a partir de uma variável de ambiente e devolve o resultado ao navegador. Dessa forma, o segredo nunca aparece no bundle JavaScript enviado ao usuário.
Introdução
O Nuxt.js é um dos frameworks mais populares para construção de aplicações Vue.js com renderização server-side (SSR) e geração estática. Quando se trata de integrar APIs externas que exigem autenticação, como a API de consulta de CPF, é fundamental que a chave de API nunca seja exposta no lado do cliente.
A abordagem recomendada em Nuxt.js é utilizar server middleware (Nuxt 3) ou server routes para criar um proxy que faz a chamada à API no lado do servidor.
Por que usar server middleware para consultas de CPF
A chave de API (x-api-key) é um segredo que não deve ser incluído em código JavaScript enviado ao navegador. Se exposta, qualquer pessoa poderia utilizá-la para consumir sua cota de consultas.
O server middleware do Nuxt.js resolve esse problema criando uma rota no servidor que atua como intermediária entre o front-end e a API externa. O fluxo funciona assim:
- O front-end faz uma requisição para uma rota interna do Nuxt (por exemplo,
/api/cpf/12345678900). - O server middleware recebe essa requisição e faz a chamada à API da CPFHub.io com a chave de API armazenada no ambiente do servidor.
- O resultado é devolvido ao front-end sem que a chave de API seja exposta.
Configuração do projeto
Estrutura de diretórios (Nuxt 3)
meu-projeto/
server/
api/
cpf/
[cpf].ts
pages/
index.vue
.env
nuxt.config.ts
Variáveis de ambiente
Crie um arquivo .env na raiz do projeto:
CPFHUB_API_KEY=SUA_CHAVE_DE_API
No nuxt.config.ts, configure o acesso à variável de ambiente:
export default defineNuxtConfig({
runtimeConfig: {
cpfhubApiKey: process.env.CPFHUB_API_KEY || ''
}
})
A propriedade runtimeConfig sem o prefixo public garante que a variável esteja disponível apenas no lado do servidor.
Criando a server route
Crie o arquivo server/api/cpf/[cpf].ts:
import { defineEventHandler, createError } from 'h3'
export default defineEventHandler(async (event) => {
const cpf = event.context.params?.cpf
if (!cpf || cpf.length !== 11 || !/^\d{11}$/.test(cpf)) {
throw createError({
statusCode: 400,
statusMessage: 'CPF inválido. Informe 11 dígitos numéricos.'
})
}
const config = useRuntimeConfig()
const apiKey = config.cpfhubApiKey
if (!apiKey) {
throw createError({
statusCode: 500,
statusMessage: 'Chave de API não configurada no servidor.'
})
}
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 10000)
try {
const response = await fetch(
`https://api.cpfhub.io/cpf/${cpf}`,
{
method: 'GET',
headers: {
'x-api-key': apiKey,
'Accept': 'application/json'
},
signal: controller.signal
}
)
clearTimeout(timeoutId)
if (!response.ok) {
if (response.status === 429) {
throw createError({
statusCode: 429,
statusMessage: 'Limite de consultas atingido. Tente novamente mais tarde.'
})
}
throw createError({
statusCode: response.status,
statusMessage: `Erro na API: ${response.statusText}`
})
}
const dados = await response.json()
return dados
} catch (error: any) {
clearTimeout(timeoutId)
if (error.name === 'AbortError') {
throw createError({
statusCode: 504,
statusMessage: 'Tempo limite excedido na consulta de CPF.'
})
}
if (error.statusCode) {
throw error
}
throw createError({
statusCode: 500,
statusMessage: 'Erro interno ao consultar CPF.'
})
}
})
Essa rota está acessível em http://localhost:3000/api/cpf/{cpf} durante o desenvolvimento e será automaticamente incluída no build de produção.
Consumindo a rota no front-end
Crie um componente Vue que permite ao usuário digitar um CPF e consultar os dados.
Página de consulta (pages/index.vue)
<template>
<div class="container">
<h1>Consulta de CPF</h1>
<form @submit.prevent="consultarCpf">
<input
v-model="cpfInput"
type="text"
placeholder="Digite o CPF (somente números)"
maxlength="11"
/>
<button type="submit" :disabled="carregando">
{{ carregando ? 'Consultando...' : 'Consultar' }}
</button>
</form>
<div v-if="resultado" class="resultado">
<p><strong>Nome:</strong> {{ resultado.data.name }}</p>
<p><strong>CPF:</strong> {{ resultado.data.cpf }}</p>
<p><strong>Data de nascimento:</strong> {{ resultado.data.birthDate }}</p>
<p><strong>Gênero:</strong> {{ resultado.data.gender }}</p>
</div>
<div v-if="erro" class="erro">
<p>{{ erro }}</p>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const cpfInput = ref('')
const resultado = ref(null)
const erro = ref('')
const carregando = ref(false)
async function consultarCpf() {
erro.value = ''
resultado.value = null
carregando.value = true
const cpf = cpfInput.value.replace(/\D/g, '')
if (cpf.length !== 11) {
erro.value = 'Informe um CPF com 11 dígitos.'
carregando.value = false
return
}
try {
const dados = await $fetch(`/api/cpf/${cpf}`)
resultado.value = dados
} catch (e: any) {
erro.value = e.data?.message || 'Erro ao consultar CPF.'
} finally {
carregando.value = false
}
}
</script>
Testando com cURL
Você pode testar a server route diretamente via cURL durante o desenvolvimento:
curl -X GET http://localhost:3000/api/cpf/12345678900 \
-H "Accept: application/json" \
--max-time 10
A resposta será o JSON retornado pela API da CPFHub.io, sem que a chave de API seja visível para o cliente.
Adicionando validação sintática no server middleware
Para evitar consultas desnecessárias à API, implemente a validação dos dígitos verificadores do CPF no próprio server middleware:
function validarDigitosCpf(cpf: string): boolean {
if (cpf.length !== 11) return false
if (/^(\d)\1{10}$/.test(cpf)) return false
let soma = 0
for (let i = 0; i < 9; i++) {
soma += parseInt(cpf.charAt(i)) * (10 - i)
}
let resto = (soma * 10) % 11
if (resto === 10) resto = 0
if (resto !== parseInt(cpf.charAt(9))) return false
soma = 0
for (let i = 0; i < 10; i++) {
soma += parseInt(cpf.charAt(i)) * (11 - i)
}
resto = (soma * 10) % 11
if (resto === 10) resto = 0
if (resto !== parseInt(cpf.charAt(10))) return false
return true
}
Adicione essa verificação antes da chamada à API para rejeitar CPFs sintaticamente inválidos sem consumir uma consulta.
Boas práticas
-
Nunca exponha a chave de API -- Utilize
runtimeConfigsem o prefixopublicpara manter segredos no servidor. -
Timeout -- Sempre inclua timeout nas requisições para evitar que o servidor fique travado.
-
Validação no front-end -- Valide o formato do CPF (11 dígitos numéricos) antes de enviar ao servidor.
-
Validação no back-end -- Revalide no server middleware, pois o front-end pode ser contornado.
-
Rate limit -- No plano gratuito da CPFHub.io, o limite é de 1 requisição a cada 2 segundos, com 50 consultas/mês. O plano Pro oferece 1 requisição por segundo e 1.000 consultas/mês por R$ 149.
Perguntas frequentes
Por que usar server routes em vez de chamar a API diretamente do componente Vue?
Chamar a API CPFHub.io diretamente do componente Vue expõe a x-api-key no bundle JavaScript do navegador, onde qualquer usuário pode inspecioná-la. Com a server route, a chave fica em variável de ambiente no servidor e nunca trafega até o cliente — essa é a abordagem recomendada pelo OWASP para proteção de segredos em aplicações web.
Como o Nuxt.js lida com o runtimeConfig em produção?
Em produção, o runtimeConfig é preenchido pelas variáveis de ambiente do servidor no momento do deploy — no Vercel, Render ou qualquer outro provedor, você define CPFHUB_API_KEY nas configurações de environment. Os valores sem o prefixo public ficam acessíveis apenas em server/ e nunca são injetados no bundle do cliente.
O que acontece se a consulta de CPF exceder o limite do plano gratuito?
A API CPFHub.io não retorna erro bloqueante ao atingir o limite de 50 consultas mensais. Em vez disso, cada consulta adicional é cobrada a R$0,15. No server middleware, o status HTTP retornado será 200 normalmente — acompanhe o consumo no dashboard em app.cpfhub.io para evitar cobranças inesperadas.
Como adicionar cache nas server routes do Nuxt para economizar consultas?
Use o composable useStorage do Nitro (camada de servidor do Nuxt 3) para armazenar resultados em memória ou Redis. Defina um TTL adequado — por exemplo, 24 horas para dados cadastrais que raramente mudam — e verifique o cache antes de chamar a API. Isso reduz o consumo de consultas e a latência percebida pelo usuário.
Conclusão
Integrar a validação de CPF em aplicações Nuxt.js com server middleware é a abordagem mais segura e eficiente para proteger sua chave de API e garantir que as consultas sejam feitas de forma controlada. Com a API da CPFHub.io, o retorno inclui nome, gênero e data de nascimento do titular em uma única requisição GET.
Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e implemente hoje mesmo a server route de validação de CPF na sua aplicação Nuxt.js.
CPFHub.io
Pronto para integrar a API?
50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.
Sobre a redação
Redação CPFHub.io
Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.



