My adventure in designing API keys
Posted by vjay15 8 days ago
Comments
Comment by bob1029 6 days ago
If you want aspects of the token to be inspectable by intermediaries, then you want json web tokens or a similar technology. You do not want to conflate these ideas. JWTs would solve the stated database concern. All you need to store in a JWT scheme are the private/public keys. Explicit tracking of the session is not required.
Comment by notpushkin 6 days ago
I suppose it’s there to avoid round-trip to the DB. Most of us just need to host the DB on the same machine instead, but given sharding is involved, I assume the product is big enough this is undesirable.
Comment by phire 6 days ago
Comment by kukkamario 6 days ago
Comment by ben-schaaf 5 days ago
Comment by phire 5 days ago
If you use a cryptographically secure hashing algorithm, mix in a secret salt and use a long enough checksum, attackers would find it nearly impossible to synthesise a correct checksum.
Comment by ben-schaaf 5 days ago
Others have pointed out that the checksum is for offline secret scanning, which makes a lot more sense to me than ddos mitigation.
Comment by phire 5 days ago
But it's trivial to make a secret checksum. Just take the key, concatenate it with a secret 256-bit key that only the servers know and hash it with sha256. External users might know the length of the checksum and that it was generated with sha256. But if they don't know the 256-bit key, then it's impossible for them to generate it short of running a brute force attack against your servers.
But it does make the checksum pretty useless for other usecases, as nobody can verify the checksum without the secret.
Comment by ben-schaaf 5 days ago
Comment by phire 5 days ago
Comment by ben-schaaf 5 days ago
Comment by locknitpicker 5 days ago
That assumption is false. The article states that the DB is hit either way.
From the article:
> The reason behind having a checksum is that it allows you to verify first whether this API key is even valid before hitting the DB,
This is absurdly redundant. Caching DB calls is cheaper and simpler to implement.
If this was a local validation check, where API key signature would be checked with a secret to avoid a DB roundtrip then that could see the value in it. But that's already well in the territory of an access token, which then would be enough to reject the whole idea.
If I saw a proposal like that in my org I would reject it on the grounds of being technically unsound.
Comment by rrr_oh_man 6 days ago
Experience tells otherwise
Comment by vjay15 6 days ago
I just was confused regarding the JWT approach, since from the research I did I saw that it's supposed to be a unique string and thats it!
Comment by petterroea 6 days ago
Comment by vjay15 5 days ago
Comment by petterroea 5 days ago
Comment by bob1029 6 days ago
Comment by agwa 5 days ago
Or are you suggesting that the API requests are signed with a private key stored in an HSM, and the JWT certifies the public key? Is that common?
Comment by bob1029 5 days ago
Very. The thing that certifies the public key is called a JWK.
https://datatracker.ietf.org/doc/html/rfc7517
This is typically hosted at a special URL that enables seamless key rotation and discovery.
https://auth0.com/docs/secure/tokens/json-web-tokens/json-we...
Comment by mattacular 5 days ago
Comment by vjay15 5 days ago
Comment by ijustlovemath 5 days ago
Comment by miningape 5 days ago
Comment by arethuza 6 days ago
Comment by vjay15 6 days ago
Comment by huflungdung 6 days ago
Comment by Hendrikto 5 days ago
Comment by weitendorf 6 days ago
Comment by vjay15 6 days ago
Comment by randomint64 6 days ago
Here is a detailed write-up on how to implement production API keys: https://kerkour.com/api-keys
Comment by 9214063141 5 days ago
1. Why do you use the API key ID AND the organization ID, and not just one of them, to prevent the confused deputy problem?
2. Why is not necessary to use something like Argon2id for hashing? You say "our secret is already cryptograhically-secure", but what does this mean exactly? Is it due to the fact that the secret is already very high entropy and cracking it, even if we use much faster hash functions like the ones mentioned in your article, it would practically not be possible even PQ with highly parallelized hardware?
Anyways, very interesting read, thank you!
Comment by jeremyloy_wt 6 days ago
Comment by randomint64 5 days ago
Comment by vjay15 6 days ago
Comment by Savageman 6 days ago
Comment by vjay15 6 days ago
Comment by ramchip 6 days ago
Comment by matja 6 days ago
That lets clients detect leaks, but malicious clients cant generate lots of valid-looking keys to spam your API endpoint and generate database load for just looking up API keys.
Comment by ramchip 5 days ago
Comment by vjay15 6 days ago
Comment by calrain 6 days ago
Even the random hex with checksum component seems overkill to me, either the API key is correct or it isn't.
Comment by andrus 6 days ago
Comment by sneak 6 days ago
Comment by vjay15 8 days ago
Comment by notpushkin 6 days ago
Reading “hex” pointing to a clearly base62-ish string was a bit interesting :-)
Also, could we shard based on a short hash of account_id, and store the same hash in the token? This way we can lose the whole api_key → account_id lookup table in the metashard altogether.
Comment by vjay15 6 days ago
But when I mentioned it to my senior he wanted me to default with the random string approach :)
Comment by vjay15 6 days ago
Comment by tlonny 6 days ago
Comment by agwa 5 days ago
Even a million rounds of hashing only adds 20 bits of security. No need if your secret is already 128 bits.
Comment by vjay15 6 days ago
Comment by numbsafari 5 days ago
Comment by vjay15 5 days ago
Comment by stanac 5 days ago
Comment by vjay15 5 days ago
Comment by tjarjoura 5 days ago
Comment by vjay15 5 days ago
Comment by pdhborges 6 days ago
Comment by vjay15 6 days ago
Comment by petterroea 6 days ago
Comment by dhruv3006 6 days ago
PS : I too am working on a APIs.Take a look here : https://voiden.md/
Comment by matja 5 days ago
Comment by out_of_protocol 5 days ago
Comment by vjay15 5 days ago
Comment by amelius 6 days ago
Comment by hk__2 5 days ago
Well I would have done that and saved half the blog post.
Comment by sneak 6 days ago
Comment by usernametaken29 6 days ago
Comment by fabian2k 6 days ago
Plain old API keys are straightforward to implement. Create a long random string and save it in the DB. When someone connects to the API, check if the API key is in your DB and use that to authenticate them. That's it.
Comment by swiftcoder 6 days ago
This is pretty much just plain-old-api-keys, at least as far as the auth mechanism is concerned.
The prefix slug and the checksum are just there so your vulnerability scanner can find and revoke all the keys folks accidentally commit to github.
Comment by vjay15 6 days ago
Comment by iamflimflam1 6 days ago
But otherwise, yes, for love of everything holy - keep it simple.
Comment by sabageti 6 days ago
Comment by notpushkin 6 days ago
Comment by SyndicateLinks 5 days ago
Comment by MORPHOICES 6 days ago
Comment by adaptit 6 days ago
Comment by Serhii-Set 5 days ago
Comment by grugdev42 6 days ago
Comment by codingjoe 5 days ago
Comment by vjay15 5 days ago
Comment by codingjoe 5 days ago
An attacker will be able to identify valid keys, but won't be able to sign them.
You can either split the values like aws or join them with a separator.
Good idea with the slug though, makes it easier to report leaked tokens to the issuer.