<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: SAAZone Studio</title>
    <description>The latest articles on DEV Community by SAAZone Studio (@saazone_studio).</description>
    <link>https://dev.to/saazone_studio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4134068%2F904d8182-493f-4b08-b688-476d06e9dc2c.png</url>
      <title>DEV Community: SAAZone Studio</title>
      <link>https://dev.to/saazone_studio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/saazone_studio"/>
    <language>en</language>
    <item>
      <title>Why Reusing the Same Username Everywhere Is a Privacy Risk</title>
      <dc:creator>SAAZone Studio</dc:creator>
      <pubDate>Tue, 22 Sep 2026 10:15:21 +0000</pubDate>
      <link>https://dev.to/saazone_studio/why-reusing-the-same-username-everywhere-is-a-privacy-risk-gbk</link>
      <guid>https://dev.to/saazone_studio/why-reusing-the-same-username-everywhere-is-a-privacy-risk-gbk</guid>
      <description>&lt;h1&gt;
  
  
  Why Reusing the Same Username Everywhere Is a Privacy Risk
&lt;/h1&gt;

&lt;p&gt;You've probably had the same username for years.&lt;/p&gt;

&lt;p&gt;Your gaming account.&lt;br&gt;
Your Reddit account.&lt;br&gt;
Your Steam profile.&lt;br&gt;
An old forum account you forgot existed.&lt;/p&gt;

&lt;p&gt;Same username everywhere.&lt;/p&gt;

&lt;p&gt;It's convenient. It's easy to remember.&lt;/p&gt;

&lt;p&gt;But there's a privacy problem with that convenience:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A unique username can become a link between your different online identities.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Someone doesn't necessarily need to hack anything to discover that two accounts belong to the same person.&lt;/p&gt;

&lt;p&gt;Sometimes, they just need to search for the same username.&lt;/p&gt;
&lt;h2&gt;
  
  
  The account-linking problem
&lt;/h2&gt;

&lt;p&gt;Imagine you use &lt;code&gt;silentfox&lt;/code&gt; everywhere.&lt;/p&gt;

&lt;p&gt;Someone finds your old forum account.&lt;/p&gt;

&lt;p&gt;They search &lt;code&gt;silentfox&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;They find a gaming profile.&lt;/p&gt;

&lt;p&gt;Then a Reddit account.&lt;/p&gt;

&lt;p&gt;Then a GitHub profile.&lt;/p&gt;

&lt;p&gt;One account mentions a city.&lt;/p&gt;

&lt;p&gt;Another contains an old photo.&lt;/p&gt;

&lt;p&gt;Another lists a programming project.&lt;/p&gt;

&lt;p&gt;None of those pieces of information had to be secret individually.&lt;/p&gt;

&lt;p&gt;But once the accounts are linked together, they can reveal much more than each account revealed by itself.&lt;/p&gt;

&lt;p&gt;Researchers have studied exactly this problem: whether the same username can be used to identify and link a person across different online communities. Studies have found that username similarity or reuse can make cross-platform profile linking possible.&lt;/p&gt;

&lt;p&gt;That's the important distinction:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The username itself may not contain personal information, but its reuse can create a connection between pieces of personal information.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NIST makes a similar distinction in its digital identity guidance: a username can be personally identifiable information when it links back to a specific person, while an arbitrary or opaque identifier may not be.&lt;/p&gt;
&lt;h2&gt;
  
  
  It's not the same as getting hacked
&lt;/h2&gt;

&lt;p&gt;This is worth clarifying.&lt;/p&gt;

&lt;p&gt;If someone finds the same username on five websites, they haven't necessarily compromised any of your accounts.&lt;/p&gt;

&lt;p&gt;They may simply have discovered that the accounts are probably connected.&lt;/p&gt;

&lt;p&gt;That's a &lt;strong&gt;privacy and identity-correlation problem&lt;/strong&gt;, not automatically an account takeover.&lt;/p&gt;

&lt;p&gt;The distinction matters because there are actually two different risks people often mix together.&lt;/p&gt;
&lt;h3&gt;
  
  
  Username reuse
&lt;/h3&gt;

&lt;p&gt;The same username can make it easier to correlate profiles across websites.&lt;/p&gt;

&lt;p&gt;An attacker might use public information from multiple accounts to build a more complete picture of someone's online activity.&lt;/p&gt;
&lt;h3&gt;
  
  
  Credential reuse
&lt;/h3&gt;

&lt;p&gt;This is more directly related to account compromise.&lt;/p&gt;

