What's the best approach for generating a new API key?

SecurityApi Key

Security Problem Overview


So with lots of different services around now, Google APIs, Twitter API, Facebook API, etc etc.

Each service has an API key, like:

AIzaSyClzfrOzB818x55FASHvX4JuGQciR9lv7q

All the keys vary in length and the characters they contain, I'm wondering what the best approach is for generating an API key?

I'm not asking for a specific language, just the general approach to creating keys, should they be an encryption of details of the users app, or a hash, or a hash of a random string, etc. Should we worry about hash algorithm (MSD, SHA1, bcrypt) etc?

Edit: I've spoke to a few friends (email/twitter) and they recommended just using a GUID with the dashes stripped.

This seems a little hacky to me though, hoping to get some more ideas.

Security Solutions


Solution 1 - Security

Use a random number generator designed for cryptography. Then base-64 encode the number.

This is a C# example:

var key = new byte[32];
using (var generator = RandomNumberGenerator.Create())
	generator.GetBytes(key);
string apiKey = Convert.ToBase64String(key);

Solution 2 - Security

API keys need to have the properties that they:

  • uniquely identify an authorized API user -- the "key" part of "API key"
  • authenticate that user -- cannot be guessed/forged
  • can be revoked if a user misbehaves -- typically they key into a database that can have a record deleted.

Typically you will have thousands or millions of API keys not billions, so they do not need to:

  • Reliably store information about the API user because that can be stored in your database.

As such, one way to generate an API key is to take two pieces of information:

  1. a serial number to guarantee uniqueness
  2. enough random bits to pad out the key

and sign them using a private secret.

The counter guarantees that they uniquely identify the user, and the signing prevents forgery. Revocability requires checking that the key is still valid in the database before doing anything that requires API-key authorization.

A good GUID generator is a pretty good approximation of an incremented counter if you need to generate keys from multiple data centers or don't have otherwise a good distributed way to assign serial numbers.


> or a hash of a random string

Hashing doesn't prevent forgery. Signing is what guarantees that the key came from you.

Solution 3 - Security

I use UUIDs, formatted in lower case without dashes.

Generation is easy since most languages have it built in.

API keys can be compromised, in which case a user may want to cancel their API key and generate a new one, so your key generation method must be able to satisfy this requirement.

Solution 4 - Security

If you want an API key with only alphanumeric characters, you can use a variant of the base64-random approach, only using a base-62 encoding instead. The base-62 encoder is based on this.

public static string CreateApiKey()
{
	var bytes = new byte[256 / 8];
	using (var random = RandomNumberGenerator.Create())
		random.GetBytes(bytes);
	return ToBase62String(bytes);
}

static string ToBase62String(byte[] toConvert)
{
	const string alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
	BigInteger dividend = new BigInteger(toConvert);
	var builder = new StringBuilder();
	while (dividend != 0) {
		dividend = BigInteger.DivRem(dividend, alphabet.Length, out BigInteger remainder);
		builder.Insert(0, alphabet[Math.Abs(((int)remainder))]);
	}
	return builder.ToString();
}

Solution 5 - Security

Update, in Chrome's console and Node.js, you can issue:

crypto.randomUUID()

Example output:

'4f9d5fe0-a964-4f11-af99-6c40de98af77'

Original answer:

You could try your web browser console by opening a new tab, hitting CTRL + SHIFT + i on Chrome, and then entering the following immediately invoked function expression (IIFE):

(async function (){
  let k = await window.crypto.subtle.generateKey(
    {name: "AES-GCM",length: 256},true,["encrypt", "decrypt"]);
  const jwk = await crypto.subtle.exportKey("jwk", k)
  console.log(jwk.k)
})()

Example output:

gv4Gp1OeZhF5eBNU7vDjDL-yqZ6vrCfdCzF7HGVMiCs

References:

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKey

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey

I'll confess that I mainly wrote this for myself for future reference...

Solution 6 - Security

An API key should be some random value. Random enough that it can't be predicted. It should not contain any details of the user or account that it's for. Using UUIDs is a good idea, if you're certain that the IDs created are random.

Earlier versions of Windows produced predictable GUIDs, for example, but this is an old story.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPhillView Question on Stackoverflow
Solution 1 - SecurityEdward BreyView Answer on Stackoverflow
Solution 2 - SecurityMike SamuelView Answer on Stackoverflow
Solution 3 - SecurityAdam RalphView Answer on Stackoverflow
Solution 4 - SecurityEdward BreyView Answer on Stackoverflow
Solution 5 - SecurityChris ChiassonView Answer on Stackoverflow
Solution 6 - SecurityDave Van den EyndeView Answer on Stackoverflow