Skip to main content
Toolsbase Logo

Base64 Encoding Explained: How It Works, When to Use It, and Common Pitfalls

Toolsbase Editorial Team
(Updated: )
Base64EncodingData ConversionWeb DevelopmentJWT

What Is Base64 Encoding?

Base64 is an encoding scheme that converts binary data into ASCII strings. As the name suggests, it uses 64 printable characters (A–Z, a–z, 0–9, +, /) plus a padding character (=) to represent any binary data in text form.

While "encoding" might sound like encryption, Base64 is not encryption. Anyone can easily decode (restore) the original data — it's simply a way to change the representation of data.

The core problem Base64 solves is fundamental: many protocols and systems were designed to handle text, not raw binary. When you need to transmit an image over an email protocol, embed a font in a CSS file, or pass binary data through a URL, you need a reliable way to represent those bytes as safe printable characters. That is exactly what Base64 does.

How Encoding Works

Let's walk through the Base64 encoding process step by step.

The Conversion Flow

  1. Treat the input data as a byte sequence (8-bit units)
  2. Split the byte sequence into 6-bit units
  3. Map each 6-bit value to its corresponding character using the conversion table
  4. Add padding (=) so the output length is a multiple of 4

The Conversion Table

A 6-bit value can represent 64 different values (0–63). Each maps to the following characters:

Value Range Characters Count
0–25 A–Z 26
26–51 a–z 26
52–61 0–9 10
62 + 1
63 / 1

That's 64 characters total, plus the padding character = for a total of 65 characters.

Example: Encoding "ABC"

Let's trace the process of encoding the string "ABC" to Base64.

Step 1: Convert to ASCII codes

A = 65 = 01000001
B = 66 = 01000010
C = 67 = 01000011

Step 2: Concatenate the 8-bit sequences and split into 6-bit units

8-bit: 01000001 01000010 01000011
6-bit: 010000 | 010100 | 001001 | 000011

Step 3: Map to characters using the conversion table

010000 = 16 → Q
010100 = 20 → U
001001 =  9 → J
000011 =  3 → D

Result: ABCQUJD

How Padding Works

When the input byte count is not a multiple of 3, the 6-bit splitting produces a remainder. In this case, missing bits are filled with zeros, and = characters are added so the output is a multiple of 4 characters.

Input Bytes Padding Example
Multiple of 3 None ABCQUJD
Remainder of 1 == AQQ==
Remainder of 2 = ABQUI=

Data Size Increase

In Base64 encoding, 3 bytes of input produce 4 characters of output. This means the encoded data is approximately 33% larger (exactly 4/3×) than the original.

Original: 3 bytes → Base64: 4 characters (4 bytes)
Increase: (4 - 3) / 3 ≈ 33%

This is a trade-off that should always be considered when using Base64.

Common Use Cases

Email Attachments (MIME)

The email protocol (SMTP) was originally designed to handle only 7-bit ASCII text. To attach binary files like images and PDFs to emails, the MIME (Multipurpose Internet Mail Extensions) standard adopted Base64 encoding.

Content-Type: image/png
Content-Transfer-Encoding: base64

iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ
AAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5E
rkJggg==

Data URIs

Base64 is used to embed images directly in HTML or CSS. This allows small icons and inline images to be displayed without additional HTTP requests, reducing the total request count.

<!-- Embedding a small icon as a Data URI -->
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUh..." alt="Icon">
/* Background image embedding in CSS */
.icon {
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0i...");
}

However, Data URIs have several caveats:

  • Base64 encoding increases data size by approximately 33%
  • Browser caching doesn't apply (since it's part of the HTML file)
  • Not suitable for large images (best limited to a few KB or less)

JWT (JSON Web Token)

JWTs, widely used as authentication tokens, use Base64URL encoding (discussed below). A JWT consists of three parts joined by dots (.).

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlRhbmFrYSJ9.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

The contents of each part:

