Fix a session token check written by hand
Your task
Your API checks a signed session token on every request. A first draft called jwt.decodeVerify, a method the library does not have, so the check is now written out by hand.
An assistant wrote authorize_token(token, expected_signature, now_epoch). It is in the editor. It has a bug. Find it and fix it.
Input and output:
token: claims joined by|, each writtenkey=value. For examplealg=HS256|sub=alice|exp=1700000100|sig=abc123==.expected_signature: the signature your server computes for this token with its own secret.now_epoch: the current time in epoch seconds (seconds since 1 January 1970).- Return
"ok:"followed by thesubvalue, or one of"reject:malformed","reject:alg","reject:signature"and"reject:expired".
Rules the tests check:
- Split the token on
|. Split each piece at its first=into a key and a value, so a value may contain=. - Keys and values are compared exactly: case matters and nothing is trimmed. Other keys, like
iss, are allowed and ignored. - The token is malformed if any of these holds:
- a piece has no
=or has an empty key (an empty token counts) - any key appears twice
alg,sub,exporsigis missingsubis emptyexpis not one or more digits from 0 to 9
- a piece has no
- Check in this order and return the first result that applies:
- The token is malformed:
"reject:malformed". algis not exactlyHS256:"reject:alg".sigis not exactly equal toexpected_signature:"reject:signature".expis less than or equal tonow_epoch:"reject:expired".
- The token is malformed:
- If none applies, return
"ok:"followed bysub.
Examples:
authorize_token("alg=HS256|sub=alice|exp=1700000100|sig=abc123==", "abc123==", 1700000000)returns"ok:alice".authorize_token("alg=HS256|sub=alice|exp=1700000100|sig=forged", "abc123==", 1700000000)returns"reject:signature".authorize_token("alg=none|sub=alice|exp=1700000100|sig=", "", 1700000000)returns"reject:alg". The empty signature matches, but the algorithm check comes first.
Then, in a sentence or two: how would you catch this kind of bug in review?
Examples
authorize_token(token: str, expected_signature: str, now_epoch: int) -> strExample 1
Input
authorize_token("alg=HS256|sub=alice|exp=1700000100|sig=abc123==", "abc123==", 1700000000)Output
"ok:alice"Example 2
Input
authorize_token("alg=HS256|sub=alice|exp=1700000100|sig=forged", "abc123==", 1700000000)Output
"reject:signature"Example 3
Input
authorize_token("alg=none|sub=alice|exp=1700000100|sig=", "", 1700000000)Output
"reject:alg"