OpenID for Node.js v0.2.0 released

I am pleased to announce the release of OpenID for Node.js v0.2.0. It deserves a blog post since the new version is a bump of the minor version number. What does this mean to the users of the library?

API changes

The API of the entire thing has changed. All callbacks exposed and used by the library are now on the form callback(error, args). This convention is familiar to Node.js developers, and gives us the advantage of simpler integration with other libraries, as well as a slight increase in the fidelity of error messages.

What has changed?

  • authenticate now expects a callback which will be called with (error, authUrl). Existing code which expects (authUrl) will not get an authUrl (but possibly an error instead), and so authentication won’t work after upgrade until you change your code.
  • verifyAssertion also expects a callback of the same form, which will be called with (error, result). Again, existing code depends on receiving a (result) call, and will break.
  • loadAssociation and saveAssociation must now accept a callback on the form (error, result) as an additional parameter. Previously, these functions were synchronous, so existing implementations will have to adapt so they call the callback rather than return.

What is new?

As usual, we have fixed several bugs. The library is gaining a community, and there have been several contributions along the 0.1 release path leading up to 0.2.0. Thank you all for your participation!

Apart from the changes above, 0.2.0 also introduces a discovery cache for caching discovered information. This cache is used to avoid additional HTTP requests when verifying assertions from the OpenID providers. The default cache is an in-memory cache, but you can implement your own by overloading two functions:

  • loadDiscoveredInformation(claimedIdentifier, callback) is expected to look for and load a cached provider for the given claimedIdentifier. It is expected to call callback(error, provider) when finished, with either an error or a provider (duh).
  • saveDiscoveredInformation(provider, callback) is expected to cache the given provider. The key for this object is provider.claimedIdentifier, which loadDiscoveredInformation uses for lookup. After saving, the function is expected to call callback(error) with an error if something failed, or nothing if all went well.

I have been very reluctant to make these significant API changes, but the recent development, reported issues, and feature requests have convinced me that a unified API, and a more familiar API for Node.js developers, is the right way. Also, adapting to the new API is a pretty easy process. I hope you agree with me that the introduction of these changes is best in the long run.

Diffie-Hellman support in Node.js

Yay! My patch implementing support for Diffie-Hellman key exchange in Node.js has finally been merged into the Node.js master branch. This will simplify the OpenID for Node.js codebase a lot. It will also make the OpenID association phase run a lot faster, since the current code does Diffie-Hellman in Javascript while the Node.js crypto version does it all in native code using OpenSSL.

A brief API overview:

  • crypto.createDiffieHellman(prime_length)
    • Creates a Diffie-Hellman key exchange object and generates a prime of the given bit length. The generator used is 2.
  • crypto.createDiffieHellman(prime, encoding='binary')
    • Creates a Diffie-Hellman key exchange object using the supplied prime. The generator used is 2. Encoding can be 'binary', 'hex', or 'base64'.
  • diffieHellman.generateKeys(encoding='binary')
    • Generates private and public Diffie-Hellman key values, and returns the public key in the specified encoding. This key should be transferred to the other party. Encoding can be 'binary', 'hex', or 'base64'.
  • diffieHellman.computeSecret(other_public_key, input_encoding='binary', output_encoding=input_encoding)
    • Computes the shared secret using other_public_key as the other party’s public key and returns the computed shared secret. Supplied key is interpreted using specified input_encoding, and secret is encoded using specified output_encoding. Encodings can be 'binary', 'hex', or 'base64'. If no output encoding is given, the input encoding is used as output encoding.
  • diffieHellman.getPrime(encoding='binary')
    • Returns the Diffie-Hellman prime in the specified encoding, which can be 'binary', 'hex', or 'base64'.
  • diffieHellman.getGenerator(encoding='binary')
    • Returns the Diffie-Hellman prime in the specified encoding, which can be 'binary', 'hex', or 'base64'.
  • diffieHellman.getPublicKey(encoding='binary')
    • Returns the Diffie-Hellman public key in the specified encoding, which can be 'binary', 'hex', or 'base64'.
  • diffieHellman.getPrivateKey(encoding='binary')
    • Returns the Diffie-Hellman private key in the specified encoding, which can be 'binary', 'hex', or 'base64'.
  • diffieHellman.setPublicKey(public_key, encoding='binary')
    • Sets the Diffie-Hellman public key. Key encoding can be 'binary', 'hex', or 'base64'.
  • diffieHellman.setPrivateKey(public_key, encoding='binary')
    • Sets the Diffie-Hellman private key. Key encoding can be 'binary', 'hex', or 'base64'.

