<?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: Sazid Ahmed</title>
    <description>The latest articles on DEV Community by Sazid Ahmed (@sazid_ahmed_bappi).</description>
    <link>https://dev.to/sazid_ahmed_bappi</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3801487%2Fe5bfa417-adcd-4af0-8a09-6a4a8941bf18.jpg</url>
      <title>DEV Community: Sazid Ahmed</title>
      <link>https://dev.to/sazid_ahmed_bappi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sazid_ahmed_bappi"/>
    <language>en</language>
    <item>
      <title>I Built a Blockchain Voting System with RSA Encryption — Here's How It Works</title>
      <dc:creator>Sazid Ahmed</dc:creator>
      <pubDate>Fri, 06 Mar 2026 13:10:22 +0000</pubDate>
      <link>https://dev.to/sazid_ahmed_bappi/i-built-a-blockchain-voting-system-with-rsa-encryption-heres-how-it-works-51p9</link>
      <guid>https://dev.to/sazid_ahmed_bappi/i-built-a-blockchain-voting-system-with-rsa-encryption-heres-how-it-works-51p9</guid>
      <description>&lt;p&gt;Digital voting is one of those problems that sounds simple until you actually think about it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do you prove a vote was counted?&lt;/li&gt;
&lt;li&gt;How do you stop someone from voting twice?&lt;/li&gt;
&lt;li&gt;How do you make results auditable without exposing who voted for whom?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built a full-stack university voting system that answers all three — using cryptography as the enforcer, not just policy. Here's how it works under the hood.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Stack&lt;/strong&gt;&lt;br&gt;
Frontend      → React + Vite          (port 5173)&lt;br&gt;
Admin Panel   → React + Vite          (port 5174)&lt;br&gt;
Backend API   → Node.js + Express     (port 3000)&lt;br&gt;
Institution   → Node.js API           (port 4000)&lt;br&gt;
Blockchain    → 4-node custom network (ports 3001–3004)&lt;br&gt;
Database      → MySQL 8               (port 3306)&lt;br&gt;
DB UI         → phpMyAdmin            (port 8080)&lt;/p&gt;

&lt;p&gt;All containerized with Docker Compose. Spin it up with one command.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Core Problem: Why Not Just Use a Database?&lt;/strong&gt;&lt;br&gt;
A SQL database is mutable. An admin can &lt;em&gt;UPDATE votes SET candidate_id = 2 WHERE candidate_id = 1&lt;/em&gt; and nobody would know. Even with audit logs, those logs can be edited too.&lt;/p&gt;

&lt;p&gt;A blockchain is append-only and distributed. Every vote is a transaction. Every transaction is hashed and linked to the previous one. Tamper with one block, and every subsequent hash breaks — detectable by every other node in the network.&lt;/p&gt;

&lt;p&gt;That's the foundation. Now let's look at what happens when someone actually casts a vote.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Vote Casting Flow&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Page Loads — Keys Are Fetched Silently
When a voter navigates to the voting page, the app fetches their cryptographic keypair in the background. Once ready, the UI confirms:
✓ Cryptographic Keys Loaded
Your vote will be encrypted and digitally signed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This isn't just a status message. It's a hard gate — you can't submit without it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flai720409poqu6bsk9b3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flai720409poqu6bsk9b3.png" alt=" " width="800" height="1034"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The Voter Selects a Candidate&lt;br&gt;
Standard radio button UI. Clean, accessible. Nothing unusual here.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Submit — The Crypto Kicks In&lt;br&gt;
This is where it gets interesting. Before any network request is made, the frontend does three things:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 1 — Build the payload&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91t6rnan4xs8km9oss0h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91t6rnan4xs8km9oss0h.png" alt=" " width="490" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 2 — Encrypt it&lt;br&gt;
The payload is encrypted with the election's RSA public key using OAEP padding:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcnim1waavy8o10g05vjo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcnim1waavy8o10g05vjo.png" alt=" " width="460" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Only the election authority holds the matching private key. The server never sees the plaintext vote.&lt;/p&gt;

&lt;p&gt;Step 3 — Sign it&lt;/p&gt;

