Comment Décoder du Base64 en JavaScript

Comment Décoder du Base64 en JavaScript

Décodez du Base64 en JavaScript correctement : atob dans le navigateur, Buffer dans Node.js, TextDecoder compatible Unicode, variantes URL-safe et gestion des erreurs.

Décoder du Base64 en JavaScript ressemble à une seule ligne de code, et pour de l'ASCII pur, c'en est une. Mais dès que vous décodez des emojis, des caractères accentués, le payload d'un JWT ou une chaîne URL-safe, l'approche naïve se brise de façons subtiles et frustrantes. Ce guide passe en revue toutes les méthodes fiables, dans le navigateur comme dans Node.js, avec les cas limites qui posent réellement problème aux développeurs en production.

Si vous avez juste besoin d'un résultat tout de suite sans écrire de code, collez votre chaîne dans Base64 Decode et lisez le texte brut instantanément. Pour tout le reste, voici comment procéder proprement avec du code.


La réponse rapide : atob()

Tous les navigateurs (et Node.js moderne) exposent deux fonctions globales :

  • btoa()binary to aSCII (encoder)
  • atob()aSCII to binary (décoder)
atob('SGVsbG8sIFdvcmxkIQ==');  // "Hello, World!"
btoa('Hello, World!');         // "SGVsbG8sIFdvcmxkIQ=="

Pour du texte ASCII simple, c'est tout ce dont vous avez besoin. Le problème, c'est qu'atob() renvoie une chaîne binaire : une chaîne où chaque caractère représente un octet (0–255). Cela fonctionne parfaitement pour les caractères latins, mais cela déforme tout ce qui sort de la plage ASCII.


Le problème d'Unicode

Essayez de décoder une chaîne Base64 contenant un caractère non ASCII et vous obtiendrez du charabia :

// "Héllo" encodé en UTF-8 puis en Base64 donne "SMOpbGxv"
atob('SMOpbGxv');  // "Héllo"  ❌ mojibake

Le é accentué est ressorti sous forme de deux caractères parasites. Pourquoi ? Parce qu'atob() vous donne des octets bruts, et que le é en UTF-8 fait deux octets (0xC3 0xA9). Traiter ces deux octets comme deux caractères distincts produit le mojibake classique é.

La solution consiste à prendre les octets renvoyés par atob() et à les décoder explicitement en UTF-8.

La méthode moderne et correcte : TextDecoder

function decodeBase64Utf8(b64) {
  const binary = atob(b64);
  const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
  return new TextDecoder('utf-8').decode(bytes);
}

decodeBase64Utf8('SMOpbGxv');  // "Héllo"  ✅

TextDecoder est intégré à tous les navigateurs modernes et à Node.js. C'est l'approche recommandée en 2024 et au-delà : rapide, basée sur les standards et correcte pour toute la plage Unicode, emojis compris.

// "🚀 launch" fait l'aller-retour correctement
const bytes = new TextEncoder().encode('🚀 launch');
const b64 = btoa(String.fromCharCode(...bytes));
decodeBase64Utf8(b64);  // "🚀 launch"  ✅

Décoder du Base64 dans Node.js

