Base64 dukker opp overalt når du begynner å lete — JWT-tokens, data-URI-er, e-postvedlegg,
API-nyttelaster som bærer binære filer. Kodingen i seg selv er definert i
RFC 4648
og er konsensmessig enkel: ta vilkårlige byte, representer dem ved hjelp av kun 64 skrivbare
ASCII-tegn. Det som snubler folk er implementasjonen i JavaScript — forskjellige
API-er i nettleser kontra Node.js, Unicode-fellen som gjør at btoa() kaster feil, og
URL-sikker variant som JWTs er avhengige av. Denne guiden dekker alt med fungerende kode.
btoa() og atob() i Nettleseren
Nettleseren har hatt
btoa()
og
atob()
lenge. Navnene er forvirrende (binary to ASCII og tilbake), men bruken er
grei for enkle strenger:
// Encode a plain ASCII string
const encoded = btoa('hello world');
console.log(encoded); // "aGVsbG8gd29ybGQ="
// Decode it back
const decoded = atob('aGVsbG8gd29ybGQ=');
console.log(decoded); // "hello world"
// A more realistic example — encoding a simple auth token
const credentials = 'apiuser:s3cr3tkey';
const basicAuth = 'Basic ' + btoa(credentials);
// "Basic YXBpdXNlcjpzM2NyM3RrZXk="
// This is exactly what HTTP Basic Authentication usesbtoa() håndterer bare strenger der
hvert tegn har et kodepunkt ≤ 255 (Latin-1-området). Send den en streng som inneholder
en emoji eller et ikke-latinsk tegn og den kaster InvalidCharacterError umiddelbart.
Dette er en av de vanligste Base64-feilene i nettleserkode.// ❌ This throws — emoji is outside Latin-1
btoa('Hello 🌍');
// Uncaught DOMException: Failed to execute 'btoa' on 'Window':
// The string to be encoded contains characters outside of the Latin1 range.
// ❌ This also throws — any non-ASCII character will do it
btoa('café');
// Uncaught DOMException: ...Håndtere Unicode Trygt i Nettleseren
Løsningen er å først kode strengen til UTF-8-byte, deretter Base64-kode disse bytene.
Den klassiske tilnærmingen bruker encodeURIComponent og en prosentdekode-teknikk. Den moderne
tilnærmingen bruker TextEncoder, som er
tilgjengelig i alle moderne nettlesere
og Node.js 11+:
// ✅ Unicode-safe encode using TextEncoder
function encodeBase64(str) {
const bytes = new TextEncoder().encode(str); // UTF-8 byte array
const binString = Array.from(bytes, byte =>
String.fromCodePoint(byte)
).join('');
return btoa(binString);
}
// ✅ Unicode-safe decode using TextDecoder
function decodeBase64(base64Str) {
const binString = atob(base64Str);
const bytes = Uint8Array.from(binString, char =>
char.codePointAt(0)
);
return new TextDecoder().decode(bytes);
}
// Now emojis and international text work fine
console.log(encodeBase64('Hello 🌍')); // "SGVsbG8g8J+MjQ=="
console.log(decodeBase64('SGVsbG8g8J+MjQ==')); // "Hello 🌍"
console.log(encodeBase64('Héllo café')); // "SMOpbGxvIGNhZsOp"
console.log(decodeBase64('SMOpbGxvIGNhZsOp')); // "Héllo café"Ha disse to hjelpefunksjonene et sted i kodebasen din og glem at bare
btoa() eksisterer. Paret TextEncoder/TextDecoder er det
riktige verktøyet for alt utover ren ASCII. Du kan prøve det akkurat nå med
Base64-koder-verktøyet.
Buffer.from() i Node.js
Node.js har sitt eget API for dette via Buffer-klassen, som håndterer koding/dekoding renere. Det er ingen Unicode-felle her fordi du eksplisitt spesifiserer inndatakodingen:
// Encode string → Base64
const encoded = Buffer.from('Hello 🌍', 'utf8').toString('base64');
console.log(encoded); // "SGVsbG8g8J+MjQ=="
// Decode Base64 → string
const decoded = Buffer.from('SGVsbG8g8J+MjQ==', 'base64').toString('utf8');
console.log(decoded); // "Hello 🌍"
// Practical example — encoding a JSON payload to embed in a config file
const config = {
apiKey: 'sk-prod-abc123',
projectId: 'proj_x9f2k',
region: 'us-east-1'
};
const encodedConfig = Buffer.from(JSON.stringify(config), 'utf8').toString('base64');
// eyJhcGlLZXkiOiJzay1wcm9kLWFiYzEyMyIsInByb2plY3RJZCI6InByb2pfeDlmMmsiLCJyZWdpb24iOiJ1cy1lYXN0LTEifQ==
// Decode and parse it back
const decodedConfig = JSON.parse(
Buffer.from(encodedConfig, 'base64').toString('utf8')
);
console.log(decodedConfig.region); // "us-east-1"Merk at btoa() og atob() også er tilgjengelige i Node.js 16+
som globaler (for nettleserkompatibilitet), men Buffer-API-et er mer idiomatisk i
Node.js og har vært der siden
Node.js v0.1.
For JSON-spesifikk koding er JSON til Base64-verktøyet hendig
for raske manuelle konverteringer.
URL-sikker Base64 — Hva JWTs Faktisk Bruker
Standard Base64 bruker + og / i alfabetet. Begge disse
tegnene er spesielle i URL-er — + betyr et mellomrom i spørringsstrenger, og /
er en stiseparator. Når du trenger Base64 i en URL eller som et JWT-segment, bruker du URL-sikker
variant: erstatt + med - og / med _,
deretter fjern =-utfyllingen. Dette er standardisert i
RFC 4648 §5
og er hva hvert JWT-bibliotek bruker internt:
// Convert standard Base64 to URL-safe Base64
function toBase64Url(base64Str) {
return base64Str
.replace(/+/g, '-')
.replace(///g, '_')
.replace(/=+$/, ''); // strip padding
}
// Convert URL-safe Base64 back to standard Base64
function fromBase64Url(base64UrlStr) {
// Restore padding — length must be a multiple of 4
const padded = base64UrlStr + '==='.slice((base64UrlStr.length + 3) % 4);
return padded
.replace(/-/g, '+')
.replace(/_/g, '/');
}
// Encode a string to URL-safe Base64
function encodeBase64Url(str) {
return toBase64Url(btoa(str));
}
// Decode URL-safe Base64 to a string
function decodeBase64Url(str) {
return atob(fromBase64Url(str));
}
// Example: manually inspect a JWT payload
const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjQyLCJyb2xlIjoiYWRtaW4iLCJpYXQiOjE3MTM0MDAwMDB9.signature';
const [header, payload] = jwt.split('.');
console.log(decodeBase64Url(header));
// {"alg":"HS256","typ":"JWT"}
console.log(decodeBase64Url(payload));
// {"userId":42,"role":"admin","iat":1713400000}Det er derfor du ser Base64-strenger som
eyJhbGciOiJIUzI1NiJ9 i JWTs — ingen utfylling, bindestreker i stedet for plusstegn.
Når du sender kodede data som en URL-spørringsparameter, bruk alltid URL-sikker variant for å
unngå ødelagte URL-er. Base64-dekoder-verktøyet håndterer begge
standard og URL-sikker Base64 automatisk.
Kode en Fil med FileReader API
En vanlig nettleseroppgave: brukeren velger et bilde eller dokument, og du trenger å sende det
til en API som Base64.
FileReader API
har readAsDataURL() for akkurat dette — det gir deg en komplett data-URI med
MIME-typen inkludert:
// Wrap FileReader in a Promise for easier async usage
function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
// result is "data:image/png;base64,iVBORw0KGgo..."
// Strip the data URI prefix to get just the Base64 string
const base64 = reader.result.split(',')[1];
resolve(base64);
};
reader.onerror = () => reject(new Error('Failed to read file'));
reader.readAsDataURL(file);
});
}
// Hook it up to a file input
const fileInput = document.getElementById('avatarUpload');
fileInput.addEventListener('change', async (event) => {
const file = event.target.files[0];
if (!file) return;
try {
const base64 = await fileToBase64(file);
console.log(`File size: ${file.size} bytes`);
console.log(`Base64 length: ${base64.length} chars`);
// Send to your API
await fetch('/api/users/42/avatar', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ image: base64, mimeType: file.type })
});
} catch (err) {
console.error('Upload failed:', err.message);
}
});Hvis du trenger den fulle data-URI-en (inkludert MIME-type-prefikset) i stedet for bare
rå Base64, hopp over .split(',')[1] og bruk reader.result direkte.
For massekonvertering av filer håndterer Bilde til Base64-verktøyet
bilder uten å skrive noen kode.
Kode Binære Data og Uint8Arrays
Noen ganger starter du ikke fra en streng eller en Fil — du har rå byte fra en
WebCrypto-operasjon, en canvas-eksport eller en WebAssembly-modul. Her er hvordan du går fra en
Uint8Array til Base64 og tilbake i begge miljøer:
// --- Browser ---
// Uint8Array → Base64 (browser)
function uint8ToBase64(bytes) {
const binString = Array.from(bytes, byte =>
String.fromCodePoint(byte)
).join('');
return btoa(binString);
}
// Base64 → Uint8Array (browser)
function base64ToUint8(base64Str) {
const binString = atob(base64Str);
return Uint8Array.from(binString, char => char.codePointAt(0));
}
// Example: export a canvas as raw PNG bytes → Base64
const canvas = document.getElementById('myCanvas');
canvas.toBlob(blob => {
blob.arrayBuffer().then(buffer => {
const bytes = new Uint8Array(buffer);
const encoded = uint8ToBase64(bytes);
console.log('PNG as Base64:', encoded.slice(0, 40) + '...');
});
}, 'image/png');
// --- Node.js ---
// Uint8Array / Buffer → Base64 (Node.js)
function uint8ToBase64Node(bytes) {
return Buffer.from(bytes).toString('base64');
}
// Base64 → Buffer (Node.js)
function base64ToBufferNode(base64Str) {
return Buffer.from(base64Str, 'base64');
}
// Example: hash a password and encode the result
const crypto = require('crypto');
const hash = crypto.createHash('sha256').update('mySecretPassword').digest();
// hash is a Buffer (which extends Uint8Array)
console.log(hash.toString('base64'));
// "XohImNooBHFR0OVvjcYpJ3NgxxxxxxxxxxxxxA=="Innbygging av Bilder som Data-URI-er
En av de mest praktiske bruken av Base64 i webutvikling er å bygge inn bilder direkte i HTML eller CSS, og eliminere en HTTP-forespørsel. Du har sannsynligvis sett data-URI-er i innebygde SVG-er eller e-postmaler. Her er mønsteret:
<!-- Inline image in HTML — no separate network request -->
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
alt="1x1 transparent pixel"
width="1"
height="1"
/>/* Inline background image in CSS — commonly used for small icons and loading spinners */
.spinner {
width: 32px;
height: 32px;
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTEyIDJhMTAgMTAgMCAxIDAgMCAyMCAxMCAxMCAwIDAgMCAwLTIweiIvPjwvc3ZnPg==");
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}// Generate a data URI from a fetched image (Node.js)
const fs = require('fs');
const path = require('path');
function imageFileToDataUri(filePath) {
const ext = path.extname(filePath).slice(1).toLowerCase();
const mimeMap = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg',
gif: 'image/gif', svg: 'image/svg+xml', webp: 'image/webp' };
const mimeType = mimeMap[ext] ?? 'application/octet-stream';
const fileData = fs.readFileSync(filePath);
const base64 = fileData.toString('base64');
return `data:${mimeType};base64,${base64}`;
}
const dataUri = imageFileToDataUri('./logo.png');
// "data:image/png;base64,iVBORw0KGgo..."
// Drop this into an <img src> or CSS background-imageEn Kompakt Verktøymodul for Begge Miljøer
I stedet for å spre btoa()-kall rundt kodebasen din, er det verdt å ha
én enkelt verktøymodul som dekker Unicode, URL-sikre varianter og fungerer i begge
nettleser og Node.js. Her er en som gjør alt det:
// base64.js — drop into any project
const isNode = typeof process !== 'undefined' && process.versions?.node;
export function encode(str) {
if (isNode) {
return Buffer.from(str, 'utf8').toString('base64');
}
// Browser: encode to UTF-8 bytes first, then Base64
const bytes = new TextEncoder().encode(str);
const binString = Array.from(bytes, b => String.fromCodePoint(b)).join('');
return btoa(binString);
}
export function decode(base64Str) {
if (isNode) {
return Buffer.from(base64Str, 'base64').toString('utf8');
}
// Browser: Base64 → bytes → UTF-8 string
const binString = atob(base64Str);
const bytes = Uint8Array.from(binString, c => c.codePointAt(0));
return new TextDecoder().decode(bytes);
}
export function encodeUrlSafe(str) {
return encode(str)
.replace(/+/g, '-')
.replace(///g, '_')
.replace(/=+$/, '');
}
export function decodeUrlSafe(str) {
const padded = str + '==='.slice((str.length + 3) % 4);
return decode(padded.replace(/-/g, '+').replace(/_/g, '/'));
}
export function encodeBytes(bytes) {
if (isNode) return Buffer.from(bytes).toString('base64');
const binString = Array.from(bytes, b => String.fromCodePoint(b)).join('');
return btoa(binString);
}
export function decodeToBytes(base64Str) {
if (isNode) return Buffer.from(base64Str, 'base64');
const binString = atob(base64Str);
return Uint8Array.from(binString, c => c.codePointAt(0));
}// Usage examples
import { encode, decode, encodeUrlSafe, decodeUrlSafe } from './base64.js';
encode('Hello 🌍'); // "SGVsbG8g8J+MjQ=="
decode('SGVsbG8g8J+MjQ=='); // "Hello 🌍"
encodeUrlSafe('[email protected]'); // "dXNlckBleGFtcGxlLmNvbQ" (no +, /, or =)
decodeUrlSafe('dXNlckBleGFtcGxlLmNvbQ'); // "[email protected]"Vanlige Fallgruver å Passe Seg For
- btoa() kaster feil på ikke-latinske tegn — alle tegn over kodepunkt 255 forårsaker
InvalidCharacterError. Bruk alltidTextEncoder-tilnærmingen ellerBuffer.from(str, 'utf8')i Node.js. - Utfylling er viktig for dekoding — Base64-strenger må ha en lengde som er et multiplum av 4. Manglende
=-utfylling gjør atatob()enten returnerer søppel eller kaster feil, avhengig av nettleseren. Gjenopprett alltid utfyllingen før du dekoder URL-sikre strenger. - Buffer vs streng-koding i Node.js —
Buffer.from(str)bruker som standard UTF-8, menBuffer.from(str, 'binary')behandler strengen som Latin-1-byte. Feil koding ved dekoding produserer forvrengt utdata som kan være vanskelig å feilsøke. - Data-URI MIME-type —
data:;base64,...(ingen MIME-type) fungerer i noen nettlesere men ikke andre. Inkluder alltid MIME-typen:data:image/png;base64,.... - Linjeskift i MIME Base64 — RFC 4648 tillater implementasjoner å sette inn linjeskift hvert 76. tegn (slik e-postkodere gjør). Både
atob()ogBuffer.from()håndterer dette, men hvis du genererer Base64 selv, ikke legg til linjeskift med mindre målsystemet forventer dem.
Oppsummering
Base64 i JavaScript er et av de emnene som ser trivielt ut helt til det biter deg.
Den korte versjonen: bruk aldri bare btoa() for noe brukergenerert — pakk det inn
med TextEncoder for å håndtere Unicode riktig. I Node.js er Buffer.from(str,
'utf8').toString('base64') riktig idiom. Når den kodede strengen havner i en
URL eller JWT, bytt til URL-sikker variant. For raske eksperimenter eller engangkonverteringer sparer
Base64-koder, Base64-dekoder
og JSON til Base64-verktøyene tid.
MDN Base64-glossarsiden
har også en solid nettleserfokusert referanse hvis du trenger en andre mening om noe av dette.