NOTE: The API is still subject to change.

I would appreciate getting a note if you actually do something useful with it. :) Play around with it and let me know what you think!

OpenID for node.js

I am happy to announce the immediate availability of my implementation of OpenID for node.js. I’ve spent a few nights working on this, which is my first node.js library, and I finally got to the point where the library was complete enough for a first public release.

Installation

Installing is very simple using npm:

npm install openid 

If you don’t use npm, you can of course just download and require. Remember dependencies from the lib folder, and remember adding paths to require.paths if necessary.

Usage

One of the main design goals for the library has been simplicity. Using OpenID for node.js is pretty simple, here’s a minimal sample server:

var openid = require('openid');
var url = require('url');
var server = require('http').createServer(
    function(req, res)
    {
        var parsedUrl = url.parse(req.url, true);
        if(parsedUrl.pathname == '/verify')
        {
            // Verify identity assertion
            var result = openid.verifyAssertion(req); // or req.url
            res.writeHead(200);
            res.end(result.authenticated ? 'Success :) ' : 'Failure :( ');
        }
        else if(parsedUrl.pathname == '/authenticate')
        {
            // Resolve identifier, associate, build authentication URL
            openid.authenticate(
                parsedUrl.query.openid_identifier, // user supplied identifier
                'http://example.com/verify', // our callback URL
                null, // realm (optional)
                false, // attempt immediate authentication first?
                function(authUrl)
                {
                    res.writeHead(302, { Location: authUrl });
                    res.end();
                });
        }
        else
        {
            // Deliver an OpenID form on all other URLs
            res.writeHead(200);
            res.end('<!DOCTYPE html><html><body>'
                + '<form method="get" action="/authenticate">'
                + '<p>Login using OpenID</p>'
                + '<input name="openid_identifier" />'
                + '<input type="submit" value="Login" />'
                + '</form></body></html>');
        }
    });
server.listen(80);

Source

I use GitHub for source control, so you can follow me and the node-openid repository there.

Licensing

OpenID for node.js is licensed under the MIT license. Details can be found in the LICENSE file on GitHub. The library includes third-party code released under the MIT and BSD licenses, see README for details.

Wishes for node.js

I’ve come across a couple of missing features which I’d love to see in node.js in the near future:

  • The crypto module should support Diffie-Hellman key exchange (OpenSSL supports it, so please provide bindings)
  • A big integer library should be available alongside the crypto module, and preferably seamlessly integrated with the crypto module – perhaps bindings to the GMP library could suffice?
  • More seamless unit testing libraries would be good

In addition, I would love to see a tailored IDE for node.js applications.

AJAST – Cross-domain REST calls using JSON injection

The typical (and original AJAX) approach to calling web services asynchronously from a browser uses the XMLHTTPRequest object to request data asynchronously. However, as most of you probably already know, requests made using this object are restricted to the same domain as the script they originate from. This means that in order to request data from services like Google Maps, Flickr, etc. you need to implement a server-side proxy on your domain to use the XMLHTTPRequest object. But what if you want to stay on the client side? Enter JSON injection.

