DEV Community

Nagarjun Palavalli
Nagarjun Palavalli

Posted on

Best practices to generate and store API keys using Node.js?

I'm building a Node.js application that primarily serves APIs. These APIs fall into two categories:

  • User APIs - to access specific user-endpoints like GET /users/:id/purchases
  • Admin APIs - allows the company / customer consuming our APIs to call admin-level endpoints like POST /users (to create a new user)

I am already securing user APIs using OAuth access tokens and refresh tokens. What is the best practice to secure my admin APIs? To be more specific, I'm looking to implement a solution like this - https://mailchimp.com/help/about-api-keys/.

The idea is to let my customer log into our admin app to create API keys so they can call our admin APIs:

  1. How do I generate keys similar to those generated by MailChimp?
  2. How do I validate these keys on the server using Node.js?

I've found dozens of articles that talk about JWTs but I doubt they are the right solution for this particular use case.

Top comments (14)

Collapse
 
leomotta121 profile image
Leonardo Motta • Edited

How did you manage it? I want to do something like this, I think I will just create a unique key and store it in the database associated with the user who created it, this way a can fetch for user data and so on.

Collapse
 
nagarjun profile image
Nagarjun Palavalli

My go-to solution for this is Google's Key Management Service (KMS) in GCP. AWS has a similar offering too. It makes encryption/decryption easy and secure without too much engineering overhead or costs.

Collapse
 
shaileshkanzariya profile image
sk • Edited

I have similar scenario, you said you used KMS. Means did you create API-Key and API-Secret keys using KMS for each user? If there are million/billion users then you create million/billion encryptions keys in KMS? As I read, KMS creates/manages encryption keys and NOT API/Secret Keys, please share details how did you implement it to help us.

Thread Thread
 
nagarjun profile image
Nagarjun Palavalli

You don't need to create new keys/secrets for each user. You need to create one key in KMS and use that key to encrypt/decrypt any number of strings. What language are you using to build your integration?

Thread Thread
 
shaileshkanzariya profile image
sk

I am using Node.js. So I am right now using "uuid/v1" to create API-Key and "Crypto.randomBytes(32)" to create API-Secret Key. How do you create these keys in your case?

Thread Thread
 
nagarjun profile image
Nagarjun Palavalli

What do you need KMS for? To encrypt your API keys/secrets before storing them in your database?

Thread Thread
 
shaileshkanzariya profile image
sk

I am looking for cloud-based mechanism/solution to create unique API and Secret Keys instead of using "uuid/v1" and "Crypto.randomBytes(32)"...

Thread Thread
 
nagarjun profile image
Nagarjun Palavalli • Edited

KMS isn't meant just for generating unique API keys. You are better off using UUID and the Crypto library to do that. They are both battle tested to create unique keys. You would use KMS as a way to encrypt/decrypt your keys before storing them in your database as you should not store keys and secrets in plain text in the database.

Thread Thread
 
shaileshkanzariya profile image
sk

Got it, thanks.

Collapse
 
leomotta121 profile image
Leonardo Motta • Edited

Thanks, because I am needing this type of solution, I will definitely search about this Google service you recommended, really thank you.

Collapse
 
davidszabo97 profile image
Dávid Szabó
  1. Generate a random string and store it in the database. As long and as complex as possible.
  2. The keys should be associated with the user who created it. Therefore you can lookup the API key in the database and find out which user it is. You can use a middleware to authenticate via API key.

Yes, I'd avoid JWTs here.

Collapse
 
nagarjun profile image
Nagarjun Palavalli

Store keys in plain text in the database? Seems like it might open up some kind of vulnerability.

Collapse
 
davidszabo97 profile image
Dávid Szabó

I never said you should store them as plain text. Encrypt them and when an API call comes in, decrypt the generated string to find out which access token it is.

Generate an ID for your access token then encrypt("ID" + "creation time") with your app secret.

Collapse
 
derekzyl profile image
derekzyl

Geniuses in the house I guess you've conquered this challenge based on what I've seen here. Waht was the best implementation you used thanks