Skip to content

Instantly share code, notes, and snippets.

@blindman2k
Last active August 29, 2015 14:15
Show Gist options
  • Save blindman2k/6aa0b03aaf0cdfec5bb8 to your computer and use it in GitHub Desktop.
Save blindman2k/6aa0b03aaf0cdfec5bb8 to your computer and use it in GitHub Desktop.
Demonstration of some different ways of authenticating a http request using a static shared key.

Securing Electric Imp agents acting as API providers

There are a myriad of different ways to secure requests to agent URLs. By default, all requests have three simple security features:

  1. the unique URL for each device is randomly generated during the BlinkUp process;
  2. the commands required to activate the agent are unknown to anyone but the developers; and
  3. all requests to https://agent.electricimp.com are SSL encrypted which prevents anyone from sniffing the contents of any request.

For many applications, this encryption plus obfuscation is sufficient security, especially if the requests to the agent are coming from a server or a controlled application. If further security/obfuscation is required we propose a few simple and common methods here. These methods also provide a bonus feature that, if the security is compromised at any point in the future, the parameters can be easily changed to reassert the security.

The four examples are:

  1. simple_auth_1 - this is the neatest and least visible technique as the shared API key is delivered "out of band" in the HTTP headers. This is the recommended approach.
  2. simple_auth_2 - this approach requires that an extra query parameter be added to the end of every request containing the API key. This approach works best when the development tools available are very simple and don't allow for HTTP headers to be added.
  3. simple_auth_3 - this is a simple but rarely seen technique for embedding the API key into the URL path itself. Again, this works best when the development tools available are very simple and don't allow for HTTP headers to be added.
  4. rocky_auth_4 - the final example demonstrates one approach to using the Rocky framework for creating powerful RESTful APIs in agents. There are other built-in functions that simplify the process of responding to HTTP requests and is roughly modelled on the Express framework for Node.js.

All of these techniques are limited to API calls from servers or applications and are not effective security measures for use by a web browser. Different techniques, usually involving unique users, login prompts and session authentication should be considered. Alternatives such as third-party OAuth authentication are particularly effective if your user base overlaps with other services such as Google, Facebook or Twitter.

// Note that this requires access to the Libraries feature of the imp platforms.
#require "rocky.class.nut:1.*"
// Generate a random uuid as an API key from https://www.uuidgenerator.net
const API_KEY = "11834b91-9194-405b-b29f-7dc423bc043b";
app <- Rocky();
// This expects a standard HTTP basic authorisation header
// Authorization: Basic YXBpa2V5OjExODM0YjkxLTkxOTQtNDA1Yi1iMjlmLTdkYzQyM2JjMDQzYg==
app.authorize(function(context) {
return context.auth.pass == API_KEY;
})
// Handle any verb used against the root (/) url path. If it gets here, it is already authenticated.
app.on("*", "/", function(context) {
context.send(200, "Access granted");
});
// Generate a random uuid as an API key from https://www.uuidgenerator.net
const API_KEY = "11834b91-9194-405b-b29f-7dc423bc043b";
// This function checks the API key is in the header "X-API-Key"
// X-API-Key: 11834b91-9194-405b-b29f-7dc423bc043b
function simple_auth_1(req, res) {
// Check the API key of every request
if (!("x-api-key" in req.headers) || req.headers["x-api-key"] != API_KEY) {
res.send(401, "Access denied");
return;
}
// Access granted, do something
res.send(200, "Access granted");
}
// Assign a callback handler for incoming HTTP requests
http.onrequest(simple_auth_1);
// Generate a random uuid as an API key from https://www.uuidgenerator.net
const API_KEY = "11834b91-9194-405b-b29f-7dc423bc043b";
// This function checks the API key is in the query parameter "apikey"
// https://agent.electricimp.com/xxxxxxxxxxx/?apikey=11834b91-9194-405b-b29f-7dc423bc043b
function simple_auth_2(req, res) {
// Check the API key of every request
if (!("apikey" in req.query) || req.query["apikey"] != API_KEY) {
res.send(401, "Access denied");
return;
}
// Access granted, do something
res.send(200, "Access granted");
}
// Assign a callback handler for incoming HTTP requests
http.onrequest(simple_auth_2);
// Generate a random uuid as an API key from https://www.uuidgenerator.net
const API_KEY = "11834b91-9194-405b-b29f-7dc423bc043b";
// This function checks the API key is the first item in the URL path
// https://agent.electricimp.com/xxxxxxxxxxx/11834b91-9194-405b-b29f-7dc423bc043b/doSomethingB
function simple_auth_3(req, res) {
// Check the API key of every request
local path = split(req.path, "/");
if (path.len() == 0 || path[0] != API_KEY) {
res.send(401, "Access denied");
return;
}
// Access granted, do something
res.send(200, "Access granted");
}
// Assign a callback handler for incoming HTTP requests
http.onrequest(simple_auth_3);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment