How to create a oAuth request using java?

J888 picture J888 · Jul 18, 2013 · Viewed 24.4k times · Source

I need to make a connection with Viagogo website using oAuth. Referring to their documentation I need to create a request similar to the following one

Using the example in step 1A, this means you may generate a signature base string that looks like the following:

GET&http%3A%2F%2Fapi.viagogo.net%2FPublic%2FSimpleOAuthAccessRequest&oauth_consumer_key%3Dtestkey%26oauth_nonce%3Dmyn0nc3%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1292404912%26oauth_version%3D1.0%26scope%3DAPI.Public

I am using the following code but when I comment lines 1,2 it return unauthorized error, and when I use them it shows oauthService.signRequest returns void.

TradeKingAPI.java

import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;

public class TradeKingAPI extends DefaultApi10a {
    @Override
    public String getRequestTokenEndpoint() {
        return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
    }
    @Override
    public String getAccessTokenEndpoint() {
        return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
    }
    @Override
    public String getAuthorizationUrl(Token requestToken) {
        return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
    }
}

main.java

import org.scribe.builder.ServiceBuilder;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.oauth.OAuthService;

import api.TradeKingAPI;
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.OAuthConstants;
import org.scribe.oauth.OAuthService;

   ........

    OAuthService oauthService = new ServiceBuilder()
            .provider(TradeKingAPI.class)
            .apiKey("My consumer key")
            .apiSecret("My secret")
            .scope("API.Public")
            .build();

    Long seconds = (System.currentTimeMillis() / 1000);
    System.out.println(">>>" + seconds);
    String stSeconds = seconds.toString();
    OAuthRequest request = new OAuthRequest(Verb.GET, "http://api.viagogo.net/Public
                                                                     /SimpleOAuthAccessRequest");

    request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, "My consumer key");
    request.addOAuthParameter(OAuthConstants.NONCE, "myn0nc3");
    request.addOAuthParameter(OAuthConstants.SIGN_METHOD, "HMAC-SHA1");
    request.addOAuthParameter(OAuthConstants.TIMESTAMP, seconds.toString());
    request.addOAuthParameter(OAuthConstants.VERSION, "1.0");
    request.addOAuthParameter("scope", "API.Public");

 1  String signature = oauthService.signRequest(OAuthConstants.EMPTY_TOKEN, request);

 2  request.addOAuthParameter(OAuthConstants.SIGNATURE,signature);
    Response response = request.send();
    System.err.println(">>" + response.isSuccessful());
    System.err.println(">>" + response.getMessage());
    System.err.println(">>" + response.getBody());

Answer

Antoine Sabot-Durand picture Antoine Sabot-Durand · Jul 22, 2013

From what I understand from Viagogo public API access documentation, the token you get in the step 1, is the equivalent to a request token in a complete OAuth 1.0a "dance".

So, you should be able to use scribe-java internal classes to get this token without doing it by hand. The only difference is that in scribe, this request sends also a callback url to the OAuth server for the next step of OAuth "dance".

As I can't get a consumer account I can only make assumption here. So let's have 2 scenarios :

Scenario 1 : Viagogo server tolerate extra parameter (i.e. call back URL)

so you can go with this code

import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;

public class TradeKingAPI extends DefaultApi10a {

    @Override
    public Verb getRequestTokenVerb()
    {
      return Verb.GET;
    }

    @Override
    public String getRequestTokenEndpoint() {
        return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
    }

    @Override
    public String getAccessTokenEndpoint() {
        return "none";
    }

    @Override
    public String getAuthorizationUrl(Token requestToken) {
        return "none";
    }
}

Then your calling code will be :

OAuthService service = new ServiceBuilder()
                            .provider(TradeKingAPI.class)
                            .signatureType(QueryString)
                            .apiKey("My consumer key")
                            .apiSecret("My secret")
                            .scope("API.Public")
                            .build();

Token requestToken = service.getRequestToken();

//make your API calls

