§OAuth
OAuth is a simple way to publish and interact with protected data. It’s also a safer and more secure way for people to give you access. For example, it can be used to access your users’ data on Twitter.
There are 2 very different versions of OAuth: OAuth 1.0 and OAuth 2.0. Version 2 is simple enough to be implemented easily without library or helpers, so Play only provides support for OAuth 1.0.
§Usage
To use OAuth, first add javaWs
to your build.sbt
file:
libraryDependencies ++= Seq(
javaWs
)
§Required Information
OAuth requires you to register your application to the service provider. Make sure to check the callback URL that you provide, because the service provider may reject your calls if they don’t match. When working locally, you can use /etc/hosts
to fake a domain on your local machine.
The service provider will give you:
- Application ID
- Secret key
- Request Token URL
- Access Token URL
- Authorize URL
§Authentication Flow
Most of the flow will be done by the Play library.
- Get a request token from the server (in a server-to-server call)
- Redirect the user to the service provider, where he will grant your application rights to use his data
- The service provider will redirect the user back, giving you a /verifier/
- With that verifier, exchange the /request token/ for an /access token/ (server-to-server call)
Now the /access token/ can be passed to any call to access protected data.
§Example
conf/routes
:
GET /twitter/homeTimeline controllers.Twitter.homeTimeline()
GET /twitter/auth controllers.Twitter.auth()
controller:
import play.libs.F.Function;
import play.libs.F.Option;
import play.libs.F.Promise;
import play.libs.oauth.OAuth;
import play.libs.oauth.OAuth.ConsumerKey;
import play.libs.oauth.OAuth.OAuthCalculator;
import play.libs.oauth.OAuth.RequestToken;
import play.libs.oauth.OAuth.ServiceInfo;
import play.libs.ws.WSClient;
import play.libs.ws.WSResponse;
import play.mvc.Controller;
import play.mvc.Result;
import com.google.common.base.Strings;
import javax.inject.Inject;
public class Twitter extends Controller {
static final ConsumerKey KEY = new ConsumerKey("...", "...");
private static final ServiceInfo SERVICE_INFO = new ServiceInfo("https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
"https://api.twitter.com/oauth/authorize",
KEY);
private static final OAuth TWITTER = new OAuth(SERVICE_INFO);
private final WSClient ws;
@Inject
public Twitter(WSClient ws) {
this.ws = ws;
}
public Promise<Result> homeTimeline() {
Option<RequestToken> sessionTokenPair = getSessionTokenPair();
if (sessionTokenPair.isDefined()) {
return ws.url("https://api.twitter.com/1.1/statuses/home_timeline.json")
.sign(new OAuthCalculator(Twitter.KEY, sessionTokenPair.get()))
.get()
.map(new Function<WSResponse, Result>(){
@Override
public Result apply(WSResponse result) throws Throwable {
return ok(result.asJson());
}
});
}
return Promise.pure(redirect(routes.Twitter.auth()));
}
public Result auth() {
String verifier = request().getQueryString("oauth_verifier");
if (Strings.isNullOrEmpty(verifier)) {
String url = routes.Twitter.auth().absoluteURL(request());
RequestToken requestToken = TWITTER.retrieveRequestToken(url);
saveSessionTokenPair(requestToken);
return redirect(TWITTER.redirectUrl(requestToken.token));
} else {
RequestToken requestToken = getSessionTokenPair().get();
RequestToken accessToken = TWITTER.retrieveAccessToken(requestToken, verifier);
saveSessionTokenPair(accessToken);
return redirect(routes.Twitter.homeTimeline());
}
}
private void saveSessionTokenPair(RequestToken requestToken) {
session("token", requestToken.token);
session("secret", requestToken.secret);
}
private Option<RequestToken> getSessionTokenPair() {
if (session().containsKey("token")) {
return Option.Some(new RequestToken(session("token"), session("secret")));
}
return Option.None();
}
}
Next: Integrating with Akka