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
Size: 466
Language: Java
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
A Java library for authenticating HTTP Requests using OAuth
The Github source repository is here. Patches and contributions are welcome.
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/
.
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.
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!
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.
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.
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.
The tests are completely self contained, and can be run using Maven:
% mvn test
The Github issue tracker is here.
Copyright 2010-2013 Twitter, Inc.
Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0