&lt;p&gt;If you reuse the same username/email &lt;strong&gt;and password&lt;/strong&gt; across websites, a breach at one service can provide credentials that attackers may try elsewhere.&lt;/p&gt;

&lt;p&gt;This is known as &lt;strong&gt;credential stuffing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;OWASP specifically identifies reuse of usernames and passwords as a factor that can make credential-stuffing attacks effective.&lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Username reuse can hurt privacy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Password reuse can hurt account security.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using both together can create both problems at once.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why a username can reveal more than you think
&lt;/h2&gt;

&lt;p&gt;Let's say someone discovers your username on an old forum.&lt;/p&gt;

&lt;p&gt;The username itself might tell them almost nothing.&lt;/p&gt;

&lt;p&gt;But they search for that same username on other services.&lt;/p&gt;

&lt;p&gt;Now they find:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Forum
  ↓
Gaming profile
  ↓
Reddit account
  ↓
GitHub profile
  ↓
Personal website
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each profile contributes another piece of information.&lt;/p&gt;

&lt;p&gt;Maybe one has your interests.&lt;/p&gt;

&lt;p&gt;Another has your approximate location.&lt;/p&gt;

&lt;p&gt;Another has your programming projects.&lt;/p&gt;

&lt;p&gt;Another has a photo.&lt;/p&gt;

&lt;p&gt;Another contains an old post that mentions your school or workplace.&lt;/p&gt;

&lt;p&gt;The individual pieces may seem harmless.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;connection between them&lt;/strong&gt; is what creates the bigger privacy issue.&lt;/p&gt;

&lt;p&gt;This is why pseudonyms work best when they actually separate identities.&lt;/p&gt;

&lt;p&gt;A different username alone isn't a perfect privacy solution, of course. Writing style, profile photos, email addresses, links, usernames that are only slightly modified, and other clues can still connect accounts.&lt;/p&gt;

&lt;p&gt;But removing an obvious common identifier is one useful step.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;While working on EvoTechTool, I wanted to make a simple tool for exactly this use case.&lt;/p&gt;

&lt;p&gt;So I built a &lt;strong&gt;username generator&lt;/strong&gt; that creates new, memorable usernames without requiring a server.&lt;/p&gt;

&lt;p&gt;The core idea is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adjectives&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;silent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;swift&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;quiet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;brave&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nouns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;raven&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wolf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cedar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;adjectives&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;adjectives&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;noun&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nouns&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nouns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9999&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;adj-noun&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;adj&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;noun&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;adj-noun-num&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;adj&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;noun&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;adj&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;noun&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The actual implementation uses larger word lists, but the basic concept is the same.&lt;/p&gt;

&lt;p&gt;Instead of asking a server to generate a username, the browser selects words locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  The generator supports multiple patterns
&lt;/h2&gt;

&lt;p&gt;The tool currently supports patterns such as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Adjective + noun&lt;/strong&gt; → &lt;code&gt;silentfox&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adjective + noun + number&lt;/strong&gt; → &lt;code&gt;silentfox42&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verb + noun&lt;/strong&gt; → &lt;code&gt;chasefox&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verb + adjective + noun&lt;/strong&gt; → &lt;code&gt;chasequietfox&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Noun + noun&lt;/strong&gt; → &lt;code&gt;foxcedar&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adjective + adjective + noun&lt;/strong&gt; → &lt;code&gt;silentbravefox&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also customize things like separators and capitalization.&lt;/p&gt;

&lt;p&gt;The goal isn't to generate completely random strings like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x7Qp9L2mK8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are great for passwords.&lt;/p&gt;

&lt;p&gt;They're not particularly memorable as usernames.&lt;/p&gt;

&lt;p&gt;Instead, the generator combines words so the result is easier to recognize and remember while still giving you many possible combinations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why generate usernames locally?
&lt;/h2&gt;

&lt;p&gt;There's a privacy benefit to keeping the generation local.&lt;/p&gt;

&lt;p&gt;The generator doesn't need to send your generated usernames to a server.&lt;/p&gt;

&lt;p&gt;The browser can select the words, construct the username, and display the result entirely on the client.&lt;/p&gt;

&lt;p&gt;That means there's no username-generation database collecting the usernames you've generated.&lt;/p&gt;

&lt;p&gt;And you can verify the behavior yourself.&lt;/p&gt;

&lt;p&gt;Open DevTools.&lt;/p&gt;

