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

OAuth 2 Token Request Error: "Empty client id".....

ANSWERED

When I get my accessToken I try to GET request it with the following code and get returned 

WWWForm form = new WWWForm();
            var headers = new Dictionary<string, string>();
            headers["GET"] = "https://www.fitbit.com/oauth2/authorize";
            headers["Authorization"] = "Bearer " + token;

            var getter = new WWW("https://api.fitbit.com/1/user/-/profile.json", null, headers);

I get my token back as 

 

c011d387c0f96dcea307ab2ec5bb33193f10c6fe

 

{"errors":[{"errorType":"oauth","fieldName":"access_token","message":"Access token invalid or expired: c011d387c0f96dcea307ab2ec5bb33193f10c6fe"}],"success":false}

 

I can't figure out what's going on to make it wrong, it's about 1 second after getting the Token so it can't be expired

 

EDIT: Also, I've come across several threads asking about an easier way to integrate OAuth and Mobile (seems that you can't do a custom redirect_uri scheme like in a lot of the big names like Facebook and such).  There was a lot of "we're working on an SDK" but I haven't come across it explicitly yet.  

 

Is there an sdk BY Fitbit?  A thing that would be super handy is a Unity SDK like what FB has done 
https://developers.facebook.com/docs/unity

Best Answer
0 Votes
1 BEST ANSWER

Accepted Solutions

@TooL wrote:

When I get my accessToken I try to GET request it with the following code and get returned 

WWWForm form = new WWWForm();
            var headers = new Dictionary<string, string>();
            headers["GET"] = "https://www.fitbit.com/oauth2/authorize";
            headers["Authorization"] = "Bearer " + token;

            var getter = new WWW("https://api.fitbit.com/1/user/-/profile.json", null, headers);

I get my token back as 

 

c011d387c0f96dcea307ab2ec5bb33193f10c6fe

 

{"errors":[{"errorType":"oauth","fieldName":"access_token","message":"Access token invalid or expired: c011d387c0f96dcea307ab2ec5bb33193f10c6fe"}],"success":false}

 

I can't figure out what's going on to make it wrong, it's about 1 second after getting the Token so it can't be expired


That's not a valid OAuth 2.0 access token. OAuth 2.0 access tokens use the JWT format. So the error is correct.

 


@TooL wrote:

 

EDIT: Also, I've come across several threads asking about an easier way to integrate OAuth and Mobile (seems that you can't do a custom redirect_uri scheme like in a lot of the big names like Facebook and such).  There was a lot of "we're working on an SDK" but I haven't come across it explicitly yet.  

 

Is there an sdk BY Fitbit?  A thing that would be super handy is a Unity SDK like what FB has done 
https://developers.facebook.com/docs/unity


No, there is no SDK by Fitbit. We've created a standard OAuth 1.0a and OAuth 2.0 Web API. This allows you to use generic OAuth 1.0a and OAuth 2.0 client libraries.

 

Also, we do support app protocols for callback redirect URIs. (We currently have a bug that don't allow hyphens in the protocol, e.g. my-app:// should be valid but isn't recognized as such yet. myapp:// would work.)

View best answer in original post

Best Answer
0 Votes
8 REPLIES 8

@TooL wrote:

When I get my accessToken I try to GET request it with the following code and get returned 

WWWForm form = new WWWForm();
            var headers = new Dictionary<string, string>();
            headers["GET"] = "https://www.fitbit.com/oauth2/authorize";
            headers["Authorization"] = "Bearer " + token;

            var getter = new WWW("https://api.fitbit.com/1/user/-/profile.json", null, headers);

I get my token back as 

 

c011d387c0f96dcea307ab2ec5bb33193f10c6fe

 

{"errors":[{"errorType":"oauth","fieldName":"access_token","message":"Access token invalid or expired: c011d387c0f96dcea307ab2ec5bb33193f10c6fe"}],"success":false}

 

I can't figure out what's going on to make it wrong, it's about 1 second after getting the Token so it can't be expired


That's not a valid OAuth 2.0 access token. OAuth 2.0 access tokens use the JWT format. So the error is correct.

 


@TooL wrote:

 

EDIT: Also, I've come across several threads asking about an easier way to integrate OAuth and Mobile (seems that you can't do a custom redirect_uri scheme like in a lot of the big names like Facebook and such).  There was a lot of "we're working on an SDK" but I haven't come across it explicitly yet.  

 

Is there an sdk BY Fitbit?  A thing that would be super handy is a Unity SDK like what FB has done 
https://developers.facebook.com/docs/unity


No, there is no SDK by Fitbit. We've created a standard OAuth 1.0a and OAuth 2.0 Web API. This allows you to use generic OAuth 1.0a and OAuth 2.0 client libraries.

 

