Amblem
Furkan Baytekin

Using WebCrypto Safely: A Practical Guide for Developers

WebCrypto browser security guide

Using WebCrypto Safely: A Practical Guide for Developers
20
4 minutes

The WebCrypto API gives you fast, native cryptography right in the browser. It’s powerful, secure, and way better than rolling your own crypto in JavaScript — but only if you use it correctly. A small mistake can silently weaken your app.

Here’s a practical guide to using WebCrypto the right way.


WebCrypto Only Works on HTTPS (Seriously)

Let’s get the basics out of the way: WebCrypto runs only in secure contexts — HTTPS or localhost.

If your site is served over plain HTTP, the API is blocked. Browsers don’t want to expose crypto features in an environment where the page could be modified in transit.

So if someone tries to test WebCrypto on a raw http:// site and everything returns errors… yeah, that’s expected.


What WebCrypto Provides

You get access to native implementations of:

Everything runs in the browser’s crypto subsystem, making it faster and safer than typical JS libraries.


Common Pitfalls (and How to Avoid Them)

1. Use AES-GCM, not AES-CBC

CBC mode is fragile and easy to misuse. GCM gives you authenticated encryption, protecting both confidentiality and integrity.

2. Never reuse IVs in AES-GCM

GCM breaks if you reuse an IV with the same key. Generate a fresh 12-byte IV every time:

js
const iv = crypto.getRandomValues(new Uint8Array(12));

Store it alongside the ciphertext.

3. Generate non-extractable keys

If a key doesn’t need to leave the browser, generate it as non-extractable:

js
crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, false, [ "encrypt", "decrypt", ]);

This protects against accidental exposures through logs or XSS.

4. Don’t hash passwords directly

Never turn a password into a key using SHA-256. It’s weak and brute-forceable.

Use PBKDF2 instead:

js
const key = await crypto.subtle.deriveKey( { name: "PBKDF2", salt, iterations: 200_000, hash: "SHA-256", }, baseKey, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"] );

Practical Usage Patterns

Secure token generation

js
function generateToken(size = 32) { const buf = new Uint8Array(size); crypto.getRandomValues(buf); return btoa(String.fromCharCode(...buf)); }

Encrypting JSON properly

js
async function encryptJSON(key, obj) { const iv = crypto.getRandomValues(new Uint8Array(12)); const data = new TextEncoder().encode(JSON.stringify(obj)); const ciphertext = await crypto.subtle.encrypt( { name: "AES-GCM", iv }, key, data ); return { iv, ciphertext }; }

Signing data with HMAC

js
const key = await crypto.subtle.generateKey( { name: "HMAC", hash: "SHA-256" }, false, ["sign", "verify"] );

Use HMAC for tamper detection when you don’t need encryption.


Safe Storage Tips


When WebCrypto Isn’t the Right Tool

Avoid using it when:

Use WebCrypto when you want:


Final Thoughts

WebCrypto is the safest way to do cryptography in the browser. Stick to authenticated encryption, generate IVs properly, use key derivation instead of plain hashes, and always run under HTTPS.


Album of the blog:

Suggested Blog Posts