Cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Missing Grant Type Parameter Value

ANSWERED

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.

Best Answer
1 BEST ANSWER

Accepted Solutions

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

https://api.fitbit.com/oauth2/token endpoint where the code was trying to refresh access tokens stopped working with urllib.request which we were using to send the request.

View best answer in original post

Best Answer
0 Votes
19 REPLIES 19

Hello Fitbit Developers,

 

I am having the same error starting yesterday.  I have never had this error before.  

Best Answer
0 Votes

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!

 

 

Best Answer
0 Votes

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.

Best Answer
0 Votes

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.

Best Answer
0 Votes

@JohnFitbit 

 

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.

Best Answer
0 Votes

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.

Best Answer
0 Votes

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. 

Best Answer
0 Votes

@jcastle0 wrote:

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. 


Hi @jcastle0:

 

Our implementation is in Java.  Can you please share more detail about your solution?

Best Answer
0 Votes

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:

https://github.com/googleapis/google-oauth-java-client/blob/master/google-oauth-client/src/main/java...

 

Please do let us know in this thread which specific change needs to be done on the client side.

 

Thank you,

Vlad

Best Answer

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.

Best Answer
0 Votes

@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.

Best Answer
0 Votes

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();

... 

Best Answer
0 Votes

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?

Best Answer
0 Votes

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

https://api.fitbit.com/oauth2/token endpoint where the code was trying to refresh access tokens stopped working with urllib.request which we were using to send the request.
Best Answer
0 Votes

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.

Best Answer
0 Votes

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. 

Best Answer
0 Votes

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,

Best Answer
0 Votes

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. 

 

Best Answer
0 Votes

@klpoland  

Do you mind sharing the code that worked for you so that I can understand what the problem is? 

Best Answer
0 Votes