Also, we do support app protocols for callback redirect URIs. (We currently have a bug that don't allow hyphens in the protocol, e.g. my-app:// should be valid but isn't recognized as such yet. myapp:// would work.)

Best Answer
0 Votes

Hmm, well I was trying to do it the way that is described in a few android instances and their uri's start with com.companyname.packagename (or flipped package/company) which the api wouldn't let me put in. (as far as I can understand the mobile should detect that uri when Fitbit redirects and then be able to catch stuff..but I haven't done native android either..)

 

I'm still a bit noobish when it comes to the web stuff as I usually just make PC/games/game logic 😛

 

So what is that "token" that I'm getting and passing to the form?  Cause that's the kind of token that is being returned when the user hits allow for me. 

 

Maybe it's just me misunderstanding the flow of OAuth but I thought it was you send the user to that page that says this app wants these permissions, they say yes or no. 

If Yes, redirect_uri with the fitbit?code=bunchOfLettersAndNumbers

The code is the token to do the access token request right? 

With that I'm supposed to do the Basic + Token (or code which ever lingo is right) POST to 

https://www.fitbit.com/oauth2/authorize

and I guess it's then supposed to return the full on access token with which we can start doing requests via GET instead of POST? 

 

Best Answer
0 Votes

When you receive the code appended to your callback (redirect), you need to exchange it using the https://api.fitbit.com/oauth2/token endpoint. See "Access Token Request" section at https://wiki.fitbit.com/display/API/OAuth+2.0

 

Then you can make GET or POST requests to whatever API endpoints you want.

Best Answer
0 Votes

But that's what I was trying to do in the original post of this thread?

 

I don't understand what I'm doing wrong in that step to not  get the access token itself.

Like what is the 

client_id=22942C&grant_type=authorization_code&redirect_uri=http%3A%2F%2Fexample.com%2Fcallback&code=1234567890

part of it? Is that just supposed to be in the data I send (not in the headers) or is that supposed to be appended to the endpoint?

 

I had changed the url I was sending it to after I dug around as well so the stuff I have now is 

WWWForm form = new WWWForm();
form.headers["POST"] = "https://api.fitbit.com/oauth2/token";
form.headers["Authorization"] = "Basic " + token;
form.headers["Content-Type"] = "application/x-www-form-urlencoded";

var getter = new WWW("https://api.fitbit.com/oauth2/token", null, form.headers);

 EDIT:

(OR, this just occured to me, is that supposed to be the encoded part that goes into the application/x-www-form-urlencoded part? such as

client_id=MYID&grant_type=authorization_code&redirect_uri=http%3A%2F%2Fwww.travisevashkevich.com%2Ffitbit&code=

but what should I be putting in the code= spot in that case?)

 

should it be this

byte[] bytesToEncode =Encoding.UTF8.GetBytes("client_id=myClientID&grant_type=authorization_code&redirect_uri=http%3A%2F%2Fwww.travisevashkevich.com%2Ffitbit&code="+token);
string encodedText = Convert.ToBase64String(bytesToEncode);

WWWForm form = new WWWForm();
form.headers["POST"] = "https://api.fitbit.com/oauth2/token";
 form.headers["Authorization"] = "Basic Y2xpZW50X2lkOmNsaWVudCBzZWNyZXQ=";
form.headers["Content-Type"] = encodedText;

var getter = new WWW("https://api.fitbit.com/oauth2/token", null, form.headers);
Best Answer
0 Votes

Hey, I think I figured out another piece to this OAuth puzzle but I'm still not clear on one part of the documentation

 

Example

This example assumes that the code URI parameter value in the callback URI was 1234567890.

POST https://api.fitbit.com/oauth2/token
Authorization: Basic Y2xpZW50X2lkOmNsaWVudCBzZWNyZXQ=
Content-Type: application/x-www-form-urlencoded

client_id=22942C&grant_type=authorization_code&redirect_uri=http%3A%2F%2Fexample.com%2Fcallback&code=1234567890

 

What am I supposed to do with the client_id part at the bottom. Is that supposed to just be tacked on to the https://api.fitbit.com/oauth2/token ?

 

I see what it is made up of but I just don't see what I'm supposd to do with it. 

 

Also, the callback&code is the one we get back from the user doing allow, correct?

Best Answer
0 Votes

Still trying to figure out what I'm supposed to fill in for a Unity POST call

I get 

https://dl.dropboxusercontent.com/u/31340003/OAuth2Failing.png  

as my return response headers

The 400 Bad Request is the error

 

 var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(_clientID + ";" + _consumerSecret);
            var encoded = Convert.ToBase64String(plainTextBytes);
            //make the content
            var content = "client_id=" + _clientID + "&grant_type=authorization_code&redirect_uri=" + CallBackUrl +
                          "callback&code=" + _returnCode;

            var bytes = Encoding.ASCII.GetBytes(content);

            // next we will dothe authorization part of the OAuth2
            var form = new WWWForm();
            form.AddField("Authorization:", "Basic " + encoded);
            form.AddField("Content-Type:", "application/x-www-form-urlEncoded");
            //form.AddField("Content: ", content);
            //form.AddField("Content-Length:", bytes.Length.ToString());

            var response = new Dictionary<string, string>();
            _statusMessage += "starting www /n";
            bWWWRequest = true;

            _wwwRequest = new WWW("https://api.fitbit.com/oauth2/token", form.data, form.headers);
            StartCoroutine(WaitForAccess(_wwwRequest));

I've tried with the commented lines (in the addfield) and get the same Bad Request.

 

I have the feeling that I'm close I just can't figure out what I'm doing wrong...

 

Edit: Also I see that I posted under my actual account as well, just so you're aware I am the OP as well 🙂

Best Answer
0 Votes

@TEvashkevich wrote:

Still trying to figure out what I'm supposed to fill in for a Unity POST call

I get 

https://dl.dropboxusercontent.com/u/31340003/OAuth2Failing.png  

as my return response headers

The 400 Bad Request is the error

 

 var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(_clientID + ";" + _consumerSecret);
            var encoded = Convert.ToBase64String(plainTextBytes);
            //make the content
            var content = "client_id=" + _clientID + "&grant_type=authorization_code&redirect_uri=" + CallBackUrl +
                          "callback&code=" + _returnCode;

            var bytes = Encoding.ASCII.GetBytes(content);

            // next we will dothe authorization part of the OAuth2
            var form = new WWWForm();
            form.AddField("Authorization:", "Basic " + encoded);
            form.AddField("Content-Type:", "application/x-www-form-urlEncoded");
            //form.AddField("Content: ", content);
            //form.AddField("Content-Length:", bytes.Length.ToString());

            var response = new Dictionary<string, string>();
            _statusMessage += "starting www /n";
            bWWWRequest = true;

            _wwwRequest = new WWW("https://api.fitbit.com/oauth2/token", form.data, form.headers);
            StartCoroutine(WaitForAccess(_wwwRequest));

I've tried with the commented lines (in the addfield) and get the same Bad Request.

 

I have the feeling that I'm close I just can't figure out what I'm doing wrong...

 

Edit: Also I see that I posted under my actual account as well, just so you're aware I am the OP as well 🙂


OK, so Unity is C#-ish and you might want to take a look at our Fitbit.NET library branch with working OAuth 2.0 handshake here:

 

https://github.com/aarondcoleman/Fitbit.NET/blob/async-portable/Fitbit.Portable/Authenticator2.cs

 

One issue I see right off the bat is that you're using a semicolon ";" instead of a colon ":"

 

You might take some inspiration from this working* code. If you can get HttpClient and JSON.net working in Unity a lot of our library can be ported (minus the async stuff I believe)

 

public async Task<OAuth2AccessToken> ExchangeAuthCodeForAccessTokenAsync(string code)
        {
            HttpClient httpClient = new HttpClient();

            string postUrl = FitbitApiBaseUrl;
            postUrl += OAuthBase;
            postUrl += "/token";

            var content = new FormUrlEncodedContent(new[] 
            {
                new KeyValuePair<string, string>("grant_type", "authorization_code"),
                new KeyValuePair<string, string>("client_id", ClientId),
                //new KeyValuePair<string, string>("client_secret", AppSecret),
                new KeyValuePair<string, string>("code", code),
                new KeyValuePair<string, string>("redirect_uri", this.RedirectUri)
            });


            string clientIdConcatSecret = Base64Encode(ClientId + ":" + AppSecret);

            httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", clientIdConcatSecret); 

            HttpResponseMessage response = await httpClient.PostAsync(postUrl, content);
            string responseString = await response.Content.ReadAsStringAsync();

            JObject responseObject = JObject.Parse(responseString);

            // Note: if user cancels the auth process Fitbit returns a 200 response, but the JSON payload is way different.
            var error = responseObject["error"];
            if (error != null)
            {
                // TODO: Actually should probably raise an exception here maybe?
                return null;
            }

            OAuth2AccessToken accessToken = new OAuth2AccessToken();

            var temp_access_token = responseObject["access_token"];
            if (temp_access_token != null) accessToken.Token = temp_access_token.ToString();

            var temp_expires_in = responseObject["expires_in"];
            if (temp_expires_in != null) accessToken.ExpiresIn = Convert.ToInt32(temp_expires_in.ToString());

            var temp_token_type = responseObject["token_type"];
            if (temp_token_type != null) accessToken.TokenType = temp_token_type.ToString();

            var temp_refresh_token = responseObject["refresh_token"];
            if (temp_refresh_token != null) accessToken.RefreshToken = temp_refresh_token.ToString();

            return accessToken;
        } 

*"Works on my machine"

Using Fitbits in Research? Check out Fitabase --www.fitabase.com
Best Answer
0 Votes

Hey Aaron, 

 

I was trying to get stuff working with your lib a few times and again tonight BUT I just found the problem after going through your code a few times. 

 

Apparently I had to UNescape my redirect_uri. (I was pre-escaping it as in the examples it was always escaped)

 

On to the next step and hopefully the last 😄

Best Answer
0 Votes