&lt;p&gt;Go to the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;Generate a few usernames.&lt;/p&gt;

&lt;p&gt;The generation itself doesn't require a request to a username-generation API.&lt;/p&gt;

&lt;p&gt;That's the same design principle I used for the password generator: if a tool doesn't need a server to perform its core function, why add one?&lt;/p&gt;

&lt;h2&gt;
  
  
  But don't overdo anonymity
&lt;/h2&gt;

&lt;p&gt;There's an important balance here.&lt;/p&gt;

&lt;p&gt;I don't think everyone should have a completely different identity on every website.&lt;/p&gt;

&lt;p&gt;If you're building a professional identity, consistency can be useful.&lt;/p&gt;

&lt;p&gt;For example, you may deliberately want the same username on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub&lt;/li&gt;
&lt;li&gt;Your portfolio&lt;/li&gt;
&lt;li&gt;LinkedIn&lt;/li&gt;
&lt;li&gt;Your developer blog&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In that situation, being discoverable is part of the goal.&lt;/p&gt;

&lt;p&gt;The problem is using that &lt;strong&gt;same identity everywhere&lt;/strong&gt;, including places where you don't necessarily want your professional or personal profiles connected.&lt;/p&gt;

&lt;p&gt;That's where separating identities becomes useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple system for usernames
&lt;/h2&gt;

&lt;p&gt;You don't need 50 completely random identities.&lt;/p&gt;

&lt;p&gt;You can divide your online accounts into a few categories.&lt;/p&gt;

&lt;h3&gt;
  
  
  Public / professional
&lt;/h3&gt;

&lt;p&gt;Use a consistent username.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub&lt;/li&gt;
&lt;li&gt;Portfolio&lt;/li&gt;
&lt;li&gt;Developer communities&lt;/li&gt;
&lt;li&gt;Professional social accounts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal here is discoverability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Personal
&lt;/h3&gt;

&lt;p&gt;Use a separate identity.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Personal forums&lt;/li&gt;
&lt;li&gt;Gaming&lt;/li&gt;
&lt;li&gt;Hobby communities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to participate without automatically connecting everything to your professional identity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Temporary / low-trust
&lt;/h3&gt;

&lt;p&gt;Use another generated username.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forums you don't plan to use long-term&lt;/li&gt;
&lt;li&gt;Sites where you don't want your normal username exposed&lt;/li&gt;
&lt;li&gt;Temporary communities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is simply to avoid unnecessarily connecting the account to your other identities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't just change one character
&lt;/h2&gt;

&lt;p&gt;This is a surprisingly common mistake.&lt;/p&gt;

&lt;p&gt;If your normal username is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;silentfox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;changing it to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;silentfox2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;doesn't accomplish much.&lt;/p&gt;

&lt;p&gt;Neither does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;silent_fox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;silentfox123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If someone is specifically looking for connections between your accounts, obvious variations can be easy to associate.&lt;/p&gt;

&lt;p&gt;A genuinely different username creates a much stronger separation than changing a number at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  A username isn't a security credential
&lt;/h2&gt;

&lt;p&gt;There's another important distinction.&lt;/p&gt;

&lt;p&gt;A username generally isn't a secret.&lt;/p&gt;

&lt;p&gt;Your password is.&lt;/p&gt;

&lt;p&gt;So changing your username does &lt;strong&gt;not&lt;/strong&gt; replace basic account security.&lt;/p&gt;

&lt;p&gt;You should still:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a unique password for every account&lt;/li&gt;
&lt;li&gt;Use a password manager&lt;/li&gt;
&lt;li&gt;Enable MFA where available&lt;/li&gt;
&lt;li&gt;Consider passkeys when supported&lt;/li&gt;
&lt;li&gt;Avoid using personal information in usernames when privacy matters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NIST currently recommends measures such as MFA, passkeys, and password managers as important ways to protect online accounts.&lt;/p&gt;

&lt;p&gt;Username separation is about &lt;strong&gt;privacy and correlation&lt;/strong&gt;, not about replacing authentication security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;I built the username generator as part of &lt;strong&gt;EvoTechTool&lt;/strong&gt;, a collection of browser-based tools focused on being free, private, and requiring no signup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Username Generator:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://evotechtool.pages.dev/username-generator.html" rel="noopener noreferrer"&gt;https://evotechtool.pages.dev/username-generator.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything needed to generate the username runs in your browser.&lt;/p&gt;

&lt;p&gt;No account.&lt;/p&gt;

&lt;p&gt;No username-generation server.&lt;/p&gt;

&lt;p&gt;No database of the usernames you generate.&lt;/p&gt;

&lt;p&gt;The idea behind the tool is pretty simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sometimes the easiest way to protect the connection between two identities is not to create the connection in the first place.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're interested in online privacy, try searching one of your old usernames across the websites you used years ago.&lt;/p&gt;

&lt;p&gt;You might be surprised by how many pieces of your online history are still connected by the same name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you use the same username everywhere, or do you separate your online identities?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Built a Password Generator That Never Sends Your Password to a Server</title>
      <dc:creator>SAAZone Studio</dc:creator>
      <pubDate>Tue, 22 Sep 2026 09:36:03 +0000</pubDate>
      <link>https://dev.to/saazone_studio/i-built-a-password-generator-that-never-sends-your-password-to-a-server-1ag2</link>
      <guid>https://dev.to/saazone_studio/i-built-a-password-generator-that-never-sends-your-password-to-a-server-1ag2</guid>
      <description>&lt;p&gt;A password generator looks like a very simple tool.&lt;/p&gt;

&lt;p&gt;Choose a length.&lt;br&gt;
Select some character types.&lt;br&gt;
Click &lt;strong&gt;Generate&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Done.&lt;/p&gt;

&lt;p&gt;But while building my own password generator, I started thinking about a more important question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where does the password actually get generated?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If a password is generated on a server, the generated value has to reach that server and then be returned to your browser. TLS can protect the connection while the data is in transit, but the server itself still has access to the generated password.&lt;/p&gt;

&lt;p&gt;That creates an additional trust requirement.&lt;/p&gt;

&lt;p&gt;So when I built the password generator for &lt;strong&gt;EvoTechTool&lt;/strong&gt;, I decided not to have a server generate the password at all.&lt;/p&gt;

&lt;p&gt;The generation happens entirely inside the browser.&lt;/p&gt;

&lt;p&gt;No password-generation API.&lt;br&gt;
No backend request.&lt;br&gt;
No account required.&lt;/p&gt;

&lt;p&gt;And it can still generate passwords when you're offline.&lt;/p&gt;

&lt;p&gt;Here's how I built it.&lt;/p&gt;
&lt;h2&gt;
  
  
  First problem: &lt;code&gt;Math.random()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;JavaScript gives us &lt;code&gt;Math.random()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It's convenient, and it's perfectly useful for many things: animations, games, randomized UI elements, and other situations where cryptographic security isn't required.&lt;/p&gt;

&lt;p&gt;But password generation is different.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Math.random()&lt;/code&gt; is not designed to provide cryptographically secure random values.&lt;/p&gt;

&lt;p&gt;For security-sensitive randomness, browsers provide the Web Crypto API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MDN describes &lt;code&gt;crypto.getRandomValues()&lt;/code&gt; as providing cryptographically strong random values. The implementation uses a pseudorandom generator seeded with sufficient entropy rather than relying on a "truly random" process for every value.&lt;/p&gt;

&lt;p&gt;That's exactly the kind of randomness I wanted for this project.&lt;/p&gt;

&lt;p&gt;A simple example looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint32Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser fills the array with cryptographically strong random values.&lt;/p&gt;

&lt;p&gt;But there's another problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The modulo bias problem
&lt;/h2&gt;

&lt;p&gt;A straightforward implementation might do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;randomValue&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;charset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks perfectly reasonable.&lt;/p&gt;

&lt;p&gt;But there's a subtle statistical problem.&lt;/p&gt;

&lt;p&gt;If the number of possible random values isn't evenly divisible by the size of the character set, some characters can be selected slightly more often than others.&lt;/p&gt;

&lt;p&gt;That's called &lt;strong&gt;modulo bias&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The difference can be tiny, but when you're deliberately building a security-focused tool, I don't see much reason to introduce a bias when it can be avoided.&lt;/p&gt;

&lt;p&gt;So I used &lt;strong&gt;rejection sampling&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The basic idea is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate a cryptographically secure random value.&lt;/li&gt;
&lt;li&gt;Calculate the largest range that can be divided evenly by the character-set size.&lt;/li&gt;
&lt;li&gt;Reject values outside that range.&lt;/li&gt;
&lt;li&gt;Use modulo only on the remaining values.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;randomIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxUint32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x100000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxUint32&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint32Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the generated index is selected without the modulo bias.&lt;/p&gt;

