HTTPjs – a new API debugging, prototyping and test tool

Today, we released a new API debugging, prototyping and test tool that is available at:

When you arrive at the site, you’ll immediately be delegated a separate sub domain, such as http://f12.http.net. This subdomain is now ready to receive any kind of HTTP requests. At the site, you get a javascript editor window, where you can prototype the server side of the API server.

All requests sent to your new domain, will be processed in your browser with your custom javascript implementation. The web site will display the full HTTP log for you to inspect.

This tool is very useful for rapid development, and testing of API clients. In example, you may select a template OAuth Server implementation to start from, then attempt to return variations, invalid responses and similar to inspect how your client behaves.

The tool was made possible with Node.js, Websockets with Socket.io, Expressjs, requirejs, Grunt, Bower.io, nconf, select2, ace, bootstrap, momentjs, highlightjs.

OAuth 2.0 with Phonegap + ChildBrowser using the JSO library

Aside

This document is also the README-Phonegap.md of the JSO library.

Using JSO with Phonegap and ChildBrowser

Using JSO to perform OAuth 2.0 authorization in WebApps running on mobile devices in hybrid environment is an important deployment scenario for JSO.

Here is a detailed instruction on setting up JSO with Phonegap for iOS and configure OAuth 2.0 with Google. You may use it with Facebook or other OAuth providers as well.

Preparations

Setup App

To create a new App

./create  /Users/andreas/Sites/cordovatest no.erlang.test "CordovaJSOTest"

Install ChildBrowser

The original ChildBrowser plugin is available here.

However, it is not compatible with Cordova 2.0. Instead, you may use this fork of ChildBrowser which should be working with Cordova 2.0:

What you need to do is to copy these files:

in to your WebApp project area, by using drag and drop into the Plugins folder in XCode.

Now you need to edit the file found in Resources/Cordova.plist found in your WebApp project area.

In this file you need to add one array entry with ‘*’ into ExternalHosts, and two entries into Plugins:

  • ChildBrowser -> ChildBrowser.js
  • ChildBrowserCommand -> ChildBrowserCommand

as seen on the screenshot.

Setting up your WebApp with ChildBrowser

I’d suggest to test and verify that you get ChildBrowser working before moving on to the OAuth stuff.

In your index.html file try this, and verify using the Simulator.

<script type="text/javascript" charset="utf-8" src="cordova-2.0.0.js"></script>
<script type="text/javascript" charset="utf-8" src="ChildBrowser.js"></script>
<script type="text/javascript">

    var deviceready = function() {
        if(window.plugins.childBrowser == null) {
            ChildBrowser.install();
        }
        window.plugins.childBrowser.showWebPage("http://google.com");
    };

    document.addEventListener('deviceready', this.deviceready, false);

</script>

Setting up JSO

Download the latest version of JSO:

The documentation on JSO is available there as well.

The callback URL needs to point somewhere, and one approach would be to put a callback HTML page somewhere, it does not really matter where, although a host you trust. And put a pretty blank page there:

<!doctype html>
<html>
    <head>
        <title>OAuth Callback endpoint</title>
        <meta charset="utf-8" />
    </head>
    <body>
        Processing OAuth response...
    </body>
</html>

Now, setup your application index page. Here is a working example:

<script type="text/javascript" charset="utf-8" src="cordova-2.0.0.js"></script>
<script type="text/javascript" charset="utf-8" src="ChildBrowser.js"></script>
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
<script type="text/javascript" charset="utf-8" src="jso/jso.js"></script>
<script type="text/javascript">

    var deviceready = function() {

        /*
         * Setup and install the ChildBrowser plugin to Phongap/Cordova.
         */
        if(window.plugins.childBrowser == null) {
            ChildBrowser.install();
        }

        // Use ChildBrowser instead of redirecting the main page.
        jso_registerRedirectHandler(window.plugins.childBrowser.showWebPage);

        /*
         * Register a handler on the childbrowser that detects redirects and
         * lets JSO to detect incomming OAuth responses and deal with the content.
         */
        window.plugins.childBrowser.onLocationChange = function(url){
            url = decodeURIComponent(url);
            console.log("Checking location: " + url);
            jso_checkfortoken('facebook', url, function() {
                console.log("Closing child browser, because a valid response was detected.");
                window.plugins.childBrowser.close();
            });
        };

        /*
         * Configure the OAuth providers to use.
         */
        jso_configure({
            "facebook": {
                client_id: "myclientid",
                redirect_uri: "https://myhost.org/callback.html",
                authorization: "https://www.facebook.com/dialog/oauth",
                presenttoken: "qs"
            }
        });

        // For debugging purposes you can wipe existing cached tokens...
        // jso_wipe();
        jso_dump();

        // Perform the protected OAuth calls.
        $.oajax({
            url: "https://graph.facebook.com/me/home",
            jso_provider: "facebook",
            jso_scopes: ["read_stream"],
            jso_allowia: true,
            dataType: 'json',
            success: function(data) {
                console.log("Response (facebook):");
                console.log(data);
            }
        });

    };

    document.addEventListener('deviceready', this.deviceready, false);