Part Content Decoded Example
Header Algorithm info {"alg": "HS256", "typ": "JWT"}
Payload User data, etc. {"sub": "1234567890", "name": "Tanaka"}
Signature Tamper detection (binary data)

Binary Data in API Responses

Base64 encoding is also used to include binary data (images, files, etc.) in JSON API responses.

{
  "fileName": "report.pdf",
  "mimeType": "application/pdf",
  "content": "JVBERi0xLjQKMSAwIG9iago8PA..."
}

Base64 in Modern Web Development

Beyond its classic use cases, Base64 appears throughout contemporary JavaScript APIs and browser features. Understanding how and where it shows up helps you write more robust web applications.

Fetch API and Binary Responses

When you retrieve binary data via the Fetch API, you often need to convert it to Base64 before storing in JSON or passing to an API that only accepts text.

// Download an image and convert to Base64
async function fetchImageAsBase64(url) {
  const response = await fetch(url);
  const blob = await response.blob();

  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve(reader.result); // "data:image/png;base64,..."
    reader.onerror = reject;
    reader.readAsDataURL(blob);
  });
}

// Alternative approach using arrayBuffer
async function fetchAsBase64(url) {
  const response = await fetch(url);
  const buffer = await response.arrayBuffer();
  const bytes = new Uint8Array(buffer);
  const binary = bytes.reduce((acc, byte) => acc + String.fromCharCode(byte), '');
  return btoa(binary);
}

FormData and File Uploads

When you need to include file contents alongside JSON metadata in a single request, Base64 in JSON is one option:

// Reading a file from an <input type="file"> as Base64
function fileToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      // reader.result is "data:image/png;base64,ABC123..."
      const base64 = reader.result.split(',')[1]; // Strip the data URI prefix
      resolve(base64);
    };
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

// Sending as JSON
async function uploadFile(file) {
  const base64Content = await fileToBase64(file);
  await fetch('/api/upload', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      filename: file.name,
      mimeType: file.type,
      content: base64Content,
    }),
  });
}

Note: For large files, multipart/form-data uploads are more efficient. Base64 is best suited for files under a few hundred kilobytes.

WebSocket Binary Messaging

WebSocket supports binary frames natively, but sometimes a text-based protocol is easier to work with — particularly when your backend expects JSON messages or when you need to log/inspect messages easily.

const ws = new WebSocket('wss://example.com/socket');

// Sending binary data as Base64 over a text WebSocket
function sendBinaryData(data) {
  const bytes = new Uint8Array(data);
  const binary = bytes.reduce((acc, b) => acc + String.fromCharCode(b), '');
  ws.send(JSON.stringify({ type: 'binary', payload: btoa(binary) }));
}

// Receiving
ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  if (msg.type === 'binary') {
    const binary = atob(msg.payload);
    const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
    // process bytes...
  }
};

Canvas and Image Manipulation

The Canvas API uses Base64 extensively when exporting images:

const canvas = document.getElementById('myCanvas');

// Export canvas as Base64 PNG
const pngBase64 = canvas.toDataURL('image/png');        // "data:image/png;base64,..."
const jpegBase64 = canvas.toDataURL('image/jpeg', 0.9); // 90% quality JPEG

// Strip prefix for storage/transmission
const base64Only = pngBase64.replace(/^data:image\/png;base64,/, '');

// Restore image from Base64
const img = new Image();
img.src = 'data:image/png;base64,' + base64Only;

Web Crypto API

The Web Crypto API operates on ArrayBuffers, so converting between Base64 and binary is a common bridge:

// Convert Base64 key to CryptoKey for AES decryption
async function importAesKey(base64Key) {
  const binary = atob(base64Key);
  const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
  return crypto.subtle.importKey('raw', bytes, { name: 'AES-GCM' }, false, ['decrypt']);
}

// Export CryptoKey back to Base64
async function exportKeyAsBase64(cryptoKey) {
  const buffer = await crypto.subtle.exportKey('raw', cryptoKey);
  const bytes = new Uint8Array(buffer);
  return btoa(bytes.reduce((acc, b) => acc + String.fromCharCode(b), ''));
}

