Sunday, May 1, 2016

Twitter OAuth Rest Api Status Parameter '@' symbol

Leave a Comment

I am using twitter rest api which is (https://api.twitter.com/1.1/).

First of all I used signpost library to generate oauth_signature. it is working well.

Upload Status endpoint (https://api.twitter.com/1.1/statuses/upload.json) is working well, but if status parameter contains '@' symbol, that is not working. So here is my code

TwitterStatusesService.java

import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.http.GET; import retrofit2.http.POST; import retrofit2.http.Path; import retrofit2.http.Query;  public interface TwitterStatusesService {     @POST("/1.1/statuses/update.json")     Call<ResponseBody> update(@Query("status") String status, @Query("in_reply_to_status_id") String inReplyToStatusId, @Query("lat") Double lat, @Query("long") Double lon, @Query("media_ids") String mediaIds); } 

TwitterStatusesAPIClient.java

import android.util.Log;  import com.twitter.sdk.android.core.TwitterAuthToken; import com.twitter.sdk.android.core.TwitterCore; import com.twitter.sdk.android.core.TwitterSession;  import okhttp3.OkHttpClient; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.Retrofit; import se.akerfeldt.okhttp.signpost.OkHttpOAuthConsumer; import se.akerfeldt.okhttp.signpost.SigningInterceptor;  public class TwitterStatusesClient {      private final String TAG = getClass().getSimpleName();      private static final String BASE_URL = "https://api.twitter.com/";      private final TwitterStatusesService apiService;      private static TwitterStatusesClient webServiceClient;      public static TwitterStatusesClient getInstance() {         if (webServiceClient == null)             webServiceClient = new TwitterStatusesClient();         return webServiceClient;     }      private TwitterStatusesClient() {         private TwitterStatusesClient() {         OkHttpOAuthConsumer consumer = new OkHttpOAuthConsumer(TWITTER_KEY, TWITTER_SECRET);          TwitterSession activeSession = TwitterCore.getInstance().getSessionManager().getActiveSession();         if (activeSession != null) {             TwitterAuthToken authToken = activeSession.getAuthToken();             String token = authToken.token;             String secret = authToken.secret;             consumer.setTokenWithSecret(token, secret);         }          OkHttpClient client = new OkHttpClient.Builder()                 .addInterceptor(new SigningInterceptor(consumer))                 .build();          Retrofit retrofit = new Retrofit.Builder()                 .baseUrl(BASE_URL)                 .client(client)                 .build();          apiService = retrofit.create(TwitterStatusesService.class);     }      public Call<ResponseBody> update(String status, String statusId, Double lat, Double lon, String mediaIds) {         return apiService.update(status, statusId, lat, lon, mediaIds);     } } 

calling api client

String status = "@example"; TwitterStatusesClient.getInstance().update(status, null, null, null, null).enqueue(new Callback<ResponseBody>() {         @Override         public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {             Log.v(TAG, "onResponse");             progressDialog.dismiss();             try {                 if (response.errorBody() != null) {                     String error = response.errorBody().string();                     Log.e(TAG, "Error : " + error);                     ToastUtils.showErrorMessage(getContext(), "Error : " + error);                     return;                 }                  String body = response.body().string();                 Log.v(TAG, "body : " + body);             } catch (Exception e) {                 e.printStackTrace();             }         }          @Override         public void onFailure(Call<ResponseBody> call, Throwable t) {             Log.v(TAG, "onFailure");             t.printStackTrace();         }     }); 

giving error :

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

but, if I will use status variable "just example" instead of "@example" ( specific point is removing @ character ) that is working. only '@' symbol is not working.

EDIT

This is my manually creating OAuth v1.0a signature signing code via retrofit interceptor :

OkHttpClient client = new OkHttpClient.Builder()             .addInterceptor(new Interceptor() {                 @Override                 public Response intercept(Interceptor.Chain chain) throws IOException {                     Request request = chain.request();                      String method = request.method();                     String baseUrl = "https://api.twitter.com" + request.url().url().getPath();                      String oauthToken = "";                     String oauthTokenSecret = "";                      TwitterSession activeSession = TwitterCore.getInstance().getSessionManager().getActiveSession();                     if (activeSession != null) {                         TwitterAuthToken authToken = activeSession.getAuthToken();                         oauthToken = authToken.token;                         oauthTokenSecret = authToken.secret;                     }                      String oauthNonce = "TXZScw4M8TG";                     String oauthSignatureMethod = "HMAC-SHA1";                     String oauthTimestamp = String.valueOf(System.currentTimeMillis() / 1000);                     String oauthVersion = "1.0";                      String parameterString = "";                      parameterString = OAuthParams.addParam(request, parameterString, "count");                     parameterString = OAuthParams.addParam(request, parameterString, "id");                     parameterString = OAuthParams.addParam(request, parameterString, "in_reply_to_status_id");                      // if any parameter added to parameterString, append '&' character.                     if (parameterString.length() > 0) {                         parameterString += "&";                     }                      parameterString += "oauth_consumer_key=" + TWITTER_KEY + "&"                             + "oauth_nonce=" + oauthNonce + "&"                             + "oauth_signature_method=" + oauthSignatureMethod + "&"                             + "oauth_timestamp=" + oauthTimestamp + "&"                             + "oauth_token=" + oauthToken + "&"                             + "oauth_version=" + oauthVersion;                      // add status parameter to parameterString.                     parameterString = OAuthParams.addParam(request, parameterString, "status");                      Log.d(TAG, "normalizedParameters : " + parameterString);                     Log.d(TAG, "parameterStringPercent : " + OAuth.percentEncode(parameterString));                      String signatureBaseString = "";                     signatureBaseString += OAuth.percentEncode(method) + "&";                     signatureBaseString += OAuth.percentEncode(baseUrl) + "&";                     signatureBaseString += OAuth.percentEncode(parameterString);                      String oauthSignature = OauthSignature.generateSignature(signatureBaseString, TWITTER_SECRET,                             oauthTokenSecret);                      String authorization = "OAuth oauth_consumer_key=\"" + TWITTER_KEY + "\", " +                             "oauth_signature_method=\"HMAC-SHA1\", " +                             "oauth_timestamp=\"" + oauthTimestamp + "\", " +                             "oauth_nonce=\"" + oauthNonce + "\", " +                             "oauth_version=\"1.0\", " +                             "oauth_token=\"" + oauthToken + "\", " +                             "oauth_signature=\"" + OAuth.percentEncode(oauthSignature) + "\"";                      Log.w(TAG, "Authorization : " + authorization);                      request = request.newBuilder()                             .addHeader("Authorization", authorization)                             .build();                     return chain.proceed(request);                 }             }).addInterceptor(interceptor).build(); 

OAuth.java

public static String percentEncode(String s) {     if (s == null) {         return "";     }     try {         return URLEncoder.encode(s, ENCODING)                 // OAuth encodes some characters differently:                 .replace("+", "%20").replace("*", "%2A")                 .replace("%7E", "~");         // This could be done faster with more hand-crafted code.     } catch (UnsupportedEncodingException wow) {         throw new RuntimeException(wow.getMessage(), wow);     } } 

OAuthSignature.java

import android.util.Base64; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec;  public class OauthSignature {  public static String generateSignature(String signatueBaseStr, String oAuthConsumerSecret, String oAuthTokenSecret) {     byte[] byteHMAC = null;     try {         Mac mac = Mac.getInstance("HmacSHA1");         SecretKeySpec spec;         if (null == oAuthTokenSecret) {             String signingKey = OAuth.percentEncode(oAuthConsumerSecret) + '&';             spec = new SecretKeySpec(signingKey.getBytes(), "HmacSHA1");         } else {             String signingKey = OAuth.percentEncode(oAuthConsumerSecret) + '&' + OAuth.percentEncode(oAuthTokenSecret);             spec = new SecretKeySpec(signingKey.getBytes(), "HmacSHA1");         }         mac.init(spec);         byteHMAC = mac.doFinal(signatueBaseStr.getBytes());     } catch (Exception e) {         e.printStackTrace();     }     return new String(Base64.encode(byteHMAC, Base64.DEFAULT)); } } 

1 Answers

Answers 1

I suggest go with fabric - https://fabric.io which has twitters various libs like twitter login, crashlytics and alss you need to setup fabric plugin with android studio. Post that you will be able to post/retrieve you tweets irrespective what you want to post.

For your question - check that '@' is special symbol where by retrofit is causing a problem. These kind of issues come up with retrofit which I have faced in different scenarios.

Try using Fabric for Twitter Login/oAuth

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment