Base64 decoderen in JavaScript β€” atob() & Buffer

Β·Front-end & Node.js DeveloperΒ·Beoordeeld doorSophie LaurentΒ·Gepubliceerd

Gebruik de gratis Base64 Decode Online direct in je browser β€” geen installatie nodig.

Base64 Decode Online online uitproberen β†’

Als ik een authenticatieprobleem in productie debugg, is een Base64 decoder het eerste waar ik naar grijp β€” JWT-payloads, webhookhandtekeningen en gecodeerde configuratiewaarden verbergen zich allemaal in Base64-strings. JavaScript biedt twee primaire ingebouwde methoden voor Base64-decodering: atob() (browser + Node.js 16+) en Buffer.from(encoded, 'base64').toString() (Node.js) β€” en ze gedragen zich heel anders wanneer de originele data Unicode-tekens bevatte. Voor een snelle eenmalige decodering zonder code te schrijven handelt ToolDeck's Base64 Decoder het meteen in je browser af. Deze handleiding behandelt beide omgevingen β€” gericht op Node.js 16+ en moderne browsers (Chrome 80+, Firefox 75+, Safari 14+) β€” met productieklare voorbeelden: UTF-8-herstel, URL-veilige varianten, JWT-decodering, bestanden, API-reacties, Node.js streams en de vier fouten die in echte codebases consistent voor onleesbare uitvoer zorgen.

  • βœ“atob(encoded) is browser-native en beschikbaar in Node.js 16+ globaal, maar geeft een binaire string terug β€” gebruik TextDecoder om UTF-8-tekst te herstellen uit inhoud boven ASCII.
  • βœ“Buffer.from(encoded, "base64").toString("utf8") is de idiomatische Node.js-aanpak en verwerkt UTF-8 automatisch zonder extra stappen.
  • βœ“URL-veilige Base64 (gebruikt in JWT's) vervangt + door -, / door _, en verwijdert =-padding. Herstel deze tekens voor je atob() aanroept, of gebruik Buffer.from(encoded, "base64url").toString() in Node.js 18+.
  • βœ“Verwijder witruimte en regeleinden voor het decoderen β€” de GitHub Contents API en veel MIME-encoders breken Base64-uitvoer om bij 60–76 tekens per regel.
  • βœ“Uint8Array.prototype.fromBase64() (TC39 Stage 3) is al beschikbaar in Node.js 22+ en Chrome 130+ en zal uiteindelijk beide omgevingen verenigen.

Wat is Base64-decodering?

Base64-decodering is het omgekeerde van codering β€” het converteert de 64-teken ASCII-representatie terug naar de originele binaire data of tekst. Elke 4 Base64-tekens worden teruggekoppeld aan precies 3 bytes. De =-opvultekens aan het einde van een gecodeerde string vertellen de decoder hoeveel extra bytes zijn toegevoegd om de laatste 3-byte-groep te voltooien.

Base64 is geen versleuteling β€” de bewerking is volledig omkeerbaar voor iedereen met de gecodeerde string. Het doel is transportveiligheid: protocollen en opslagformaten ontworpen voor 7-bit ASCII-tekst kunnen geen willekeurige binaire bytes verwerken, en Base64 overbrugt die kloof. Veelvoorkomende JavaScript-decoderingssituaties zijn het inspecteren van JWT-payloads, het uitpakken van Base64-gecodeerde JSON-configuraties uit omgevingsvariabelen, het extraheren van binaire bestandsinhoud uit REST-API's en het decoderen van data-URI's in de browser.

Before Β· text
After Β· text
ZGVwbG95LWJvdDpzay1wcm9kLWE3ZjJjOTFlNGIzZDg=
deploy-bot:sk-prod-a7f2c91e4b3d8

atob() β€” De browser-native decoderingsfunctie

atob() (ASCII-to-binary) is beschikbaar in browsers sinds IE10 en werd een global in Node.js 16.0 als onderdeel van het WinterCG-compatibiliteitsinitiatief. Het werkt ook native in Deno, Bun en Cloudflare Workers β€” geen import vereist.

De functie geeft een binaire string terug: een JavaScript-string waarbij elk teken een codepunt heeft dat gelijk is aan één ruwe bytewaarde (0–255). Dit is belangrijk: als de originele data UTF-8-tekst bevatte met tekens boven U+007F (geaccentueerde letters, Cyrillisch, CJK, emoji), is de teruggegeven string de ruwe bytereeks, geen leesbare tekst. Gebruik TextDecoder om het te herstellen (behandeld in het volgende gedeelte).

Minimaal werkend voorbeeld

JavaScript (browser / Node.js 16+)
// 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-a7f2c91e4b3d8

Round-trip verificatie

JavaScript
// 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
Opmerking:atob() en btoa() maken deel uit van de WinterCG Minimum Common API β€” dezelfde specificatie die Fetch, URL en crypto in niet-browser runtimes regelt. Ze gedragen zich identiek in Node.js 16+, Bun, Deno en Cloudflare Workers.

UTF-8-tekst herstellen na decodering

De meest voorkomende valkuil bij atob() is het misverstand over het retourtype. Wanneer de originele tekst als UTF-8 was gecodeerd voor Base64, geeft atob() een Latin-1 binaire string terug, niet de leesbare tekst:

JavaScript
// 'АлСксСй Иванов' 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

De juiste aanpak gebruikt TextDecoder om die ruwe bytes als UTF-8 te interpreteren:

TextDecoder-aanpak β€” veilig voor elke Unicode-uitvoer

JavaScript (browser + Node.js 16+)
// 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: 250
Opmerking:In Node.js kun je de TextDecoder-stap helemaal overslaan β€” gebruik Buffer.from(encoded, 'base64').toString('utf8'). Het interpreteert de gedecodeerde bytes automatisch als UTF-8 en is sneller voor grote invoer.

Buffer.from() in Node.js β€” Volledige decoderingshandleiding

In Node.js is Buffer de idiomatische API voor alle binaire bewerkingen inclusief Base64-decodering. Het verwerkt UTF-8 native, geeft een echte Buffer terug (binair-veilig), en ondersteunt sinds Node.js 18 de 'base64url'-coderingssnelkoppeling voor URL-veilige varianten.

Een omgevingsvariabele-configuratie decoderen

Node.js
// 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) // 100

Een binair bestand herstellen uit een .b64-bestand

Node.js
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 bytes

Asynchroon decoderen met foutafhandeling

Node.js
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`)

Base64-decoderingsfuncties β€” Parameterreferentie

Snelle referentie voor de parameters van de twee primaire native decoderings-API's, opgemaakt als naslagwerk bij het schrijven of controleren van code.

atob(encodedData)

ParameterTypeVereistBeschrijving
encodedDatastringJaStandaard Base64-string met de tekens +, /, =. URL-veilige varianten (-, _) gooien InvalidCharacterError. Witruimte is niet toegestaan.
Retourneert: binaire string β€” het codepunt van elk teken is gelijk aan één ruwe bytewaarde (0–255). Geen Unicode-string; geef door aan TextDecoder om UTF-8-tekst te herstellen.

Buffer.from(input, inputEncoding) / .toString(outputEncoding)

ParameterTypeStandaardBeschrijving
inputstring | Buffer | TypedArray | ArrayBuffervereistDe Base64-gecodeerde string om te decoderen, of een buffer met gecodeerde bytes.
inputEncodingBufferEncoding"utf8"Stel in op "base64" voor standaard Base64 (RFC 4648 Β§4), of "base64url" voor URL-veilige Base64 (RFC 4648 Β§5, Node.js 18+).
outputEncodingstring"utf8"Codering voor .toString()-uitvoer. Gebruik "utf8" voor leesbare tekst, "binary" voor een Latin-1 binaire string compatibel met atob()-uitvoer.
startinteger0Byte-offset binnen de gedecodeerde Buffer om te beginnen met lezen. Doorgegeven aan .toString() als tweede argument.
endintegerbuf.lengthByte-offset om te stoppen met lezen (exclusief). Doorgegeven aan .toString() als derde argument.
Retourneert:Buffer van .from(). Geeft string terug van .toString(). Bewaar als Buffer (roep .toString() niet aan) wanneer de gedecodeerde inhoud binair is β€” afbeeldingen, PDF's, audio.

URL-veilige Base64 β€” JWT's en URL-parameters decoderen

JWT's gebruiken URL-veilige Base64 (RFC 4648 Β§5) voor alle drie segmenten. URL-veilige Base64 vervangt + door - en / door _, en verwijdert het afsluitende =-padding. Dit direct doorgeven aan atob() zonder herstel produceert onjuiste uitvoer of gooit een fout.

Browser β€” tekens en padding herstellen voor decodering

JavaScript (browser)
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_3a7f91c2

Node.js 18+ β€” native 'base64url'-codering

Node.js 18+
// 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_3a7f91c2

Base64 decoderen uit bestanden en API-reacties

In productiecode vindt Base64-decodering het vaakst plaats bij het verwerken van externe API's die inhoud in gecodeerde vorm leveren. Beide scenario's hebben belangrijke valkuilen rondom witruimte en binaire vs. tekstuitvoer. Als je alleen een gecodeerde reactie wilt inspecteren tijdens debuggen, plak het direct in de Base64 Decoder β€” hij verwerkt standaard- en URL-veilige modi direct.

Inhoud van de GitHub Contents API decoderen

JavaScript
// 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}`)

Een Base64-gecodeerd binair bestand van een API decoderen (browser)

JavaScript (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')!)

Base64-decodering via de opdrachtregel in Node.js en Shell

Voor CI/CD-scripts, debuggingsessies of eenmalige decoderingstaken zijn shell-tools en Node.js-oneliners sneller dan een volledig script. Let op dat de vlag-naam verschilt tussen macOS en Linux.

bash
# ── 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"}
Opmerking:Op macOS gebruikt base64 -D om te decoderen (hoofdletter D), terwijl Linux -d (kleine letter) gebruikt. Dit breekt CI-scripts stilletjes β€” gebruik een Node.js-oneliner wanneer het doelplatform niet gegarandeerd Linux is.

Krachtig alternatief: js-base64

De belangrijkste reden om naar een bibliotheek te grijpen is omgevingsoverschrijdende consistentie. Als je een pakket levert dat zowel in de browser als in Node.js werkt zonder bundler-configuratie, vereist Buffer omgevingsdetectie en atob() vereist de TextDecoder-omweg. js-base64 (100M+ wekelijkse npm-downloads) verwerkt beide transparant.

bash
npm install js-base64
# or
pnpm add js-base64
JavaScript
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) // true

Terminaluitvoer met syntaxismarkering

Bij het schrijven van CLI-debugging-tools of inspectie-scripts is gewone console.log-uitvoer moeilijk te lezen voor grote JSON-payloads. chalk (het meest gedownloade npm-pakket voor terminalkleur) gecombineerd met Base64-decodering produceert leesbare, scanbare terminaluitvoer β€” handig voor JWT-inspectie, API-reactie-debugging en configuratie-auditing.

