Category Archives: REST

Digg oAuth using Scribe

I really like the Scribe library for doing oAuth in Java.  It uses a fluent API, a very slim dependency structure, and is ready to use in android apps.  So, when I needed to connect to Digg’s API for a Java app, I looked at Scribe first.

Unfortunately, Scribe doesn’t support Digg out of the box (it does however, support Facebook, Yahoo, FourSquare, Vimeo, and many others).  Adding support for a new service is simple.

Lets start with a sample client application:

package org.scribe.examples;

import java.util.Scanner;

import org.scribe.builder.ServiceBuilder;
import org.scribe.builder.api.DiggApi;
import org.scribe.model.*;
import org.scribe.oauth.OAuthService;

public class DiggExample {
  private static final String NETWORK_NAME = "Digg";
  private static final String PROTECTED_RESOURCE_URL = "http://services.digg.com/2.0/comment.digg";

  public static void main(String[] args) {
    // Replace these with your own api key and secret
    String apiKey = "myKey";
    String apiSecret = "mySecret";
    OAuthService service = new ServiceBuilder().provider(DiggApi.class).apiKey(apiKey).apiSecret(apiSecret).build();
    Scanner in = new Scanner(System.in);

    System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ===");
    System.out.println();

    // Obtain the Request Token
    System.out.println("Fetching the Request Token...");
    Token requestToken = service.getRequestToken();
    System.out.println("Got the Request Token!");
    System.out.println();

    // Obtain the Authorization URL
    System.out.println("Fetching the Authorization URL...");
    String authorizationUrl = service.getAuthorizationUrl(requestToken);
    System.out.println("Got the Authorization URL!");
    System.out.println("Now go and authorize Scribe here:");
    System.out.println(authorizationUrl);
    System.out.println("And paste the authorization code here");
    System.out.print(">>");
    Verifier verifier = new Verifier(in.nextLine());
    System.out.println();

    // Trade the Request Token and Verfier for the Access Token
    System.out.println("Trading the Request Token for an Access Token...");
    Token accessToken = service.getAccessToken(requestToken, verifier);
    System.out.println("Got the Access Token!");
    System.out.println("(if your curious it looks like this: " + accessToken + " )");
    System.out.println();

    // Now let's go and ask for a protected resource!
    System.out.println("Now we're going to access a protected resource...");
    OAuthRequest request = new OAuthRequest(Verb.POST, PROTECTED_RESOURCE_URL);
    request.addBodyParameter("comment_id", "20100729223726:4fef610331ee46a3b5cbd740bf71313e");
    service.signRequest(accessToken, request);
    Response response = request.send();
    System.out.println("Got it! Lets see what we found...");
    System.out.println();
    System.out.println(response.getCode());
    System.out.println(response.getBody());

    System.out.println();
    System.out.println("Thats it man! Go and build something awesome with Scribe! :)");

  }
}

Simple enough – pay special attention to line 18. This is scribe’s fluent api for setting up the oAuth provider. After that, we have a pretty simple workflow – get a request token, ask the user to authorize the application, and trade the request token in for an access token.

The code to make this all work is even easier. Scribe provides 2 base classes – DefaultApi10a and DefaultApi20 (for oAuth v1.0a and oAuth v2 respectively). Since Digg’s api uses oAuth v1, we just extend DefaultApi10a and plug in the right info, like so:


package org.scribe.builder.api;

import org.scribe.model.Token;

public class DiggApi extends DefaultApi10a {

  private static final String AUTHORIZATION_URL = "http://digg.com/oauth/authorize?oauth_token=%s";
  private static final String BASE_URL = "http://services.digg.com/oauth/";

  @Override
  public String getRequestTokenEndpoint() {
    return BASE_URL + "request_token";
  }

  @Override
  public String getAccessTokenEndpoint() {
    return BASE_URL + "access_token";
  }

  @Override
  public String getAuthorizationUrl(Token requestToken) {
    return String.format(AUTHORIZATION_URL, requestToken.getToken());
  }
}

Thats it, we’re done. You can get the code here

Advertisements
Tagged , ,

A Tale of 2 Authentications

I’ve recently had the opportunity to work with the REST APIs for two great services, Dropbox & SugarSync.

For the uninitiated, SugarSync and Dropbox are two competing cloud storage providers.  While Dropbox seems to have better name recognition, SugarSync provides a better pricing model, and great support across different Operating Systems & Mobile Platforms.  However, I’m not here to talk about the merits of the products,  I’m here to talk about the APIs, specifically the Authentication methods they use, and what other API developers can learn from them

Authentication

Dropbox –  The first obstacle with a service like Dropbox is authentication.  Dropbox uses oAuth v1.  While I usually find oAuth documentation confusing (and Dropbox is no exception), it is pretty easy to master with modern toolkits.  Within a few minutes, I was able to get my Dropbox request token (in ruby):


dropboxSession = DropboxSession.new('myKey', 'mySecret')
@dropBoxRequestToken = dropboxSession.get_request_token()

As is typical with oAuth, I can then send this request token to  dropbox, they request that the user authenticate it, and I receive my access token.

SugarSync – This one is a little different.  SugarSync avoids the oAuth route, and instead provides a simple authentication method.  You make a call, providing the user’s credentials, as well as your app key & secret, SugarSync responds with an authorization token.  As opposed to oAuth, I just have to make a single POST call to https://api.sugarsync.com/authorization, and I’m done in 1 step.  Cool, huh?

What’s wrong with Sugar Sync’s authentication model?

I see this after time.

  1. Developer creates API
  2. Developer wants to avoid storing user names and passwords, so developer looks at access-token based authentication.
  3. Developer finds oAuth to be too cumbersome.
  4. Developer creates one-off token based authentication.

The error is the idea that non-oAuth, token based authentication is any more secure than simplyusing HTTP Basic Authentication (the simplest of all authentication schemes) over SSL.  The argument goes like this:

Token Authentication Defender:  If we HTTP Basic Authentication, the API clients will either have to store the user name & password, or ask the user for it each time they access the service.  We don’t want the clients to store the password, to avoid potential exposure.

Me:  How are you going to stop me from storing the password?  If I have to get the credentials from the user once, and send it to an “Authorize” call, what is going to stop me from saving it into my database?  Nothing.

Some Simple Guidelines

In this particular situation, I’d suggest that the SugarSync team move to an oAuth service.  It really is bad practice for their 3rd party apps to gain access to their users credentials.  oAuth, which slightly more complicated, provides the separation of concerns that this kind of API needs.  SugarSync should worry about username/password verification, and your app should simply sign the requests appropriately.

As for the APIs that I’ll design in the future, I’ll probably follow these (overly general) guidelines

  1. Is the API intended for a large number of 3rd party apps to access?  Is it essentially useless without the user providing credentials?  In these cases, oAuth seems like a winner.
  2. Is this an API mostly for use between various products within the same company?  Do I feel comfortable with the client applications passing through a password?  In this case, HTTP Basic Auth is the easy way out, both for the API designer and consumer.  Just make sure you use SSL.
  3. Do I have a really, really, really good reason to build a brand new authentication method?  Is my problem really unique compared to what Facebook, Twitter, or Dropbox does?  Am I prepared to open source some code and write about my solution to prevent it from becoming a one-off monster that the team will regret?  If so, maybe, just maybe, I’ll write a new authentication method…

Update 7-31-2012 Since this was written, SugarSync has changed their API to remove the need to store a users password. Definitely a step in the right direction. You can see the process here.

Tagged , , , , ,
%d bloggers like this: