SeguridadHMACSesionesCriptografíaVerificación

Same text format doesn't mean the same signature

Published on 2026-08-31 · Xiliux

We had the same session written twice —one copy per application— and a shared library to stop duplicating it. The token looks identical in all three: id|version|expiry|signature, an HMAC-SHA256 over the payload.

The temptation was obvious: «same three-field format, the migration is transparent, live cookies keep working». We took it for granted.

Before touching anything we computed the signature of one payload with both implementations and compared it against the library's real fixed vector —a frozen token, pasted as a literal in the tests precisely for this—. They didn't match.

The cause wasn't the format. As it hardened, the library had started prepending the length of the signing domain to the HMAC message (a fix against a prefix ambiguity). With the empty domain of a normal session that already changes the message: one signature is HMAC(payload) and the other HMAC([8 zero bytes]‖payload). Same text, different signature.

Consequence: migrating to the shared library logs every user out on deploy. It's not a bug —the library is stricter, not weaker— but it's a real disruption you decide and announce, not one you discover in production.

The method lesson: a round-trip test —issue and verify with the same binary— measures the codec against itself. It stays green even if you change the separator, the field order or the base64 engine… and it would log everyone out without a single red test. The only thing that discriminates is a fixed vector: a real frozen token, verified by today's binary. If it goes red, what was stored stopped being readable —and that gets decided, not regenerated—.

The rule we kept: signature compatibility isn't read off the format. You measure it against a frozen artifact before claiming «compatible with what's already issued».

FAQ

Why isn't a test that issues and verifies the token enough?

Because it measures the codec against itself: issuing and verifying with the same binary stays consistent even if you change the format, and it would log everyone out without going red. You need a fixed vector —a real frozen token— that only the correct format verifies.

What is a «domain length prefix»?

When signing inside a domain (to separate, say, a session from an intermediate 2FA token) the domain's length is prepended to the HMAC message. Without it, domain‖payload is ambiguous and two different pairs produce the same signature; with it, the encoding is injective.

Can you migrate without logging anyone out?

Yes, with a dual-verification window: accept both signatures, issue with the new one, and drop the old one after the maximum session lifetime. We chose the single logout because it's simpler and leaves no transitional code someone has to dismantle later.

← More articlesRequest a quote