bash
npm install chalk
# chalk v5+ is ESM-only β€” use import, not require
Node.js
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:    1717203600
Opmerking:Gebruik chalk alleen voor terminal-/CLI-uitvoer β€” nooit voor inhoud die naar bestanden wordt geschreven, API-reacties of log-aggregatoren. ANSI-escapecodes corrumperen niet-terminal consumers: logplatforms (Datadog, Splunk), JSON-logparsers en CI-logviewers tonen ze allemaal als onleesbare tekenreeksen.

Grote Base64-bestanden decoderen met Node.js Streams

Wanneer een Base64-gecodeerd bestand ~50 MB overschrijdt, wordt het volledig laden in geheugen met readFileSync() een probleem. Node.js streams laten je data in stukken decoderen β€” maar Base64 vereist veelvouden van 4 tekens per stuk (elke 4-tekengroep decodeert naar precies 3 bytes) om padding-fouten aan stukgrenzen te voorkomen.

Node.js
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')
Opmerking:De stukgrootte moet een veelvoud van 4 tekens zijn bij het lezen van Base64-tekst, zodat elk stuk alleen volledige 4-tekengroepen bevat. Het voorbeeld gebruikt 4 Γ— 1024 Γ— 192 = 786.432 tekens (768 KB). Voor bestanden onder 50 MB is readFile() + Buffer.from(content.trim(), 'base64') eenvoudiger en snel genoeg.

