When working on web projects, we frequently use JSON Web Tokens (JWT) to encrypt user information into a single Base64 string payload. JWT provides a straightforward method to store user data in a single string, aiding the server in validating their information. However, while JWT includes a secret key, storing sensitive data such as passwords or secret codes can be a significant mistake.
JWT is simply an encoded base64 string that can be easily decoded using tools like jwt.io. While both JWT and JWE tokens cannot prevent hacking, JWT tokens allow attackers to view the data in case of a breach, whereas JWE tokens make this virtually impossible.
To keep user data safe in the browser, how you handle tokens really matters. Follow these best practices:
Use short-lived tokens
Tokens should expire quickly. Even if someone gets access to a token, it becomes useless after a short time.
Always validate the audience
Ensure the token is meant for your application only, not for any other service.
Verify the issuer
Accept tokens only from trusted sources that you control.
Use HTTPS everywhere
HTTPS prevents attackers from intercepting tokens during network requests.
Store tokens securely
Avoid localStorage. Prefer HTTP-only, secure cookies to reduce XSS risks.
Purpose of secret key in JWT
Many developers assume that the JWT secret key encrypts the token, making it fully secure — but that’s a common misunderstanding.
In reality, the SECRET_KEY in JWT is used only for signing, not encryption. When a JWT is created, it is signed using the secret key. On every request, the server verifies this signature to ensure:
The token was issued by a trusted server (your VPS)
The token data has not been modified
For example, if someone tries to change role: user to role: admin, the token verification will fail because the attacker doesn’t have your secret key.
However, JWT data is still readable by anyone who gets access to the token. This becomes risky when JWTs are stored in browser localStorage. If your site is vulnerable to XSS (Cross-Site Scripting), an attacker can inject malicious code and steal the JWT.
Once stolen, the attacker can impersonate the user until the token expires, gaining access to protected resources.
Because of these risks, JWT is often considered unsafe for storing sensitive information, especially on the client side.
To add an extra layer of security, you can use JWE (JSON Web Encryption). JWE encrypts the token payload, ensuring that even if the token is stolen, the data inside remains unreadable.
Let’s see how JWE improves token security and how it works.

Json Web Encryption.
What is JSON Web Encryption?
JWE is a way to encrypt data so only the intended receiver can read it. It’s a IEFT (Internet Engineering Task Force) standard for representing encrypted content using JSON. It is use to protects sensitive information (like user data or certain ids) by encrypting the payload, not just signing it(like JWT does).
How JWE encryption works
When JWE is used, Auth0 first creates a JWT access token containing claims and signs it using JWS to ensure integrity. This signed token is then encrypted using JWE and serialized in JWE Compact format.
As a result:
JWS ensures the token is not tampered with
JWE keeps the token’s data confidential
This combination provides both security and privacy for access token claims.
Sender creates the data (payload) like username, id, email, role etc. Then on server this payload is encrypted (not just signed) using your private key. Only the receiver has the key to decrypt it.

How to use JWE in Nodes.
There are two ways to use JWE. First one using NPM package and another one is JWE flow using crypto.
Here I will show you implementation of JWE using NPM package called "jose" or "node-jose". It has more than 20M downloads and is trusted and widely used. Manual implementation is not recommended as you will have to create all the things manually like private key generation, building logic for encryption, prepare JWE structure and more. for learning purposes you can do this but for production you must use trusted package.
Implementing - JWE in Node.js.
Install NPM package - jose
npm install joseCreate & Encrypt a JWE (server side)
import { SignJWT, EncryptJWT } from 'jose';
// secrets / keys
const SIGN_SECRET = new TextEncoder().encode('signing-secret');
const ENC_SECRET = new TextEncoder().encode('encryption-secret');
// create JWE
export async function generateJWE(payload: any) {
// 1. Sign (JWS)
const signedJWT = await new SignJWT(payload)
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('1h')
.sign(SIGN_SECRET);
// 2. Encrypt (JWE)
const encryptedJWT = await new EncryptJWT({ token: signedJWT })
.setProtectedHeader({ alg: 'dir', enc: 'A256GCM' })
.encrypt(ENC_SECRET);
return encryptedJWT;
}It will first signed token just like JWT and then will encrypt it to make it more confidential.
Now This generated JWE from your payload can be share will the client will full confidence. No one will decrypt this token without your private key. Make sure you have strong Secrete key as it will be use throughout the process or lifetime.
Now communication between server and client is more secure and no need to worried about cyber attacks like XSS(cross site scripting).
Decrypt & Verify JWE
import { jwtDecrypt, jwtVerify } from 'jose';
export async function decodeJWE(jwe: string) {
// 1. Decrypt
const { payload } = await jwtDecrypt(jwe, ENC_SECRET);
// 2. Verify signed JWT inside
const signedToken = payload.token as string;
const verified = await jwtVerify(
signedToken,
SIGN_SECRET
);
return verified.payload;
}Conclusion
JWE provides an extra layer of security compared to a standard JWT by encrypting the token’s data, not just signing it. This means that even if someone intercepts the token, they cannot read its contents without the correct decryption key.
However, encryption does not mean everything should be stored inside the token.
Even with JWE:
Never store passwords, OTPs, or raw secrets
Avoid highly sensitive personal data (Aadhaar, card numbers, etc.)
JWE doesn’t replace good security practices — it strengthens them. When used correctly, it significantly reduces the risk of data exposure compared to plain JWT.
Thanks for reading this article pls like and share with your friends. For more updates you can subscribe our newsletter.
LOADING...

