<?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>Forem: Kyrylo Sotnykov</title>
    <description>The latest articles on Forem by Kyrylo Sotnykov (@ksotnykov).</description>
    <link>https://forem.com/ksotnykov</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%2F3258866%2Fa4784277-d303-4ced-920e-75db2e731b0b.jpg</url>
      <title>Forem: Kyrylo Sotnykov</title>
      <link>https://forem.com/ksotnykov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ksotnykov"/>
    <language>en</language>
    <item>
      <title>Front-end Signing and Back-end Verification in JavaScript Applications</title>
      <dc:creator>Kyrylo Sotnykov</dc:creator>
      <pubDate>Tue, 17 Jun 2025 14:15:06 +0000</pubDate>
      <link>https://forem.com/ksotnykov/front-end-signing-and-back-end-verification-in-javascript-applications-32d7</link>
      <guid>https://forem.com/ksotnykov/front-end-signing-and-back-end-verification-in-javascript-applications-32d7</guid>
      <description>&lt;p&gt;We live in a time of offline apps, AI-generated content, and decentralized storage. In this world, guaranteeing data authenticity is no longer optional. Here’s how you can sign data on the front-end and verify on the back-end — simply and securely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Data Integrity Matters&lt;/strong&gt;&lt;br&gt;
Whether you’re syncing user-generated data, caching files locally, or fetching data from unstrusted APIs or IPFS — you’d like to have a way to tell if the data is still valid and unchanged.&lt;/p&gt;

&lt;p&gt;Some real-world use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Digitally signed documents or contracts&lt;/li&gt;
&lt;li&gt;Secure exports/imports between systems&lt;/li&gt;
&lt;li&gt;App configurations stored locally&lt;/li&gt;
&lt;li&gt;Offline apps that sync later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What We Want to Achieve&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The front-end signs the data with a private key (in-memory or user secret derived)&lt;/li&gt;
&lt;li&gt;The back-end verifies the signature with public key (safely stored in .env or config)&lt;/li&gt;
&lt;li&gt;Optionally, we validate the shape of the data with JSON Schema&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;How to do it in JS/TS?&lt;/strong&gt;&lt;br&gt;
You can use sign-proof — a lightweight Typescript library build on Ed25519 cryptography with JSON Schema support.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install sign-proof
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Storage &amp;amp; Generation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You need to generate Ed25519 key pair only once per user or session. This is how to handle keys securely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { generateKeyPair } from 'sign-proof';

const { publicKey, privateKey } = generateKeyPair();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Private key: This should be kept secret in the browser, for example by using encrypted localStorage or a session.&lt;/li&gt;
&lt;li&gt;Public key: Can be securely shared with back-end for signature verification&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Example: Make the key pair on first login or account registration in the browser and send the publicKey to the back-end to associate it with the user. Store the privateKey securely on the client (e.g. memory, IndexedDB, secure storage)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Front-end: Signing the Data&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { signData} from 'sign-proof';

const privateKey = '...'; // base64

// Example user input
const payload = { message: 'Hello world!', userId: 5 };

// Sign it
const proof = signData(payload, privateKey);

// Send to backend
const signed = { payload, proof};
fetch('/api/messages/send', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(signed),
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Back-end: Verifying the Data&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { verifyData} from 'sign-proof';

app.post('/api/message/send', (req, res) =&amp;gt; {
  const { payload, proof}: SignedData&amp;lt;any&amp;gt; = req.body;

  // Get public key from database
  const publicKey = database.getPublicKey(payload.userId);

  // Verify proof
  const isValid = verifyData({ payload, proof }, publicKey);

  if (!isValid) return res.status(400).send({ ok: false, reason: 'Invalid signature' });

  // Proceed with trusted data
  res.send({ ok: true });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why Ed25519?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lightweight, speedy elliptic-curve algorithm&lt;/li&gt;
&lt;li&gt;No heavy libraries or key infrastructure&lt;/li&gt;
&lt;li&gt;Extremely small footprint — front-end-friendly&lt;/li&gt;
&lt;li&gt;Used by Signal, WhatsApp, and blockchain systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;br&gt;
It this workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signing is performed on the front-end using the private key&lt;/li&gt;
&lt;li&gt;Verification is performed on the back-end using only the public key&lt;/li&gt;
&lt;li&gt;By separating the concerns between verify and sign, you have a secure, scalable, and tamper-proof data-validation process — across environments and devices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why Not Try It Yourself&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/sign-proof" rel="noopener noreferrer"&gt;NPM Package&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/KirillSotnikov/sign-proof" rel="noopener noreferrer"&gt;GitHub Repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give it a ⭐ if you find it helpful!&lt;/p&gt;

</description>
      <category>web3</category>
      <category>security</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
