Reputation: 18794
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.
Upvotes: 157
Views: 170657
Reputation: 66
I'd like to add an implementation in Java, that uses class KeyPairGenerator
to gen a public key using RSA, then convert it to base64. Lastly you can also pretty your API key by eliminating all the slash char and extract only the last part of the generated public key.
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
public static String generateMyAPIKey() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
byte[] publicKey = keyGen.genKeyPair().getPublic().getEncoded();
String base64Binary = DatatypeConverter.printBase64Binary(publicKey).replaceAll("/", "");
return base64Binary.substring(base64Binary.length() - 32);
}
Upvotes: 1
Reputation: 816
2023 Note: In Chrome, the default new tab page does not allow the use of the cryptography module in the console, so please use a different page.
Update, in Chrome's console and Node.js, you can issue:
crypto.randomUUID()
Example output:
4f9d5fe0-a964-4f11-af99-6c40de98af77
Original answer (stronger):
You could try your web browser console by opening a new tab on any site (see 2023 note at the top of this answer), 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...
Upvotes: 18
Reputation: 8337
Yet another more updated version of previous answers - but more compact and new-javascripty than before!
#!/usr/bin/env node
const { subtle } = require('crypto').webcrypto
subtle
.generateKey({ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt'])
.then(key => subtle.exportKey('jwk', key))
.then(jwk => console.log(jwk.k))
Run:
$ node /tmp/genkey.js
Mtra_qEFS7F76HrpgDAP2rBsb4pJ4w2hTL8UUyxalRA
Upvotes: 4
Reputation: 21
One popular way is to generate a random string using a cryptographically secure pseudo-random number generator (CSPRNG) and then encode this string with base64 encoding. This can provide a high level of security, as the keys are difficult to guess, and can be of virtually any length.
The other approach, as your friends suggested, is to use a GUID/UUID. It's true that some might find this to be a little "hacky", but in practice, it works well.
As for the hashing algorithms, if you choose to go the hashing route, it's generally recommended to use a strong algorithm like SHA256 or SHA3. Algorithms like MD5 and SHA1 are considered to be broken and should not be used for new systems.
Here is the Python code:
import secrets
import base64
def generate_api_key():
# Generate 32 random bytes
random_bytes = secrets.token_bytes(32)
# Convert those bytes into a URL-safe base64 string
api_key = base64.urlsafe_b64encode(random_bytes).decode("utf-8")
return api_key
print(generate_api_key())
Upvotes: 1
Reputation: 2440
I liked Chris Chiasson's use of crypto.subtle
in a browser, but wanted a command-line version. If you have NodeJS installed, this can be saved in a file (e.g., mkapikey.js
):
#!/usr/bin/env node
crypto.subtle.generateKey({name:"AES-GCM", length:256},true,
["encrypt","decrypt"]).then(key => {crypto.subtle.exportKey("jwk",key).
then(jwk => {console.log(jwk.k)})});
Either chmod +x
to an executable or invoke with node mkapikey.js
.
chmod +x mkapikey.js
./mkapikey.js
4SvnAK87DD0t3WMS878UCY-obmADtPeBn6X4gFOtUig
Upvotes: 2
Reputation: 3551
In the terminal, you can use openssl
like so:
openssl rand -hex 32
Example output:
1e846f3fcf103f64ca10fa4eac73bfae32ef10750bf4eae29132dc099526c561
Upvotes: 13
Reputation: 41658
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();
}
Upvotes: 10
Reputation: 41658
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);
Upvotes: 93
Reputation: 120516
API keys need to have the properties that they:
Typically you will have thousands or millions of API keys not billions, so they do not need to:
As such, one way to generate an API key is to take two pieces of information:
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.
Upvotes: 40
Reputation: 17415
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.
Upvotes: 1
Reputation: 29956
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.
Upvotes: 8