Base64 Decode JavaScript — atob() e Buffer
Use o Decodificador Base64 Online gratuito diretamente no seu navegador — sem instalação.
Experimentar Decodificador Base64 Online online →Quando depuro um problema de autenticação em produção, a primeira coisa que busco é um decodificador Base64 — payloads de JWT, assinaturas de webhooks e valores de configuração codificados estão todos escondidos dentro de strings Base64. O JavaScript oferece duas abordagens integradas principais para decodificar base64: atob() (navegador + Node.js 16+) e Buffer.from(encoded, 'base64').toString() (Node.js) — e eles se comportam de forma muito diferente quando os dados originais contêm caracteres Unicode. Para uma decodificação pontual sem escrever código, o Decodificador Base64 do ToolDeck resolve instantaneamente no seu navegador. Este guia cobre ambos os ambientes — direcionado ao Node.js 16+ e navegadores modernos (Chrome 80+, Firefox 75+, Safari 14+) — com exemplos prontos para produção: recuperação UTF-8, variantes seguras para URL, decodificação de JWT, arquivos, respostas de API, streams do Node.js e os quatro erros que geram sistematicamente saídas corrompidas em projetos reais.
- ✓atob(encoded) é nativo no navegador e está disponível globalmente no Node.js 16+, mas retorna uma string binária — use TextDecoder para recuperar texto UTF-8 de qualquer conteúdo acima do ASCII.
- ✓Buffer.from(encoded, "base64").toString("utf8") é a abordagem idiomática do Node.js e lida com UTF-8 automaticamente sem etapas extras.
- ✓O Base64 seguro para URL (usado em JWTs) substitui + por -, / por _, e remove o preenchimento =. Restaure-os antes de chamar atob(), ou use Buffer.from(encoded, "base64url").toString() no Node.js 18+.
- ✓Remova espaços em branco e quebras de linha antes de decodificar — a API de Conteúdos do GitHub e muitos codificadores MIME quebram a saída Base64 a cada 60–76 caracteres por linha.
- ✓Uint8Array.prototype.fromBase64() (TC39 Estágio 3) já está disponível no Node.js 22+ e Chrome 130+ e eventualmente unificará ambos os ambientes.
O que é Decodificação Base64?
A decodificação Base64 é a operação inversa da codificação — converte a representação ASCII de 64 caracteres de volta aos dados binários ou texto originais. Cada 4 caracteres Base64 correspondem exatamente a 3 bytes. Os caracteres de preenchimento = no final de uma string codificada indicam ao decodificador quantos bytes extras foram adicionados para completar o último grupo de 3 bytes.
Base64 não é criptografia — a operação é completamente reversível por qualquer pessoa que tenha a string codificada. Seu propósito é a segurança no transporte: protocolos e formatos de armazenamento projetados para texto ASCII de 7 bits não conseguem lidar com bytes binários arbitrários, e o Base64 preenche essa lacuna. Os cenários comuns de decodificação em JavaScript incluem inspecionar payloads de JWT, desempacotar configurações JSON codificadas em Base64 de variáveis de ambiente, extrair conteúdo de arquivos binários de APIs REST e decodificar URIs de dados no navegador.
ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=
deploy-bot:sk-prod-a7f2c91e4b3d8
atob() — A Função de Decodificação Nativa do Navegador
atob() (ASCII-to-binary, ASCII para binário) está disponível nos navegadores desde o IE10 e se tornou um global no Node.js 16.0 como parte da iniciativa de compatibilidade WinterCG. Também funciona nativamente no Deno, Bun e Cloudflare Workers — sem necessidade de importação.
A função retorna uma string binária: uma string JavaScript onde cada caractere tem um ponto de código igual a um valor de byte bruto (0–255). Isso importa: se os dados originais eram texto UTF-8 com caracteres acima de U+007F (letras acentuadas, cirílico, CJK, emoji), a string retornada é a sequência de bytes brutos, não texto legível. Use TextDecoder para recuperá-lo (abordado na próxima seção).
Exemplo mínimo funcional
// Decoding an HTTP Basic Auth credential pair received in a request header
// Authorization: Basic ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=
function parseBasicAuth(header: string): { serviceId: string; apiKey: string } {
const base64Part = header.replace(/^Basics+/i, '')
const decoded = atob(base64Part)
const [serviceId, apiKey] = decoded.split(':')
return { serviceId, apiKey }
}
const auth = parseBasicAuth('Basic ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=')
console.log(auth.serviceId) // deploy-bot
console.log(auth.apiKey) // sk-prod-a7f2c91e4b3d8Verificação de ida e volta
// Verify lossless recovery for ASCII-only content const original = 'service:payments region:eu-west-1 env:production' const encoded = btoa(original) const decoded = atob(encoded) console.log(encoded) // c2VydmljZTpwYXltZW50cyByZWdpb246ZXUtd2VzdC0xIGVudjpwcm9kdWN0aW9u console.log(decoded === original) // true
atob() e btoa() fazem parte da API Mínima Comum do WinterCG — a mesma especificação que governa Fetch, URL e crypto em ambientes que não são navegadores. Comportam-se de forma idêntica no Node.js 16+, Bun, Deno e Cloudflare Workers.Recuperando Texto UTF-8 Após a Decodificação
O erro mais comum com atob() é interpretar mal seu tipo de retorno. Quando o texto original foi codificado como UTF-8 antes do Base64, atob() retorna uma string binária Latin-1, não o texto legível:
// 'Алексей Иванов' was UTF-8 encoded then Base64 encoded before transmission const encoded = '0JDQu9C10LrRgdC10Lkg0JjQstCw0L3QvtCy' // ❌ atob() returns the raw UTF-8 bytes as a Latin-1 string — garbled output console.log(atob(encoded)) // "Алексей Р˜РІР°РЅРѕРІ" ← byte values misread as Latin-1
A abordagem correta usa TextDecoder para interpretar esses bytes brutos como UTF-8:
Abordagem com TextDecoder — segura para qualquer saída Unicode
// Unicode-safe Base64 decode utilities
function fromBase64(encoded: string): string {
const binary = atob(encoded)
const bytes = Uint8Array.from(binary, ch => ch.charCodeAt(0))
return new TextDecoder().decode(bytes)
}
function toBase64(text: string): string {
const bytes = new TextEncoder().encode(text)
const chars = Array.from(bytes, byte => String.fromCharCode(byte))
return btoa(chars.join(''))
}
// Works with any language or script
const orderNote = 'Confirmed: 田中太郎 — São Paulo warehouse, qty: 250'
const encoded = toBase64(orderNote)
const decoded = fromBase64(encoded)
console.log(decoded === orderNote) // true
console.log(decoded)
// Confirmed: 田中太郎 — São Paulo warehouse, qty: 250Buffer.from(encoded, 'base64').toString('utf8'). Ele interpreta os bytes decodificados como UTF-8 automaticamente e é mais rápido para entradas grandes.Buffer.from() no Node.js — Guia Completo de Decodificação
No Node.js, Buffer é a API idiomática para todas as operações binárias, incluindo a decodificação Base64. Lida com UTF-8 nativamente, retorna um Buffer adequado (seguro para binários) e, desde o Node.js 18, suporta o atalho de codificação 'base64url' para variantes seguras de URL.
Decodificando uma variável de ambiente de configuração
// Server config stored as Base64 in an env variable (avoids JSON escaping in shell)
// DB_CONFIG=eyJob3N0IjoiZGItcHJpbWFyeS5pbnRlcm5hbCIsInBvcnQiOjU0MzIsImRhdGFiYXNlIjoiYW5hbHl0aWNzX3Byb2QiLCJtYXhDb25uZWN0aW9ucyI6MTAwfQ==
const raw = Buffer.from(process.env.DB_CONFIG!, 'base64').toString('utf8')
const dbConfig = JSON.parse(raw)
console.log(dbConfig.host) // db-primary.internal
console.log(dbConfig.port) // 5432
console.log(dbConfig.maxConnections) // 100Restaurando um arquivo binário a partir de um arquivo .b64
import { readFileSync, writeFileSync } from 'node:fs'
import { join } from 'node:path'
// Read the Base64-encoded certificate and restore the original binary
const encoded = readFileSync(join(process.cwd(), 'dist', 'cert.b64'), 'utf8').trim()
const certBuf = Buffer.from(encoded, 'base64')
writeFileSync('./ssl/server.crt', certBuf)
console.log(`Restored ${certBuf.length} bytes`)
// Restored 2142 bytesDecodificação assíncrona com tratamento de erros
import { readFile, writeFile } from 'node:fs/promises'
async function decodeBase64File(
encodedPath: string,
outputPath: string,
): Promise<number> {
try {
const encoded = await readFile(encodedPath, 'utf8')
const binary = Buffer.from(encoded.trim(), 'base64')
await writeFile(outputPath, binary)
return binary.length
} catch (err) {
const code = (err as NodeJS.ErrnoException).code
if (code === 'ENOENT') throw new Error(`File not found: ${encodedPath}`)
if (code === 'EACCES') throw new Error(`Permission denied: ${encodedPath}`)
throw err
}
}
// Restore a PDF stored as Base64
const bytes = await decodeBase64File('./uploads/invoice.b64', './out/invoice.pdf')
console.log(`Decoded ${bytes} bytes — PDF restored`)Funções de Decodificação Base64 — Referência de Parâmetros
Referência rápida dos parâmetros das duas principais APIs de decodificação nativas, formatada para uso como consulta ao escrever ou revisar código.
atob(encodedData)
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| encodedData | string | Sim | String Base64 padrão usando os caracteres +, /, =. Variantes seguras para URL (-, _) lançam InvalidCharacterError. Espaços em branco não são permitidos. |
Buffer.from(input, inputEncoding) / .toString(outputEncoding)
| Parâmetro | Tipo | Padrão | Descrição |
|---|---|---|---|
| input | string | Buffer | TypedArray | ArrayBuffer | obrigatório | A string codificada em Base64 a decodificar, ou um buffer contendo bytes codificados. |
| inputEncoding | BufferEncoding | "utf8" | Defina "base64" para Base64 padrão (RFC 4648 §4), ou "base64url" para Base64 seguro para URL (RFC 4648 §5, Node.js 18+). |
| outputEncoding | string | "utf8" | Codificação para a saída de .toString(). Use "utf8" para texto legível, "binary" para uma string binária Latin-1 compatível com a saída de atob(). |
| start | integer | 0 | Deslocamento de byte dentro do Buffer decodificado para começar a leitura. Passado para .toString() como segundo argumento. |
| end | integer | buf.length | Deslocamento de byte onde a leitura é interrompida (exclusivo). Passado para .toString() como terceiro argumento. |
Base64 Seguro para URL — Decodificando JWTs e Parâmetros de URL
Os JWTs usam Base64 seguro para URL (RFC 4648 §5) para os três segmentos. O Base64 seguro para URL substitui + por - e / por _, e remove o preenchimento = final. Passar isso diretamente para atob() sem restaurá-lo produz saída incorreta ou lança uma exceção.
Navegador — restaurar caracteres e preenchimento antes de decodificar
function decodeBase64Url(input: string): string {
const base64 = input.replace(/-/g, '+').replace(/_/g, '/')
const padded = base64 + '==='.slice(0, (4 - base64.length % 4) % 4)
const binary = atob(padded)
const bytes = Uint8Array.from(binary, ch => ch.charCodeAt(0))
return new TextDecoder().decode(bytes)
}
// Inspect a JWT payload segment (the middle part between the two dots)
const jwtToken = 'eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2U4YjRkIiwicm9sZSI6ImVkaXRvciIsIndvcmtzcGFjZUlkIjoid3NfM2E3ZjkxYzIiLCJleHAiOjE3MTcyMDM2MDB9'
const payload = decodeBase64Url(jwtToken)
const claims = JSON.parse(payload)
console.log(claims.userId) // usr_9f2a1c3e8b4d
console.log(claims.role) // editor
console.log(claims.workspaceId) // ws_3a7f91c2Node.js 18+ — codificação nativa 'base64url'
// Node.js 18 added 'base64url' as a first-class Buffer encoding — no manual replace needed
function decodeJwtSegment(segment: string): Record<string, unknown> {
const json = Buffer.from(segment, 'base64url').toString('utf8')
return JSON.parse(json)
}
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2U4YjRkIiwicm9sZSI6ImVkaXRvciIsIndvcmtzcGFjZUlkIjoid3NfM2E3ZjkxYzIiLCJleHAiOjE3MTcyMDM2MDB9.SIGNATURE'
const [headerB64, payloadB64] = token.split('.')
const header = decodeJwtSegment(headerB64)
const payload = decodeJwtSegment(payloadB64)
console.log(header.alg) // HS256
console.log(payload.role) // editor
console.log(payload.workspaceId) // ws_3a7f91c2Decodificando Base64 de Arquivos e Respostas de API
No código de produção, a decodificação Base64 ocorre com mais frequência ao consumir APIs externas que entregam conteúdo em formato codificado. Ambos os cenários têm advertências importantes sobre espaços em branco e saída binária versus texto. Se você só precisa inspecionar uma resposta codificada durante a depuração, cole-a diretamente no Decodificador Base64 — ele lida com os modos padrão e seguro para URL instantaneamente.
Decodificando conteúdo da API de Conteúdos do GitHub
// GitHub Contents API returns file content as Base64, wrapped at 60 chars per line
async function fetchDecodedFile(
owner: string,
repo: string,
path: string,
token: string,
): Promise<string> {
const res = await fetch(
`https://api.github.com/repos/${owner}/${repo}/contents/${path}`,
{ headers: { Authorization: `Bearer ${token}`, Accept: 'application/vnd.github.v3+json' } }
)
if (!res.ok) throw new Error(`GitHub API ${res.status}: ${res.statusText}`)
const data = await res.json() as { content: string; encoding: string }
if (data.encoding !== 'base64') throw new Error(`Unexpected encoding: ${data.encoding}`)
// ⚠️ GitHub wraps at 60 chars — strip newlines before decoding
const clean = data.content.replace(/\n/g, '')
return Buffer.from(clean, 'base64').toString('utf8')
}
const openApiSpec = await fetchDecodedFile('acme-corp', 'platform-api', 'openapi.json', process.env.GITHUB_TOKEN!)
const spec = JSON.parse(openApiSpec)
console.log(`API version: ${spec.info.version}`)Decodificando um binário Base64 de uma API (navegador)
// Some APIs return binary content (images, PDFs) as Base64 JSON fields
async function downloadDecodedFile(endpoint: string, authToken: string): Promise<void> {
const res = await fetch(endpoint, { headers: { Authorization: `Bearer ${authToken}` } })
if (!res.ok) throw new Error(`Download failed: ${res.status}`)
const { filename, content, mimeType } = await res.json() as {
filename: string; content: string; mimeType: string
}
// Decode Base64 → binary bytes → Blob
const binary = atob(content)
const bytes = Uint8Array.from(binary, ch => ch.charCodeAt(0))
const blob = new Blob([bytes], { type: mimeType })
// Trigger browser download
const url = URL.createObjectURL(blob)
const a = Object.assign(document.createElement('a'), { href: url, download: filename })
a.click()
URL.revokeObjectURL(url)
}
await downloadDecodedFile('/api/reports/latest', sessionStorage.getItem('auth_token')!)Decodificação Base64 pela Linha de Comando no Node.js e Shell
Para scripts de CI/CD, sessões de depuração ou tarefas de decodificação pontuais, as ferramentas de shell e os comandos de uma linha do Node.js são mais rápidos do que um script completo. Note que o nome do flag difere entre macOS e Linux.
# ── macOS / Linux system base64 ───────────────────────────────────────
# Standard decoding (macOS uses -D, Linux uses -d)
echo "ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=" | base64 -d # Linux
echo "ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=" | base64 -D # macOS
# Decode a .b64 file to its original binary
base64 -d ./dist/cert.b64 > ./ssl/server.crt # Linux
base64 -D -i ./dist/cert.b64 -o ./ssl/server.crt # macOS
# URL-safe Base64 — restore + and / before decoding
echo "eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2UifQ" | tr '-_' '+/' | base64 -d
# ── Node.js one-liner — works on Windows too ───────────────────────────
node -e "process.stdout.write(Buffer.from(process.argv[1], 'base64').toString())" "ZGVwbG95LWJvdA=="
# deploy-bot
# URL-safe (Node.js 18+)
node -e "process.stdout.write(Buffer.from(process.argv[1], 'base64url').toString())" "eyJhbGciOiJIUzI1NiJ9"
# {"alg":"HS256"}base64 usa -D para decodificar (D maiúsculo), enquanto o Linux usa -d (minúsculo). Isso quebra scripts de CI silenciosamente — use um comando de uma linha do Node.js quando a plataforma de destino não estiver garantida como Linux.Alternativa de Alto Desempenho: js-base64
O principal motivo para recorrer a uma biblioteca é a consistência entre ambientes. Se você distribui um pacote que funciona tanto no navegador quanto no Node.js sem configuração de bundler, Buffer requer detecção de ambiente e atob() requer o trabalho extra com TextDecoder. js-base64 (mais de 100 milhões de downloads semanais no npm) lida com ambos de forma transparente.
npm install js-base64 # or pnpm add js-base64
import { fromBase64, fromBase64Url, isValid } from 'js-base64'
// Standard decoding — Unicode-safe, works in browser and Node.js
const raw = fromBase64('eyJldmVudElkIjoiZXZ0XzdjM2E5ZjFiMmQiLCJ0eXBlIjoiY2hlY2tvdXRfY29tcGxldGVkIiwiY3VycmVuY3kiOiJFVVIiLCJhbW91bnQiOjE0OTAwfQ==')
const event = JSON.parse(raw)
console.log(event.type) // checkout_completed
console.log(event.currency) // EUR
// URL-safe decoding — no manual character replacement needed
const jwtPayload = fromBase64Url('eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2U4YjRkIiwicm9sZSI6ImVkaXRvciJ9')
const claims = JSON.parse(jwtPayload)
console.log(claims.role) // editor
// Validate before decoding untrusted input
const untrusted = 'not!valid@base64#'
if (!isValid(untrusted)) {
console.error('Rejected: invalid Base64 input')
}
// Binary output — second argument true returns Uint8Array
const pngBytes = fromBase64('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', true)
console.log(pngBytes instanceof Uint8Array) // trueSaída de Terminal com Realce de Sintaxe
Ao escrever ferramentas de depuração CLI ou scripts de inspeção, a saída simples de console.log é difícil de ler para payloads JSON grandes. chalk (o pacote npm mais baixado para colorir terminais) combinado com a decodificação Base64 produz uma saída de terminal legível e escaneável — útil para inspeção de JWT, depuração de respostas de API e auditoria de configurações.
npm install chalk # chalk v5+ is ESM-only — use import, not require
import chalk from 'chalk'
// Decode and display any Base64 value with smart type detection
function inspectBase64(encoded: string, label = 'Decoded value'): void {
let decoded: string
try {
decoded = Buffer.from(encoded.trim(), 'base64').toString('utf8')
} catch {
console.error(chalk.red('✗ Invalid Base64 input'))
return
}
console.log(chalk.bold.cyan(`\n── ${label} ──`))
// Attempt JSON pretty-print
try {
const parsed = JSON.parse(decoded)
console.log(chalk.green('Type:'), chalk.yellow('JSON'))
for (const [key, value] of Object.entries(parsed)) {
const display = typeof value === 'object' ? JSON.stringify(value) : String(value)
console.log(chalk.green(` ${key}:`), chalk.white(display))
}
return
} catch { /* not JSON */ }
// Plain text fallback
console.log(chalk.green('Type:'), chalk.yellow('text'))
console.log(chalk.white(decoded))
}
// Inspect a Base64-encoded JWT payload
const tokenParts = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2U4YjRkIiwicm9sZSI6ImVkaXRvciIsImV4cCI6MTcxNzIwMzYwMH0.SIGNATURE'.split('.')
inspectBase64(tokenParts[0], 'JWT Header')
inspectBase64(tokenParts[1], 'JWT Payload')
// ── JWT Header ──
// Type: JSON
// alg: HS256
// typ: JWT
//
// ── JWT Payload ──
// Type: JSON
// userId: usr_9f2a1c3e8b4d
// role: editor
// exp: 1717203600Decodificar Arquivos Base64 Grandes com Streams do Node.js
Quando um arquivo codificado em Base64 ultrapassa ~50 MB, carregá-lo inteiramente na memória com readFileSync() se torna um problema. Os streams do Node.js permitem decodificar dados em fragmentos — mas o Base64 requer múltiplos de 4 caracteres por fragmento (cada grupo de 4 caracteres decodifica exatamente 3 bytes) para evitar erros de preenchimento nos limites dos fragmentos.
import { createReadStream, createWriteStream } from 'node:fs'
import { pipeline } from 'node:stream/promises'
async function streamDecodeBase64(inputPath: string, outputPath: string): Promise<void> {
const readStream = createReadStream(inputPath, { encoding: 'utf8', highWaterMark: 4 * 1024 * 192 })
const writeStream = createWriteStream(outputPath)
let buffer = ''
await pipeline(
readStream,
async function* (source) {
for await (const chunk of source) {
buffer += (chunk as string).replace(/\s/g, '') // strip any whitespace/newlines
// Decode only complete 4-char groups to avoid mid-stream padding issues
const remainder = buffer.length % 4
const safe = buffer.slice(0, buffer.length - remainder)
buffer = buffer.slice(buffer.length - remainder)
if (safe.length > 0) yield Buffer.from(safe, 'base64')
}
if (buffer.length > 0) yield Buffer.from(buffer, 'base64')
},
writeStream,
)
}
// Decode a 200 MB video that was stored as Base64
await streamDecodeBase64('./uploads/product-demo.b64', './dist/product-demo.mp4')
console.log('Stream decode complete')4 × 1024 × 192 = 786.432 caracteres (768 KB). Para arquivos abaixo de 50 MB, readFile() + Buffer.from(content.trim(), 'base64') é mais simples e rápido o suficiente.Erros Comuns
Já vi esses quatro erros repetidamente em projetos JavaScript — eles tendem a permanecer ocultos até que um caractere não ASCII ou uma resposta de API com quebras de linha chegue ao caminho de decodificação em produção.
Erro 1 — Usar atob() sem TextDecoder para conteúdo UTF-8
Problema: atob() retorna uma string binária onde cada caractere é um valor de byte bruto. Sequências multibyte UTF-8 (cirílico, CJK, caracteres acentuados) aparecem como caracteres Latin-1 corrompidos. Solução: envolva a saída em TextDecoder.
// ❌ atob() returns the raw UTF-8 bytes as a Latin-1 string const encoded = '0JDQu9C10LrRgdC10Lkg0JjQstCw0L3QvtCy' const decoded = atob(encoded) console.log(decoded) // "Алексей Р˜РІР°РЅРѕРІ" ← wrong
// ✅ Use TextDecoder to correctly interpret the UTF-8 bytes const encoded = '0JDQu9C10LrRgdC10Lkg0JjQstCw0L3QvtCy' const binary = atob(encoded) const bytes = Uint8Array.from(binary, ch => ch.charCodeAt(0)) const decoded = new TextDecoder().decode(bytes) console.log(decoded) // Алексей Иванов ✓
Erro 2 — Passar Base64 seguro para URL diretamente para atob()
Problema: Os segmentos de JWT usam - e _ em vez de + e /, sem preenchimento. atob() pode retornar dados incorretos ou lançar uma exceção. Solução: restaure os caracteres padrão e adicione o preenchimento antes.
// ❌ URL-safe JWT segment passed directly — unreliable const jwtPayload = 'eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2UifQ' const decoded = atob(jwtPayload) // May produce wrong result or throw
// ✅ Restore standard Base64 chars and padding first
function decodeBase64Url(input: string): string {
const b64 = input.replace(/-/g, '+').replace(/_/g, '/')
const pad = b64 + '==='.slice(0, (4 - b64.length % 4) % 4)
const bin = atob(pad)
const bytes = Uint8Array.from(bin, ch => ch.charCodeAt(0))
return new TextDecoder().decode(bytes)
}
const decoded = decodeBase64Url('eyJ1c2VySWQiOiJ1c3JfOWYyYTFjM2UifQ')
// {"userId":"usr_9f2a1c3e"} ✓Erro 3 — Não remover quebras de linha do Base64 quebrado por linhas
Problema: A API de Conteúdos do GitHub e os codificadores MIME quebram a saída Base64 a 60–76 caracteres por linha. atob() lança InvalidCharacterError nos caracteres \n. Solução: remova todos os espaços em branco antes de decodificar.
// ❌ GitHub API content field contains embedded newlines const data = await res.json() const decoded = atob(data.content) // ❌ throws InvalidCharacterError
// ✅ Strip newlines (and any other whitespace) before decoding const data = await res.json() const clean = data.content.replace(/\s/g, '') const decoded = atob(clean) // ✓
Erro 4 — Chamar .toString() em conteúdo binário decodificado
Problema: Quando os dados originais são binários (imagens, PDFs, áudio), chamar .toString('utf8') substitui sequências de bytes não reconhecidas por U+FFFD, corrompendo silenciosamente a saída. Solução: mantenha o resultado como Buffer — não o converta para string.
// ❌ .toString('utf8') corrupts binary content
import { readFileSync, writeFileSync } from 'node:fs'
const encoded = readFileSync('./uploads/invoice.b64', 'utf8').trim()
const corrupted = Buffer.from(encoded, 'base64').toString('utf8') // ❌
writeFileSync('./out/invoice.pdf', corrupted) // ❌ unreadable PDF// ✅ Keep the Buffer as binary — do not convert to a string
import { readFileSync, writeFileSync } from 'node:fs'
const encoded = readFileSync('./uploads/invoice.b64', 'utf8').trim()
const binary = Buffer.from(encoded, 'base64') // ✓ raw bytes preserved
writeFileSync('./out/invoice.pdf', binary) // ✓ valid PDFMétodos de Decodificação Base64 em JavaScript — Comparação Rápida
| Método | Saída UTF-8 | Saída binária | Seguro para URL | Ambientes | Requer instalação |
|---|---|---|---|---|---|
| atob() | ❌ precisa de TextDecoder | ✅ string binária | ❌ restauração manual | Navegador, Node 16+, Bun, Deno | Não |
| TextDecoder + atob() | ✅ UTF-8 | ✅ via Uint8Array | ❌ restauração manual | Navegador, Node 16+, Deno | Não |
| Buffer.from().toString() | ✅ utf8 | ✅ manter como Buffer | ✅ base64url (Node 18+) | Node.js, Bun | Não |
| Uint8Array.fromBase64() (TC39) | ✅ via TextDecoder | ✅ nativo | ✅ opção alphabet | Chrome 130+, Node 22+ | Não |
| js-base64 | ✅ sempre | ✅ Uint8Array | ✅ integrado | Universal | npm install |
Escolha atob() apenas quando o conteúdo decodificado for garantidamente texto ASCII. Para qualquer texto fornecido pelo usuário ou em múltiplos idiomas em um navegador, use TextDecoder + atob(). Para código do lado do servidor no Node.js, Buffer é a opção correta por padrão — lida com UTF-8 automaticamente e mantém dados binários intactos. Para bibliotecas de múltiplos ambientes, js-base64 elimina todos os casos extremos.
Perguntas Frequentes
Ferramentas Relacionadas
Para decodificar com um clique sem escrever nenhum código, cole sua string Base64 diretamente no Decodificador Base64 — ele lida com os modos padrão e seguro para URL com saída imediata no seu navegador.
Alex is a front-end and Node.js developer with extensive experience building web applications and developer tooling. He is passionate about web standards, browser APIs, and the JavaScript ecosystem. In his spare time he contributes to open-source projects and writes about modern JavaScript patterns, performance optimisation, and everything related to the web platform.
Sophie is a full-stack developer focused on TypeScript across the entire stack — from React frontends to Express and Fastify backends. She has a particular interest in type-safe API design, runtime validation, and the patterns that make large JavaScript codebases stay manageable. She writes about TypeScript idioms, Node.js internals, and the ever-evolving JavaScript module ecosystem.