02-16-2016 19:39
02-16-2016 19:39
I've been trying to get my anrdroid application to return an access token after recieving an authorization code. I follow the instructions in the API docs at https://dev.fitbit.com/docs/oauth2/#access-token-request by converting CLIENT_ID:CLIENT_SECRET to base 64 and adding the basic authorization header, along with the access token https://api.fitbit.com/oauth2/token with the client_id, grant_type (=authorization_code), the redirect uri and the authorization code.
This is the method I use to request an access token.
//Constants
public static final String API_KEY = "##########################";
public static final String SECRET_KEY = "##########################";
public static final String CLIENT_ID = "##################";
public static final String REDIRECT_URL = "https://www.fitbit.com/user/498NHZ";
public static final String REDIRECT_URI = "https%3A%2F%2Fwww.fitbit.com%2Fuser%2F498NHZ";
public static final String AUTHORIZATION_URL = "https://www.fitbit.com/oauth2/authorize";
public static final String ACCESS_TOKEN_URL = "https://api.fitbit.com/oauth2/token";
public static final String SECRET_KEY_PARAM = "client_secret";
public static final String GRANT_TYPE_PARAM = "grant_type";
public static final String RESPONSE_TYPE_PARAM = "response_type";
public static final String RESPONSE_TYPE_VALUE = "code";
public static final String GRANT_TYPE= "authorization_code";
public static final String CLIENT_ID_PARAM = "client_id";
public static final String STATE_PARAM = "state";
public static final String REDIRECT_URI_PARAM = "redirect_uri";
public static final String SCOPE = "scope";
public static final String SCOPE_PARAM = "activity%20nutrition%20heartrate%20location%20nutrition%20profile%20settings%20sleep%20social%20weight";
public static final String QUESTION_MARK = "?";
public static final String AMPERSAND = "&";
public static final String EQUALS = "=";
private class PostRequestAsyncTask extends AsyncTask<String, Void, Boolean> {
@Override
protected Boolean doInBackground(String... urls) {
if (urls.length > 0) {
String url = urls[0];
String client = CLIENT_ID + ":" + SECRET_KEY;
Log.i("Authorize", "Authorization IDs: " + client);
String client_encode = Base64.encodeToString(client.getBytes(), 0);
Log.i("Authorize", "Base 64 Authorization Code: " + client_encode);
HttpPost httppost = new HttpPost(url);
httppost.setHeader("Authorization", "Basic " + client_encode);
httppost.setHeader("Content-Type", "application/x-www-form-urlencoded");
HttpURLConnection conn = null;
System.out.println("executing request " + httppost.getRequestLine());
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpost = new HttpPost(url);
try {
HttpResponse response = httpClient.execute(httppost);
if (response != null) {
//If status is OK 200
HttpEntity entity = response.getEntity();
String r = EntityUtils.toString(entity);
Log.i("Authorize", "Status Code: " + response.getStatusLine().getStatusCode());
if (response.getStatusLine().getStatusCode() == 200) {
/* store access token */
}
}
}
} catch(Exception e) {
Log.e("Authorize", e.getLocalizedMessage());
}
}
return false;
}
};It doesn't get past the second if statement because the response returns a 400 error code (bad request).
The method which returns the request URI using the authorization code:
private static String getAccessTokenUrl(String authorizationToken){
return ACCESS_TOKEN_URL
+QUESTION_MARK
+CLIENT_ID_PARAM+EQUALS+CLIENT_ID
+AMPERSAND
+GRANT_TYPE_PARAM+EQUALS+GRANT_TYPE
+AMPERSAND
+REDIRECT_URI_PARAM+EQUALS+REDIRECT_URI
+AMPERSAND
+RESPONSE_TYPE_VALUE+EQUALS+authorizationToken;
}
This is the output when I run this method:
02-16 18:50:37.391 25245-25245/com.seniorproject.rheanna.diabetesapp I/Authorize: Loading Auth URL: https://www.fitbit.com/oauth2/authorize?response_type=code&client_id=227FKG&redirect_uri=https%3A%2F%2Fwww.fitbit.com%2Fuser%2F498NHZ&scope=activity%20nutrition%20heartrate%20location%20nutrition%20profile%20settings%20sleep%20social%20weight 02-16 18:50:37.611 25245-25471/com.seniorproject.rheanna.diabetesapp E/libEGL: validate_display:255 error 3008 (EGL_BAD_DISPLAY) 02-16 18:50:38.251 25245-25245/com.seniorproject.rheanna.diabetesapp I/Authorize: Auth token recieved: d99d6dd797f3397b24d6bf95b3459cf8f3fb7354 02-16 18:50:38.251 25245-25491/com.seniorproject.rheanna.diabetesapp I/Authorize: Base 64 Authorization Code: MjI3RktHOjQ5OWI5YzI3OWM3YjYwN2ZiY2M5MWRlMTFiYjZiN2E2 02-16 18:50:38.261 25245-25245/com.seniorproject.rheanna.diabetesapp W/cr_BindingManager: Cannot call determinedVisibility() - never saw a connection for the pid: 25245 02-16 18:50:38.261 25245-25491/com.seniorproject.rheanna.diabetesapp I/System.out: executing request POST https://api.fitbit.com/oauth2/token?client_id=#######&grant_type=authorization_code&redirect_uri=https%3A%2F%2Fwww.fitbit.com%2Fuser%2F498NHZ&code=d99d6dd797f3397b24d6bf95b3459cf8f3fb7354 HTTP/1.1 02-16 18:50:38.291 25245-25491/com.seniorproject.rheanna.diabetesapp I/System.out: Thread-97802(ApacheHTTPLog):Reading from variable values from setDefaultValuesToVariables 02-16 18:50:38.291 25245-25491/com.seniorproject.rheanna.diabetesapp I/System.out: Thread-97802(ApacheHTTPLog):isSBSettingEnabled false 02-16 18:50:38.291 25245-25491/com.seniorproject.rheanna.diabetesapp I/System.out: Thread-97802(ApacheHTTPLog):isShipBuild true 02-16 18:50:38.291 25245-25491/com.seniorproject.rheanna.diabetesapp I/System.out: Thread-97802(ApacheHTTPLog):SMARTBONDING_ENABLED is false 02-16 18:50:38.291 25245-25491/com.seniorproject.rheanna.diabetesapp I/System.out: Thread-97802(ApacheHTTPLog):SmartBonding Enabling is false, SHIP_BUILD is true, log to file is false, DBG is false 02-16 18:50:38.861 25245-25491/com.seniorproject.rheanna.diabetesapp I/System.out: AsyncTask #4 calls detatch() 02-16 18:50:38.861 25245-25491/com.seniorproject.rheanna.diabetesapp I/Authorize: Status Code: 400
I have tried differen't combinations of access token URLs, different HTTP methods, and I always get the same error, and at this point I don't know what else to try.