How To Encode and Decode Strings with Base64 in JavaScript

Anastasios Antoniadis

Updated on:

Below is a comprehensive guide on how to work with Base64 encoding and decoding in JavaScript. It includes an introduction to what Base64 is, why it is used, step-by-step instructions, a glossary of relevant terms, and a frequently asked questions (FAQ) section.

Base64 is a method of encoding arbitrary binary data (such as images or any other file content) into a string of ASCII (American Standard Code for Information Interchange) characters. Because it only uses a limited set of 64 characters—letters, digits, plus sign (+), slash (/), and the equals sign (=) for padding—this encoded data can be safely transmitted in environments that handle textual data.

Why Use Base64 Encoding in JavaScript?

Data transmission: Base64 strings are safe for transportation over media that can handle only textual data (for example, HTML forms, URLs, JSON, or email).

Browser compatibility: Many JavaScript environments (both in the browser and on the server with Node.js) have built-in methods to handle Base64 encoding/decoding.

Embed resources: You can embed small images, fonts, or other binary data directly in HTML or CSS files using Base64 to reduce the number of external resources.

Step-by-Step: Encoding and Decoding in the Browser

1. Using btoa() and atob() Functions

Modern browsers implement two primary functions for Base64 operations:

  • btoa(): Binary to ASCII. Encodes a string into Base64.
  • atob(): ASCII to Binary. Decodes a Base64-encoded string back to a raw string.

Example: Encoding a String

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>Base64 Encoding Example</title>
</head>
<body>
  <script>
    const originalString = "Hello, Base64!";
    // Encode the string using btoa()
    const encodedString = btoa(originalString);

    console.log("Original String:", originalString); // "Hello, Base64!"
    console.log("Base64 Encoded:", encodedString);   // "SGVsbG8sIEJhc2U2NCE="
  </script>
</body>
</html>

Example: Decoding a String

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>Base64 Decoding Example</title>
</head>
<body>
  <script>
    const encodedString = "SGVsbG8sIEJhc2U2NCE=";
    // Decode the string using atob()
    const decodedString = atob(encodedString);

    console.log("Base64 Encoded:", encodedString); // "SGVsbG8sIEJhc2U2NCE="
    console.log("Decoded String:", decodedString); // "Hello, Base64!"
  </script>
</body>
</html>

2. Handling Non-ASCII/Unicode Characters

The btoa() and atob() functions in many browsers only support ASCII characters. If you need to encode or decode strings with characters outside the ASCII range (such as emojis or certain accented characters), you need to properly convert your string to UTF-8 before encoding and from UTF-8 after decoding.

One popular approach is to use JavaScript’s TextEncoder and TextDecoder APIs:

// Encoding Unicode string to Base64
function encodeUnicodeToBase64(str) {
  const utf8Bytes = new TextEncoder().encode(str); // UTF-8 byte array
  let binary = "";
  utf8Bytes.forEach((byte) => {
    binary += String.fromCharCode(byte);
  });
  return btoa(binary);
}

// Decoding from Base64 to Unicode string
function decodeBase64ToUnicode(base64) {
  const binary = atob(base64);
  const bytes = new Uint8Array([...binary].map((char) => char.charCodeAt(0)));
  return new TextDecoder().decode(bytes);
}

// Example usage:
const unicodeString = "Hello, 你好! 🌍";
const encoded = encodeUnicodeToBase64(unicodeString);
const decoded = decodeBase64ToUnicode(encoded);

console.log("Original:", unicodeString);
console.log("Encoded:", encoded);
console.log("Decoded:", decoded);

Encoding and Decoding in Node.js

Node.js provides a built-in Buffer class that has straightforward methods for Base64 conversion:

// Encoding
const originalString = "Hello, Base64!";
const buffer = Buffer.from(originalString, "utf8");
const encodedString = buffer.toString("base64"); // "SGVsbG8sIEJhc2U2NCE="