&lt;p&gt;The encrypted payload is signed with the voter's private key:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0j2xz75fdmaounutw8zc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0j2xz75fdmaounutw8zc.png" alt=" " width="477" height="133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This proves authenticity — the vote came from this voter — without linking the voter to their candidate choice.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Receipt
After the blockchain records the transaction, the voter gets a receipt:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtuvtouj976zpjmyt7io.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwtuvtouj976zpjmyt7io.png" alt=" " width="800" height="1247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F97mj4bkfiqikx28erakt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F97mj4bkfiqikx28erakt.png" alt=" " width="563" height="135"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The nullifier is the key innovation here. It's a cryptographic commitment derived from the voter's identity and the election ID — unique enough to detect double votes, but revealing nothing about the actual vote.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Double-Vote Prevention
Try to vote again in the same election:&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;You have already voted in this election.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj9nh85hqqjp1vtjvnwl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj9nh85hqqjp1vtjvnwl2.png" alt=" " width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two-layered enforcement:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On-chain — The nullifier is stored on the blockchain. If the same nullifier appears twice, the transaction is rejected at the consensus level.&lt;br&gt;
Application layer — The backend checks the nullifier in the database before even submitting to the chain.&lt;br&gt;
Neither layer alone is sufficient. Together they're airtight.&lt;/p&gt;

&lt;p&gt;The Blockchain Network&lt;br&gt;
Four nodes run in Docker containers. Each node:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintains a full copy of the chain&lt;/li&gt;
&lt;li&gt;Participates in block consensus&lt;/li&gt;
&lt;li&gt;Validates incoming transactions (vote receipts)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxbjkfz7ay5a31nlabjil.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxbjkfz7ay5a31nlabjil.png" alt=" " width="511" height="127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nodes discover each other via peer discovery on startup. A vote isn't confirmed until it's accepted by the network — no single node can fabricate or alter a result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Privacy by Design — Not by Policy&lt;/strong&gt;&lt;br&gt;
The system is designed so that it is architecturally impossible to correlate a voter's identity with their candidate choice — even by the developers.&lt;/p&gt;

&lt;p&gt;What's public           &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;That a vote was cast &lt;/li&gt;
&lt;li&gt;The transaction hash &lt;/li&gt;
&lt;li&gt;The nullifier
&lt;/li&gt;
&lt;li&gt;The final tally&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What's private&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Who the vote was for&lt;/li&gt;
&lt;li&gt;The plaintext vote payload&lt;/li&gt;
&lt;li&gt;The voter-candidate mapping&lt;/li&gt;
&lt;li&gt;Individual choices&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This separation isn't achieved through access controls or database permissions. It's enforced by the cryptography itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Running It Locally&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp90k0ddqeioegoah5wmk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp90k0ddqeioegoah5wmk.png" alt=" " width="453" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it. All 10 containers start automatically:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qt6z6i519zv6s91e0uc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qt6z6i519zv6s91e0uc.png" alt=" " width="464" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'd Do Differently&lt;/strong&gt;&lt;br&gt;
Zero-knowledge proofs instead of nullifiers. A nullifier is good. A ZK-SNARK is better — it lets you prove "I am eligible to vote and haven't voted yet" without revealing any identity information at all. It's significantly more complex to implement, but the privacy gain is substantial.&lt;/p&gt;

&lt;p&gt;On-chain tallying. Right now, tallying happens off-chain in the backend. A smart contract approach where tallying is computed on-chain would eliminate the last remaining trust assumption.&lt;/p&gt;

&lt;p&gt;Threshold decryption. Currently a single election authority holds the decryption key. Splitting that key across multiple authorities using Shamir's Secret Sharing would prevent any single party from decrypting votes prematurely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaway&lt;/strong&gt;&lt;br&gt;
The big lesson from this project: don't use access controls where you could use cryptography.&lt;/p&gt;

&lt;p&gt;Access controls say "you're not allowed to see this." Cryptography says "you literally cannot see this." One requires trust in the system operator. The other doesn't.&lt;/p&gt;

&lt;p&gt;In a voting system — where the entire point is that no one has to trust anyone — that difference is everything.&lt;/p&gt;

&lt;p&gt;Have questions about the architecture, the crypto primitives, or the blockchain consensus mechanism? Drop them in the comments — happy to dig in.&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>cryptography</category>
      <category>security</category>
      <category>docker</category>
    </item>
    <item>
      <title>Building the Registration and Login Flow for My Blockchain Voting System</title>
      <dc:creator>Sazid Ahmed</dc:creator>
      <pubDate>Tue, 03 Mar 2026 11:03:23 +0000</pubDate>
      <link>https://dev.to/sazid_ahmed_bappi/building-the-registration-and-login-flow-for-my-blockchain-voting-system-36e3</link>
      <guid>https://dev.to/sazid_ahmed_bappi/building-the-registration-and-login-flow-for-my-blockchain-voting-system-36e3</guid>
      <description>&lt;p&gt;When people hear about a blockchain voting app, they usually think about ballot encryption, digital signatures, vote verification, and blockchain integrity.&lt;/p&gt;

