twitter/joauth

Name: joauth

Owner: Twitter, Inc.

Description: A Java library for authenticating HTTP Requests using OAuth

Created: 2010-12-16 22:21:23.0

Updated: 2018-01-11 09:40:09.0

Pushed: 2017-08-23 20:52:59.0

Homepage:

Size: 466

Language: Java

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

JOAuth Build Status Coverage Status

A Java library for authenticating HTTP Requests using OAuth

Features

The Github source repository is here. Patches and contributions are welcome.

Non-Features
Building

Dependencies: commons-codec (specs & mockito-all to run the tests). These dependencies are managed by the build system.

v3.0.1 and higher - Use maven to build:

% mvn clean install

v.1.1.2 is the last version that can be built using scala 2.7.7, and now resides in the scala27 branch. v1.2 and above require scala > 2.8.1. v3.0.1 and above uses maven instead of sbt, and require scala 2.9.2

v.6.0.0 require JDK 1.6. Test require scala 2.9.2

Below v3.0.1 - Use sbt (simple-build-tool) to build:

% sbt clean update compile

The finished jar will be in dist/.

Understanding the Implementation

JOAuth consists of five traits, each of which is invoked with an apply method.

There are “Standard” and “Const” implementations of the Unpacker, Normalizer, Signer, and the Verifier traits, for easy dependency injection. Each trait has a companion object with apply methods for the default instantiation of the corresponding Standard implementations.

Usage
Basic Usage

Create an unpacker, and use it to unpack the Request. The Unpacker will either return an OAuth1Request or OAuth2Request object or throw an UnpackerException.

import com.twitter.joauth.Unpacker

val unpack = Unpacker()
try {
  unpack(request) match {
    case req: OAuth1Request => handleOAuth1(req)
case req: OAuth1TwoLeggedRequest => handleOAuth1TwoLegged(req)
    case req: OAuth2Request => handleOAuth2(req)
    case _ => // ignore or throw
  }
} catch {
  case e:UnpackerException => // handle or rethrow
  case _ => // handle or rethrow
}

Once the request is unpacked, the credentials need to be validated. For an OAuth2Request, the OAuth Access Token must be retrieved and validated by your authentication service. For an OAuth1Request the Access Token, the Consumer Key, and their respective secrets must be retrieved, and then passed to the Verifier for validation. For an OAuth1TwoLeggedRequest, the Consumer Key must be retrieved and passed to the Verifier for validation.

import com.twitter.joauth.{Verifier, VerifierResult}

val verify = Verifier()
verify(oAuth1Request, tokenSecret, consumerSecret) match {
  case VerifierResult.BAD_NONCE => // handle bad nonce
  case VerifierResult.BAD_SIGNATURE => // handle bad signature
  case VerifierResult.BAD_TIMESTAMP => // handle bad timestamp
  case VerifierResult.OK => //success!
}

That's it!

Advanced Usage
Getting Parameter Key/Values

There are two apply methods in the Unpacker trait. The one-argument version takes a Request, and the two-argument version takes a Request and a Seq[KeyValueHandler]. A KeyValueHandler is a simple trait that the Unpacker uses as a callback for every Key/Value pair encountered in either the query string or POST data (if the Content-Type is application/x-www-form-urlencoded). If there are duplicate keys, the KeyValueHandler will get invoked for each.

The JOAuth library provides a few basic KeyValueHandlers, and it's easy to add your own. For example, suppose you want to get a list of key/values, including duplicates, from the request you're unpacking. You can do this by passing a DuplicateKeyValueHandler to the unpacker.

val unpack = Unpacker()
val handler = new DuplicateKeyValueHandler
val unpackedRequest = unpack(request, Seq(handler))
doSomethingWith(handler.toList)

The DuplicateKeyValueHandler is invoked for each key/value pair encountered, and a List[(String, String)] can be extracted afterwards.

You can also construct your own KeyValueHandlers, and there are a few useful KeyValueHandlers already defined. There's a TransformingKeyValueHandler, which wraps an underlying KeyValueHandler such that either the key or value or both are transformed before the underlying handler is invoked.

For example, suppose you want to get all values of a single parameter, and you want it UrlDecoded first.

class ValuesOnlyKeyValueHandler(key: String) extends KeyValueHandler {
  val buffer = new ArrayBuffer[String]
  def apply(k: String, v: String) {
    if (k == key)
      buffer += v
  }
  def toList = buffer.toList
}

object UrlDecodingTransformer extends Transformer {
  def apply(str: String) = URLDecoder.decode(str)
}

class UrlDecodedKeyValueHandler(underlying: KeyValueHandler)
  extends TransformingKeyValueHandler(underlying, UrlDecodingTransformer, UrlDecodingTransformer)

val unpack = Unpacker()
val handler = new ValuesOnlyKeyValueHandler("SpecialKey")
val wrappedHandler = UrlDecodedMyValueOnlyKeyValueHandler(handler)
val unpackedRequest = unpack(request, Seq(wrappedHandler))
doSomethingWith(handler.toList)

Obviously it would be a little easier to just call request.getParameterValues(“SpecialKey”) in this example, but we hope it's not hard to see that passing custom KeyValueHandlers into the unpacker can be a powerful tool. In particular, they're an easy way to get access to POST data after the Unpacker has ruined your HttpServletRequest by calling getInputStream.

KeyValueHandlers are used in the JOAuth source code to collect OAuth and non-OAuth parameters from the GET, POST and Authorization header.

Other Unpacker Tricks

You can pass in a custom Normalizer or custom parameter and header KeyValueParsers to the Unpacker apply method if you really want to, but you're on your own.

Using Normalizer and Signer

You can use the Normalizer and Signer to sign OAuth 1.0a requests.

val normalize = Normalizer()
val sign = Signer()

val normalizedRequest = normalize(scheme, host, port, verb, path, params, oAuthParams)
val signedRequest = sign(normalizedRequest, tokenSecret, consumerSecret)

The parameters are passed as a List[(String, String)], and the OAuth params are passed in an OAuthParams instance.

Running Tests

The tests are completely self contained, and can be run using Maven:

% mvn test
Reporting problems

The Github issue tracker is here.

Contributors
License

Copyright 2010-2013 Twitter, Inc.

Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.