&lt;p&gt;The performance difference is negligible for the small number of random values needed to generate a normal password.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual password generation
&lt;/h2&gt;

&lt;p&gt;With that in place, generating the password becomes fairly straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generatePassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;charset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;charset&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;charset&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part isn't the loop.&lt;/p&gt;

&lt;p&gt;It's where the randomness comes from.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the generator uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And instead of asking a server to generate the password, everything happens locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why client-side generation?
&lt;/h2&gt;

&lt;p&gt;There are a few reasons I prefer this architecture for a password generator.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. No password-generation request
&lt;/h3&gt;

&lt;p&gt;The browser doesn't need to send the generated password to an API.&lt;/p&gt;

&lt;p&gt;The password is created locally.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Less trust required
&lt;/h3&gt;

&lt;p&gt;A server-side generator means you have to trust the service handling the generated password.&lt;/p&gt;

&lt;p&gt;A local generator removes the password-generation server from the architecture entirely.&lt;/p&gt;

&lt;p&gt;That's not a guarantee that the entire website is magically secure — browsers, extensions, devices, malware, screenshots, clipboard access, and other parts of the environment still matter.&lt;/p&gt;

&lt;p&gt;But it does remove one unnecessary place where the generated password could be exposed.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. You can inspect it yourself
&lt;/h3&gt;

&lt;p&gt;This is something I really like about client-side tools.&lt;/p&gt;

&lt;p&gt;Open DevTools and go to the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;Generate a password.&lt;/p&gt;

&lt;p&gt;You can inspect what the page is doing instead of simply trusting a statement like "your password never leaves your browser."&lt;/p&gt;

&lt;p&gt;For a genuinely local implementation, generating a password doesn't require a request to a password-generation API.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I put into the tool
&lt;/h2&gt;

&lt;p&gt;The password generator in EvoTechTool currently supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Passwords up to 128 characters&lt;/li&gt;
&lt;li&gt;Uppercase letters&lt;/li&gt;
&lt;li&gt;Lowercase letters&lt;/li&gt;
&lt;li&gt;Numbers&lt;/li&gt;
&lt;li&gt;Symbols&lt;/li&gt;
&lt;li&gt;Excluding ambiguous characters such as &lt;code&gt;l&lt;/code&gt;, &lt;code&gt;I&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;O&lt;/code&gt;, and &lt;code&gt;0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Password strength information&lt;/li&gt;
&lt;li&gt;Entropy calculation&lt;/li&gt;
&lt;li&gt;Offline generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interface is intentionally simple.&lt;/p&gt;

&lt;p&gt;I didn't want the security-related part of the tool buried under unnecessary features.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about password strength?
&lt;/h2&gt;

&lt;p&gt;This part is interesting because a password can look complicated without actually being very random.&lt;/p&gt;

&lt;p&gt;For a uniformly random password, a simplified entropy calculation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;entropy = length × log₂(character_set_size)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, increasing the password length increases the possible number of combinations exponentially.&lt;/p&gt;

&lt;p&gt;But entropy calculations have an important limitation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They describe the randomness of the generation process, not a guarantee about how long a real attacker will take to crack the password.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The actual difficulty of cracking a password depends on things such as the attack model, hashing algorithm, rate limiting, hardware, and whether the password was actually generated uniformly.&lt;/p&gt;

&lt;p&gt;So I treat the crack-time figure in the tool as an estimate rather than a promise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Random passwords vs. human-created passwords
&lt;/h2&gt;

&lt;p&gt;This is also why I prefer generated passwords for accounts where I don't need to memorize the password.&lt;/p&gt;

&lt;p&gt;Humans are surprisingly predictable when creating passwords.&lt;/p&gt;

&lt;p&gt;We tend to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;familiar words&lt;/li&gt;
&lt;li&gt;names&lt;/li&gt;
&lt;li&gt;dates&lt;/li&gt;
&lt;li&gt;patterns&lt;/li&gt;
&lt;li&gt;substitutions like &lt;code&gt;@&lt;/code&gt; for &lt;code&gt;a&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;predictable capitalization&lt;/li&gt;
&lt;li&gt;repeated structures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A randomly generated password doesn't have those human patterns.&lt;/p&gt;

&lt;p&gt;NIST's current Digital Identity Guidelines allow passwords to be randomly assigned and emphasize the value of password managers and randomly generated unique passwords.&lt;/p&gt;

&lt;p&gt;NIST also notes that password managers can help users create unique, long, complex passwords for different accounts.&lt;/p&gt;

