0

This is my request code. aa means my consumer key and bb is userAcessTokenSecret. I changed the values for the sake of security. I don't know is it becasue of cursor parameter or the ways of encoding and hashing the values and keys.

public static void getLocationAndNameOfFollowers(String userAcessToken, String userAcessTokenSecret) throws IOException, InvalidKeyException, NoSuchAlgorithmException {

    userAcessTokenSecret = "bb";
    String signingKey = GenerateSignature.oAuthSigningKey("aa", userAcessTokenSecret);
    long ts  = new Timestamp(System.currentTimeMillis()).getTime() / 1000;
    String timeStamp = String.valueOf(ts);
    String nonce = GenerateSignature.generateNonce("aa", timeStamp);
    String baseString = GenerateSignature.oAuthBaseString("GET", "https://api.twitter.com/1.1/followers/list.json?",
            "cursor-1", "fHkdJVy3x1fKE1Yop9qraJyCp", userAcessToken, timeStamp, nonce);
    String oauth_signature = GenerateSignature.oAuthSignature(baseString, signingKey);


    JSONObject response = Unirest.get("https://api.twitter.com/1.1/followers/list.json?cursor=-1")
            .header("Content-Type", "application/x-www-form-urlencoded")
            .header("Authorization", "OAuth oauth_consumer_key=\"consumer_key\"," +
                    "oauth_token=" + "\"" + userAcessToken +"\""+ "," +
                    "oauth_signature_method=" + "\"HMAC-SHA1\"," +
                    "oauth_timestamp=" + "\""+timeStamp + "\"" + "," +
                    "oauth_nonce="     + "\""+nonce     +  "\"" + "," +
                    "oauth_version=\"1.0\"," +
                    "oauth_signature=" + "\"" +oauth_signature + "\"")
            .asJson().getBody().getObject();

The code in below contains my helper functions.

private static String percentEncoding(String originalString) {
    String encodedString = Base64.getUrlEncoder().encodeToString(originalString.getBytes());
    return encodedString;
}

public static String oAuthBaseString(String method, String url, String parameters, String key, String token, String timestamp, String nonce) {
    System.out.println("generated sorted parameter string -> "+generateSortedParameterString(parameters, key, token, timeStamp , nonce));
    String res = method +  "&" + percentEncoding(url)
            + "&" + generateSortedParameterString(parameters, key, token, timeStamp , nonce);

    System.out.println("oauth base string -> \n\n\n" + res);

    return res;
}


public static String oAuthSignature(String baseString, String tokenSecret) throws NoSuchAlgorithmException, InvalidKeyException {

    byte[] bytes = baseString.getBytes(StandardCharsets.UTF_8);
    Mac mac = Mac.getInstance("HmacSHA1");
    mac.init(new SecretKeySpec(bytes, "HmacSHA1"));
    byte[] res = mac.doFinal(tokenSecret.getBytes(StandardCharsets.UTF_8));

    return percentEncoding(Base64.getEncoder().toString());

}

public static String oAuthSigningKey(String consumerSecret, String accessTokenSecret) {
    return consumerSecret + "&" + accessTokenSecret;
}


public static String generateNonce(String consumerKey, String timeStamp) {
    String nonce = Base64.getEncoder().encodeToString((consumerKey + ":" + timeStamp).getBytes());
    return nonce;
}

public static String generateSortedParameterString(String parameter, String key, String token, String timeStamp, String nonce) {

    Map<String, String> parameters = new LinkedHashMap<>();


    parameters.put("oauth_consumer_key", key);
    parameters.put("oauth_nonce", nonce);
    parameters.put("oauth_signature_method", "HMAC-SHA1");
    parameters.put("oauth_timestamp", timeStamp);
    parameters.put("oauth_token", token);
    parameters.put("oauth_version", "1.0");

    System.out.println("parameter map is here -> "+parameters);

    String parameterString = parameters.entrySet().stream()
                                       .sorted(Map.Entry.comparingByKey())
                                       .map(e -> percentEncoding(e.getKey()) + "=" + percentEncoding(e.getValue()))
                                       .collect(Collectors.joining("&"));

    return parameterString;

}

I am getting this response

{"errors":[{"code":32,"message":"Could not authenticate you."}]}

baruj
  • 43
  • 7
  • Twitter4J and several other libraries do this for you, is there a reason to implement this yourself? – Andy Piper Aug 28 '20 at 00:51
  • I didn't know that library. I'll take a look at it. thanks. – baruj Aug 28 '20 at 00:57
  • You can refer [this](https://stackoverflow.com/questions/3756257/absolute-minimum-code-to-get-a-valid-oauth-signature-populated-in-java-or-groovy/59765764#59765764) answer if you want to generate Twitter API signature without 3rd party library, – Smile Aug 28 '20 at 04:09

1 Answers1

0

I see your code and looks like you may not have finished the steps needed before you make a call to get followers.

Since Twitter follows OAuth1 here is what you need to do for this. If you confirm that you have done these then I can help you with the signing process.

The variables that you are working with

  • consumerKey = Copied from twitter during registration
  • accesstokenSecret = Copied from twitter during registration
  • oauth_token = Received as response from step 1 below
  • oauth_token_secret = Received as response from step 2 below
  • oauth_verifier = Received as response from step 3 below
  • accesstoken = Received as response from step 4 below. Finally to be used while signing all API calls

Steps for OAuth 1.0 that twitter follows

  1. GET oauth_token making signed call to https://api.twitter.com/oauth/request_token. Twitter will return oauth_token and oauth_token_secret
  2. Redirect user to https://api.twitter.com/oauth/authorize?oauth_token={{oauth_token}}
  3. User Authenticates and twitter will send a code to your redirect url
  4. Then send a signed request to https://api.twitter.com/oauth/access_token to recieve the access_token

The process for signing are the same for each step with changes to the baseString and signing key. If you have achieved the signing logic for step1. All the others should work.

If you have not done the above steps and are struggling with signing at step1 then I'll help you with the basic structure of signing. Do confirm?

I work at Pathfix and we built it out as a middleware to solve the exact problem without having you to download SDK. If you are dealing with multiple Providers, you will eventually notice the lack of reusability and bulk of unneccessary code. It might save you hours and $$. All of what you are trying to achieve can take you not more than 10 minutes :)

Ralph
  • 309
  • 1
  • 8