</script>

OAuth 2.0 Providers and State

It seems there is a bunch of OAuth 2.0 providers that does not support the (required to be supported) state parameter.

I just updated the jso library to be able to deal with that.

When you are unable to keep state, you’ll run into at least two challenges:

  • you don’t know from who the access token is sent (if you accept multiple providers on the same callback)
  • you don’t know what scopes you sent in the request. It would be natural to fallback to this scope in your token cache, if scopes were not provided in the response. Now, instead, you need to configure global scope fallbacks.

The jso documentation is updated, on how to deal with this.

Web Application Cloud Engine for edu. Teaser: App Store

I’m currently working with a web application cloud engine, and this is a teaser of a very simple application running in the engine, representing a kind of an App Store making use of open APIs.

Soon we’ll present more advanced web application demos making use of distributed and highly available cloud storage, cross-federated authentication, privacy controls, SOA gatekeeper, and a whole lot of sparkling OAuth love and magic. We may run into WebDAV, WebFinger, Contact search, Invitation, group exchange with VOOT, notifications, gadgets and a lot more.

Stay tuned for updates.

Best-Practice for dealing with OAuth 2.0 Token expiration at the Consumer

Not dealing properly with token validity can cause rare and unwanted effects for end-users. You don’t want to do that. This documents tries to sum up the best practice on this.

Estimate the validity period of an obtained token

When the consumer obtains a new access token, it will usually store the token in some storage for potential future use. It is very reccomended to also estimate the validity period for a token when sent to storage, in order to know that the token is expired without the need to “test” it.

At the time the consumer receives an access token response, the validity period of the token can be decided using any of these indicators, in the given order:

  • The expires_in property in the access token response. This value is reccomended to be included by the provider.
  • A special scope indicating validity period of the token. In example a scope offline may be defined to mean infinite validity.
  • A default value of validity period, typically per provider.
  • A default value of the consumer implementation, if none of the above is given. It may be infinite, or it may be a limited period.

Note 1: there is no way to indicate infinite validity period in the expires_in property (unfortunately).

Note 2: Of the indicators listed above, only the expires_in parameter is obtained in a standarized way. All other parameters are somehow configured in the client, based upon textual documentation of the provider API, or out of band agreements.

Detecting an expired tokens when using it

Even if you follow best-practice to associate a stored access token with a validity period, for a number of reasons you also should be able to deal with the fact that the token is invalid even if you assume it is valid:

  • the OAuth spec does not provide measures to protect against clock skew
  • as all of the indicators (except expires_in) are defined in documentation, out of band or manually entered, if the default value of the provider changes, the consumer is unlikely to adopt to the new validity period immediately.
  • the token may be invalidated by other means at the provider than expiration. There is no mechamisms built in for notifying the consumer about a token being invalidated.

Consequently, a consumers will have to deal with the situation of using an expired token.

First, it is extremely important that the consumer is able to detect the difference between generic errors at the protected endpoint and errors due to an expired token. If and only if the token is expired it is very important that the consumer uses the refresh token or starts a new flow to obtain a new valid token.

The OAuth 2.0 Core spec does not mention with a single word how to detect expired tokens. Instead this is discussed in each of the token type specs, including the popular Bearer Tokens.

For the bearer tokens, an expired token will result in the following response from a protected endpoint:

HTTP/1.1 401 Unauthorized 
WWW-Authenticate: Bearer realm="example", 
    error="invalid_token", 
    error_description="The access token expired"

The consumer should check for both the status code 401, and that the error field is set to invalid_token before requesting a new token from the provider.

Facebook

Facebook claims to be using OAuth 2.0 for its graph API. OAuth 2.0 library writers will have to balance facebook and spec compliance with care.

When a consumer uses an expired token, Facebook responds with:

HTTP/1.1 400 Bad Request
WWW-Authenticate: OAuth "Facebook Platform" "invalid_token" 
    "Error validating access token: Session has expired 
    at unix time 1334415600. The current unix time is 1334822619."

It could be tempting to treat all 4XX responses as expired tokens, but that is not reccomended.

Instead I would provide a specific fallback for Facebook, like this:

if (status_code === 401 && parsed_www_authenticate["error"] === "invalid_token")
    throw new InvalidTokenException();
if (status_code === 400 && 
        www_authenticate contains 'OAuth "Facebook Platform" "invalid_token"')
    throw new InvalidTokenException();

Other broken providers

If you know about other popular providers that do not follow the specification on expired tokens, contact me and I’ll adjust this document.

Federated OAuth 2.0 SAML VOOT Chat Proof of Concept