Base64 Encoding in Different Languages

Here's how to perform Base64 encoding and decoding in six major languages.

JavaScript (Browser / Node.js)

// Browser environment (btoa/atob handle strings, not arbitrary binary)
const encoded = btoa("Hello, World!");        // "SGVsbG8sIFdvcmxkIQ=="
const decoded = atob("SGVsbG8sIFdvcmxkIQ=="); // "Hello, World!"

// For non-ASCII strings in the browser, encode to UTF-8 first
const encodeUnicode = (str) => btoa(
  encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
    (_, p1) => String.fromCharCode(parseInt(p1, 16)))
);

// Node.js (handles arbitrary binary cleanly)
const buf = Buffer.from("Hello, World!", "utf-8");
const encoded = buf.toString("base64");
const decoded = Buffer.from(encoded, "base64").toString("utf-8");

// Base64URL (URL-safe) in Node.js
const base64url = buf.toString("base64url");

Python

import base64

# Basic encode/decode
encoded = base64.b64encode(b"Hello, World!").decode("utf-8")
# "SGVsbG8sIFdvcmxkIQ=="
decoded = base64.b64decode(encoded).decode("utf-8")
# "Hello, World!"

# URL-safe variant
url_safe = base64.urlsafe_b64encode(b"Hello+World/Test").decode("utf-8")
# "SGVsbG8rV29ybGQvVGVzdA=="  (+ and / replaced with - and _)

# Encoding a file
with open("image.png", "rb") as f:
    file_b64 = base64.b64encode(f.read()).decode("utf-8")

Go

package main

import (
    "encoding/base64"
    "fmt"
)

func main() {
    // Standard Base64
    encoded := base64.StdEncoding.EncodeToString([]byte("Hello, World!"))
    fmt.Println(encoded) // "SGVsbG8sIFdvcmxkIQ=="

    decoded, err := base64.StdEncoding.DecodeString(encoded)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(decoded)) // "Hello, World!"

    // URL-safe Base64 (no padding)
    urlEncoded := base64.RawURLEncoding.EncodeToString([]byte("Hello, World!"))
    fmt.Println(urlEncoded) // "SGVsbG8sIFdvcmxkIQ"
}

Java

import java.util.Base64;
import java.nio.charset.StandardCharsets;

// Java 8+ built-in Base64 support
byte[] input = "Hello, World!".getBytes(StandardCharsets.UTF_8);

// Standard encoder
String encoded = Base64.getEncoder().encodeToString(input);
// "SGVsbG8sIFdvcmxkIQ=="

byte[] decoded = Base64.getDecoder().decode(encoded);
String original = new String(decoded, StandardCharsets.UTF_8);
// "Hello, World!"

// URL-safe encoder
String urlEncoded = Base64.getUrlEncoder().encodeToString(input);

// Without padding
String noPadding = Base64.getEncoder().withoutPadding().encodeToString(input);

PHP

<?php
// Standard Base64
$encoded = base64_encode("Hello, World!");
// "SGVsbG8sIFdvcmxkIQ=="

$decoded = base64_decode($encoded);
// "Hello, World!"