&lt;p&gt;Those parts matter, but before any of them can be trusted, the system has to solve a simpler problem first:&lt;/p&gt;

&lt;p&gt;How do we make sure only valid users can register and log in?&lt;/p&gt;

&lt;p&gt;For my university voting system, I designed the registration and login flow to start with institutional identity verification instead of a normal open signup form.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I Didn’t Use a Regular Signup Flow&lt;/strong&gt;&lt;br&gt;
In a standard web app, users usually enter a name, email, and password and create an account immediately.&lt;/p&gt;

&lt;p&gt;That approach is too weak for a voting system.&lt;/p&gt;

&lt;p&gt;I wanted registration to be tied to an institutional source of truth, so the process starts with a university-issued ID. The user cannot just type arbitrary profile data and create an account.&lt;/p&gt;

&lt;p&gt;Instead, the app verifies the ID against the institution members directory and loads the official record from there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Registration Flow&lt;/strong&gt;&lt;br&gt;
The registration process in my app has three steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Verify institution ID&lt;/strong&gt;&lt;br&gt;
The user enters their student, teacher, or staff ID.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmjfz2gyipl6t6f1zs4p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmjfz2gyipl6t6f1zs4p.png" alt=" " width="800" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The backend checks that ID against the institutional directory. If the record exists, the system loads the official member information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;full name&lt;/li&gt;
&lt;li&gt;institutional email&lt;/li&gt;
&lt;li&gt;role&lt;/li&gt;
&lt;li&gt;department&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means identity data comes from the directory, not from free-form user input.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkgvrzgpqwmq045em0i9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkgvrzgpqwmq045em0i9.png" alt=" " width="800" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Verify institutional email with OTP&lt;/strong&gt;&lt;br&gt;
After the ID is confirmed, the system sends a 6-digit OTP to the institutional email address linked to that member record.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3kwq81lzkwwmjd47r4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3kwq81lzkwwmjd47r4c.png" alt=" " width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The OTP flow includes a few controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;code expires after 10 minutes&lt;/li&gt;
&lt;li&gt;maximum 3 verification attempts&lt;/li&gt;
&lt;li&gt;60-second cooldown before requesting another code&lt;/li&gt;
&lt;li&gt;verified OTP is consumed after successful registration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This adds a second proof that the person registering is actually connected to the institutional identity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedzzxr24e4id8vw4fv4p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedzzxr24e4id8vw4fv4p.png" alt=" " width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Set password and create account&lt;/strong&gt;&lt;br&gt;
Once the OTP is verified, the user sets a password and completes registration.&lt;/p&gt;

&lt;p&gt;At that point, the backend creates the user account using the verified institutional data. The registration process also prepares the account for the secure voting flow by associating cryptographic key material with the user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7uy5oylw9hnob1lcn0dt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7uy5oylw9hnob1lcn0dt.png" alt=" " width="800" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So registration is doing more than account creation. It is also establishing identity and preparing the user for secure participation in the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How I Prevent Duplicate Registration&lt;/strong&gt;&lt;br&gt;
Preventing duplicate registration was a key part of this design.&lt;/p&gt;

&lt;p&gt;In a voting system, duplicate registration is not just a usability issue. It is a trust issue.&lt;/p&gt;

&lt;p&gt;I handled it in multiple layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the institution directory tracks whether a member is already registered&lt;/li&gt;
&lt;li&gt;the frontend can identify already-registered members early&lt;/li&gt;
&lt;li&gt;before sending OTP, the backend checks whether the institution ID already exists&lt;/li&gt;
&lt;li&gt;during final registration, the backend checks again by institution ID and email&lt;/li&gt;
&lt;li&gt;after successful registration, the member is marked as a registered voter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3kop5cju24ufnwb4dj6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs3kop5cju24ufnwb4dj6.png" alt=" " width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I prefer this layered approach because critical checks should not rely on only one screen or one database query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Login Flow&lt;/strong&gt;&lt;br&gt;
After registration does the heavy trust-building work, login stays simple.&lt;/p&gt;

