DEV Community

Trần Xuân Ái
Trần Xuân Ái

Posted on

How to Format WiFi QR Code Payloads Safely: A Complete Client-Side Sanitization Guide

Stop Pasting Your WiFi Passwords Into Sketchy Online Generators

It is Friday at 4:45 PM. Your operations team asks you to generate a dozen QR codes for a new guest network across three office floors. The network uses complex, auto-generated WPA2 keys with semicolons, backslashes, and colons.

What do most developers do? They search Google for "WiFi QR code generator," click the first link, and paste their plain text credentials into an unverified form field. In doing so, they send sensitive infrastructure credentials straight to a random backend database.

In this guide, we are going to look at how to format WiFi QR code payloads safely using entirely client-side logic. We will write a robust utility to escape problematic inputs, generate compliant raw payloads, and archive them safely without letting a single byte leave your local browser sandbox.


The Problem: The Deceptively Simple WiFi URI Scheme

At first glance, the schema for a WiFi QR code looks incredibly basic. It is a structured string starting with the protocol identifier WIFI: followed by key-value pairs separated by semicolons.

Here is what a vanilla payload looks like:

WIFI:S:MyAwesomeNetwork;T:WPA;P:SuperSecretPassword;H:false;;
Enter fullscreen mode Exit fullscreen mode

But what happens when your security policy dictates that passwords must contain special characters? Let us say your password is p@ss;word:\test.

If you naive-join this string, the parser (usually a mobile device camera app) reads the semicolon in p@ss; as the end of the password parameter. It then attempts to parse word:\test as the next configuration block. The connection fails, your users get frustrated, and you spend hours debugging why "the QR code doesn't work."

Moreover, many third-party generators do not handle escaping at all. They blindly dump your input into a templated string, resulting in broken payloads or, worse, credential leakage when their database gets indexed by search engines.


Why Existing Solutions Suck

If you inspect the network tab on popular QR code generators, you will see a familiar, depressing pattern. When you click "Generate," a POST request goes out to a server with your raw SSID and password. The server generates an image file using a library like qrcode or qrencode and sends back a PNG.

This architecture is fundamentally flawed for three reasons:

  1. Zero Privacy: Your corporate network credentials are sent over the wire and processed on external hardware.
  2. High Latency: Every edit requires a round-trip network request.
  3. Fragile Escaping: Backend scripts often run naive regex replacements that miss complex, nested escaping rules required by the ZXing barcode scanning library standard.

Sanitizing Raw Outputs in Client-Side QR Generation

To build a highly secure, offline-first generator, we must handle the raw string construction in the client's memory. The ZXing specification (the de facto standard for QR-based WiFi configuration) mandates that specific characters must be escaped using a single backslash (\).