&lt;p&gt;So you don't need to memorize a different random password for every website.&lt;/p&gt;

&lt;p&gt;Let the password manager handle that part.&lt;/p&gt;

&lt;h2&gt;
  
  
  One important distinction
&lt;/h2&gt;

&lt;p&gt;There's a difference between &lt;strong&gt;password generation&lt;/strong&gt; and &lt;strong&gt;password storage&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article is about generating passwords.&lt;/p&gt;

&lt;p&gt;If you're building an application that stores users' passwords, that's a completely different problem.&lt;/p&gt;

&lt;p&gt;You should never store users' passwords as plaintext. Modern password-storage guidance recommends appropriate password hashing algorithms such as Argon2id, bcrypt, or PBKDF2 rather than reversible encryption or plaintext storage.&lt;/p&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generating a password securely and storing a password securely are two different engineering problems.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use a password generator properly
&lt;/h2&gt;

&lt;p&gt;If you're using a password generator, I'd follow a few simple rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Use a unique password for every account
&lt;/h3&gt;

&lt;p&gt;If one password is compromised, you don't want the same password protecting five other accounts.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Use a password manager
&lt;/h3&gt;

&lt;p&gt;You don't need to memorize dozens of random passwords.&lt;/p&gt;

&lt;p&gt;A password manager can generate and store unique credentials for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Check whether the generator is actually client-side
&lt;/h3&gt;

&lt;p&gt;Don't blindly trust a website's privacy claim.&lt;/p&gt;

&lt;p&gt;Open DevTools.&lt;/p&gt;

&lt;p&gt;Watch the Network tab.&lt;/p&gt;

&lt;p&gt;Generate a password and see what requests are made.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Don't paste sensitive passwords into random websites
&lt;/h3&gt;

&lt;p&gt;Even if a generator claims to be secure, think about the trust model before using it.&lt;/p&gt;

&lt;p&gt;For a client-side generator, the ideal architecture is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your Browser
     │
     ├── Generate random values
     │
     ├── Build password
     │
     └── Display password

     No password-generation server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the architecture I wanted for my own tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;I built the password generator as part of &lt;strong&gt;EvoTechTool&lt;/strong&gt;, a collection of small browser-based tools focused on being free, private, and requiring no signup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Password Generator:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://evotechtool.pages.dev/password-generator.html" rel="noopener noreferrer"&gt;https://evotechtool.pages.dev/password-generator.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project is built around a simple idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Free · Private · No Signup&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the password generator specifically, the goal is straightforward:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generate the password where it belongs — inside your browser.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're building a password generator yourself, I'd pay particular attention to two things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use a cryptographically secure random source such as &lt;code&gt;crypto.getRandomValues()&lt;/code&gt;, and consider whether the password actually needs to leave the browser.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The UI can always be improved later.&lt;/p&gt;

&lt;p&gt;The security model should come first.&lt;/p&gt;




&lt;p&gt;What do you think about client-side password generation?&lt;/p&gt;

&lt;p&gt;Do you prefer generating passwords entirely in the browser, or do you see situations where a server-side generator makes more sense?&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>webdev</category>
      <category>privacy</category>
    </item>
    <item>
      <title>I Built a Free WebRTC Leak Test (And Why Your VPN Might Be Lying to You)</title>
      <dc:creator>SAAZone Studio</dc:creator>
      <pubDate>Mon, 21 Sep 2026 18:48:36 +0000</pubDate>
      <link>https://dev.to/saazone_studio/i-built-a-free-webrtc-leak-test-and-why-your-vpn-might-be-lying-to-you-1g85</link>
      <guid>https://dev.to/saazone_studio/i-built-a-free-webrtc-leak-test-and-why-your-vpn-might-be-lying-to-you-1g85</guid>
      <description>&lt;p&gt;You pay $10 a month for a VPN. You think you're safe.&lt;/p&gt;

&lt;p&gt;But a single line of JavaScript on any website can still see your real IP address. It's called a WebRTC leak, and most VPN users don't even know it exists.&lt;/p&gt;

&lt;p&gt;I found out about this while building a privacy tool suite. I added a WebRTC test because I wanted to know if my own VPN was actually working.&lt;/p&gt;

&lt;p&gt;Spoiler: it wasn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is WebRTC?
&lt;/h2&gt;

&lt;p&gt;WebRTC (Web Real-Time Communication) is the browser technology that powers video calls, voice chat, and peer-to-peer file sharing. It's what makes Google Meet, Discord, and WhatsApp Web work without any plugins.&lt;/p&gt;

