Possible security concern with the API keys implementation

Looking at the implementation of api keys in ServiceStack, I think the providers all write and read the api keys in the storage as plaintext.
Since the api key can be used to authenticate a user, they are similar to passwords (or worse, because they do not need a username to authenticate).
This equivalence means that storing api keys as plaintext is similar to storing passwords in plain text, which is a security issue in case the database or data are leaked.

Shouldn’t api keys be stored as hashes, the same as a password? It does mean that it’s no longer possible to retrieve an api key after it’s been generated, but would close this security concern.

API Keys need to be stored in plain text since they need to be displayed to the user.

  • Unlike passwords, they need to be stored in plain-text in order to be able to match the user it belongs to, unless you force users to also provide their Username or Id along with their API Key with every request.
  • Unlike passwords, they need to be readily available in plain text in all client applications using them since they need to be used without human intervention.
  • Unlike passwords, they’re random cryptographically generated high entropy strings making them impossible to guess.
  • Unlike passwords, they’re unique and not reused, limiting their attack surface to compromise other users’ other accounts.

API Keys are not passwords and shouldn’t be thought of as such, they’re a Bearer Token Auth Provider, what differentiates them with other bearer tokens like Session Cookies or JWT Access Tokens is longevity, which is by design to allow authenticated API integrations. If you want to limit their scope you can do what NuGet have recently decided to and invalidate API Keys after a year, which comes at the cost of inconveniencing your Customers (i.e. who’ll get annoyed each time their CI release or production application fails and forces rotation of API Keys).

The risk is they’re vulnerable when the App database is compromised, which would mean the entire Users’s database is already compromised. Typically Organizations also require users to change their password after a database breach, even when it just stores password hashes since weak passwords would still be vulnerable to a brute force attack. Likewise all API Keys should be invalidated after data breaches.

ServiceStack’s API Key provider was modelled after Stripe API Keys which as they’re recoverable are also not hashed. I’d assume most B2B services supporting API Key access must also store them in plain text given I rarely need to provide my Username with my API Keys.

If you do want to use hashed API Keys you’ll need to implement your own bespoke solution since they’ll only be available in the end-user UI implemented in the portal your Customers use to generate and access their API Keys, you would also need to force Customers to store and send additional information with their API key (which is atypical for Bearer Tokens). It’s not something we could create a generic solution for.