What Is the alg Field in a JWT Token

It's one small field sitting quietly in the JWT header. But get it wrong — or ignore it — and you've got a serious security problem on your hands.

When you decode the header of a JWT token, there are usually just two things in it:

{ "alg": "HS256", "typ": "JWT" }

Most beginners look at this and skip right past it. The typ part is obvious. The alg part looks like a technical detail that doesn't matter much.

It really does matter. More than you'd expect.

So What Does alg Actually Mean?

The alg field tells your server which algorithm was used to create the token's signature. When the server verifies the token, it uses that algorithm to check whether the signature is valid.

Think of it like a wax seal on an old letter. The seal proves the letter hasn't been opened or changed. The alg field tells you what kind of stamp was used to make that seal — so you know how to check it.

Without this information, your server wouldn't know how to verify the signature at all.

The Algorithms You'll Actually See

There are quite a few JWT algorithms out there, but in practice most apps use one of these:

Algorithm Full Name Key Type Best For
HS256 HMAC + SHA-256 Shared secret key Single server / most web apps
HS384 HMAC + SHA-384 Shared secret key Slightly stronger HMAC variant
HS512 HMAC + SHA-512 Shared secret key High-security HMAC variant
RS256 RSA + SHA-256 Public/private key pair Multiple services, microservices
ES256 ECDSA + SHA-256 Public/private key pair Modern apps, smaller key size

For most beginners building a regular web app with a single backend server, HS256 is the right starting point. It's simple, well-supported, fast, and secure when used with a strong secret key.

HS256 vs RS256 — What's the Real Difference?

This is the question most people hit next. Both are secure. But they work very differently.

HS256 uses a single shared secret key. The same key signs the token and verifies it. Simple. But it means every service that needs to verify tokens must have access to that secret key.

RS256 uses a key pair — a private key to sign and a public key to verify. The private key stays on your auth server. The public key can be shared freely with any service that needs to verify tokens.

If you have one server, use HS256. If you have multiple services that all need to verify tokens but shouldn't have your signing key, RS256 is the better fit.

Makes sense, right?

How to Set the Algorithm in Node.js

The jsonwebtoken library defaults to HS256 automatically. But you can be explicit about it, which is always a good idea:

const jwt = require('jsonwebtoken'); // HS256 — default, uses your secret key const token = jwt.sign( { userId: user.id }, process.env.JWT_SECRET, { algorithm: 'HS256', // explicit is better than implicit expiresIn: '15m' } ); // When verifying, specify which algorithm you expect jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'] // only accept HS256 — important! }, (err, decoded) => { if (err) return res.status(403).json({ error: 'Invalid token' }); req.user = decoded; next(); });

Notice the algorithms: ['HS256'] in the verify options. That array is there for a reason, and it's a really important one.

The alg: none Attack — This One Is Worth Knowing

There's a well-known attack that exploits the alg field directly. It's called the alg: none vulnerability and it's affected real libraries in the past.

Here's how it works. Some older or badly written JWT libraries trusted whatever algorithm the token itself claimed to use. An attacker could take a valid token, change "alg": "HS256" to "alg": "none" in the header, strip the signature entirely, and send it.

The vulnerable server would think: "alg is none, so there's nothing to verify." And it would just... accept the token. No signature check at all.

Completely forged tokens. Full access. No secret key needed.

// What an attacker would craft: { "alg": "none", // No algorithm = no signature check "typ": "JWT" } // Payload with whatever claims they want // No signature at all

Modern libraries like jsonwebtoken reject alg: none by default. But the safest practice is to explicitly tell your verifier which algorithm to accept — and never include none in that list.

// Safe - only accept HS256 jwt.verify(token, secret, { algorithms: ['HS256'] }); // Dangerous - never do this jwt.verify(token, secret, { algorithms: ['HS256', 'none'] });

That one line of defence closes the door completely.

There's Also an Algorithm Confusion Attack

There's a second attack worth knowing about, especially if you ever move from HS256 to RS256.

RS256 uses a public key to verify tokens. That public key is meant to be shared openly. But some vulnerable servers would accept a token signed with HS256 using the public key as the secret.

An attacker who knows your public key — which you shared openly — could use it as an HS256 secret to sign forged tokens. If your server doesn't lock down which algorithm it accepts, it might verify them successfully.

Again, the fix is the same. Always specify exactly which algorithm your server expects:

// If you use RS256, only accept RS256 jwt.verify(token, publicKey, { algorithms: ['RS256'] }); // Never leave algorithms open-ended or accept multiple // unless you have a very specific reason to

Two lines of code. Both attacks blocked.

Which Algorithm Should You Actually Use?

For most beginners and small to medium apps — HS256. It's fast, simple, well-tested, and perfectly secure with a strong key.

For microservices or systems where multiple services verify tokens but only one signs them — RS256 or ES256.

For anything requiring smaller token sizes and modern cryptography — ES256 is worth considering.

Don't overthink it. Pick HS256, set a strong secret, and move on. You can always change the algorithm later if your needs grow. And when you do change it, generate a fresh secret key to go with it.

I always generate mine at jwtsecretkeygenerator.com — a proper cryptographically random key that's long enough to make HS256 genuinely secure. The algorithm choice only matters if the key backing it is solid. A weak key with a strong algorithm is still a weak key.

One Small Field, Bigger Impact Than It Looks

The alg field is two lines in your JWT header. Most people never think about it. But it directly controls how your token signatures are verified — and ignoring it has caused real security breaches in real applications.

Set your algorithm explicitly. Lock down what your verifier accepts. Never allow none. Use a strong key.

That's all it takes to get this right.

💡 Three Rules for alg: Always set it explicitly when signing → Always specify algorithms: ['HS256'] (or whichever you use) when verifying → Never include 'none' in that list. Follow these three and the common alg-related attacks simply don't apply to your app.