Base64 in JavaScript — atob() e Buffer
Usa il Decoder Base64 Online gratuito direttamente nel tuo browser — nessuna installazione.
Prova Decoder Base64 Online online →Quando eseguo il debug di un problema di autenticazione in produzione, la prima cosa che cerco è un Decoder Base64 — i payload JWT, le firme dei webhook e i valori di configurazione codificati si nascondono tutti all'interno di stringhe Base64. JavaScript offre due approcci nativi principali per decodificare in base64: atob() (browser + Node.js 16+) e Buffer.from(encoded, 'base64').toString() (Node.js) — e si comportano in modo molto diverso quando i dati originali contenevano caratteri Unicode. Per una decodifica rapida senza scrivere codice, il Decoder Base64 di ToolDeck lo gestisce istantaneamente nel tuo browser. Questa guida copre entrambi gli ambienti — con target Node.js 16+ e browser moderni (Chrome 80+, Firefox 75+, Safari 14+) — con esempi pronti per la produzione: recupero UTF-8, varianti URL-safe, decodifica JWT, file, risposte API, stream Node.js, e i quattro errori che producono sistematicamente output corrotto nei codebase reali.
- ✓atob(encoded) è nativo del browser e disponibile in Node.js 16+ globalmente, ma restituisce una stringa binaria — usa TextDecoder per recuperare il testo UTF-8 da qualsiasi contenuto oltre l'ASCII.
- ✓Buffer.from(encoded, "base64").toString("utf8") è l'approccio idiomatico di Node.js e gestisce l'UTF-8 automaticamente senza passaggi aggiuntivi.
- ✓Il Base64 URL-safe (usato nei JWT) sostituisce + con -, / con _, e rimuove il padding =. Ripristina questi caratteri prima di chiamare atob(), oppure usa Buffer.from(encoded, "base64url").toString() in Node.js 18+.
- ✓Rimuovi gli spazi e i caratteri di nuova riga prima di decodificare — l'API GitHub Contents e molti codificatori MIME suddividono l'output Base64 a 60–76 caratteri per riga.
- ✓Uint8Array.prototype.fromBase64() (TC39 Stage 3) è già disponibile in Node.js 22+ e Chrome 130+ e unificherà infine entrambi gli ambienti.
Cos'è la decodifica Base64?
La decodifica Base64 è l'operazione inversa della codifica — converte la rappresentazione ASCII a 64 caratteri di ritorno ai dati binari o testo originali. Ogni 4 caratteri Base64 corrispondono esattamente a 3 byte. I caratteri di padding = alla fine di una stringa codificata indicano al decodificatore quanti byte aggiuntivi sono stati aggiunti per completare l'ultimo gruppo di 3 byte.
Il Base64 non è crittografia — l'operazione è completamente reversibile da chiunque abbia la stringa codificata. Il suo scopo è la sicurezza del trasporto: i protocolli e i formati di archiviazione progettati per il testo ASCII a 7 bit non possono gestire byte binari arbitrari, e il Base64 colma questa lacuna. Gli scenari comuni di decodifica JavaScript includono l'ispezione dei payload JWT, il disimballaggio delle configurazioni JSON codificate in Base64 dalle variabili d'ambiente, l'estrazione del contenuto di file binari dalle API REST e la decodifica delle data URI nel browser.
ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=
deploy-bot:sk-prod-a7f2c91e4b3d8
atob() — La funzione di decodifica nativa del browser
atob()(ASCII-to-binary) è disponibile nei browser sin da IE10 ed è diventata una funzione globale in Node.js 16.0 come parte dell'iniziativa di compatibilità WinterCG. Funziona anche nativamente in Deno, Bun e Cloudflare Workers — nessuna importazione necessaria.
La funzione restituisce una stringa binaria: una stringa JavaScript in cui ogni carattere ha un code point uguale a un valore di byte grezzo (0–255). Questo è importante: se i dati originali erano testo UTF-8 contenente caratteri oltre U+007F (lettere accentuate, cirillico, CJK, emoji), la stringa restituita è la sequenza di byte grezza, non testo leggibile. Usa TextDecoder per recuperarlo (trattato nella sezione successiva).
Esempio minimale funzionante
// 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 del round-trip
// 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() fanno parte della WinterCG Minimum Common API — la stessa specifica che governa Fetch, URL e crypto negli ambienti non-browser. Si comportano in modo identico in Node.js 16+, Bun, Deno e Cloudflare Workers.Recuperare il testo UTF-8 dopo la decodifica
L'insidia più comune con atob() è fraintendere il suo tipo di ritorno. Quando il testo originale è stato codificato in UTF-8 prima del Base64, atob() restituisce una stringa binaria Latin-1, non il testo leggibile:
// 'Алексей Иванов' 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
L'approccio corretto usa TextDecoder per interpretare quei byte grezzi come UTF-8:
Approccio TextDecoder — sicuro per qualsiasi output 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'). Interpreta i byte decodificati come UTF-8 automaticamente ed è più veloce per input di grandi dimensioni.Buffer.from() in Node.js — Guida completa alla decodifica
In Node.js, Bufferè l'API idiomatica per tutte le operazioni binarie inclusa la decodifica Base64. Gestisce l'UTF-8 nativamente, restituisce un Buffer appropriato (sicuro per il binario), e da Node.js 18 supporta la scorciatoia di codifica 'base64url' per le varianti URL-safe.
Decodifica di una variabile d'ambiente di configurazione
// 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) // 100Ripristino di un file binario da un file .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 asincrona con gestione degli errori
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`)Funzioni di decodifica Base64 — Riferimento parametri
Riferimento rapido per i parametri delle due principali API di decodifica native, formattato per essere usato come consultazione durante la scrittura o la revisione del codice.
atob(encodedData)
| Parametro | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
| encodedData | string | Sì | Stringa Base64 standard che usa i caratteri +, /, =. Le varianti URL-safe (-, _) generano InvalidCharacterError. Gli spazi non sono consentiti. |
Buffer.from(input, inputEncoding) / .toString(outputEncoding)
| Parametro | Tipo | Predefinito | Descrizione |
|---|---|---|---|
| input | string | Buffer | TypedArray | ArrayBuffer | obbligatorio | La stringa codificata in Base64 da decodificare, o un buffer contenente byte codificati. |
| inputEncoding | BufferEncoding | "utf8" | Impostare su "base64" per il Base64 standard (RFC 4648 §4), o "base64url" per il Base64 URL-safe (RFC 4648 §5, Node.js 18+). |
| outputEncoding | string | "utf8" | Codifica per l'output .toString(). Usa "utf8" per il testo leggibile, "binary" per una stringa binaria Latin-1 compatibile con l'output di atob(). |
| start | integer | 0 | Offset di byte nel Buffer decodificato da cui iniziare la lettura. Passato a .toString() come secondo argomento. |
| end | integer | buf.length | Offset di byte a cui fermare la lettura (escluso). Passato a .toString() come terzo argomento. |
Base64 URL-safe — Decodificare JWT e parametri URL
I JWT usano il Base64 URL-safe (RFC 4648 §5) per tutti e tre i segmenti. Il Base64 URL-safe sostituisce + con - e / con _, e rimuove il padding finale =. Passare questo direttamente a atob() senza ripristino produce output errato o genera un errore.
Browser — ripristina i caratteri e il padding prima della decodifica
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 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_3a7f91c2Decodificare Base64 da file e risposte API
Nel codice di produzione, la decodifica Base64 avviene più spesso quando si consumano API esterne che forniscono contenuto in forma codificata. Entrambi gli scenari presentano importanti insidie relative agli spazi e all'output binario rispetto al testo. Se hai solo bisogno di ispezionare una risposta codificata durante il debug, incollala direttamente nel Decoder Base64 — gestisce le modalità standard e URL-safe istantaneamente.
Decodifica del contenuto dall'API GitHub Contents
// 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}`)Decodifica di un binario codificato in Base64 da un'API (browser)
// 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 Base64 da riga di comando in Node.js e Shell
Per script CI/CD, sessioni di debug o attività di decodifica occasionali, gli strumenti shell e i comandi Node.js in una riga sono più veloci di uno script completo. Nota che il nome del parametro differisce tra 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 per decodificare (D maiuscola), mentre Linux usa -d (minuscola). Questo può far fallire silenziosamente gli script CI — usa un comando Node.js in una riga quando la piattaforma di destinazione non è garantita essere Linux.Alternativa ad alte prestazioni: js-base64
Il motivo principale per usare una libreria è la coerenza tra ambienti. Se pubblichi un pacchetto che gira sia nel browser che in Node.js senza configurazione del bundler, Bufferrichiede il rilevamento dell'ambiente e atob() richiede la soluzione alternativa con TextDecoder. js-base64 (oltre 100 milioni di download settimanali su npm) gestisce entrambi in modo trasparente.
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) // trueOutput terminale con evidenziazione della sintassi
Quando si scrivono strumenti CLI di debug o script di ispezione, l'output grezzo di console.log è difficile da leggere per payload JSON di grandi dimensioni. chalk(il pacchetto npm più scaricato per la colorazione del terminale) combinato con la decodifica Base64 produce output terminale leggibile e scansionabile — utile per l'ispezione JWT, il debug delle risposte API e l'auditing della configurazione.
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: 1717203600Decodificare file Base64 di grandi dimensioni con gli stream Node.js
Quando un file codificato in Base64 supera ~50 MB, caricarlo interamente in memoria con readFileSync() diventa un problema. Gli stream Node.js ti permettono di decodificare i dati a blocchi — ma il Base64 richiede multipli di 4 caratteri per blocco (ogni gruppo di 4 caratteri si decodifica in esattamente 3 byte) per evitare errori di padding ai confini dei blocchi.
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 caratteri (768 KB). Per file inferiori a 50 MB, readFile() + Buffer.from(content.trim(), 'base64') è più semplice e sufficientemente veloce.Errori comuni
Ho visto questi quattro errori ripetutamente nei codebase JavaScript — tendono a restare nascosti fino a quando un carattere non-ASCII o una risposta API suddivisa su più righe raggiunge il percorso di decodifica in produzione.
Errore 1 — Usare atob() senza TextDecoder per contenuto UTF-8
Problema: atob() restituisce una stringa binaria dove ogni carattere è un valore di byte grezzo. Le sequenze multi-byte UTF-8 (cirillico, CJK, lettere accentuate) appaiono come caratteri Latin-1 corrotti. Soluzione: avvolgi l'output in 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) // Алексей Иванов ✓
Errore 2 — Passare Base64 URL-safe direttamente ad atob()
Problema: I segmenti JWT usano - e _ invece di + e /, senza padding. atob() può restituire dati errati o generare un errore. Soluzione: ripristina prima i caratteri standard e riaggiungi il padding.
// ❌ 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"} ✓Errore 3 — Non rimuovere i caratteri di nuova riga dal Base64 suddiviso su più righe
Problema: L'API GitHub Contents e i codificatori MIME suddividono l'output Base64 a 60–76 caratteri per riga. atob() genera una InvalidCharacterError sui caratteri \n. Soluzione: rimuovi tutti gli spazi prima di decodificare.
// ❌ 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) // ✓
Errore 4 — Chiamare .toString() su contenuto binario decodificato
Problema: Quando i dati originali sono binari (immagini, PDF, audio), chiamare .toString('utf8') sostituisce le sequenze di byte non riconosciute con U+FFFD, corrompendo silenziosamente l'output. Soluzione: mantieni il risultato come Buffer — non convertirlo in stringa.
// ❌ .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 PDFMetodi di decodifica Base64 in JavaScript — Confronto rapido
| Metodo | Output UTF-8 | Output binario | URL-safe | Ambienti | Installazione richiesta |
|---|---|---|---|---|---|
| atob() | ❌ richiede TextDecoder | ✅ stringa binaria | ❌ ripristino manuale | Browser, Node 16+, Bun, Deno | No |
| TextDecoder + atob() | ✅ UTF-8 | ✅ via Uint8Array | ❌ ripristino manuale | Browser, Node 16+, Deno | No |
| Buffer.from().toString() | ✅ utf8 | ✅ mantieni come Buffer | ✅ base64url (Node 18+) | Node.js, Bun | No |
| Uint8Array.fromBase64() (TC39) | ✅ via TextDecoder | ✅ nativo | ✅ opzione alphabet | Chrome 130+, Node 22+ | No |
| js-base64 | ✅ sempre | ✅ Uint8Array | ✅ integrato | Universale | npm install |
Scegli atob()solo quando il contenuto decodificato è garantito essere testo ASCII. Per qualsiasi testo fornito dall'utente o multilingue in un browser, usa TextDecoder + atob(). Per il codice lato server Node.js, Bufferè il default corretto — gestisce l'UTF-8 automaticamente e mantiene i dati binari intatti. Per le librerie multi-ambiente, js-base64 elimina tutti i casi limite.
Domande frequenti
Strumenti correlati
Per una decodifica con un clic senza scrivere codice, incolla la tua stringa Base64 direttamente nel Decoder Base64 — gestisce le modalità standard e URL-safe con output immediato nel tuo browser.
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.