OAuthRequest request = new OAuthRequest(Verb.GET,
                       "http://api.viagogo.net/Public/Event/235");
service.signRequest(requestToken, request);
Response response = request.send();
System.out.println(response.getBody());

But as I said, if Viagogo security is a bit strict and it refuses the useless param oauth_callback, you'll need to switch to scenario 2

Scenario 2 : Build your own OAuthService

In this scenario you have to create a new OAuthService to avoid dealing with OAuthCallback parameter.

import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.*;
import org.scribe.oauth.OAuth10aServiceImpl;

import java.util.Map;

public class OAuth10aServiceForViagogo extends OAuth10aServiceImpl {

    private OAuthConfig config;
    private DefaultApi10a api;

    public OAuth10aServiceForViagogo(DefaultApi10a api, OAuthConfig config) {
        super(api, config);

        this.api = api;
        this.config = config;
    }

    private void addOAuthParams(OAuthRequest request, Token token) {
        request.addOAuthParameter(OAuthConstants.TIMESTAMP, api.getTimestampService().getTimestampInSeconds());
        request.addOAuthParameter(OAuthConstants.NONCE, api.getTimestampService().getNonce());
        request.addOAuthParameter(OAuthConstants.CONSUMER_KEY, config.getApiKey());
        request.addOAuthParameter(OAuthConstants.SIGN_METHOD, api.getSignatureService().getSignatureMethod());
        request.addOAuthParameter(OAuthConstants.VERSION, getVersion());
        request.addOAuthParameter(OAuthConstants.SCOPE, config.getScope());
        request.addOAuthParameter(OAuthConstants.SIGNATURE, getSignature(request, token));

    }

    private String getSignature(OAuthRequest request, Token token) {

        String baseString = api.getBaseStringExtractor().extract(request);
        String signature = api.getSignatureService().getSignature(baseString, config.getApiSecret(), token.getSecret());

        return signature;
    }

    private void appendSignature(OAuthRequest request) {
        for (Map.Entry<String, String> entry : request.getOauthParameters().entrySet()) {
            request.addQuerystringParameter(entry.getKey(), entry.getValue());
        }
    }

    @Override
    public Token getRequestToken(RequestTuner tuner) {
        OAuthRequest request = new OAuthRequest(api.getRequestTokenVerb(), api.getRequestTokenEndpoint());

        addOAuthParams(request, OAuthConstants.EMPTY_TOKEN);
        appendSignature(request);

        Response response = request.send(tuner);
        String body = response.getBody();

        return api.getRequestTokenExtractor().extract(body);
    }
}

TrakingApi class will be slightly different to create the an OAuth10aServiceForViagogo when calling createService :

import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.Token;

public class TradeKingAPI extends DefaultApi10a {

    @override
    public OAuthService createService(OAuthConfig config)
    {
      return new OAuth10aServiceForViagogo(this, config);
    }

    @Override
    public Verb getRequestTokenVerb()
    {
      return Verb.GET;
    }

    @Override
    public String getRequestTokenEndpoint() {
        return "http://api.viagogo.net/Public/SimpleOAuthAccessRequest";
    }

    @Override
    public String getAccessTokenEndpoint() {
        return "none";
    }

    @Override
    public String getAuthorizationUrl(Token requestToken) {
        return "none";
    }
}

Then your calling code will be the same :

    OAuthService service = new ServiceBuilder()
                                .provider(TradeKingAPI.class)
                                .signatureType(QueryString)
                                .apiKey("My consumer key")
                                .apiSecret("My secret")
                                .scope("API.Public")
                                .build();

    Token requestToken = service.getRequestToken();

    //make your API calls

    OAuthRequest request = new OAuthRequest(Verb.GET,
                           "http://api.viagogo.net/Public/Event/235");
    service.signRequest(requestToken, request);
    Response response = request.send();
    System.out.println(response.getBody());

I didn't test all this code because I can't access consumer and secret key, but it should be close to what you need.