07-09-2019 09:52
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-09-2019 09:52
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
Hi All,
I have a bit of code that has been working for months that started throwing an error recently, and I'm not sure why. I do not believe we made any changes to this code that would cause it to break. The error happens when trying to refresh access tokens via the API. Here is the relevant code in Python 3:
#Use this URL to refresh the access token TokenURL = "https://api.fitbit.com/oauth2/token" #From the developer site, add b for base64 encode OAuthTwoClientID = b"MyID" ClientOrConsumerSecret = b"MyKey" concatCode = OAuthTwoClientID + b":" + ClientOrConsumerSecret #Form the data payload BodyText = {'grant_type': 'refresh_token', 'refresh_token': RefToken} #URL Encode it BodyURLEncoded = urllib.parse.urlencode(BodyText).encode('utf-8') #Start the request tokenreq = urllib.request.Request(TokenURL, BodyURLEncoded) #Add the headers, first we base64 encode the client id and client secret with a : inbetween and create the authorisation header base64string = base64.b64encode(concatCode) tokenreq.add_header(b'Authorization', b'Basic %s' % base64string) tokenreq.add_header(b'Content-Type', b'application/x-www-form-urlencoded') #Fire off the request tokenresponse = urllib.request.urlopen(tokenreq)
This code is running in Amazon Lambda, and the Refresh Token is being queried from a database elsewhere in the script. The request results in the following error:
{"errors":[{"errorType":"invalid_request","message":"Missing \'grant_type\' parameter value. Visit https://dev.fitbit.com/docs/oauth2 for more information on the Fitbit Web API authorization process."}],"success":false}
I'm clearly adding the grant type in the body, but Fitbit doesn't seem to be recognizing it for some reason. I have a feeling that it has to do with the encoding, but I can't make it work.
Answered! Go to the Best Answer.
Accepted Solutions
07-17-2019 06:33
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-17-2019 06:33
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi John,
I work with James maintaining the app with which we are using FitBit and wrote the solution code. Previously, the app used urllib with Python 3, specifically urllib.request, .error, and .parse to send requests and catch errors. Interestingly enough, it seems that only calls to the

07-09-2019 12:55
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-09-2019 12:55
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hello Fitbit Developers,
I am having the same error starting yesterday. I have never had this error before.

07-09-2019 15:17
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post



07-09-2019 15:17
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi @cycore,
I'm sorry to hear that you are receiving a grant_type - missing error and I'll be happy to assist.
So that I can check if you are formatting your refresh token request correctly, can you provide me with your refresh token request? (Do not include your Base64 encoded string and refresh token).
It sounds like you might be missing the grant_type=refresh_token as mentioned in https://dev.fitbit.com/build/reference/web-api/oauth2/#refreshing-tokens
It should look similar to this:
POST https://api.fitbit.com/oauth2/token Authorization: [Redacted] Content-Type: application/x-www-form-urlencoded grant_type=refresh_token&refresh_token=[Redacted]
Looking forward to your response!

07-09-2019 15:32 - edited 07-09-2019 15:55
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-09-2019 15:32 - edited 07-09-2019 15:55
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi @JohnFitbit
Did you need this from me as well? Those elements are all present in the request generated from the code above.
EDIT: See below for my request info.

07-09-2019 15:55
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-09-2019 15:55
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi @JohnFitbit
Here is my info in case it helps. I'm sending these requests via Amazon Lambda, so I'm copying the request parameters out of the Cloudwatch logs for you. The request is generated by the code I provided above:
https://api.fitbit.com/oauth2/token {b'Authorization': b'Basic [Redacted]', b'Content-type': b'application/x-www-form-urlencoded'} b'grant_type=refresh_token&refresh_token=[Redacted]'
Like I said before, this code has been working for months, but yesterday started returning HTTP 400 errors for all of the refresh token requests.

07-10-2019 05:47
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-10-2019 05:47
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Just so we are clear, both @cycore and myself are reporting that this error started unexpectedly on 7/8/2019. To reiterate, in my case the error is happening with code that has been in production for months.

07-10-2019 15:26
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-10-2019 15:26
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hello JohnFitbit,
jcastle0 is correct, both of us are having the error starting 7/08/2019. I have never had this error before so I must have been doing it right. And I have double checked that the parameter 'grant_type' is set as grant_type=refresh_token in the POST body.
Anyway, here is one of the refresh token needs to be renewed.
19f432edef8697ae97e4ca4ffa1688aa7cca9d93d38a3e65adc95a3dbd2bc0f4
Thank you.

07-10-2019 19:18
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-10-2019 19:18
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
We swapped out urllib for the requests module and it appears to be working now. No idea why Fitbit all of a sudden stopped working with urllib. If it breaks again I'll post back here.

