6 ms·
Making Beautiful API Keys
- theamk 2y agoOne of the best things you can do to your API key is to give it a fixed prefix. Makes it very easy to tell that you have the right string, to detect accidental secret leakage, etc... IMHO this makes key much more beautiful than any internal structure.
- adriancooney 2y agoAgreed. I first seen it at Stripe (along with prefixing every ID). Whoever at Stripe (or where ever it was invented) needs a good pat on that back. It's adoption has been a huge for DX generally.
- notpushkin 2y agoI’ve made a library for that! https://codeberg.org/prettyid https://codeberg.org/prettyid
- dewey 2y agoWhy should anyone vendor a dependency in a critical functionality for three lines of code (https://codeberg.org/prettyid/js/src/branch/master/lib/index.ts https://codeberg.org/prettyid/js/src/branch/master/lib/index...)?
- verdverm 2y agoonly if I can leftpad it first?
- HideousKojima 2y agoThat's the JavaScript/Node ecosystem in a nutshell. See the LeftPad fiasco and the mere existence of the IsOdd and IsEven packages for more poor judgement.
- notpushkin 2y agoTo be honest that’s because I didn’t flesh out JS counterpart yet. My plan was to have something similar to the Python version: https://codeberg.org/prettyid/python https://codeberg.org/prettyid/python Of course, if you like the idea but don’t want to add another dependency, you can copy-paste the three-liner as it is! (And I’m sure it’s not even copyrightable right now :-)
- fusspawn 2y agomultiple dependencies, Also requires two other packages to run its 3 lines of code. "dependencies": { "@scure/base": "^1.1.7", "uuidv7": "^1.0.1" }
- kqr 2y ago...but you'll have those dependencies anyway!
- xdennis 2y agoThere's a similar proposal called TypeID: https://github.com/jetify-com/typeid https://github.com/jetify-com/typeid E.g.: user_2x4y6z8a0b1c2d3e4f5g6h7j8k
- notpushkin 2y agoThis is actually pretty good! And it seems to be compatible with my implementation (it’s also UUIDv7 and base32 alphabet is the same, but without mapping from OIL to 01).
- jjice 2y agoI'm a big fan of prefixed keys as well. If I could go back in time, I would've made my current company's API keys prefixed. Sometimes you'll chat with a customer and just notice the same isn't right and realize the key is all wrong. It's a lot easier if it starts with `company_XXXXX`. Also denoting environment (live vs test in Stripe) with a prefix is actually critical in my eyes. I also like prefixed resource IDs. Stripe is the first one that comes to mind, but I've run into it multiple times where a customer is describing an issue and it turns out the ID they're trying to lookup is for a different resource (often similar). You don't get those accumulated hours of support time back...
- moebrowne 2y agoAgreed. I like what GitHub did with their API tokens, not only adding prefixes but also a checksum. https://github.blog/engineering/platform-security/behind-githubs-new-authentication-token-formats/ https://github.blog/engineering/platform-security/behind-git...
- dspillett 2y agoI would agree with that. Also, I don't really want API keys and such to be generally pretty. If things that have no business being end-user facing are ugly then they are less likely to be allowed to accidentally become end-user facing. If being pretty or otherwise user-friendly is a priority, then I'd go with trying to make them readable/pronounceable rather than shorter, even if that actually makes them longer. There are numerous projects out there¹²³ for doing just that. You could even use the 256-word example³ with multiple small dictionaries, and give people a choice from various possibilities that map to the same number. ---- [1] https://github.com/Debdut/uuid-readable https://github.com/Debdut/uuid-readable [2] https://github.com/Martichou/uuid-readable-rs https://github.com/Martichou/uuid-readable-rs [3] https://github.com/anton-bot/guid-in-words https://github.com/anton-bot/guid-in-words
- yread 2y agoI like adding a suffix as well: (optional) human readable expiration date
- progforlyfe 2y agoactual functional features in API keys! How dare you! aesthetics over all!!
- mtmail 2y ago"encodes UUIDs to a readable Key format via the Base32-Crockford codec and also decodes them back to UUIDs." Example: "d1756360-5da0-40df-9926-a76abff5601d" => "38QARV0-1ET0G6Z-2CJD9VA-2ZZAR0X" I think now you risk having 0 vs O or I vs 1 readability issues. [edit: good news, I was wrong]
- notpushkin 2y agoBase32-Crockford doesn’t have 0 and 1 for this exact reason! (Seems uuidkey authors have decided to remove O and I instead, but the effect is the same) EDIT: I’ve looked it up and I was wrong! Crockford alphabet does use all digits (0–9), but doesn’t have O, I or L. When decoding, O is mapped back to 0 and both I and L are mapped to 1. Sorry for the confusion!
- copperlight 2y agohttps://www.crockford.com/base32.html https://www.crockford.com/base32.html > We chose a symbol set of 10 digits and 22 letters. We exclude 4 of the 26 letters: I L O U. I had never heard of Base32 Crockford before. The whole rationale is clever.
- mrweasel 2y agoGiven that API keys are likely to simply be copy-pasted, I don't honestly think this matters all that much. If you're have the risk to users confusing 0 and O, then you can't use either. Your users aren't going to know that you're running Base32-Crockford and that they'll only encounter 0 and 1, never O, I or L. We did a "password" generator, for people who made a purchase, but didn't want an account. To view an order they'd then need to enter a code, found in their confirmation email. Those codes where really short, 8 or 10 characters, no 0,1,I,O,L,U,V and all upper case. If the user entered the code in lower case, we'd automatically upper case it. You'd never use these as a real password, but for a temporary order tracking page they pretty much removed all of the input mistakes people could make.
- notpushkin 2y ago> Given that API keys are likely to simply be copy-pasted, I don't honestly think this matters all that much. Yeah, I think it’s not that important for API keys particularly. It’s possible that some IDs would be spoken over a phone for example, but it’s probably rare. > If you're have the risk to users confusing 0 and O, then you can't use either. Your users aren't going to know that you're running Base32-Crockford and that they'll only encounter 0 and 1, never O, I or L. The way Crockford got around that was, OIL are allowed when decoding the string (and just replaced by 0 and 1 accodringly). So if used mistypes O in place of 0, it’s still going to decode just fine. I think it should work alright for stuff like license keys or “passwords” like in your case (although your solution works too!)
- PaulHoule 2y agoI invented (more or less) Crockford Base32 back in 2001 which I called "Base32t" (t for Tapir, because it was part of the "Tapir User Management System") for encoding password reset tokens and such. (Minus those squicky check symbols... Right out of the mind that left us the seductive but slightly flawed JSON [1]) I used T.U.M. for a number of sites including one that was in the Alexa top 2000, even though it was open source it got no pickup from anyone else. The standard at the time was to pick up some software like PHPNuke which did a lot of things badly as opposed to my Yahoo-inspired approach of "pick the best of breed software and plug them into a common user management system". The idea didn't get any traction until 2013 when things like this popped up like mushrooms. Seemed the missing features were "vendor lock-in", "somebody else owns your user database", "they might shut down, get bought by Google or kick you out of the free tier." [1] I've seen it enough that I'd expect higher uptake if you inject small flaws into a specification like that.
- anticorporate 2y agoI love the throwback reference to the Diablo II CD key. There are some CD keys that will be forever etched in my brain, no matter how many PINs I struggle to remember. I suspect a good number of you know far too much of a certain string that starts with FCKGW.
- tommica 2y agoFor those who don't know: https://scribe.rip/@cristian.nedelcu/fckgw-rhqq2-yxrkt-8tg6w-2b7q8-the-notorious-windows-xp-key-195c6601daf7 https://scribe.rip/@cristian.nedelcu/fckgw-rhqq2-yxrkt-8tg6w...
- kqr 2y agoFull article: https://archive.is/TDE9g https://archive.is/TDE9g
- mossTechnician 2y agoThis topic looked interesting, so I hunted down a better frontend for that full Medium article[0]. The writing is unsatisfying, doesn't really say anything, and by the last paragraph ("The tale of the product key... is a continuing demonstration of the never-ending struggle that takes place between the technological sector and the unyielding world of hackers") I was convinced the author was just posting a ChatGPT response. Which is sad, because I'd have liked to see the backstory for something apparently shrouded in mystery. But since there appears to be little explanation to how that key was leaked before Windows itself went on sale, I'll just enjoy the memory of the cultural phenomenon[1][2]. [0] https://freedium.cfd/https://medium.com/@cristian.nedelcu/fckgw-rhqq2-yxrkt-8tg6w-2b7q8-the-notorious-windows-xp-key-195c6601daf7 https://freedium.cfd/https://medium.com/@cristian.nedelcu/fc... [1] https://news.ycombinator.com/item?id=19298196 https://news.ycombinator.com/item?id=19298196 [2] https://marco.org/2007/06/18/wow-fckgw-has-its-own-wikipedia-mention-flickr https://marco.org/2007/06/18/wow-fckgw-has-its-own-wikipedia...
- mrweasel 2y agoThat reference to CD keys is nice and when I look at their example vs. the Diablo II CD key I think they fall a bit short of creating something the looks nice. It's simply down to size, the example key they generate is just to long, to the point where I don't see the value. It's a cute idea, but I really don't like the extra level of indirection, especially as I feel like there's nothing gained. The base32 encoded key is no more beautiful that the uuid7. I think it's to easy for someone to look at this and go uuid7().upper() and assume that's the same thing, if they just look at the key.
- voidUpdate 2y agoIt may just be personal preference but I think I'd find it more beautiful if there were 5 characters per block, instead of 7. It has a better rhythm to say it in my head
- robertclaus 2y agoThis type of key editing always makes me nervous. I know how uuids behave. I'm not a security expert, but I'm 99% sure the formatting steps here don't increase the chance of key collisions or security implications significantly. Is that 1% risk worth it?
- ramchip 2y agoThere's a 1:1 mapping (a bijection) between uuid and uuidkeys, therefore there are as many possible uuidkeys as there are uuids, and the risk of collision is the same.
- jalk 2y agoI'm 99.9999% sure that your 1% risk is incorrect, given they are just reformatting UUIDv7
- Merad 2y agoBase 32 is just an encoding, so it doesn't modify the underlying data of the uuid, it presents the data in a different display format. It's the same as how the number 10 can be represented as decimal 10, binary 0b1010, octal 0o12, hex 0xA, etc.
- jaccola 2y agoI agree - the reformatted IDs are shorter than the originals, so by the pigeonhole principle you are increasing the chance of collision. I doubt this matters in reality for this case, but the number of comments stating "there is no difference" or something to this effect shows how any added step can easily be misunderstood and could (in the worst case) introduce a fatal security flaw.
- ramchip 2y agoUUIDs are longer because they use a less efficient encoding (base16 vs base32), not because they contain more entropy.
- lovasoa 2y agoDashes in API keys are really annoying. Double-clicking doesn’t select the full key, which just adds extra hassle. It would be much better if they used a continuous string without any separators. Makes copying and pasting way easier, and doesn't affect security at all.
- noman-land 2y agoDouble click and drag is your friend.
- OptionOfT 2y agoSide note: this seems to work differently on Mac. I had to wait a little bit before the drag function would drag and not change the selection.
- noman-land 2y agoI don't experience this on any of my devices! It's instantaneous.
- BUMBLING_FOOL 2y ago[flagged]
- verdverm 2y agoyou're my hero today
- noman-land 2y agoHappy to help. Check out triple click as well. And maybe 4???
- boredumb 2y agoI really don't care about the aesthetics of a string but this is 100% my issue when interacting with UUIDs.
- 2y ago
- error404x 2y agoThis is so amazing, thanks for sharing! I usually create an API key like this: `sk_${randomUUID().replace(/-/g, '')}`.
- philo23 2y agoA bit off topic, but on the copying issue with dashes, you can wrap the whole key in a span styled with “user-select: all” to improve the copying experience. Well, on the web at least!
- stitched2gethr 2y agoI guess this is an unpopular opinion given the existing comments, but I don't get it. They spent time and energy on this instead of writing features or fixing bugs and I don't think it matters at all. The only interaction I have with my API keys is copying them from one place to another. If I need to manually identify a key then putting the first or last few chars, whatever they are, in my working memory is more than sufficient.
- a12k 2y agoI totally agree. This looks like a pretty new startup too. I would be livid if my team had spent so much time on this instead of building capabilities to get the startup traction.
- alt227 2y agoIt looks like they wanted a reason to make a shiny blog post to get attention for their startup. Judging by the fact its on the front page of HN and we are all commenting on it, looks like they succeeded.
- hombre_fatal 2y agoYall are so dramatic. It's a trivial library to write. 99% of it is just deciding what you want the output to look like + writing the blog post.
- great_wubwub 2y agoYeah, the code is easy but navel-gazing and agonizing over the prettiest way to replace a long jumble of dash-separated lowercase characters with a slightly shorter jumble of dash-separated uppercase characters is an insane thing to spend any time on at all. Convince me this has any commercial value and isn't just bikeshedding.
- hombre_fatal 2y agoThis is just what it looks like to care about the details, though certainly a more trivial case than most. The resistance to it is part of why most engineer-types like HNers can't build UX. They think it's all agonizing and navel-gazing, so they don't deliberate over anything. And they don't practice it, so when they see someone making deliberate UX decisions, even trivial ones, they think it must have taken a lot of time. Good UX comes from a chain of trivial-looking decisions in isolation and a culture of caring about it.
- progbits 2y agoThis is missing a checksum which helps secret scanning avoid false positives in other high entropy strings. See for example: https://docs.github.com/en/code-security/secret-scanning/secret-scanning-partnership-program/secret-scanning-partner-program#identify-your-secrets-and-create-regular-expressions https://docs.github.com/en/code-security/secret-scanning/sec...
- majkinetor 2y agoCrockford has a checksum though
- progbits 2y agohttps://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L111 https://github.com/agentstation/uuidkey/blob/master/uuidkey.... They don't appear to check validity though? I haven't tested it so maybe someone else can double check.
- majkinetor 2y agoyes they do. We use it in prod
- a12k 2y agoThis is the very definition of bikeshedding. It should be included as a reference in any definition of that term.
- bkummel 2y ago+1
- deleted 2y ago[deleted]
- remram 2y agoI use URLs as API keys, so they are self-descriptive (links to a page that tells you what it is/what service it's for) and self-revocable (there's a button, no need to post it to a GitHub repo to have them revoke it for you with their secret scanner [1]). I bring this up a lot [2] but I do think there is value in being able to tell if something is a secret and tell where to go to revoke it if found. Most current API keys use some sort of prefix at least (AWS, SendGrid, GitHub, etc). [1]: https://docs.github.com/en/code-security/secret-scanning/introduction/supported-secret-scanning-patterns https://docs.github.com/en/code-security/secret-scanning/int... [2]: https://news.ycombinator.com/item?id=28296864 https://news.ycombinator.com/item?id=28296864
- fusspawn 2y agoI really dont see the benefit of these. its just guids with extra steps. its not any easier to read than guids. its an alphanumeric random string in both systems. yes theres is kinda symetrical. but im not going to find it easier to communicate/remember say: 38QARV0-1ET0G6Z-2CJD9VA-2ZZAR0X any easier than i am d1756360-5da0-40df-9926-a76abff5601d both are long random strings. both are awkward to have to read over say a phone call. what am I missing here?
- gioazzi 2y agoI love using Crockford's Base32 to encode "invite codes" or any ID that you may want to share/write down/spell out: don't have to worry about mixing up O-s and zeroes - or care about casing. I try to make it obvious in UI by automatically converting to uppercase, replacing O->0 etc, and adding a dash in the middle.
- smashed 2y agoI don't quite understand the need for a timestamp. This only reduces entropy? You wouldn't think of using the current date in a password prefix for example. Aren't you going to track the keys in a database, where you can keep the tenant id and creation time, scope of the key and any other significant metadata anyway? A static prefix + checksum, maybe a version number so you can future-proof the system sounds like best practice. For example `ASKEY1-(128bit random base32 encoded)-(chksum)`.
- tzury 2y agoAPI keys and UUIDs serve fundamentally different purposes, even though they may look similar as random strings: 1. API keys are security credentials: - They are meant to be secret and revocable - They often encode metadata about permissions and identity - Compromised API keys must be invalidated and replaced - They function like passwords for authentication/authorization 2. UUIDs are identifiers: - They are designed to be globally unique but not secret - They contain no inherent permissions or privileges - There's no security risk if others know a UUID - They function like serial numbers for identification To use an analogy: An API key is like the key to your house (needs to be kept secret, grants access, can be changed if compromised), while a UUID is like your house's street address (can be public, just identifies the location, doesn't grant any access by itself). Thinking they're equivalent is like saying your house key and address are the same thing just because they're both strings of characters. This misconception could lead to serious security vulnerabilities if API keys are treated with the same casualness as UUIDs. PS, we all liked this site, right? https://everyuuid.com/ https://everyuuid.com/
- bArray 2y ago> The dashes do remove easy double-click copying, but we think this a fine trade off for readability. We don't want users copying and pasting them everywhere, in fact we want them to be handled with care. Ideally, users copy each key exactly once - when they generate the key from our dashboard - so we added a copy button to our UI to solve that case. Or, just ignore the dashes? It's not that difficult, we have the technology.
- pksunkara 2y agoThis ulid Postgres extension doesn't have any performance issues compared to native uuidv7 in Postgres. https://github.com/pksunkara/pgx_ulid https://github.com/pksunkara/pgx_ulid. Just wanted to bring it up since it looks like the author didn't come across it when looking for ulid generators in postgres. Disclaimer: I built it.
- benterix 2y agoThe author mentions readability - if they care about it, they should eliminate all ambiguous characters like 0Oo1l.
- moebrowne 2y agoThey use Crockford Base32 encoding which does exactly that.
- benterix 2y agoI don't think so since the sample key they present in the big image contains many of these. The caption is "An example API key generated by github.com/gofrs/uuid and encoded with github.com/agentstation/uuidkey." - so something is wrong.
- alt227 2y agoYou need to look harder at the encoding standard. After generation all o are mapped to 0 and all l are mapped to 1 so yes there are 0 and 1 but there are never o and l.
- hdjjhhvvhga 2y agoAh, so you need to know that first, otherwise it's still ambiguous to people reading them.
- stby 2y agoBase 32 does that for them, it excludes the lower case letters and I L O U.
- cynicalsecurity 2y agoThis is an absolute useless feature. It's actually even dangerous, because the "beauty" of API keys makes absolutely no sense. Only security matters.
- rw_panic0_0 2y agobro your username speaks for itself lol
- balls187 2y agoThis reminds me of every time I heard a complaint that a url is “ugly”
- skerit 2y agoWhat's up with these comments? Let these folks format their keys the way they want.
- alt227 2y ago> Overall, developers like to use UUIDs - they just don't like how they look. I have never ever heard a developer even mention the way api keys look before.
- xdennis 2y ago> uppercase letters and numbers for "blocky" aesthetics and readability I'm not sure if this is meant to be read as "uppercase (letters and numbers)", but it is effectively what he's referring to. Lowercase digits do exist[1], but there's no Unicode encoding for them and fonts typically have to choose to support one or the other. [1]: https://en.wikipedia.org/wiki/Text_figures https://en.wikipedia.org/wiki/Text_figures
- bkummel 2y agoI'm not sure whether the result is more readable than a UUID. With a UUID you at least know that it can only be [0-9A-F]. Besides, who on earth _types_ API keys? You should copy/paste them and store them in a password manager. So they don't _need_ to be readable.
- deleted 2y ago[deleted]
- realaleris149 2y agoI used https://github.com/jetify-com/typeid https://github.com/jetify-com/typeid for generating api keys for a project. They are nice because you can use prefixes for different type of keys and know immediately what they represent. No dashes also makes them easier to copy paste.
- seveibar 2y agoIMO the prefixed api key convention with a public portion and base58 encoding that i wrote about 2 years ago is so so much better than CD-key style API keys https://github.com/seamapi/prefixed-api-key https://github.com/seamapi/prefixed-api-key
- savannahkc 2y agoHey everyone. Thanks for all the discussion on the article. We wanted to respond to a few common themes: 0. Some folks don't care about API Keys, that's okay! But for those of you who did respond and do care, we are updating our design based on your feedback. 1. When we got to work on making our API Keys, we looked for an obvious standard but didn't find one. So we decided on our approach quickly and put together uuidkey in an afternoon. We knew it was not going to be everyone’s preferred design, but we wrote up the article to share our thought process as well as generate some marketing. We are happy to see that the article did well and we got feedback! :) 2. The ability to double-click to copy, which was lost with the addition of dashes, was more important to developer commenters than we thought it'd be (even if only needed once). We heard you, so we've already updated https://github.com/agentstation/uuidkey https://github.com/agentstation/uuidkey to support a `WithoutHyphens` option for the `Encode` function so you can generate keys without dashes. 3. Some folks were worried that our resulting key after encoding has fewer bits of entropy compared to the original UUID. The Crockford base32 encoding does not reduce entropy, it is a 1:1 mapping. 4. One quality piece of feedback pointed out that the UUID spec warns against using UUIDv7 (only 74 bits of entropy) and even UUIDv4 (standard 122 bits of entropy) alone for API Keys. We plan on still supporting UUIDv7 and UUIDv4, but will add additional entropy bits to follow the official recommendation. 4. Lots of commenters like prefixes, which make it easier to identify & search for keys (particularly to ensure they don’t get accidentally committed to a repo). We plan to add an option for that. Worth mentioning that a few folks pointed us to Github's auth token implementation that includes prefixes, which is a pretty great standard - https://github.blog/engineering/platform-security/behind-githubs-new-authentication-token-formats/ https://github.blog/engineering/platform-security/behind-git... Thanks again for reading, debating, and giving us some good advice! We want a product that feels good for developers to use. :D