Nikita Shah Nikita Shah - 1 month ago 26
Android Question

Withings API integration in android

I am building Android App which shows Withings user's activity data in my Application.

But when I am trying to call refresh_token url:

https://oauth.withings.com/account/request_token?oauth_callback=******&oauth_consumer_key=******&oauth_nonce=******&oauth_signature=CcMrI7JaI8M5tEenye3s95wx%2BZ4%3D&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1477386344&oauth_version=1.0


Then I am getting Invalid Signature response like below:

{
"status":0,
"message":"Invalid signature :\n CcMrI7JaI8M5tEenye3s95wx+Z4= .. \n{\"oauth_callback\":\"******\",\"oauth_consumer_key\":\"ce54bd6c671546ef8f8d394c0db4bd86688289d5f7fb39f371c5ebce4d01\",\"oauth_nonce\":\"f339febe0fdf4b53b953501e45a049db\",\"oauth_signature\":\"CcMrI7JaI8M5tEenye3s95wx+Z4=\",\"oauth_signature_method\":\"HMAC-SHA1\",\"oauth_timestamp\":\"1477386344\",\"oauth_version\":\"1.0\"}\n{\"base_string\":\"GET&https%3A%2F%2Foauth.withings.com%2Faccount%2Frequest_token&oauth_callback%3D******%26oauth_consumer_key%3D******%26oauth_nonce%3Df339febe0fdf4b53b953501e45a049db%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1477386344%26oauth_version%3D1.0\"}\n{\"key\":\"******\",\"secret\":\"******\",\"callback_url\":null}"
}

Answer

First of all you can use the scribe lib
On my sample code I have an Authentication Activity that has an WebView that the user uses to verify the app. Then that Authentication Activity sends back to the MainActivity the response.

On my example I am storing locally on a DB the authenticated user to not ask every time the credentials.
Also I am sending the access token to python server that will get all data stored on Withings Cloud to save it to my Server DB and represent them on a Graph Activity. {I have removed that part}

Because of the copy paste maybe something is missing but most of the code is here

public class WithingsApi extends DefaultApi10a {

    private static final String AUTHORIZATION_URL ="https://oauth.withings.com/account/authorize?oauth_token=%s";
    private static final String apiKey = "API_KEY";
    private static final String apiSecret = "API_SECRET";

    @Override
    public String getRequestTokenEndpoint() {
        return "https://oauth.withings.com/account/request_token";
    }

    @Override
    public String getAccessTokenEndpoint() {
        return "https://oauth.withings.com/account/access_token";
    }

    @Override
    public String getAuthorizationUrl(Token requestToken) {
        return String.format(getAUTHORIZATION_URL(), requestToken.getToken());
    }

    public static String getKey(){
        return apiKey;
    }

    public static String getSecret(){
        return apiSecret;
    }

    public static String getAUTHORIZATION_URL() {
        return AUTHORIZATION_URL;
    }

}




@SuppressLint("SetJavaScriptEnabled")
public class AuthenticationActivity extends Activity {
    final String LOGTAG = "WITHINGS";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_authentication);

        final WebView wvAuthorise = (WebView) findViewById(R.id.wvAuthorise);
        wvAuthorise.getSettings().setJavaScriptEnabled(true);
        wvAuthorise.setWebViewClient(new MyWebViewClient(wvAuthorise));

        MainActivity.service = new ServiceBuilder().provider(WithingsApi.class)
                .apiKey(WithingsApi.getKey())
                .apiSecret(WithingsApi.getSecret())
                .build();

        new Thread(new Runnable() {
            public void run() {
                MainActivity.requestToken = MainActivity.service.getRequestToken();
                final String authURL = MainActivity.service.getAuthorizationUrl(MainActivity.requestToken);
                wvAuthorise.post(new Runnable() {
                    @Override
                    public void run() {
                        wvAuthorise.loadUrl(authURL);
                    }
                });             

            }
        }).start();

    }

    class MyWebViewClient extends WebViewClient{
        WebView wvAuthorise;
        MyWebViewClient(WebView wv){
            wvAuthorise = wv;
        }
        @Override
        public void onPageFinished(WebView view, String url) {
                getUSERID(url);
        }
    }

    private void getUSERID(final String url) {

        try {
            String divStr = "userid=";
            int first = url.indexOf(divStr);

            if(first!=-1){
                final String userid = url.substring(first+divStr.length());

                Intent intent = new Intent();
                intent.putExtra("USERID",userid);
                setResult(RESULT_OK,intent);
                finish();
            }
            else
            {
                //...
            }

        } catch (Exception e) {
            Log.e(LOGTAG,e.getMessage());
            //...
        }
    }
}



public class MainActivity extends FragmentActivity {

    public static OAuthService service;
    public static Token requestToken;
    String secret, token;
    Token accessToken;
    String userId = "";

    private UsersDataSource datasource;
    private TextView nameTV;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        _mainActivity = this;

        nameTV = (TextView) findViewById(R.id.nameTitleTextView);
        nameTV.setText("--");

        getCredentials();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode,
            Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);

        if (requestCode == AUTHENTICATION_REQUEST) {

            if (resultCode == RESULT_OK) {
                Bundle extras = intent.getExtras();
                if (extras != null) {
                    userId = extras.getString("USERID");

                    getAccessTokenThread.execute((Object) null);
                }
            }
        }
    }
    @Override
    protected void onResume() {
        datasource.open();
        super.onResume();
    }

    @Override
    protected void onPause() {
        datasource.close();
        super.onPause();
    }

    private void getCredentials() {
        try {
            datasource = new UsersDataSource(this);
            datasource.open();

            List<User> users = datasource.getAllUsers();

            if (users.isEmpty()) {
                startAuthenticationActivity();
            } else {
                // TODO load all users and if isn't anyone correct
                // startAuthenticationActivity
                secret = users.get(0).getSecret();
                token = users.get(0).getToken();
                userId = users.get(0).getUserId();
                Log.i(LOGTAG, "secret  : " + secret);
                Log.i(LOGTAG, "token  : " + token);
                Log.i(LOGTAG, "userId  : " + userId);
                try {
                    service = new ServiceBuilder().provider(WithingsApi.class)
                            .apiKey(WithingsApi.getKey())
                            .apiSecret(WithingsApi.getSecret()).build();
                    accessToken = new Token(token, secret);

                    loadData();
                } catch (Exception ex) {
                    startAuthenticationActivity();
                }

            }
        } catch (Exception ex) {
            Log.e(LOGTAG, "try on create" + ex.getLocalizedMessage());
        }
    }

    private void startAuthenticationActivity() {
        Intent intent = new Intent(this,
                ics.forth.withings.authentication.AuthenticationActivity.class);
        startActivityForResult(intent, AUTHENTICATION_REQUEST);
    }

    AsyncTask<Object, Object, Object> getAccessTokenThread = new AsyncTask<Object, Object, Object>() {
        @Override
        protected Object doInBackground(Object... params) {
            accessToken = service
                    .getAccessToken(requestToken, new Verifier(""));

            secret = accessToken.getSecret();
            token = accessToken.getToken();
            return null;
        }

        @Override
        protected void onPostExecute(Object result) {
            // authentication complete send the token,secret,userid, to python
            datasource.createUser(token, secret, userId);
            loadData();
        };

    };
}

UPDATE
OAuthService class is from Scribe
Token class is from Scribe
UserDataSource class is a DB Helper Class more here