// URL-safe Base64 (PHP doesn't have a built-in urlsafe function)
function base64url_encode(string $data): string {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

function base64url_decode(string $data): string {
    return base64_decode(strtr($data, '-_', '+/'));
}

$urlSafe = base64url_encode("Hello+World/Test");

Ruby

require 'base64'

# Standard Base64
encoded = Base64.strict_encode64("Hello, World!")
# "SGVsbG8sIFdvcmxkIQ=="

decoded = Base64.strict_decode64(encoded)
# "Hello, World!"

# URL-safe Base64
url_encoded = Base64.urlsafe_encode64("Hello, World!")
# "SGVsbG8sIFdvcmxkIQ=="

# Encode with line breaks (MIME style) — adds newline every 60 chars
mime_encoded = Base64.encode64("Hello, World!")
# "SGVsbG8sIFdvcmxkIQ==\n"

Base64 Variants

Beyond standard Base64, there are variants for specific use cases.

Base64URL

A variant designed for use in URLs and filenames, replacing + with - and / with _. Used in JWTs and URL parameters. The padding = may also be omitted.

Standard Base64 Base64URL
+ -
/ _
= (padding) May be omitted

MIME Base64

A variant for email transmission that inserts line breaks (CRLF) every 76 characters.

Base64 vs Other Encoding Schemes

Base64 is not the only way to represent binary data as text. Choosing the right scheme depends on your use case.

Comparison Table

Scheme Output charset Size overhead Typical use
Base64 A-Z, a-z, 0-9, +, / ~33% Email, Data URIs, JWT
Base64URL A-Z, a-z, 0-9, -, _ ~33% URL params, JWT, OAuth
Hex (Base16) 0-9, a-f 100% Checksums, crypto hashes, debugging
Percent encoding ASCII + %XX Variable URL query strings
ASCII85 (Base85) 85 printable chars ~25% PostScript, PDF internals

Hex Encoding

Hex (Base16) represents each byte as exactly two hexadecimal digits. The output is always twice the size of the input.

// Convert bytes to hex
const bytesToHex = (bytes) =>
  Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');

// Convert hex to bytes
const hexToBytes = (hex) =>
  new Uint8Array(hex.match(/.{2}/g).map(byte => parseInt(byte, 16)));

// SHA-256 output is commonly displayed as hex
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashHex = bytesToHex(new Uint8Array(hashBuffer));
// "a665a45920422f9d417e4867efdc4fb8..."

When to use hex: checksums (MD5, SHA hashes), cryptographic outputs, color values (#FF5733), MAC addresses, byte-level debugging. Hex is less compact than Base64 but far more readable to humans.

URL Percent Encoding

Percent encoding (also called URL encoding) replaces unsafe URL characters with %XX where XX is the hexadecimal byte value.

// Built-in browser/Node.js functions
encodeURIComponent("Hello World! ñ")
// "Hello%20World!%20%C3%B1"

decodeURIComponent("Hello%20World!")
// "Hello World!"

// Note: encodeURI vs encodeURIComponent
// encodeURI preserves URL structure characters (/, :, ?, etc.)
// encodeURIComponent encodes everything except A-Z a-z 0-9 - _ . ! ~ * ' ( )

When to use percent encoding: query string values, form submissions, embedding special characters in URLs. Do not use Base64 for URLs — use percent encoding or Base64URL.

Choosing the Right Encoding

Situation Use
Binary data in JSON or XML Base64
Image/font in HTML/CSS Base64 (Data URI)
Token in URL param Base64URL
Authentication header payload (JWT) Base64URL
Hash output display Hex
URL query string values Percent encoding
Large binary file transfer Neither — use multipart/form-data

Pros and Cons

Pros

  • Safely transmits binary data over text-based protocols
  • Composed entirely of ASCII characters, eliminating the risk of character encoding issues
  • Allows embedding binary data in text formats like JSON and XML
  • Encoding and decoding are fast and easy to implement
  • Universal support in every programming language and environment

Cons

  • Data size increases by approximately 33%
  • Incurs (minor) processing overhead for encoding and decoding
  • Inefficient for transferring large amounts of binary data
  • Not human-readable (you can't determine the content by looking at it)
  • btoa() in browsers doesn't handle multi-byte characters natively

Security Considerations

Let's address common misconceptions and security concerns about Base64.

Base64 Is Not Encryption

The most important point: Base64 is not encryption. Encoded data can be decoded by anyone. Simply Base64-encoding passwords, API keys, or other sensitive information does not constitute a security measure.

// This is NOT a security measure
const encoded = btoa("my-secret-password");
// "bXktc2VjcmV0LXBhc3N3b3Jk" → anyone can decode this

To protect sensitive information, use proper encryption algorithms like AES.

JWT Payloads Are Readable

The payload portion of a JWT is only Base64URL-encoded, not encrypted. This means anyone who obtains the token can read the payload contents. JWT signatures are for tamper detection, not for content confidentiality.

If you need to include sensitive data in a JWT, use JWE (JSON Web Encryption) to encrypt the payload.

Input Validation

When decoding Base64 data received from external sources, don't forget to validate the input. The Base64 string may be malformed, or the decoded data may contain unexpected content.

function safeBase64Decode(input) {
  // Validate Base64 string format
  if (!/^[A-Za-z0-9+/]*={0,2}$/.test(input)) {
    throw new Error("Invalid Base64 string");
  }
  try {
    return atob(input);
  } catch {
    throw new Error("Failed to decode Base64 string");
  }
}

Debugging Base64 Issues

Base64 problems are common and often subtle. Here are the most frequent issues and how to diagnose them.

Problem 1: "Invalid character" or decode failure

Symptom: atob() throws InvalidCharacterError, or a server returns a 400 error when you send Base64.

Cause: The string contains characters that are not valid Base64. Common culprits:

  • Newlines (\n) inserted by MIME Base64 or copy-pasted from terminal output
  • Spaces added during formatting
  • Using standard Base64 (+, /) where Base64URL (-, _) is expected, or vice versa

Fix:

// Strip all whitespace before decoding
const clean = base64String.replace(/\s/g, '');
const decoded = atob(clean);

// Convert between standard and URL-safe
const toUrlSafe = (b64) => b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
const toStandard = (b64url) => {
  let s = b64url.replace(/-/g, '+').replace(/_/g, '/');
  while (s.length % 4) s += '='; // Restore padding
  return s;
};

Problem 2: Garbled text after decoding (UTF-8 issues)

Symptom: Non-ASCII characters (Japanese, Arabic, emoji) decode to garbage.

Cause: btoa() only handles characters in the Latin-1 range (code points 0–255). Passing a string with characters above U+00FF throws an error in some environments and produces wrong output in others.

Fix:

// Encoding multi-byte strings correctly
function encodeToBase64(str) {
  const bytes = new TextEncoder().encode(str);
  const binary = bytes.reduce((acc, b) => acc + String.fromCharCode(b), '');
  return btoa(binary);
}

// Decoding back to multi-byte string
function decodeFromBase64(base64) {
  const binary = atob(base64);
  const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
  return new TextDecoder().decode(bytes);
}

Problem 3: Wrong padding

Symptom: Decode works sometimes but fails for certain inputs.

Cause: Base64 output length must be a multiple of 4. If padding = characters are stripped (common in Base64URL), standard decoders will fail.

Fix:

function addPadding(base64) {
  const pad = base64.length % 4;
  if (pad === 2) return base64 + '==';
  if (pad === 3) return base64 + '=';
  return base64;
}

Problem 4: Size unexpectedly large

Symptom: A 1 MB image becomes 1.37 MB after Base64 encoding.

Cause: This is expected — Base64 adds ~33% overhead. If you're storing or transmitting large binaries, consider alternatives.

Diagnostic checklist:

  • Is Base64 really necessary, or can you use binary transfer (multipart/form-data, binary WebSocket)?
  • Are you double-encoding? (e.g., encoding an already-encoded string)
  • Are you including the data:image/png;base64, prefix in size calculations?

Problem 5: btoa() not defined

Symptom: ReferenceError: btoa is not defined in Node.js.

Cause: btoa/atob are browser globals added to Node.js in v16 but unavailable in older versions.

Fix:

// Node.js (all versions)
const encoded = Buffer.from(input, 'utf-8').toString('base64');
const decoded = Buffer.from(encoded, 'base64').toString('utf-8');

// Or polyfill for older Node.js
if (typeof btoa === 'undefined') {
  global.btoa = (str) => Buffer.from(str, 'binary').toString('base64');
  global.atob = (b64) => Buffer.from(b64, 'base64').toString('binary');
}

Quick Diagnostic Checklist

Symptom Most likely cause First check
Decode throws error Invalid chars or wrong variant Strip whitespace, check +/- and //_
Garbled non-ASCII Not UTF-8 encoded before btoa Use TextEncoder
Padding error Missing = at end Add padding to make length % 4 === 0
btoa undefined Older Node.js Use Buffer
Output too large Expected behavior Consider binary transfer instead

Ready to try Base64 encoding yourself? Use our Base64 Converter tool to encode and decode strings instantly in your browser.

Frequently Asked Questions

Q: Is Base64 the same as encryption?

No. Base64 is an encoding scheme, not encryption. Anyone can decode Base64 data back to its original form without any key. If you need to protect data, use a proper encryption algorithm like AES-256. Base64 is for data representation, not data protection.

Q: Why does Base64 increase file size by 33%?

Every 3 bytes (24 bits) of input maps to 4 Base64 characters (each representing 6 bits). So 3 bytes becomes 4 bytes — a 33.3% increase. With padding, the overhead is always at most 33%. For most use cases this is acceptable, but for large binary files you should prefer binary transfer methods.

Q: What is the difference between Base64 and Base64URL?

Standard Base64 uses + and / as the 62nd and 63rd characters. These characters have special meaning in URLs (+ = space, / = path separator), so Base64URL replaces them with - and _. Base64URL also typically omits the padding =. Use Base64URL for JWTs, OAuth tokens, and anything that appears in a URL.

Q: Can I use Base64 to embed large images in HTML?

Technically yes, but it is not recommended for large images. Base64 increases image size by ~33%, and the encoded string is part of the HTML document, so it cannot be cached separately by the browser. Best practice is to use Base64 only for very small images (under ~2 KB) such as inline SVG icons or tiny UI sprites. Use <img src="url"> with proper caching headers for everything else.

Q: Why does btoa() throw an error with Japanese characters?

btoa() only accepts characters in the Latin-1 range (code points 0–255). Japanese characters have code points above 255, so you must encode the string to UTF-8 bytes first. Use TextEncoder to get the bytes, then convert to a binary string before calling btoa(). In Node.js, Buffer.from(str, 'utf-8').toString('base64') handles this correctly without any extra steps.

Q: How do I decode a JWT to read its payload?

A JWT payload is the second segment (between the two dots). It uses Base64URL encoding with no padding. To decode it in JavaScript:

function decodeJwtPayload(token) {
  const base64url = token.split('.')[1];
  // Convert Base64URL to standard Base64
  const base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');
  // Add padding
  const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, '=');
  return JSON.parse(atob(padded));
}

Remember: the payload is readable by anyone. Never store sensitive information in a JWT payload unless you are also using JWE encryption.

Q: Is Base64 still relevant in modern web development?

Absolutely. Base64 is used in JWTs (ubiquitous in API authentication), email attachments, inline images, the Canvas API, the Web Crypto API, WebSocket text messages, and dozens of other places. While HTTP/2 and binary WebSocket frames reduce some historical use cases, Base64 remains a fundamental tool for any developer working with web APIs and binary data.

Q: What is the fastest way to encode a large file to Base64 in Node.js?

Use the fs module with Buffer:

const fs = require('fs');
const encoded = fs.readFileSync('large-file.bin').toString('base64');

For streaming large files, use a transform stream to avoid loading the entire file into memory:

const { Transform } = require('stream');
const base64Stream = new Transform({
  transform(chunk, encoding, callback) {
    this.push(chunk.toString('base64'));
    callback();
  }
});
fs.createReadStream('large-file.bin').pipe(base64Stream).pipe(process.stdout);

Conclusion

Base64 is a simple yet practical encoding scheme for converting binary data to text form. It is used in many areas of web development, including email attachments, Data URIs, JWTs, API responses, and modern browser APIs like Canvas and Web Crypto. Understanding the approximately 33% size increase trade-off is key to using it appropriately. When choosing between Base64, hex, and percent encoding, match the scheme to your use case. And always remember: Base64 is not encryption — never use it as a substitute for proper security measures.