Guides

HS256 vs RS256: Which JWT Signing Algorithm?

Ingrid Solbergยทยท8 min read

I once spent a morning chasing a bug that turned out to be a philosophy problem. A partner team couldn't verify the tokens our service issued, so someone "fixed" it by emailing them our signing secret. It worked instantly โ€” and it also meant a second company could now mint tokens indistinguishable from ours. That's the moment HS256 versus RS256 stops being trivia and becomes a decision about who is allowed to forge your identity.

Both are algorithms that sign a JSON Web Token โ€” the signature is what makes a JWT tamper-evident. They do the same job. What they don't share is a trust model, and that's the whole comparison.

HS256: one shared key, whispered between two parties

HS256 is symmetric. Under the hood it's HMAC with SHA-256: you take the token's contents, mix in a secret key, and produce a signature. To verify, you take the same contents, mix in the same secret, and check the signatures match. One key does both jobs.

The catch is baked into that sentence: the verifier needs the same secret that signs. Whoever can check a token can also produce one. Inside a single backend that both hands out and accepts its own tokens, that's completely fine โ€” there's exactly one party, the secret never travels, and you get the simplest, fastest option there is. You can feel the shape of it in the HMAC Generator: give it a message and a key, and the signature falls out.

It's like a house key you copy for everyone who needs to get in. Perfect while "everyone" is you and your housemates. The problem starts the day you hand a copy to the neighbor so they can check whether the door is locked โ€” because now they can also open it.

RS256: a signature anyone can check but only you can write

RS256 is asymmetric. It uses a key pair: a private key that signs and a mathematically linked public key that only verifies. You keep the private key locked away on the issuing server. The public key you can publish to the entire world โ€” post it on a webpage if you like โ€” and anyone can use it to confirm a token is genuine, yet no one can use it to forge one.

That's the property my partner team actually needed. With RS256, we'd have sent them the public key, they'd verify every token perfectly, and they'd still be structurally incapable of issuing their own. The signature works like a handwritten signature on a contract: everyone recognizes it as yours, but only your hand produces it.

The real trade-off is trust, not speed

People frame this as a performance question โ€” and yes, HS256 is faster to sign and verify, because HMAC is cheap and RSA math is not. On a busy service that difference can matter. But it's rarely the deciding factor, because the number that dominates is how many parties verify your tokens.

  • One party issues and verifies? HS256. There's no key to distribute, so its one weakness never applies.
  • Many parties verify, one party issues? RS256. You give out a public key that can't sign, and you never risk a signing secret leaking across a boundary you don't control.

This maps almost perfectly onto architecture. A single monolith authenticating its own users leans HS256. A fleet of microservices, or a public API where external developers must validate tokens, or anything behind a hosted identity provider โ€” that's RS256 territory, which is why nearly every provider defaults to it.

The alg trap you must not skip

There's a security footgun that applies to both, and it has sunk real production systems. A JWT announces its own algorithm in the header โ€” {"alg":"RS256"}. Naive verification code reads that field and trusts it. Attackers noticed. Two classic attacks follow: setting alg to none to strip the signature entirely, or taking an RS256 system and submitting an HS256 token signed with the public key (which the server foolishly feeds to an HMAC check as if it were a secret).

The fix is one rule: decide server-side which algorithm you accept and reject everything else. Don't let the token pick. When you're debugging, decode a copy to inspect the header and payload with the JWT Decoder, pull the raw token cleanly out of an Authorization header with the Bearer Token Parser, and check its lifetime with the JWT Expiration Checker โ€” but do that inspection on a scratch copy, never by relaxing what your verifier enforces.

Which one, in one line

Use HS256 when a single trusted service both issues and verifies its tokens and the secret never leaves โ€” it's simpler and faster with no downside there. Use RS256 the instant a token has to be verified by anyone who shouldn't be able to create one, which covers most distributed and public-facing systems. And whichever you pick, pin the algorithm on the server. For where signing sits in the wider auth picture, see JWT vs session cookies and what a refresh token does.

Try the tools

Frequently Asked Questions

What's the difference between HS256 and RS256?

HS256 uses one shared secret for both signing and verifying (it's HMAC with SHA-256). RS256 uses a private key to sign and a matching public key to verify (RSA with SHA-256). The practical difference is who can create a valid token: with HS256, anyone who can verify can also sign; with RS256, only the private-key holder can sign.

Is RS256 more secure than HS256?

Neither is inherently weaker โ€” both are secure when used correctly. RS256 is safer for distributed systems because verifiers only receive the public key and can't forge tokens. HS256 is perfectly safe inside a single service that issues and verifies its own tokens and never shares the secret.

When should I use HS256?

When one trusted backend both issues and verifies the tokens, and the secret never leaves that boundary. It's simpler, faster to compute, and has no key-distribution problem because there's only ever one party holding the key.

When should I use RS256?

When multiple services, clients, or third parties need to verify tokens but must not be able to issue them โ€” microservices, public APIs, or any setup backed by an identity provider like Auth0, Okta, or Google that publishes its public keys.

Can I switch a JWT from HS256 to RS256 later?

Yes, but it's a key-management change: generate an RSA key pair, sign with the private key, and publish the public key (usually via a JWKS endpoint) to your verifiers. Tokens signed the old way stay valid until they expire, so you can roll over gradually rather than all at once.

IS

Ingrid Solberg writes for CodeUtilityKit, where the team builds free, privacy-first developer tools that run entirely in your browser. Every guide is written and reviewed by developers who use these tools daily.