07-11-2019 08:14
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-11-2019 16:28
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-11-2019 16:28
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
Dear John, all,
I can confirm the issue occurs on the refresh token endpoint with the Google OAuth 2.0 library we use as well:
While reading the code in the Google library (RefreshToken:
super(transport, jsonFactory, tokenServerUrl, "refresh_token");
where super is:
public TokenRequest(HttpTransport transport, JsonFactory jsonFactory, GenericUrl tokenServerUrl, String grantType)...
For your reference, the code is at:
Please do let us know in this thread which specific change needs to be done on the client side.
Thank you,
Vlad
07-15-2019 05:52
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-15-2019 05:52
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Our implementation is python. We were sending the token refresh request using the urllib module when this error started. We stopped using that module and started using the requests module to send of the refresh token request and the error went away. I don't know why that stopped the error, but it did and we are back functioning normally now.

07-15-2019 08:33 - edited 07-15-2019 08:36
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-15-2019 08:33 - edited 07-15-2019 08:36
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
@cycore The method in google-oauth2 which refreshes the token is final. I ended up implementing the request by hand as well. Below part of my java code, in case it helps you:
import org.json.JSONObject; import org.apache.http.client.HttpClient; //... final HttpClient client = HttpClientBuilder.create().build();
final String base64 = Base64.getEncoder().encodeToString(String.format("%s:%s", connectorConstants.getClientId(), connectorConstants.getClientSecret()).getBytes());
final HttpPost httpPost = new HttpPost(connectorConstants.getOAuth20AccessRefreshTokenRequestUri());
httpPost.addHeader("Authorization", String.format("Basic %s", base64)); httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
final List<NameValuePair> params = new ArrayList<>(); params.add(new BasicNameValuePair("refresh_token", credential.getRefreshToken())); params.add(new BasicNameValuePair("grant_type", "refresh_token")); try { httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); } catch (final UnsupportedEncodingException e) { // Handle... } try { final HttpResponse response = client.execute(httpPost); final HttpEntity respEntity = response.getEntity(); final String content = EntityUtils.toString(respEntity); final JSONObject json = new JSONObject(content);
// Process the JSON here...
} catch (final IOException e) { // Handle... }
Feel free to ask anything.

07-15-2019 10:00 - edited 07-15-2019 10:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-15-2019 10:00 - edited 07-15-2019 10:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi @vladmanea,
My code is very similar to yours. The code has been in production in for more than a year and never had an issue until Jul. 8. Any idea?
NetHttpTransport transport = new NetHttpTransport();
HttpRequestFactory requestFactory = transport.createRequestFactory();
// Set 'Authorization' header based on Fitbit specifications. //
HttpHeaders headers = new HttpHeaders();
headers.setAuthorization(FitbitAuthorizationCredentials.getCredentials(clientId, clientSecret));
headers.setContentType("application/x-www-form-urlencoded");
Map<String, String> parameters = new HashMap<>();
parameters.put("grant_type", "refresh_token");
parameters.put("refresh_token", refreshToken);
HttpRequest httpPost = requestFactory.buildPostRequest(new GenericUrl(apiURI), new UrlEncodedContent(parameters));
httpPost.setHeaders(headers);
httpPost.setThrowExceptionOnExecuteError(false);
HttpResponse httpResponse = httpPost.execute();
...

07-15-2019 15:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post



07-15-2019 15:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi Everyone,
Thanks for sharing all that information.
Our team is currently investigating the reports we are seeing around the invalid_request - missing grant type errors. One of the causes we've seen so far for this problem is setting the header "Content-Type: application/json", which is not supported.
For those still experiencing the issue, can you please PM me the actual POST requests you are sending? I am not able to see the requests that are sent with the code provided. I need to see the headers, the endpoint, and the post body in order to see what may be throwing the error for you.
@jcastle0 Since you swapped out your urllib, would you share which one you're using and what version it is?

07-17-2019 06:33
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-17-2019 06:33
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi John,
I work with James maintaining the app with which we are using FitBit and wrote the solution code. Previously, the app used urllib with Python 3, specifically urllib.request, .error, and .parse to send requests and catch errors. Interestingly enough, it seems that only calls to the

07-17-2019 07:06
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-17-2019 07:06
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi @cycore,
I worked with James on fixing this problem and wrote the solution code for it. I'm not sure how the HTTP request libraries are in Java, but in Python, the difference between urllib and requests seems to be how many lines of code it takes to make a request and how the request is packaged. For instance, the main change I made in sending the request through the requests module was that I made a header object that included both authorization header parameters and added that as a keyword parameter to the requests.post() function with the token URL and the body of the request which creates and sends the request in one line rather than using urllib to create the request with the token URL and body, add headers to that request, then send it off (as seen in the original code snippet). I created the request with the headers included rather than adding headers to an already built request. I'm not sure what that changes or if there is something wrong with urllib and how it creates or sends requests with respect to this app, but if this is a problem in other languages as well, it could be deeper than that. Hope this helps.

08-05-2019 01:02
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

08-05-2019 01:02
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Unfortunately this solution didn't solve anything for Java implementations!
We are using Java in our backend and this problem is still relevant.
We are using apache http client for making the oAuth requests everything worked perfectly till the 8.7
Is anybody mange to solve the problem without switching library?
Is anybody switched to OkHttp and can report that it solved the problem?
@JohnFitbit can you tell us what got change in your side because obviously something got change.

08-05-2019 10:56
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post



08-05-2019 10:56
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hi @Av_Gu,
I'm sorry to hear that you are running into the invalid_grant issue. I am not aware of any changes that we've made to the authorization process as of late.
So that I can investigate, can you please private message me the actual POST authorization requests you are sending as well as the responses you are receiving? I need to see the headers, the endpoint, and the post body in order to see what may be throwing the error for you.
I look forward to hearing from you,

08-05-2019 11:54
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

08-05-2019 11:54
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Thank you all responded to my post. Sorry, there were a few pressing urgent things I had to attend to.
I will post back when I have some updates.

07-29-2020 08:40 - edited 07-29-2020 08:43
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-29-2020 08:40 - edited 07-29-2020 08:43
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Do you mind sharing the code that worked for you so that I can understand what the problem is?