&lt;p&gt;The user logs in with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;institution ID&lt;/li&gt;
&lt;li&gt;password&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqtk2mk0dq0vom0i7t7jw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqtk2mk0dq0vom0i7t7jw.png" alt=" " width="800" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The backend then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;checks whether the user exists&lt;/li&gt;
&lt;li&gt;verifies the password&lt;/li&gt;
&lt;li&gt;issues a JWT token&lt;/li&gt;
&lt;li&gt;returns the authenticated user profile&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That token is used to access protected features like elections and voting operations.&lt;/p&gt;

&lt;p&gt;I intentionally kept login straightforward because the identity validation has already happened during registration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why This Matters&lt;/strong&gt;&lt;br&gt;
One of the biggest lessons from building this part of the project is that secure systems depend heavily on their entry points.&lt;/p&gt;

&lt;p&gt;Blockchain and cryptography can protect voting operations, but they do not fix a weak registration process.&lt;/p&gt;

&lt;p&gt;If the wrong users can register, or if identity is not validated properly, the trust model starts with a flaw.&lt;/p&gt;

&lt;p&gt;That is why I spent time designing registration and login as part of the security architecture, not just the user onboarding flow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Closing&lt;/strong&gt;&lt;br&gt;
This registration and login design helped me connect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;institutional identity verification&lt;/li&gt;
&lt;li&gt;OTP-based email validation&lt;/li&gt;
&lt;li&gt;duplicate-registration prevention&lt;/li&gt;
&lt;li&gt;authenticated access with JWT.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For me, this became a reminder that in systems like digital voting, trust starts long before the first vote is cast.&lt;/p&gt;

&lt;p&gt;It starts at registration.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>blockchain</category>
      <category>security</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Building the Institution Members Module for My Blockchain Voting App</title>
      <dc:creator>Sazid Ahmed</dc:creator>
      <pubDate>Mon, 02 Mar 2026 10:49:39 +0000</pubDate>
      <link>https://dev.to/sazid_ahmed_bappi/building-the-institution-members-module-for-my-blockchain-voting-app-1jon</link>
      <guid>https://dev.to/sazid_ahmed_bappi/building-the-institution-members-module-for-my-blockchain-voting-app-1jon</guid>
      <description>&lt;p&gt;One of the less flashy but most important parts of my blockchain voting application is the Institution Members module.&lt;/p&gt;

&lt;p&gt;When people hear "blockchain voting system", they usually think about encrypted ballots, signatures, audit logs, and blockchain-based integrity. Those parts matter, but before any of that works, the system has to solve a more basic problem:&lt;/p&gt;

&lt;p&gt;How do we make sure only valid institution members can register?&lt;/p&gt;

&lt;p&gt;That question is why I built this module.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I Needed This Feature&lt;/strong&gt;&lt;br&gt;
A voting application cannot use a normal open signup flow.&lt;/p&gt;

&lt;p&gt;If anyone can register with arbitrary identity data, the trust model becomes weak from the start. In this project, I wanted registration to begin from a controlled institutional directory instead of trusting user-entered details.&lt;/p&gt;

&lt;p&gt;So I created an Institution Members feature that acts as the eligibility source for account creation.&lt;/p&gt;

&lt;p&gt;It stores records like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;institution ID&lt;/li&gt;
&lt;li&gt;full name&lt;/li&gt;
&lt;li&gt;institutional email&lt;/li&gt;
&lt;li&gt;role&lt;/li&gt;
&lt;li&gt;department&lt;/li&gt;
&lt;li&gt;year level&lt;/li&gt;
&lt;li&gt;voter registration status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means registration is tied to known institutional data rather than self-declared identity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9veyzrh0z3izuo8bo9vs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9veyzrh0z3izuo8bo9vs.png" alt=" " width="800" height="806"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How It Works in the Registration Flow&lt;/strong&gt;&lt;br&gt;
The module is directly connected to the registration process.&lt;/p&gt;

&lt;p&gt;The flow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A user enters their institution ID.&lt;/li&gt;
&lt;li&gt;The backend looks up that ID in the institution directory.&lt;/li&gt;
&lt;li&gt;If the record exists, the system loads the official member data.&lt;/li&gt;
&lt;li&gt;If the member is already registered, the process stops and the user is asked to log in.&lt;/li&gt;
&lt;li&gt;If the member is eligible, the system sends an OTP to the official institutional email.&lt;/li&gt;
&lt;li&gt;After OTP verification, the user sets a password and completes registration.&lt;/li&gt;
&lt;li&gt;The backend creates the voter account using the verified directory data.&lt;/li&gt;
&lt;li&gt;The member is marked as a registered voter in the directory.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This design avoids trusting identity fields typed manually by the user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why OTP Verification Matters&lt;/strong&gt;&lt;br&gt;
A valid institution ID alone should not be enough to register.&lt;/p&gt;