Today I’m demoing a proof of concept chat service making use of federated Login and cross-federated group exchange with the VOOT protocol. The chat application is written in Javascript, and is making use of HTML5 WebSockets for Real time communication. The server side is running on Node.js.

The javascript client is using OAuth 2.0 implicit grant with the JSO library we recently released. The user access token is requested with a specific scope for having access to groups. The access token is cahced in localstorage, and send to the chat server during the first registration message. The VOOT provider is done using a new PHP OAuth 2.0 library we have not released yet. It supports using MongoDB and Mysql for storage.

This is only a simple demo of what cross-federated real-time collaboration software can be like. Next step could be adding WebRCT video or audio, file, slide sharing etc.

See also:

Releasing an OAuth 2.0 Javascript Library

In case anyone find it useful, here is a new OAuth 2.0 javascript library.

It would be useful for me if people tested it and reported any problems. I have limited access to alternative OAuth 2.0 provider implementations, so I’ve only tested a few of the commercial ones so far.

Some use cases, where I think this is useful:

  • given an API with CORS support.
  • in native web apps running in example phone gap, running in file:// context and are thereby not limited by same-origin.
  • in situations where you bypass the token to your own proxying webserver, but would like to setup the tokens etc using javascript for more control of the user interface.

Feedback is welcome.

Complicated Flows, OpenSocial, OpenID Connect, Discovery and Consent

I’m currently working on some projects involving a bit more complicated “flows”, than I’m used to.

We’re used to work with Identity Providers communicating with Service Providers, and that’s more or less it. What we will see, is service providers communicating with each others, and consumers retrieving information from multiple sources.

OAuth will play a significant role in this new game.

I believe our challenges and headaches are moved from complex protocols and simple flows, to maintaining a simple and intuitive user experience with simple protocols, but much more complex architectures and flows.

Here is an example that I’m currently struggling with;

We will create a Foodle OpenSocial Gadget that runs inside the SurfConext OpenSocial Container, to present an aggregated free/busy information with availability information for when members of the current group context is available for a meeting.

Here is how it will work (by default). Worth mentioning, this is the worth case scenario, much of the consent and choices are remembered for subsequent flows.

Foodle offers a Gadget, installed in a space in the SurfConext portal.

  1. The user heads to the portal.
  2. The user do Identity Provider Discovery at SurfConext.
  3. The user logs in to the IdP.
  4. The user performs consent to accept user data is sent from IdP to SurfConext.
  5. The user can now access the portal, and moves on to a space where the Foodle gadget is installed.
  6. The user will need to consent that the Foodle Gadget is accessing the OpenSocial context.
  7. The Foodle Gadget would need to establish a trusted connection with the Foodle Backend using the Foodle third-party REST API, starting the three-legged OAuth dance. This will involve a popup window.
  8. Part of the three-legged OAuth dance, first goes IdP Discovery.
  9. Next the user logs in, most likely this bullet is skipped due to Single Sign-On.
  10. User needs to consent that attributes are released from the IdP to Foodle.
  11. Then, the user needs to consent that the Foodle Gadget instance is allowed to access Foodle content on behalf of the current user.
  12. Now, the Gadget has established a trusted connection to the Foodle backend, the Foodle Gadget has access to the group context through the OpenSocial javascript API, but yet, the Foodle backend does not have access to the group context. To allow that, the Foodle backend would need to do a three-legged Oauth dance with the SurfConext Container OpenSocial REST API. And to start that the backend would need control of the user, so the Gadget has to somehow do a popup window (again).
  13. Part of the three-legged OAuth dance, the user has to consent that the Foodle Backend can access the OpenSocial conext (including group info) at the SurfConext portal OpenSocial REST API.
  14. Now, the Foodle Gadget performs a protected OAuth call to the Foodle Backend through the OpenSocial Javascript API, for the free/busy data. In the request body, the current group context is included.
  15. The Foodle Backend performs a protected Oauth call to the OpenSocial REST API to get the group members of the current group, and verifies that the current user is member of the group.
  16. The Foodle backend uses a yet to be detirmined protocol to explore the CALdav/iCalendar Free/busy endpoints for each of the group members.
  17. The Foodle backend retrieves free/busy data using CALDav or similar.
  18. The Foodle backend responds with free/busy data to the Foodle Gadget.
  19. The Foodle gadget displays the data to the end user.

This will result in an unacceptable user experience. Involving popups, and no less than 5 consent screens and two IdP discoveries.

There are tons of approaches to optimize this particular use case, but I’m more interested in the more generic solutions to the flow of this and similar integrations. So that’s one of the many things I’m thinking about these days.

Aggregated free busy is already implemented last year as one of the group-aware features on Foodle – read more…

One thought; I’ve earlier thought of the main motivation to replace SAML with OpenID Connect, would be the simpler protocol, but I’m tending to say that a simpler flow of future use cases would be the best selling point of OpenID Connect.