// Decoding
const decodedBuffer = Buffer.from(encodedString, "base64");
const decodedString = decodedBuffer.toString("utf8"); // "Hello, Base64!"

console.log("Original:", originalString);
console.log("Encoded:", encodedString);
console.log("Decoded:", decodedString);

Node’s Buffer approach automatically handles UTF-8 encoding when you specify "utf8".

Common Use Cases

Data URLs: Embedding images or other files directly into HTML or CSS files.

Transferring binary data over JSON: Because JSON can only handle textual data, Base64 is a standard solution for sending images or other binary content in JSON format.

Basic authentication headers: The HTTP Basic Auth system uses Base64 to encode username and password pairs.

Secure storage: While Base64 is not encryption, sometimes it is used to obscure data for simple storage or obfuscation.

Glossary

  1. ASCII (American Standard Code for Information Interchange): An older character encoding standard for electronic communication, primarily representing English characters.
  2. Base64: An encoding scheme to represent binary data in an ASCII string format using 64 printable characters.
  3. btoa(): A browser function (binary to ASCII) that encodes a string into Base64.
  4. atob(): A browser function (ASCII to binary) that decodes a Base64 string.
  5. Buffer: A global object in Node.js for handling raw binary data.
  6. Encode: Converting data from one format to another, typically to facilitate safe transfer or storage.
  7. Decode: Converting encoded data back to its original format.
  8. UTF-8: A variable-width character encoding used to encode all possible characters (Unicode).
  9. Obfuscation: The act of making data harder to interpret without necessarily adding cryptographic security.

FAQ

1. Is Base64 the same as Encryption?

No, Base64 is not encryption. It is simply a form of encoding that makes data more convenient to handle in text-based formats. It provides no inherent security or privacy.

2. Why does the btoa() function throw an error for some characters?

btoa() typically supports only ASCII text. Characters outside the ASCII range may cause errors. To handle non-ASCII characters, you need to convert them to UTF-8 byte arrays first (using TextEncoder, for instance).

3. What if I need to use Base64 encoding in older browsers that do not support btoa()/atob()?

You can use third-party libraries (like js-base64) that provide similar functionality for browsers that don’t support these native functions.

4. How do I handle URLs that need Base64-encoded data?

Base64 encoding can include characters such as + and /, which may not be URL-safe. A common approach is to perform “URL-safe Base64” by replacing + with - and / with _. Some utility libraries or frameworks provide these functions.

5. What is the purpose of the = signs in Base64?

The equals sign (=) is used for padding in Base64, ensuring that the encoded data’s length is a multiple of 4. Without proper padding, the decoder might not know how to properly handle the last bytes of encoded data.

6. Is there any size overhead in using Base64?

Yes. Base64 encoding adds around 33% overhead compared to the original binary data. For every 3 bytes of binary data, Base64 produces 4 bytes of encoded data.

7. Why do I see different Base64 results for the same original data sometimes?

  • Newlines: Some encoders insert newlines in the output for readability.
  • URL-safe variations: Replacing + and / with - and _.
  • Character encoding differences: Always ensure you’re consistently using UTF-8 or another specified encoding to avoid discrepancies.

Conclusion

Base64 encoding is a versatile and widely supported method for converting binary data to ASCII text, making it indispensable for tasks like embedding images in HTML, sending binary data over text-based protocols, or simply storing binary information in a text format. JavaScript provides convenient built-in functions—btoa() and atob() in the browser, and the Buffer class in Node.js—to perform these conversions. For non-ASCII characters, ensure you handle UTF-8 encoding and decoding properly.

Use Base64 judiciously—remember it is not a security measure but rather a means of encoding data for safe textual transport or storage. If you have sensitive data, you should look into actual encryption solutions beyond simple Base64 encoding.

With these guidelines, examples, and best practices, you should be able to confidently handle Base64 encoding and decoding in your JavaScript projects.

Anastasios Antoniadis
Find me on
Latest posts by Anastasios Antoniadis (see all)

Leave a Comment