JSON injection, or actually script tag injection, is a rather common technique that circumvents the XMLHTTPRequest limitation by dynamically injecting script tags into the calling page. A script tag can have any domain as its source, which means that cross-domain calls are possible. The technique is also referred to as JSON callbacks, although it really is not limited to JSON payloads. The technique is also referred to as JSONP, although the original JSONP is a bit more extensive than just callbacks using script injection.

It really is a neat technique without a cool term. JSONP is a term for a superset of JSON injection. A more precise term than JSON injection would be Javascript injection, but that’s already used to describe vulnerabilities in web pages where malicious Javascript code is injected through e.g. links from external sites. I hereby propose the term AJASTAsynchronous Javascript And Script Tags. At least it’ll be the name of my implementation. If it doesn’t catch on for anything but that, we’ll even be a bit more confused than we already are. Now, what do we require to do AJAST?

AJAST requirements

The requirements an AJAST request lays on the server-side are the following:

  1. The server must provide its services through HTTP GET requests.
  2. The client must be able to supply the name of a callback function that the response will be wrapped in.
  3. The server is expected to provide a response on the form callback(payload), where callback is the name of the callback function supplied by the client, and payload is the payload returned by the server. The payload can be XML, JSON, or any other form of data that the Javascript callback function can accept as a single argument.

These requirements are already fulfilled by many REST services, but they are still hard to use in an AJAST fashion due to client side challenges. The two main requirements for an AJAST library are:

  1. Complete handling of requests. Nothing more than a URL and a callback should be needed to create a request.
  2. Timeouts is a show stopper for AJAST. With script injection, it is difficult to know if a call completes, and from an AJAST usage perspective it is essentially impossible to create a decent solution without knowing if requests complete or not.

Security is another obvious challenge, although in my view it is a challenge for the Internet in general rather than AJAST in particular. Developers creating cross-domain applications should be aware of the security risks involved, and take measures to prevent security breaches accordingly. There is no silver bullet.

Although several examples for implementing an AJAST request are found around the web, I found no fully functional stand-alone implementations. Dan Theurer’s article on script requests provides code that can be used to create an implementation, but leaves the timeout problem unsolved. Toolkits such as Dojo also implement variations on the approach using IFrame requests, but they are a lot more hairy, and I really don’t want a framework (or parts of it) bloating the web site I am creating just to be able to do AJAST. I want a library that can perform just the task that I want it to perform, and perform it well.

An AJAST library

So, I decided to create my own AJAST library, OX.AJAST, complete with the following features:

  • A fully encapsulated mechanism for making AJAST calls
    You simply supply a URL, the name of the callback parameter that will be appended to the URL, and a callback function.
  • Support for timeouts
    Remote requests can of course time out, and time outs need to be handled. Apart from the obvious security challenges involved with using AJAST (note that I’m not saying they’re defects, they’re challenges for us developers to handle) , this is the hardest challenge for AJAST requests. Without the ability of specifying timeouts, we’re essentially in the dark with regards to whether or not a request will complete. OX.AJAST neatly supports timeouts by wrapping the supplied callbacks, putting on a timer, and checking for completion when the timer times out.
  • Guarantee that the callback function will be called
    Whatever happens, and as a direct consequence of the timeout support, the library guarantees that the callback function will be called. For this reason, the callback function must accept two arguments, the first a boolean indicating if the request succeeded or not, the other a string containing the response from the call. If the first argument is false, the call may have timed out or failed.

Using the AJAST call function

There are two ways of using OX.AJAST. The simplest is to use the call function.

  // Create a function that will be called when the AJAST request completes
  function callCompleted(success, data)
  {
    if(!success)
      alert('Fail');
    else
      alert('Received: ' + data);
  }
  // Call a service
  OX.AJAST.call(
    'http://xampl.com/rest?arg=foo', 
    'callback', 
    callCompleted);

The call function will execute the request by appending &callback=wrapper to the URL and injecting a <script> tag with the final URL as the src attribute. This will add a call to the DOM as soon as the data is received, which the browser will execute.

The function called from the injected script tag is a wrapper around the callCompleted function provided to the call function. The wrapper function is created by the call function, and handles timeouts and deletion of the script tag after the callCompleted function completes. As mentioned, by using this wrapper, the AJAST library can guarantee that callCompleted will be called, which significantly eases the handling of asynchronous calls for users of the library.

The function also allows you to specify how long the request will wait for a response before it times out. The default timeout is 5 seconds. Finally, you can pass an argument specifying if you want the response to be automatically decoded from JSON before it is passed to your callback function.

// Call with a 10 second timeout, decode JSON response
OX.AJAST.call(
  'http://xampl.com/rest?arg=foo', 
  'callback', 
  callCompleted, 
  10000, 
  true);

As stated above, all callback functions must be on the form callbackfunction(success, data){}, where success indicates whether or not the asynchronous call succeeded, and data is any data that was received from the call. It is also important to note that data may be undefined, but success will always be true or false.

Using the AJAST broker

The AJAST broker encapsulates a common pattern for REST requests using HTTP GET. Many RESTful services found online typically use some kind of root URL of the form http://xampl.com/rest as the base URL for all their REST services. The query string determines which service is requested, as well as the arguments for the service.

For the services that follow this pattern, the AJAST library provides a Broker class that encapsulates the process of calling the REST services.

The example below shows how the request from the first example can be made using the broker.

// Create a broker object
var broker = new OX.AJAST.Broker(
  'http://xampl.com/rest', 
  'callback'
);
// Perform the same call using the broker
broker.call({arg: 'foo'}, callCompleted);

The broker also supports the specification of a timeout limit, automated JSON decoding, and also provides the option of passing a set of default arguments that will be passed with every request, such as a Flickr API key.

// Create a broker object
var broker = new OX.AJAST.Broker(
  'http://xampl.com/rest', 
  'callback', 
  true, // Decode JSON response
  10000, // Timeout in ms
  {APIKey : '123'} // Default parameters
);

Now let’s do something useful with it.

A real example: Flickr using AJAST

To keep the example as simple as possible, we’ll create the functions necessary for a page which fetches the most recent photos from Flickr.

Luckily, Flickr supports REST and JSON callbacks in a lovely manner, so we’ll use the broker for our calls.

function flickrGetRecent()
{
  // Create  a broker
  var broker = new OX.AJAST.Broker(
    'http://api.flickr.com/services/rest/', 
    'jsoncallback', 
    true, 
    10000,
    {api_key: 'YourVeryOwnFlickrApiKey', 
      format: 'json'});</p>

<p>// Perform the call
  broker.call(
    {method: 'flickr.photos.getRecent'}, 
    recentFetched);
}

We’ve told the broker to call a function named recentFetched when the recent photos have been fetched, so let’s implement that as well. To keep the example simple, we’ll just append the photos to the body of the document.

function recentFetched(success, rsp)
{
  // Check for failure
  if(!success || !rsp || rsp.stat != 'ok')
  {
    alert('Call failed');
    return;
  }</p>

<p>// For each photo...<br />
  for(i in rsp.photos.photo)
  {
    photo = rsp.photos.photo[i];</p>

<pre><code>// Create an img element
img = document.createElement('img');

// Set its source to a valid Flickr URL
img.setAttribute('src', 
  'http://farm' + (photo.farm || 1) + 
  '.static.flickr.com/' + photo.server + 
  '/' + photo.id + '_' + photo.secret + '_t.jpg');

// Append the element
document.body.appendChild(img);
</code></pre>

<p>}
}

Now we just have to call flickrGetRecent from somewhere in a document, and the most recent photos will be appended to the document. A full example can be seen here. Note that you will need a Flickr API key to test it.

As you can see, the OX.AJAST library is really easy to use, and enables you to do pure client-side REST service calls across domain boundaries with hardly any effort. I hope you find it useful. Drop a comment if you have problems or suggestions, or if you create improvements to it. Now start using AJAST!