Back to Feed
article 2m read

Scheduling app threw on a missing signing key, and the agent took three tries to make it explain itself

With no key to sign login tokens, my scheduling app just threw. The agent's three tries ended with a plain false and a notice on the login page, which is friendlier and also one forgotten check away from signing tokens with an empty key.

Article DepthPractice

Flow

Guards from lookup to hash

  1. 1Lookup

    Returns false when the key is absent or empty.

  2. 2Signer and checker

    Test for false before doing any hashing.

  3. 3Endpoint and login page

    Return a server error, set no cookie, and tell the owner where to set a key.

  4. 4Shared signing function

    Not built yet: throw when the key is missing or short, so a forgotten check is loud.

Crash was the staff scheduling app's one answer for a missing signing key.

That key signs the login tokens. The app looks for it in an environment variable, then in the config file, and an empty value counts as missing. When it found nothing, it threw an exception. The code that makes tokens and the code that checks them both asked for the key in the middle of their work, and neither handled the error. So a request that needed the key ended in a fatal error and probably a generic error page. Nothing got signed with a missing key, but nobody was told what to fix either.

Three branches in under an hour

The agent made three branches for this in under an hour, each bigger than the last. The first made the token checker say "not logged in" instead of crashing. The second did the same for the token maker, and made the sign-in endpoint return a server error with no cookie. The third stopped using an exception at all. Now the lookup returns false when there's no key, and the maker and checker test for that before doing any work. The login page checks for a key first and tells the person to set one. The README shows how to generate a random value.

All three branches also carried the same unrelated front-end edits. That's clutter in a change about secrets.

Where false turns into a key

An exception can't be ignored, but a false can. PHP will treat false as an empty string when a function wants text. So if any future code forgets to check, it signs tokens with an empty key, and anyone can make those. Login would look fine while being wide open.

The third version checks in the four places that use the key, and tests prove that making a token and checking a token both return false when the key is empty.

What's missing is a guard underneath all of them. The hashing step still accepts an empty key. If you're building something similar, put the check in one small signing function that throws when the key is missing or short:

if (strlen($key) < 32) throw new LogicException('no usable signing key');

Keep reading

Pick up a connected idea or branch into a nearby one.

5 paths forward