These characters are:

  • Backslash (\)
  • Semicolon (;)
  • Colon (:)
  • Comma (,)
  • Double Quote (")

Let's visualize the transition from raw user input to a sanitized, raw string output:

Raw Password:   My\Password;Is:Cool
Step 1 (Escape \): My\\Password;Is:Cool
Step 2 (Escape ;): My\\Password\;Is:Cool
Step 3 (Escape :): My\\Password\;Is\:Cool
Final Payload:  WIFI:S:MySSID;T:WPA;P:My\\Password\;Is\:Cool;;
Enter fullscreen mode Exit fullscreen mode

If you skip Step 1, the parser treats the sequence \; as an invalid escape sequence or strips it entirely, breaking the payload structure. Let us dive into writing code that handles this flawlessly.


How to Format WiFi QR Code Payloads Safely

Let's construct a pure TypeScript module that handles payload validation, sanitization, and output formatting. This code runs 100% in-browser, maintaining complete user privacy.

export type WifiEncryption = 'WPA' | 'WEP' | 'nopass';

export interface WifiConfig {
  ssid: string;
  password?: string;
  encryption: WifiEncryption;
  hidden?: boolean;
}

/**
 * Escapes special characters for the ZXing WiFi QR payload standard.
 * Mandated characters: \, ;, :, , , "
 */
export function escapeWifiField(value: string): string {
  if (!value) return '';
  return value
    .replace(/\\/g, '\\\\') // Must escape backslash first
    .replace(/;/g, '\\;')
    .replace(/:/g, '\\:')
    .replace(/,/g, '\\,')
    .replace(/"/g, '\\"');
}

/**
 * Formats a WifiConfig object into a compliant, raw WiFi QR URI string.
 */
export function generateWifiPayload(config: WifiConfig): string {
  const {
    ssid,
    password = '',
    encryption = 'nopass',
    hidden = false
  } = config;

  if (!ssid.trim()) {
    throw new Error('SSID cannot be empty');
  }

  const escapedSsid = escapeWifiField(ssid);
  const escapedPassword = encryption !== 'nopass' ? escapeWifiField(password) : '';
  const isHidden = hidden ? 'true' : 'false';

  return `WIFI:S:${escapedSsid};T:${encryption};P:${escapedPassword};H:${isHidden};;`;
}
Enter fullscreen mode Exit fullscreen mode

Running Validations and Sanitization Live

Let us write a small test suite to prove that this sanitization functions perfectly even with the most complex inputs imaginable.

const complexConfig: WifiConfig = {
  ssid: "Home;Network:Active",
  password: "P@ss\\word;123",
  encryption: "WPA",
  hidden: true
};

const rawPayload = generateWifiPayload(complexConfig);
console.log(rawPayload);
// Output: WIFI:S:Home\;Network\:Active;T:WPA;P:P@ss\\\\word\;123;H:true;;
Enter fullscreen mode Exit fullscreen mode

Observe how \\\\ represents the escaped backslash in the generated payload, while \; handles the semicolon. Any compliant barcode reader will parse this string and reconstruct the original password exactly as intended.


Better Workflow: Archiving and Local Export

Once you have generated these payloads, you often need to save or share them with system administrators. Rather than saving them to a cloud database, we can export them as a structured, sanitized JSON file or dynamic local storage array.

This allows you to load configuration backups offline, re-generate QR codes instantly, or audit the raw outputs without sending data to an external API.

Here is how you can build a local export loop using browser-native APIs:

export function downloadPayloadArchive(configs: WifiConfig[]): void {
  const payloadData = configs.map(config => ({
    ...config,
    generatedPayload: generateWifiPayload(config),
    exportedAt: new Date().toISOString()
  }));

  const jsonString = JSON.stringify(payloadData, null, 2);
  const blob = new Blob([jsonString], { type: 'application/json' });
  const url = URL.createObjectURL(blob);

  const link = document.createElement('a');
  link.href = url;
  link.download = `wifi_payloads_${Date.now()}.json`;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  URL.revokeObjectURL(url);
}
Enter fullscreen mode Exit fullscreen mode

This simple workflow guarantees that your physical credentials remain entirely inside your local execution context.


Performance & Security Tradeoffs

When writing security-adjacent utilities, we must evaluate our design decisions.

Criteria Client-Side Generation Server-Side Generation
Data Privacy 100% Secure (No network calls) Vulnerable (Credentials sent over HTTP)
Performance < 1ms (Native JS execution) 100ms - 2000ms (Network dependent)
Offline Availability Works anywhere (PWA / Local asset) Requires active internet connection
Asset Management Local exports / Raw text copying Image hosting required

By generating the raw outputs locally, you completely eliminate the security risks of data interception, backend database breaches, and server downtime.


A Pragmatic Toolkit for Everyday Developers

I got tired of uploading sensitive configuration data, raw client JSON payloads, and encrypted JWT tokens to sketchy, ad-filled online tools that send those payloads to unknown backends. It felt like a massive security risk waiting to explode.

So, I built a suite of secure utilities that run 100% locally in your browser's sandbox. I published it at fullconvert.cloud — it is fast, free, and completely secure.

If you need to check raw outputs, escape parameters, or sanitize inputs, you can use utilities like the URL Encode / Decode Tool or verify configuration files with the JSON Formatter and Validator completely offline.


Final Thoughts on Generating Offline WiFi QR Configurations

Writing reliable tools does not mean you have to build complex cloud architectures. When handling sensitive payloads like local credentials, a clean, client-driven TypeScript utility is both the safest and most performant option.

By implementing proper escaping rules for semicolons, colons, and backslashes, you can easily ensure cross-platform compatibility without relying on external servers. Keep your pipelines local, keep your users secure, and stop pasting secrets into unverified text boxes.

Happy hacking! If you found this useful, let me know in the comments how your team manages local network provisioning configs.

Top comments (0)