Frog Developer Platform

Introducing OAuth

3:16PM May 25th
3
*

The core of the Frog Development Platform is the HTTP API. FDP "widgets" are a convenient javascript environment in which to communicate with this API and present something to the user, but sometimes they are not powerful enough to achieve what you want. If you find your application needs local structured storage, you want to write it in a particular language (i.e. PHP, Ruby, Python rather than javascript), or you cannot achieve the security you need in client side programming, you will need to consider writing your own application outside the FDP widget environment.

If you write an application outside the FDP widget environment, you still need to communicate with frog data and API. You can do this using a standard protocol called oAuth. The job of "oAuth" is to safely allow an external application to authenticate against and communicate with your Frog server.

Terminology

Lets say we want to build an online assessment for our students; it requires features that make it impossible to build as a normal Frog page or as an FDP widget (our easiest options). So, instead we choose to build a separate application in our language of choice (lets say PHP). Students using this application need to authenticate using the Frog server, and the application needs to communicate with the Frog server. So our application needs to talk to Frog.

In oAuth speak, the Frog server is a Service Provider. It holds the master user details and authoriative version of data. Our application itself is called a Consumer. The user interacts with our application, which in turn interacts with the Frog server.

Connectivity Requirements

To use oAuth your application will need to speak directly to the Frogbox (the communication is direct rather than routed through the client's browser. Therefore where you host your application is important, it needs to be able to 'see' the Frog server. For example, if you host your application externally, your Frog server needs to be visible externally (not hidden behind a VPN).

Managing Consumers

Not just anyone can connect to your Frog server; you need to explicitally whitelist applications ("consumers") in the toolkit. To do this go into the toolbox, click on the “FDP” tab and then “oAuth”. Create a new consumer by filling in a name and then clicking 'Add'.

Your application will need to know its public and private key. If you click the 'show auth' link next to your new application these keys will be displayed. You will need to store this public key and secret key somewhere where you own application can access them.

It is important to realise that the oAuth model leaves full control in the hands of the Frog server (and therefore Frog administrator). In this admin interface you can enable and disable the applications that can connect to the Frogbox at any time with immediate effect. You will notice that you already have some standard consumers (such as one for our Outlook Plugin product) that we have already created on your server. Most of these you can enable and disable yourself.

Consumer Application Logic

A brief overview of the oAuth process required for our web application would be:

  1. Student arrives at my web application (not logged in yet)
  2. My application contacts the Frog server for a "request token", at the same time providing a callback URL
  3. My application redirects the user to the Frog server
  4. User is presented with a page on the Frog server allowing them to login and specifying that they are allowing access to my application
  5. User is redirected back to my application once they have logged in and allowed it
  6. My application now contacts the Frog server again to exchange the (now authorised) request token for a permenant "acess token"
  7. My application can now make a request to the API using the access token to retrieve data from the Frog server.

As you can see, it's quite a merry dance! There are many good online tutorials about the technical details of oAuth 1.0 implementation, so I will point you in that direction rather than reproduce another set here; all the information you need about the Frog implementation is detailed in the next section.

Frog oAuth Details

Frog is a standard implemention of the oAuth 1.0a protocol, and all requests must be signed with the HMAC-SHA1 algorithm.

Endpoint URL
request token http://frogserver.com/api/1/oauth1.php/request-token
authorise http://frogserver.com/app/login
access token http://frogserver.com/api/1/oauth1.php/access-token

"Out of Bounds" applications

If you are implmentating oAuth connections to your Frog server on a desktop application (e.g. an AIR or iphone app) which does not have a URL, Frog's oAuth implementation supports an "Out of Bounds" mode. When getting a request token provide the string 'oob' as the callback URL. Once the user has authenticated on the frogbox, they will be given a code to enter in your application, your application can then use this as the oAuth verification code to exchange the request token for an access token.

Connecting to the API

The HTTP API endpoint of http://frogserver.com/api/1/ is oAuth aware so you can make any requests to the existing APIs documented on this site. A particularly useful method straight after you have gained the access-token is http://frogserver.com/api/1/?method=auth.whoami.

The HTTP API supports the standard oauth parameters and signature being passed via either:

  • GET params
  • POST params
  • the Authorisation header

The header method is recommended.

An important caveat applies at this point: the platform supports oAuth connectivity but when you connect through a consumer that connection assumes all the roles of the person that has authenticated. i.e. unlike FDP widgets an oAuth consumer cannot be restricted to just a sub-section of roles and the actions they can perform are anything that they could do within the platform if they logged in directly (theoretically, obviously at this point they are restricted by what is actually in the API). Restricting consumers to a sub-set of roles is something we are working towards, but is not here yet.

Examples

We have an example hacked together PHP application that can be used as a learning tool run locally, or members of the community had added various solutions in the comments of this post.

This tutorial started life as a question from David Welch about when the oAuth documentation would be released, but it built up a useful comment trail so turned it into an actual tutorial itself (thus some of the answers being addressed to David!)

7 Comments

4:43PM May 25th
3

Hi David --

Yup, you're right our documentation is currently catching up with our actual release. We are writing a proper tutorial and will be releasing a demo application (an inter-school quiz) fairly shortly. I understand your enthusiasm to get stuck in, this is a great addition to our platform so in this reply I will include very briefly the absolute essentials that you need to start using it.

To use oAuth your school will need to have a publically accessible URL (that's not hidden behind a VPN).

Your oAuth client needs to know 3 URLs:

  • The request token endpoint is http://frogserver.com/api/1/oauth1.php/request-token
  • The authorise endpoint is http://frogserver.com/app/login
  • The access token endpoint is http://frogserver.com/api/1/oauth1.php/access-token

The HTTP API endpoint is http://frogserver.com/api/1/ is oAuth aware so you can make any requests to the existing APIm documented on this site, a particularly useful method straight after you have gained the access-token is http://frogserver.com/api/1/?method=auth.whoami (also not yet documented).

The HTTP api documented on this site is demo-ed used within FDP widgets, to use over oAuth you need to pass in the parameters as either GET or POST params (GET for retrieval, POST for an action that changes data i.e. mostly GET). The only "special" parameter is 'method', the other params are as documented. i.e. to get the user details for user id 23 and 56

http://frogserver.com/api/1/?method=user.getinfo&id=23,56

Obviously in all the above frogserver.com is your own school public URL. Any API request authenticated by oAuth will need to have a bunch more params but these are the standard params as defined by the oAuth spec.

The oAuth 1.0a specification is supported. Requests must be signed with the HMAC-SHA1 algorithm, and the authorisation can be sent in the Authorization header (preferred), POSt or GET parameters. Out-of-bounds (OOB) applications (i.e. non-web applications) are supported if the request token callback string is set to 'oob'.

To start using oAuth you must register your application on the Frogbox you wish to oAuth against. To do this go into the toolbox, click on the “FDP” tab and then “oAuth”. Create an application and then you will need to store your consumer key and secret somewhere where you application can access them.

Phew! You got all that :-P?

Some links to get you started if you're new to oAuth...

oAuth is a standard protocol so these documents and implmentation should apply, just swap out the URL endpoints for the endpoints of your own frogbox as specified above.

An important caveat applies at this point: this release brings oAuth connectivity to the platform but when you connect through a consumer that connection assumes all the roles of the person that has authenticated. i.e. unlike FDP widgets an oAuth consumer cannot be restricted to just a sub-section of roles and the actions they can perform are anything that they could do within the platform if they logged in directly (theoretically, obviously at this point they are restricted by what is actually in the API). Restricting consumers to a sub-set of roles is something we are working towards, but is not here yet.

Does that help? I think that covers the basics but we'll be releasing something a bit more friendly soon to help get you started. Any particular questions, just fire away and we'll do our best to explain.

I don't know what your language of choice is to build an oAuth app in, but if its PHP I recommend the PECL oAuth extension, super handy and does a lot of the hard work for you. - Rob Tuley
Brilliant, thanks for that... although, I don't suppose you could post a basic sample of the response that's given for a GET request to http://frogserver.com/api/1/?method=auth.whoami I'm guessing it's a similar response to twitter's response, e.g. http://apiwiki.twitter.com/w/page/22554689/Twitter-REST-API-Method:-account%C2%A0verify_credentials You might find the Quiz module on Drupal helpful for starting off with putting together an inter-school quiz, there's an OAuth connector for drupal (which is what I'm faffing around with). - David Welch
Brilliant... just managed to integrate Frog user login with Drupal, really easy, copies in ID, username (I'm guessing there's no fullname field in the API response, so I would have to concatenate firstname/surname if I wanted to use that instead), and profile image url... and keeps in sync. This is great stuff! Would still be good to see a sample 'whoami' response though, to get field mapping working I really just hit a few buttons (notably, instructing Drupal that the mapped fields are CSS selectors). - David Welch
The whoami response depends on the context a little, but if you are authenticated with oAuth as a user, the response will be identical to the user.getInfo response (bare-bones), but not as an array of user objects, just a scalar user object. Hopefully that helps enough; we'll get some proper docs up shortly. Glad to hear that the oAuth implmentation works pretty much out-of-the-box with Drupal. - Rob Tuley
7:54AM Aug 15th
1

In the spirit of sharing, below is the source for an Abobe Air oAuth pin implementation with a few calls to get the users details. It uses the https://github.com/bytespider/jsOAuth script for the heavy lifting. You can find the complete app @ http://dl.dropbox.com/u/236573/source.zip.

    $(document).ready(function(){
      var user, config;
      var api_url = '';

      config = {
        consumerKey: '',
        consumerSecret: '',
        requestTokenUrl: api_url + '/api/1/oauth1.php/request-token',        
        authorizationUrl:   api_url + '/app/login',      
        accessTokenUrl: api_url + '/api/1/oauth1.php/access-token'
      };

      var oauth = new OAuth(config);
      oauth.fetchRequestToken(auth_window, error_handler);

      function auth_window(url){
        window.open(url, 'authorise', 'height=400, width=500');
      }

      function error_handler(data){
        air.Introspector.Console.log(data);
      }

      function populate_user_data(id){
        oauth.get(api_url + "/api/1/?method=auth.whoami",
          function (response_whoami) {
            response_whoami = jQuery.parseJSON(response_whoami.text);

            oauth.get(api_url + "/api/1/?method=users.getinfo&id=" + response_whoami.data.id,
              function (response_getinfo){
                response_getinfo = jQuery.parseJSON(response_getinfo.text);
                user = response_getinfo.data[0];
                $('body').append('<div><p>hi ' + user.firstname + '.  I\'ve got the user data on ya..</p></div><table><tr><td>ID</td><td>' + user.id + '</td></tr><tr><td>UUID</td><td>' + user.uuid + '</td></tr><tr><td>Name</td><td>' + user.firstname + ' ' + user.surname + '</td></tr></table>');
                $('#authorise-pin').fadeOut();
              }, 
              error_handler
            );
          }, 
          error_handler
        );
      }

      $('#authorise-pin').submit(function(){
        pin = $('#pin').val();
        oauth.setVerifier(pin);
        oauth.fetchAccessToken(populate_user_data, error_handler);
        return false;
      });
    });
8:04PM Aug 12th
1

Here is my solution in Java for Android 2.2. It uses the Signpost OAuth library. I have cut and pasted the bits out of the class that are the most important.

    private static OAuthConsumer consumer;
private static OAuthProvider provider;

//Acquire a request token
public void Authorize() throws OAuthMessageSignerException, OAuthNotAuthorizedException, OAuthExpectationFailedException, OAuthCommunicationException 
{

    //Initialise global OAuthConsumer and OAuthProvider here
    consumer = new DefaultOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
    provider = new DefaultOAuthProvider(REQUEST_TOKEN_RESOURCE, ACCESS_TOKEN_RESOURCE, AUTHORIZE_URL);

    //Step 1 Request token from frog server
    String authurl = provider.retrieveRequestToken(consumer,OAuth.OUT_OF_BAND);

    //load the auth url in the webview
    webview.loadUrl(authurl);

This bit is a simple authorize method which sets up the consumer and provider variables. It gets the request token from the request token url via the provider passing the key and secret from within consumer along with an OOB parameter. It then prompts the webview to load the login and connect url (frog connect).

public void FetchPIN()
{
    try
    {
        webview.getSettings().setJavaScriptEnabled(true);
        webview.addJavascriptInterface(new JSInterface(), "HTMLOut");

        webview.loadUrl("javascript:window:HTMLOut.showHTML('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');");

        String html = FetchedHTML;
        if (html != "")
        {
            String divstart = "<p><strong>Your authorisation code is ";
            if (html.contains(divstart))
            {
                //found authentication page
                int lastIndexOfStartString = html.lastIndexOf(divstart);
                String[] splits = html.split("\n");
                String code = "";
                for (int i = 0; i < splits.length; i++)
                {
                    //Log.i("HTMLLINE", splits[i]);
                    if (splits[i].contains(divstart))
                    {
                        String[] linesplits = splits[i].split(" ");
                        for (int a = 0; a < linesplits.length; a++)
                        {
                            if (linesplits[a].contains(","))
                            {
                                //Log.i("KEYLINE", linesplits[a]);
                                //found key code item
                                code = linesplits[a].substring(0, 6);
                                AUTH_PIN = code;
                                Log.i("RQ", AUTH_PIN);
                                i = splits.length;
                                a = linesplits.length;
                                //Next Step is to get AccessToken
                                provider.retrieveAccessToken(consumer, AUTH_PIN);

                                ACCESS_TOKEN = consumer.getToken();
                                ACCESS_SECRET = consumer.getTokenSecret();

                                //Query the server
                                String response = SendASignedRequest("http://frog.themfg.co.uk/api/1/?method=auth.whoami");

                                //close webview and show in from
                            }
                        }
                    }
                }
            }
        }
    }
    catch (Exception e)
    {
        System.out.println("ERROR: " + e.getMessage());
    }

}

This section parses the webview and pulls the html content out. It is a bit messy so apologies for that - but it parses through HTML looking for the "Your authorisation code is " bit and extracts the authorization pin code. Examples on the web doing this step usually say "Prompt the user to goto this url and enter the pin into the application". This does an extract so you're not worrying about the user getting the pin wrong - it is frog specific though.

It stores the AUTH_PIN globally, and the requests the access token and secret through the oauth library and stores those globally.

The last step calls to the "get something from the server" method, which is shown below:

public String SendASignedRequest(String requestString) throws IOException, OAuthMessageSignerException, OAuthExpectationFailedException, OAuthCommunicationException
    {
        //ask server something
        URL url = new URL(requestString);
        HttpURLConnection request = (HttpURLConnection) url.openConnection();
        consumer.sign(request);

        System.out.println("Response: " + request.getResponseCode());
        System.out.println("Body: " + request.getResponseMessage());
        return request.getResponseMessage();
    } 

This method takes the request string (what you want to pass to the frog api, and signs the request with the consumer (and the authentication done previously). It just prints out the response code (should be 200) and the response message.

This and the code in C# above should be a good enough backbone for any mobile applications for Android, J2ME and Win Phone 7. iPhone apps will probably require different libraries - haven't really looked into any Objective-C oauth applications... yet.

2:43PM Aug 10th
1
private static String CONSUMER_KEY = "";
    private static String CONSUMER_SECRET = "";

    private static String REQUEST_URL = "http://frogserver/api/1/oauth1.php/request-token";
    private static String AUTH_END_POINT = "http://frogserver/app/login?oauth_token=";
    private static String ACCESS_END_POINT = "http://frogserver/api/1/oauth1.php/access-token";

    private static String REQUEST_TOKEN = "";
    private static String ACCESS_SECRET = "";
    private static String ACCESS_TOKEN = "";
    private static String CALLBACK_URL = "FrogTimetable:///frog";
    private OAuth.Manager oauth;
    public Form1()
    {
        InitializeComponent();
        Authorize();
    }

    public void Authorize()
    {
        //step 1 get request token
        oauth = new OAuth.Manager();
        oauth["consumer_key"] = CONSUMER_KEY;
        oauth["consumer_secret"] = CONSUMER_SECRET;
        oauth.AcquireRequestToken(REQUEST_URL, "POST");

        var url = AUTH_END_POINT + oauth["token"];
        webBrowser1.Url = new Uri(url);
    }

    private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        try
        {


        //when website loaded
        var divMarkerStart = "<p><strong>Your authorisation code is ";
        var divMarkerEnd = ",";
        String doc = webBrowser1.DocumentText;

        String substr1 = doc.Substring(doc.IndexOf(divMarkerStart) + divMarkerStart.Length);
        String substr2 = substr1.Substring(0, substr1.IndexOf(divMarkerEnd));

            if (substr2.Length < 7)
            {
                REQUEST_TOKEN = substr2; //got request token
                GetAccessToken();
            }
        }
        catch (Exception ex)
        {

            //throw;
        }

        //webBrowser1.Dispose();

        //start next stage
        //Get Access Token

    }

    public void GetAccessToken()
    {
        oauth.AcquireAccessToken(ACCESS_END_POINT, "POST", REQUEST_TOKEN);
        byte[] buf = new byte[1024];
        //get user status or frog example
        String teststr = "http://frogserver/api/1/?method=auth.whoami";
        var authHeader = oauth.GenerateAuthzHeader(teststr, "GET");
        var request = (HttpWebRequest)WebRequest.Create(teststr);
        request.Method = "GET";
        request.PreAuthenticate = true;
        request.AllowWriteStreamBuffering = true;
        request.Headers.Add("Authorization", authHeader);

        using (var response = (HttpWebResponse)request.GetResponse())
        {
            if (response.StatusCode != HttpStatusCode.OK)
            {
                MessageBox.Show("There's been a problem trying to pull from frog: " + Environment.NewLine + response.StatusDescription);

            }
            StringBuilder sb = new StringBuilder();
            System.IO.Stream stream = response.GetResponseStream();
            string tempstr = "";
            int cnt = 0;
            do
            {
                cnt = stream.Read(buf, 0, buf.Length);
                if (cnt != 0)
                {
                    tempstr = Encoding.ASCII.GetString(buf, 0, cnt);
                    sb.Append(tempstr);
                }
            }
            while (cnt > 0);

            UserInfo ui = parseUserInfo(sb.ToString());
        }

    }`enter code here`

This is a solution in C#.NET (4.0 - although it doesn't differ from 2,3 or 3.5) for OAuth in Frog. It uses an open source C# Oauth wrapper - although the other free libraries knocking around the web will do the same sort of stuff.

I am going to port this to android over the week to see if I can get any joy with that.

Had a few responses of Bad Request (400) - mainly due to incorrect use of POST and GET so watch out for that.

Hope this helps anyone looking into doing OAuth and Frog,

Marc

Brill contribution, cheers Marc - John Walker
The location of the OAuth.cs library is in this project: http://cropperplugins.codeplex.com/SourceControl/changeset/view/72088#1710422 There are others knocking around and I am developing the Android app using Scribe found through this site which has links to libraries for other languages: http://oauth.net/code/ - Marc Pruchniewicz
1:37PM Feb 28th
0

Hi All

Many libraries generate nonce of 8 chars, the frog provider requires at least 10.

5:12PM Aug 10th
0

Great stuff, our docs are very slow aren't they sorry! Will raise internally. Note that doing POSTs to the api you need to be careful with the placement of the parameters -- our api expects ?method=users.getInfo&fmt=xml in the GET paramters always, and if you need to POST, the actual params to pass to the function in the POST portion. The two are treated differently in the way the oAuth signature is built.

Ideally I'd like to be able to pull out things like the authenticated user's timetable, deadlines or something similar to start with. I will post java (android) code when its fully working and maybe an objective c version for iphone if I feel sympathetic to non-android users. - Marc Pruchniewicz
1
5:12PM Aug 10th
0

Repeated, ignore this.

Ask a Question
Widget code generator
Watch our FDP Screencasts
Download our FDP Cheat Sheet

Badges

We've introduced badges to the FDP, get involved to open up more badges.

  • gold cup badge 500+ points
  • silver cup badge101-499 points
  • red rosette badge51-100 points
  • green rosette badge6-50 points
  • blue rosette badge0-5 points

FDP Support

This site should become your first port of call for all things FDP. If you have feedback or would like to see additional services on this site please contact us on fdp@frogtrade.com

a Frog site