Generating Cosmos DB Auth Tokens in Postman

If you read the official article that describes how access control works in Cosmos DB, you’ll see this handy Node.js function for generating authentication tokens using a master key:

var crypto = require("crypto");  

function getAuthorizationTokenUsingMasterKey(verb, resourceType, resourceId, date, masterKey) {  
    var key = new Buffer(masterKey, "base64");  
    var text = (verb || "").toLowerCase() + "\n" +   
               (resourceType || "").toLowerCase() + "\n" +   
               (resourceId || "") + "\n" +   
               date.toLowerCase() + "\n" +   
               "" + "\n";  
    var body = new Buffer(text, "utf8");  
    var signature = crypto.createHmac("sha256", key).update(body).digest("base64");  
    var MasterToken = "master";  
    var TokenVersion = "1.0";  
    return encodeURIComponent("type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + signature);  
}

That’s nice. However, what if I want to generate a Cosmos DB auth token in a Postman pre-request script? The built-in Node.js crypto module isn’t available in Postman but CryptoJS is. This version of the script which does a few encodings the CryptoJS way should do the trick:

var now = new Date().toUTCString();
pm.environment.set("utcDate", now);

var verb = 'GET';
var resourceType = pm.variables.get("resourceType");
var resourceId = pm.variables.get("resourceId");

var text = (verb || "").toLowerCase() + "\n" + (resourceType || "").toLowerCase() + "\n" + (resourceId || "") + "\n" + now.toLowerCase() + "\n" + "" + "\n";
var key = CryptoJS.enc.Base64.parse(pm.variables.get("masterKey"));
var signature = CryptoJS.HmacSHA256(text, key).toString(CryptoJS.enc.Base64);

var MasterToken = "master";
var TokenVersion = "1.0";
var authToken = encodeURIComponent("type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + signature);

pm.environment.set("authToken", authToken);

For the script to work, you’ll need to define a few variables in a Postman environment file:

  • utcDate – this will be set by the script. It’s used in the calculation of the auth token and will also be placed into an HTTP header named x-ms-date.
  • masterKey – don’t be stupid. Production secrets shouldn’t be stored in a Postman environment file. Copy the primary or secondary master key from your Cosmos DB account into this variable. If you’re only performing GET operations, you should be able to use a read-only key here.
  • authToken – this will be computed by the script and placed into the Authorization HTTP header.
  • resourceId – the path to the object(s) you want to reference. For example, I have a database named Finance with a collection named Investors. The resourceId would be set to “dbs/Finance/colls/Investors” in that case.
  • resourceType – the type of resource you wish to access. If I’m after documents, I’ll save “docs” here. See the Cosmos DB documentation for other resource types such as “dbs” or “colls”.

One value I was not able to fetch from the Postman Sandbox was the HTTP method of the current request. Unfortunately I hard-coded that in the script to “GET” for now. If you know how to obtain that value using the Sandbox API, let me know and I’ll update this article.

As the Cosmos DB documentation explains, there are a few required headers when making calls through Cosmos DB’s REST API. It’s worth mentioning a few of them here:

  • x-ms-date – the UTC date that’s also used in the computation of the auth token. Since the pre-request script captures this and places it in the environment file, that same variable can (and should be) used to send this header.
  • x-ms-version – the latest version of the Cosmos DB REST API is 2017-02-22 so I hard-coded that. See the Cosmos DB documentation for other versions and the features they introduced.
  • Authorization – set by the execution of the pre-request script. Interestingly, Cosmos DB Authorization headers have no scheme named in them which is something of a no-no per the HTTP specification.

Now, set the address for Postman to fetch to:

https://<<account>>.documents.azure.com/{{resourceId}}/{{resourceType}}

Where <<account>> is your Cosmos DB account name and {{resourceId}} and {{resouceType}} are resolved from the environment file as described above. When you send the request, you should get back the objects you’ve requested. If you’ve requested a lot of documents with your query, you may get an HTTP response header called x-ms-continuation as described here which would require you to use the continuation pattern to get more results.

Leave a comment

Your email address will not be published. Required fields are marked *