Veelgemaakte fouten

Ik heb deze vier fouten herhaaldelijk gezien in JavaScript-codebases β€” ze blijven verborgen totdat een niet-ASCII-teken of een regelafgebroken API-reactie het decoderingspad in productie bereikt.

Fout 1 β€” atob() gebruiken zonder TextDecoder voor UTF-8-inhoud

Probleem: atob() geeft een binaire string terug waarbij elk teken één ruwe bytewaarde is. UTF-8-meerbyte-reeksen (Cyrillisch, CJK, geaccentueerde tekens) verschijnen als gecorrumpeerde Latin-1-tekens. Oplossing: de uitvoer door TextDecoder laten lopen.

Before Β· JavaScript
After Β· JavaScript
// ❌ 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) // АлСксСй Иванов βœ“

Fout 2 β€” URL-veilige Base64 direct doorgeven aan atob()

Probleem: JWT-segmenten gebruiken - en _ in plaats van + en /, zonder padding. atob() kan onjuiste data teruggeven of een fout gooien. Oplossing: standaardtekens en padding eerst herstellen.

Before Β· JavaScript
After Β· JavaScript
// ❌ 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"} βœ“

Fout 3 β€” Regeleinden niet verwijderen uit regelafgebroken Base64

Probleem: De GitHub Contents API en MIME-encoders breken Base64-uitvoer om bij 60–76 tekens per regel. atob() gooit InvalidCharacterError op \n-tekens. Oplossing: alle witruimte verwijderen voor het decoderen.

Before Β· JavaScript
After Β· JavaScript
// ❌ 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) // βœ“

Fout 4 β€” .toString() aanroepen op gedecodeerde binaire inhoud