&lt;p&gt;Someone might know another person’s ID, so I added OTP verification to the institutional email address associated with that record. That gives the system a second proof that the registrant is actually linked to the institutional identity.&lt;/p&gt;

&lt;p&gt;It is a simple mechanism, but it makes the registration boundary much stronger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How I Prevent Duplicate Registration&lt;/strong&gt;&lt;br&gt;
Duplicate registration was one of the key problems I wanted to solve.&lt;/p&gt;

&lt;p&gt;In this module, I handle it in multiple layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the institution directory tracks whether a member is already registered using a voter status flag&lt;/li&gt;
&lt;li&gt;the frontend shows registered members as unavailable&lt;/li&gt;
&lt;li&gt;the backend checks whether the institution ID already exists before sending OTP&lt;/li&gt;
&lt;li&gt;the backend checks again during final registration using both institution ID and email&lt;/li&gt;
&lt;li&gt;the institution directory enforces unique institution IDs and emails&lt;/li&gt;
&lt;li&gt;after successful registration, the member is marked as a voter to block future attempts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I prefer this layered approach because registration integrity should not depend on a single UI check or one database lookup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Learned&lt;/strong&gt;&lt;br&gt;
This module reminded me that secure systems are often shaped by the parts that seem ordinary.&lt;/p&gt;

&lt;p&gt;A directory lookup, a status flag, an OTP check, and a uniqueness constraint may not sound as interesting as blockchain logic, but these controls define who is allowed into the system at all.&lt;/p&gt;

&lt;p&gt;And in a voting app, that matters a lot.&lt;/p&gt;

&lt;p&gt;For me, this was a useful reminder that trust starts before vote casting. It starts at registration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Closing&lt;/strong&gt;&lt;br&gt;
The Institution Members module became one of the core trust layers in my blockchain voting project. It helped me connect institutional eligibility, email verification, and duplicate prevention into a registration flow that is much harder to abuse.&lt;/p&gt;

&lt;p&gt;I’ll be sharing more modules from the system next, including how registration connects to the actual voting flow.&lt;/p&gt;

</description>
      <category>node</category>
      <category>blockchain</category>
      <category>cybersecurity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>University Voting System (Blockchain Based)</title>
      <dc:creator>Sazid Ahmed</dc:creator>
      <pubDate>Mon, 02 Mar 2026 10:36:21 +0000</pubDate>
      <link>https://dev.to/sazid_ahmed_bappi/university-voting-system-blockchain-based-1k8j</link>
      <guid>https://dev.to/sazid_ahmed_bappi/university-voting-system-blockchain-based-1k8j</guid>
      <description>&lt;p&gt;I’m excited to start sharing my project updates, beginning with the overall application I’ve been building: a blockchain-based voting system designed for secure, transparent, and privacy-focused digital elections.&lt;br&gt;
The application brings together multiple components into one complete ecosystem:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;a voter-facing frontend&lt;/li&gt;
&lt;li&gt;a backend API for election and user management&lt;/li&gt;
&lt;li&gt;a custom blockchain node for vote record integrity&lt;/li&gt;
&lt;li&gt;an admin panel for managing elections&lt;/li&gt;
&lt;li&gt;an institution API for identity-related workflows&lt;/li&gt;
&lt;li&gt;monitoring tools for system health and observability&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal of this project is not just to create an online voting app, but to build a system that addresses the bigger challenges of digital voting:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;voter authentication&lt;/li&gt;
&lt;li&gt;ballot privacy&lt;/li&gt;
&lt;li&gt;vote integrity&lt;/li&gt;
&lt;li&gt;double-vote prevention&lt;/li&gt;
&lt;li&gt;auditability&lt;/li&gt;
&lt;li&gt;verifiability&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So far, the application supports the core voting flow, including registration, login, election creation, vote casting, and result viewing. It also includes cryptographic protections, audit logging, Docker-based deployment, and monitoring support.&lt;/p&gt;

&lt;p&gt;What makes this project especially interesting to me is that it sits at the intersection of software engineering, cybersecurity, cryptography, and system design. It’s been a strong learning experience in building something that needs to be functional, secure, and trustworthy at the same time.&lt;br&gt;
Starting tomorrow, I’ll share the system module by module and explain the features and functionality of each part in more detail.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6xsi655invi0mfr72s0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6xsi655invi0mfr72s0.png" alt=" " width="800" height="796"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>blockchain</category>
      <category>security</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
