this post was submitted on 16 May 2025
20 points (95.5% liked)

Rust

6918 readers
56 users here now

Welcome to the Rust community! This is a place to discuss about the Rust programming language.

Wormhole

[email protected]

Credits

  • The icon is a modified version of the official rust logo (changing the colors to a gradient and black background)

founded 2 years ago
MODERATORS
 

So I've had this idea for an API for a while but the problem I keep coming back to is authentication. I'm using rocket to actually code it. I looked through the rocket docs and it looks like the closest thing to API key authentication it has are cookies.

I then went and looked at some other APIs to see if I can copy their layouts and it looks like a lot of them use an API key and then a secret API key for authentication. Did some more googling and stackoverflow said that it's more secure to use a pair like that.

So that leaves me with the actual question: how do you actually implement this feature? Do you just generate API keys and throw them a database to be looked up later? Should they be written/read to a file to be used later(probably not a good option I'd guess).

Just for reference I'm using rocket, sqlx and postgres.

top 10 comments
sorted by: hot top controversial new old
[–] [email protected] 3 points 14 hours ago (1 children)

If you are looking to do something like Github's Personal Access Tokens (PAT) then it is easiest to just think about it like a password:

  • Create a high entropy (secure) string
  • Store the hash of the string in a database table
  • Store the permissions and other metadata with the PAT's hash
  • Validate the PAT (permissions, revoke status, etc) on each request to the server

Storing the hash of the token, like you do with passwords, is a good practice in case your db is ever compromised as it wont leave the tokens accessible and reusable without a lot of effort.

[–] [email protected] 2 points 3 hours ago

Don't forget to add some salt to that hash.

[–] [email protected] 1 points 11 hours ago

That depends on scale. For our IOT device, we just had a private key on the device and gave the customer an encrypted packet that had their privileges spelled out, and set a field on their user account appropriately. That wouldn't be secure at scale, but it worked really well for our B2B app.

If I were doing something at scale, I'd follow suggestions from others here.

[–] [email protected] 6 points 20 hours ago (1 children)

I'd recommend switching away from Rocket if you can. It is not very actively maintained and Axum has become the better choice.

[–] ExperimentalGuy 2 points 13 hours ago

Thanks for the update, I wrote using rocket a few years ago so I figured everyone was still using that!

[–] [email protected] 8 points 1 day ago* (last edited 1 day ago) (2 children)

This is more of a cryptography question than a Rust question, but typically you'll use a so-called key diversification function (KDF) for this. See: https://en.wikipedia.org/wiki/Key_derivation_function (another term for the same thing, with slightly different connotations).

For an API key, you might have a user ID sent in the clear, and a secret key SK on the server. The KDF you would use would be something like HMAC-SHA256 truncated to 128 bits. Then the API key would be KDF(SK, ID). You will want a way to invalidate ID's and issue new ones so the person can cycle or change their API key. You could add a parameter P to the UID for this purpose, but again you have to be able to invalidate it.

You want to be very careful with SK on the server side. In financial apps (where the key can steal real money) you'd encapsulate it in a hardware security module (HSM). For less high-value apps you could still wrap it in its own HSM-like interface in its own process, that the rest of the app queries through a local socket. The idea is that the KDF process has a smaller attack surface than the big complicated web app. It can also implement throttling (limit the number of queries per second) in case a compromise app starts trying to spew API keys, and so on.

Added: your idea of just generating keys randomly and storing them in the database is also ok, but again you have to pay some attention to security, dealing with the possibility of the key table spilling, etc.

[–] ExperimentalGuy 4 points 1 day ago (1 children)

Sweet, thanks for the link! I didn't realize it was that complicated.

Do you know if there's a crate or library that already implements this functionality that I can pull from?

[–] [email protected] 1 points 22 hours ago

I didn't mean to make it sound complicated! What is the application if you don't mind my asking? Basically the paranoia level you need increases with the threat level ;). I'm afraid I don't know anything about the crate world. I'm sure there is an HMAC function in some Rust library though.

[–] [email protected] 1 points 19 hours ago (1 children)

Why is the secret key on the server side? Is this for the server to trust the client, or the client to trust the server?

[–] [email protected] 1 points 10 hours ago

It's so the server can generate any of the API keys as needed, instead of having to store them all. This matters more when you want to do the authentication on a low resource device like an HSM, or otherwise keep the authentication process away from the main server app, to lower the attack surface. Again, depending on the application, it might not be worth it.