Node.js dispose de sa propre API, plus claire, via la classe Buffer. Vous n'avez pas du tout besoin d'atob() (même s'il existe en tant que fonction globale depuis Node 16).

// Décoder du Base64 en chaîne UTF-8
Buffer.from('SMOpbGxv', 'base64').toString('utf-8');  // "Héllo"

// Encoder une chaîne UTF-8 en Base64
Buffer.from('Héllo', 'utf-8').toString('base64');     // "SMOpbGxv"

Buffer gère Unicode correctement d'emblée parce que vous lui indiquez l'encodage de sortie ('utf-8'). C'est la manière idiomatique de décoder du Base64 dans n'importe quel JavaScript côté serveur, y compris les gestionnaires Express, les fonctions serverless et les scripts de build.

Décoder vers des octets bruts (fichiers, images)

Lorsque le Base64 représente des données binaires —une image, un PDF, une clé cryptographique— ne le convertissez pas en chaîne. Conservez-le sous forme de Buffer :

import { writeFileSync } from 'node:fs';

const b64 = 'iVBORw0KGgoAAAANSUhEUgAA...';   // un PNG, encodé
const buffer = Buffer.from(b64, 'base64');
writeFileSync('output.png', buffer);          // écrit la véritable image

Convertir des données binaires en chaîne UTF-8 les corromprait, car la plupart des séquences d'octets ne sont pas de l'UTF-8 valide.


Gérer le Base64 URL-safe

Les JWT, les jetons OAuth et de nombreuses API utilisent le Base64 URL-safe (RFC 4648 §5), qui échange deux caractères et supprime souvent le remplissage :

Standard URL-safe
+ -
/ _
remplissage = généralement omis

atob() natif et Buffer.from(..., 'base64') attendent l'alphabet standard, vous devez donc d'abord normaliser :

function decodeBase64Url(b64url) {
  // 1. Restaurer l'alphabet standard
  let b64 = b64url.replace(/-/g, '+').replace(/_/g, '/');
  // 2. Rajouter le remplissage pour que la longueur soit un multiple de 4
  while (b64.length % 4) b64 += '=';
  // 3. Décoder en UTF-8
  const bytes = Uint8Array.from(atob(b64), c => c.charCodeAt(0));
  return new TextDecoder('utf-8').decode(bytes);
}

// Décoder le segment de payload d'un JWT
const payload = 'eyJ1c2VyIjoiam9obiIsImFkbWluIjp0cnVlfQ';
decodeBase64Url(payload);  // '{"user":"john","admin":true}'

Node 16+ accepte aussi directement l'encodage 'base64url', qui gère tout cela pour vous :

Buffer.from('eyJ1c2VyIjoiam9obiJ9', 'base64url').toString('utf-8');
// '{"user":"john"}'

Si vous voulez inspecter un jeton sans écrire de code, le décodeur de JWT effectue pour vous le découpage et le décodage Base64URL. Pour comprendre la vue d'ensemble de la façon dont ces formats sont liés, consultez encodage vs décodage.


Gestion des erreurs

atob() lève une DOMException ("InvalidCharacterError") lorsque l'entrée n'est pas du Base64 valide. Encadrez toujours le décodage d'une protection, surtout quand l'entrée provient d'utilisateurs ou d'API externes :

function safeDecode(b64) {
  try {
    const bytes = Uint8Array.from(atob(b64), c => c.charCodeAt(0));
    return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
  } catch (err) {
    return null;  // Base64 invalide ou UTF-8 invalide
  }
}

Passer { fatal: true } à TextDecoder le fait lever une exception sur les séquences d'octets mal formées au lieu d'insérer silencieusement des caractères de remplacement (). C'est généralement ce que vous voulez : échouer bruyamment plutôt que livrer du texte corrompu.

Causes fréquentes d'échecs de décodage :

  • Espaces ou sauts de ligne dans la chaîne : retirez-les avec .replace(/\s/g, '') avant de décoder (le Base64 MIME coupe les lignes à 76 caractères).
  • Remplissage manquant : rajoutez des = jusqu'à ce que la longueur soit divisible par 4.
  • Caractères URL-safe (-, _) passés à un décodeur standard : normalisez-les d'abord.
  • Données encodées deux fois : quelqu'un a encodé une chaîne déjà encodée.

Une fonction réutilisable et prête pour la production

Voici une fonction unique qui gère l'entrée standard et URL-safe, les espaces, le remplissage manquant et Unicode, adaptée à la fois au navigateur et à Node.js moderne :

function decodeBase64(input) {
  let b64 = input.trim()
    .replace(/\s+/g, '')      // retirer les sauts de ligne MIME
    .replace(/-/g, '+')       // URL-safe → standard
    .replace(/_/g, '/');
  while (b64.length % 4) b64 += '=';   // corriger le remplissage
  const bytes = Uint8Array.from(atob(b64), c => c.charCodeAt(0));
  return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
}

Intégrez-la à n'importe quel projet et elle se comportera de manière prévisible face aux chaînes désordonnées du monde réel que vous recevez réellement.


FAQ

Pourquoi atob() renvoie-t-il des caractères bizarres pour du texte accentué ou des emojis ?

Parce qu'atob() renvoie une chaîne binaire d'octets bruts, et non du texte décodé. Les caractères UTF-8 multioctets (accents, emojis, CJK) reviennent sous forme d'octets séparés et s'affichent en mojibake. Faites passer les octets par TextDecoder('utf-8') pour récupérer le texte d'origine.

atob() est-il obsolète ?

Non. atob() et btoa() restent standard et pris en charge partout. Ils sont simplement de bas niveau : ils opèrent sur des chaînes binaires, vous les associez donc à TextDecoder/TextEncoder pour Unicode. Dans Node.js, Buffer est le choix le plus ergonomique.

Comment décoder du Base64 dans Node.js sans atob() ?

Utilisez Buffer.from(str, 'base64').toString('utf-8') pour du texte, ou conservez le Buffer tel quel pour des données binaires comme des images et des fichiers. Pour une entrée URL-safe, utilisez l'encodage 'base64url' (Node 16+).

Comment décoder le payload d'un JWT en JavaScript ?

Découpez le jeton sur ., prenez le deuxième segment (le payload) et décodez-le en Base64 URL-safe, puis appliquez JSON.parse() au résultat. Notez que cela ne fait que lire le jeton : cela ne vérifie pas la signature. Utilisez le décodeur de JWT pour inspecter les jetons visuellement.

Quelle est la différence entre le Base64 standard et URL-safe ?

Le Base64 standard utilise + et / et complète avec =. Le Base64 URL-safe les remplace par - et _ et omet généralement le remplissage, de sorte que la chaîne peut circuler dans les URL et les noms de fichiers sans échappement. Normalisez l'entrée URL-safe vers l'alphabet standard avant de décoder avec atob().

Comment puis-je décoder du Base64 sans écrire la moindre ligne de code ?

Collez la chaîne dans Base64 Decode, et le texte brut apparaît instantanément dans votre navigateur. Il gère automatiquement les espaces, les caractères URL-safe et le remplissage manquant, et aucune donnée ne quitte jamais votre appareil.

Essayez par vous-même

Utilisez notre outil en ligne gratuit pour commencer immédiatement

Ouvrir l'outil