&lt;p&gt;To establish a direct connection between two browsers, WebRTC needs to know the network addresses on both ends. So it asks the browser for:&lt;/p&gt;

&lt;p&gt;Your local IP (like 192.168.1.5)&lt;/p&gt;

&lt;p&gt;Your public IP (the one your ISP assigned you)&lt;/p&gt;

&lt;p&gt;The second one is the problem. Even if you're behind a VPN, WebRTC can still fetch your real public IP through a separate channel. This is called a WebRTC leak.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Your VPN is supposed to hide your real IP. That's the whole point.&lt;/p&gt;

&lt;p&gt;If a website can detect your real IP through WebRTC, then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Advertisers can identify you across VPN sessions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Websites can geo-locate you to your real city&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Malicious actors can target your real network&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your VPN bill is basically wasted.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the test works
&lt;/h2&gt;

&lt;p&gt;The core API is RTCPeerConnection. Here's a simplified version:&lt;br&gt;
javascript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RTCPeerConnection&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;iceServers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stun:stun.l.google.com:19302&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onicecandidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ipRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;([&lt;/span&gt;&lt;span class="sr"&gt;0-9&lt;/span&gt;&lt;span class="se"&gt;]{1,3}(\.[&lt;/span&gt;&lt;span class="sr"&gt;0-9&lt;/span&gt;&lt;span class="se"&gt;]{1,3}){3})&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ipRegex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Detected IP:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDataChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createOffer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offer&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocalDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offer&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What this does:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Creates a new peer connection with a STUN server&lt;/li&gt;
&lt;li&gt;Registers a listener for ICE candidates (network paths the browser found)&lt;/li&gt;
&lt;li&gt;Each candidate contains an IP address — often the real one, not the VPN's&lt;/li&gt;
&lt;li&gt;We extract the IP with a regex and log it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The tool then compares that IP against the public IP your browser normally reports. If they're different, you have a leak.&lt;/p&gt;

&lt;h2&gt;
  
  
  The comparison logic
&lt;/h2&gt;

&lt;p&gt;Simple version:&lt;/p&gt;

&lt;p&gt;Public IP (from a normal API call): what your VPN shows the world&lt;/p&gt;

&lt;p&gt;WebRTC IP (from ICE candidate): what the browser actually knows about your network&lt;/p&gt;

&lt;p&gt;If they match → your VPN is working.&lt;br&gt;
If they differ → your real IP is leaking.&lt;/p&gt;

&lt;p&gt;You can also detect the local IP (192.168.x.x). That's less dangerous, but it reveals what router you're behind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built this client-side
&lt;/h2&gt;

&lt;p&gt;Most IP leak tests are free — until they aren't. They log your IP, sell the data, or ask you to create an account to see the full results.&lt;/p&gt;

&lt;p&gt;I wanted something different. So I built it into EvoTechTool, my free tool suite.&lt;/p&gt;

&lt;p&gt;The whole test runs in your browser. No backend, no logs, no server. The check happens on your device and the results stay there. You can verify this by opening your browser's DevTools and watching the network tab — nothing leaves your machine.&lt;/p&gt;

&lt;p&gt;You can try it here: &lt;a href="https://evotechtool.pages.dev/whats-my-ip.html" rel="noopener noreferrer"&gt;https://evotechtool.pages.dev/whats-my-ip.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Turn off your VPN, run the test, note your IP. Turn on your VPN, run it again. If the IP is the same, your VPN is leaking. If it's different, you're good.&lt;/p&gt;

&lt;h2&gt;
  
  
  What other leaks exist
&lt;/h2&gt;

&lt;p&gt;WebRTC is not the only one. Browsers leak through:&lt;/p&gt;

&lt;p&gt;DNS — requests may go through your ISP even with a VPN active&lt;/p&gt;

&lt;p&gt;IPv6 — if your VPN only tunnels IPv4, your real IPv6 address can still leak&lt;/p&gt;

&lt;p&gt;Browser fingerprinting — identifies you without needing an IP&lt;/p&gt;

&lt;p&gt;Time zone and language — two pieces of data that narrow your location significantly&lt;/p&gt;

&lt;p&gt;I check time zone and language in the tool too, because they're often what gives away your VPN.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bigger picture
&lt;/h2&gt;

&lt;p&gt;WebRTC is a good technology. Video calls without plugins are great. But the trade-off is that your browser knows more about your network than you might want it to share.&lt;/p&gt;