Probleem: Wanneer de originele data binair is (afbeeldingen, PDF's, audio), vervangt .toString('utf8') niet-herkende bytereeksen door U+FFFD, waardoor de uitvoer stilletjes wordt gecorrumpeerd. Oplossing: het resultaat als Buffer bewaren β€” niet converteren naar een string.

Before Β· JavaScript
After Β· JavaScript
// ❌ .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 PDF

JavaScript Base64-decodeermethoden β€” Snelle vergelijking

MethodeUTF-8-uitvoerBinaire uitvoerURL-veiligOmgevingenInstallatie vereist
atob()❌ TextDecoder nodigβœ… binaire string❌ handmatig herstellenBrowser, Node 16+, Bun, DenoNee
TextDecoder + atob()βœ… UTF-8βœ… via Uint8Array❌ handmatig herstellenBrowser, Node 16+, DenoNee
Buffer.from().toString()βœ… utf8βœ… als Buffer bewarenβœ… base64url (Node 18+)Node.js, BunNee
Uint8Array.fromBase64() (TC39)βœ… via TextDecoderβœ… nativeβœ… alphabet optionChrome 130+, Node 22+Nee
js-base64βœ… altijdβœ… Uint8Arrayβœ… ingebouwdUniverseelnpm install

Kies atob() alleen wanneer de gedecodeerde inhoud gegarandeerd ASCII-tekst is. Voor door gebruikers aangeleverde of meertalige tekst in een browser, gebruik TextDecoder + atob(). Voor Node.js server-side code is Buffer de juiste standaard β€” het verwerkt UTF-8 automatisch en houdt binaire data intact. Voor omgevingsoverschrijdende bibliotheken elimineert js-base64 alle randgevallen.

Veelgestelde vragen

Waarom geeft atob() gecorrumpeerde tekens terug in plaats van leesbare tekst?
atob() geeft een binaire string terug waarbij elk teken één ruwe byte vertegenwoordigt (0–255), geen Unicode-codepunt. Als de originele tekst als UTF-8 was gecodeerd, zal elk teken boven U+007F β€” Cyrillisch, Arabisch, CJK-ideogrammen, geaccentueerde letters β€” verschijnen als twee of meer gecorrumpeerde Latin-1-tekens. De oplossing: de uitvoer door TextDecoder laten lopen: const bytes = Uint8Array.from(atob(encoded), ch => ch.charCodeAt(0)); const text = new TextDecoder().decode(bytes). In Node.js gebruik Buffer.from(encoded, 'base64').toString('utf8') die dit automatisch verwerkt.
Hoe decodeer ik een JWT-token payload in JavaScript?
Een JWT heeft drie URL-veilige Base64-segmenten gescheiden door punten: header.payload.signature. Om de payload te decoderen: const [, payloadB64] = token.split('.'). In de browser: herstel standaardtekens, voeg padding toe, decodeer met atob() en TextDecoder. In Node.js 18+: Buffer.from(payloadB64, 'base64url').toString('utf8'). Belangrijk: decoderen onthult alleen de claims β€” het verifieert NIET de handtekening. Gebruik een goede JWT-bibliotheek (jsonwebtoken, jose) voor geverifieerde decodering in productie.
Wat is het verschil tussen atob() en Buffer.from() voor decodering?
atob() is beschikbaar in alle JavaScript-omgevingen (browser, Node.js 16+, Bun, Deno) zonder imports, maar geeft een binaire string terug β€” TextDecoder is nodig om UTF-8-inhoud naar leesbare tekst te converteren. Buffer.from(encoded, 'base64') is alleen voor Node.js / Bun, geeft een echte Buffer terug (binair-veilig), verwerkt UTF-8 native en ondersteunt 'base64url' in Node.js 18+. Voor server-side code is Buffer eenvoudiger. Voor browsercode is atob() + TextDecoder de standaard. Voor omgevingsoverschrijdende bibliotheken abstraheert js-base64 het verschil.
Hoe decodeer ik URL-veilige Base64 in de browser?
URL-veilige Base64 vervangt + door -, / door _, en verwijdert =-padding. Herstel ze voor atob() aan te roepen: const b64 = input.replace(/-/g, '+').replace(/_/g, '/'); const padded = b64 + '==='.slice(0, (4 - b64.length % 4) % 4); const text = new TextDecoder().decode(Uint8Array.from(atob(padded), c => c.charCodeAt(0))). In Node.js 18+: Buffer.from(input, 'base64url').toString('utf8') doet het in één aanroep.
Hoe decodeer ik Base64-inhoud van de GitHub API in JavaScript?
De GitHub Contents API geeft bestandsinhoud terug als standaard Base64 met regeleinden elke 60 tekens. Verwijder ze voor decodering: const clean = data.content.replace(/\n/g, ''). In de browser: new TextDecoder().decode(Uint8Array.from(atob(clean), c => c.charCodeAt(0))). In Node.js: Buffer.from(clean, 'base64').toString('utf8'). Voor binaire bestanden (afbeeldingen, PDF's) de Buffer bewaren zonder .toString() te roepen β€” direct doorgeven aan writeFile of de reactiestroom.
Kan ik een Base64-gecodeerde afbeelding decoderen in JavaScript zonder bibliotheek?
Ja. In de browser: const binary = atob(encoded); const bytes = Uint8Array.from(binary, ch => ch.charCodeAt(0)); const blob = new Blob([bytes], { type: 'image/png' }); const url = URL.createObjectURL(blob). Voor een img src, bouw in plaats daarvan een data-URI: const src = 'data:image/png;base64,' + encoded β€” dit slaat de decodeerstap volledig over. In Node.js: Buffer.from(encoded, 'base64') gevolgd door writeFileSync('./out.png', buffer). De hoofdregel: roep .toString() nooit aan op de gedecodeerde Buffer wanneer de inhoud binair is.

Gerelateerde tools

Voor een decodering met één klik zonder code te schrijven, plak je Base64-string direct in de Base64 Decoder β€” hij verwerkt standaard- en URL-veilige modi met onmiddellijke uitvoer in je browser.

Ook beschikbaar in:PythonGoJavaC#
AC
Alex ChenFront-end & Node.js Developer

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.

SL
Sophie LaurentTechnisch beoordelaar

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.