20

I am writing an app that will expose an API. The application allows people to create workspaces and add users to them. Each user will have a unique token. When they make an API call, they will use that token (which will identify them as that user using that workspace.

At the moment I am doing this:

var w = new Workspace(); // This is a mongoose model
w.name = req.body.workspace;
w.activeFlag = true;
crypto.randomBytes(16, function(err, buf) {
    if(err){
        next(new g.errors.BadError503("Could not generate token") );
    } else {
        var token = buf.toString('hex');

        // Access is the list of users who can access it. NOTE that
        // the token is all they will pass when they use the API
        w.access = {  login: req.session.login, token:token, isOwner: true };
        w.save( function(err){
            if(err){
                next(new g.errors.BadError503("Database error saving workspace") );

Is this a good way to generate API tokens?

Since the token is name+workspace, maybe I should do something like md5(username+workspace+secret_string) ...?

4 Answers 4

20

If you using mongodb just use ObjectId, othewise I recommend substack's hat module.

To generate id is simple as

var hat = require('hat');

var id = hat();
console.log(id); // 1c24171393dc5de04ffcb21f1182ab28
Sign up to request clarification or add additional context in comments.

5 Comments

I don't think it is safe to use mongodb's ObjectId. It has some rule to generate and is somehow based on time. So someone could generate many ObjectId based on time and test if they are really tokens.
I would also refrain from ObjectId and use hat instead.
I would suggest to store only hash of that token in database, which you can not do with ObjectId.
Mongodb's ObjectID does not have sufficient entropy. Here's more detail about MongoDB = stackoverflow.com/a/15436118/257082. Additionally, using MongoDB in a replicated setup may cause challenges with your application logic requiring a sufficiently random ObjectID
Downvoted because of ObjectID recommendation. ObjectIDs are predictable, low entropy and leak information about how and when they were generated. Not at all suitable for use as an API key in the traditional sense. See the MongoDB documentation for more information: docs.mongodb.com/manual/reference/method/ObjectId.
7

How does this code make sure your token is unique? I believe you could have collision of numbers with this code. I believe you need to have a sort of sequence number like in this commit from socket.io.

Also you could use npm projects like for example:

to ensure uniqueness.

1 Comment

I am surprised that the UUID package (v4 only!) is cryptographically safe. But I looked it up. It is. That's cool.
4

I think the following are the best solution for Generating API tokens

Speakeasy is more secure because this key is only available for a small time period (e.g, 30 second)

Comments

1

Why not just use UUIDv4 if you are looking for something unique? If you are interested in some other type of hashing (as mentioned previous hat is a good choice), you might look at speakeasy - https://github.com/markbao/speakeasy. It not only generates random keys but it can also create timebased twofactor authentication keys if you ever really want to layer on additional security strength.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.