&lt;p&gt;Understanding that trade-off is the first step to fixing it.&lt;/p&gt;

&lt;p&gt;If you use a VPN for privacy, run the test. If it fails, switch to a VPN that handles WebRTC properly, or disable WebRTC in your browser settings.&lt;/p&gt;

&lt;p&gt;And if you're a developer building privacy tools — don't make your users sign up to see their own IP.&lt;/p&gt;

&lt;p&gt;What other browser APIs do you think developers use without understanding the privacy trade-offs?&lt;/p&gt;

&lt;p&gt;I built this as part of EvoTechTool, a free suite of browser-based tools (QR generator, password generator, IP checker, username generator) from SAAZone Studio in Dhaka, Bangladesh. Everything runs client-side. No signup, no tracking, no server.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>showdev</category>
      <category>privacy</category>
      <category>security</category>
    </item>
    <item>
      <title>How I Built a Fully Client-Side QR Code Generator (And Why I Avoided a Backend)</title>
      <dc:creator>SAAZone Studio</dc:creator>
      <pubDate>Sun, 20 Sep 2026 12:57:18 +0000</pubDate>
      <link>https://dev.to/saazone_studio/how-i-built-a-fully-client-side-qr-code-generator-and-why-i-avoided-a-backend-5a49</link>
      <guid>https://dev.to/saazone_studio/how-i-built-a-fully-client-side-qr-code-generator-and-why-i-avoided-a-backend-5a49</guid>
      <description>&lt;h2&gt;
  
  
  The Problem with Most QR Generators
&lt;/h2&gt;

&lt;p&gt;I was building a simple tool for my own use and needed to generate a QR code for a WiFi network. I tried the popular free tools, and they all did the same thing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; They routed the QR code through their own server.&lt;/li&gt;
&lt;li&gt; They set an expiry date (7 days, 30 days, etc.).&lt;/li&gt;
&lt;li&gt; They charged you to keep the QR code alive after that.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I was frustrated. A QR code is just a pattern of black and white squares that encodes a URL. &lt;strong&gt;Why does it need to expire?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's when I decided to build my own.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Goal: A Truly Private, Client-Side Tool
&lt;/h2&gt;

&lt;p&gt;My goal was simple: create a QR code generator where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The QR code points directly to the content (no redirect server).&lt;/li&gt;
&lt;li&gt;The tool runs entirely in the user's browser.&lt;/li&gt;
&lt;li&gt;There is no backend, no database, and no tracking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This meant the QR code would never expire. It would work forever, even if my site went offline.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tech Stack: Keeping It Simple
&lt;/h2&gt;

&lt;p&gt;I chose to build the tool with plain HTML, CSS, and JavaScript.&lt;/p&gt;

&lt;p&gt;I didn't need React, Next.js, or a server. The entire logic for generating the QR code could run in the browser. This kept the site incredibly fast, and it meant I could host it for free on Cloudflare Pages.&lt;/p&gt;

&lt;p&gt;The core of the tool uses a small JavaScript library to generate the QR code image, but everything else—the UI, the form logic, and the history feature—is built from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hardest Part: No Backend
&lt;/h2&gt;

&lt;p&gt;The biggest challenge was figuring out how to handle features without a server.&lt;/p&gt;

&lt;p&gt;For example, I wanted users to be able to see a history of the QR codes they had generated. But I didn't want to store that data on a server. The solution was to use the browser's &lt;code&gt;localStorage&lt;/code&gt; API. This means the history is saved locally on the user's device, and it's never sent anywhere. It's private by design.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Building this tool taught me a valuable lesson: &lt;strong&gt;you don't always need a complex framework or a backend.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For many simple tools, the browser is a powerful enough platform on its own. By removing the server, I also removed the need for user accounts, privacy policies about data storage, and a lot of complexity.&lt;/p&gt;

&lt;p&gt;It made me think about how many other tools could be built this way—fast, free, and private.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;The tool I built is called EvoTechTool. It's a free, client-side QR code generator with support for 11 types of content (URL, WiFi, vCard, etc.). Everything runs in your browser.&lt;/p&gt;

&lt;p&gt;You can check it out here: &lt;strong&gt;&lt;a href="https://evotechtool.pages.dev" rel="noopener noreferrer"&gt;https://evotechtool.pages.dev&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'd love to hear your thoughts on building serverless, client-side tools. Do you think this approach is the future for simple utilities?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>privacy</category>
    </item>
  </channel>
</rss>
