[GH-ISSUE #139] Error with Fitbit Oauth 2.0 #86

Closed
opened 2026-03-03 16:45:33 +03:00 by kerem · 4 comments
Owner

Originally created by @fnk0 on GitHub (Nov 8, 2015).
Original GitHub issue: https://github.com/OAuthSwift/OAuthSwift/issues/139

So... Fitbit switched from Oauth 1.0 to 2.0... and one of the problems with their new oauth is that it requires a Basic authentication header for the token exchange.

As described in their docs the authentication for the header should follow the following standards:

Authorization Header

The Authorization header must be set to Basic followed by a space, then the Base64 encoded string of your application's client id and secret concatenated with a colon. For example, the Base64 encoded string, Y2xpZW50X2lkOmNsaWVudCBzZWNyZXQ=, is decoded as "client_id:client secret".

They also use Form url encoded...
Here's a example of the header for the token exchange.

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

The errors that I receive when trying to exchange the token are:

HTTP Status 401: Unauthorized, Response: {"errors":[{"errorType":"invalid_client","message":"Incorrect authorization method. Visit https://dev.fitbit.com/docs/oauth2 for more information on the Fitbit Web API authorization process."}],"success":false}
Originally created by @fnk0 on GitHub (Nov 8, 2015). Original GitHub issue: https://github.com/OAuthSwift/OAuthSwift/issues/139 So... Fitbit switched from Oauth 1.0 to 2.0... and one of the problems with their new oauth is that it requires a Basic authentication header for the token exchange. As described in their docs the authentication for the header should follow the following standards: Authorization Header The Authorization header must be set to Basic followed by a space, then the Base64 encoded string of your application's client id and secret concatenated with a colon. For example, the Base64 encoded string, Y2xpZW50X2lkOmNsaWVudCBzZWNyZXQ=, is decoded as **"client_id:client secret".** They also use Form url encoded... Here's a example of the header for the token exchange. ``` POST https://api.fitbit.com/oauth2/token Authorization: Basic Y2xpZW50X2lkOmNsaWVudCBzZWNyZXQ= Content-Type: application/x-www-form-urlencoded ``` The errors that I receive when trying to exchange the token are: ``` HTTP Status 401: Unauthorized, Response: {"errors":[{"errorType":"invalid_client","message":"Incorrect authorization method. Visit https://dev.fitbit.com/docs/oauth2 for more information on the Fitbit Web API authorization process."}],"success":false} ```
kerem 2026-03-03 16:45:33 +03:00
Author
Owner

@phimage commented on GitHub (Nov 9, 2015):

maybe a workaround, did you try with a url like this into access_token_url
https://client_id:client secret@api.fitbit.com/oauth2/token

anyway the postOAuthAccessTokenWithRequestTokenByCode send secret using query string
We must find a cool way to allow custom header ie. change "Bearer : token" by "Basic: base64(clientid:secret)"

Can add an enum param
which modify parameters["grant_type"] = "authorization_code" to "password"
then client and credential must check the type before creating headers

http://tools.ietf.org/html/draft-ietf-oauth-v2-23
4.3. Resource Owner Password Credentials Grant

<!-- gh-comment-id:155045918 --> @phimage commented on GitHub (Nov 9, 2015): maybe a workaround, did you try with a url like this into access_token_url https://client_id:client secret@api.fitbit.com/oauth2/token anyway the `postOAuthAccessTokenWithRequestTokenByCode` send secret using query string We must find a cool way to allow custom header ie. change "Bearer : token" by "Basic: base64(clientid:secret)" Can add an enum param which modify parameters["grant_type"] = "authorization_code" to "password" then client and credential must check the type before creating headers http://tools.ietf.org/html/draft-ietf-oauth-v2-23 4.3. Resource Owner Password Credentials Grant
Author
Owner

@phimage commented on GitHub (Nov 18, 2015):

Read from FiBit doc

Applications should upgrade to OAuth 2.0 by March 14, 2016. OAuth 1.0a support will be removed from the Fitbit Web API on April 12, 2016.

so we must do it ;)

Fitbit supports the Authorization Code Grant and Implicit Grant flows as defined in RFC 6749.

not password grant

response_type required
code for Authorization Code Grant flow
token for Implicit Grant flow

you can try with "token"

grant_type required authorization_code
so they use Basic with authorization_code, not Bearer
so I can't rely on this , see my previous comment

I think I make confusion between Auth headers used for the auth flow, and the Auth headers used after auth (to make api call)
In RFC Auth headers are not mandatory for auth, but sometime necessary and will be Basic one
see 4.1.3. Access Token Request
http://tools.ietf.org/html/draft-ietf-oauth-v2-23

Doing this just to get token work (but I can commit because other api could failed)

        let utf8str = "\(self.consumer_key):\(self.consumer_secret)".dataUsingEncoding(NSUTF8StringEncoding)
        if let base64Encoded = utf8str?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
        {
            return ["Authorization":  "Basic \(base64Encoded)"]
        }

iOS applications may use the SFSafariViewController class instead of app switching to Safari. Use of the WKWebView or UIWebView class is prohibited.

I will add an handler type with this controller as example or into framework
edit: 11424b643a

<!-- gh-comment-id:157613050 --> @phimage commented on GitHub (Nov 18, 2015): Read from FiBit doc > Applications should upgrade to OAuth 2.0 by March 14, 2016. OAuth 1.0a support will be removed from the Fitbit Web API on April 12, 2016. so we must do it ;) > Fitbit supports the Authorization Code Grant and Implicit Grant flows as defined in RFC 6749. not password grant > response_type required > code for Authorization Code Grant flow > token for Implicit Grant flow you can try with "token" > grant_type required authorization_code > so they use Basic with authorization_code, not Bearer > so I can't rely on this , see my previous comment I think I make confusion between Auth headers used for the auth flow, and the Auth headers used after auth (to make api call) In RFC Auth headers are not mandatory for auth, but sometime necessary and will be Basic one see 4.1.3. Access Token Request http://tools.ietf.org/html/draft-ietf-oauth-v2-23 Doing this just to get token work (but I can commit because other api could failed) ``` swift let utf8str = "\(self.consumer_key):\(self.consumer_secret)".dataUsingEncoding(NSUTF8StringEncoding) if let base64Encoded = utf8str?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0)) { return ["Authorization": "Basic \(base64Encoded)"] } ``` > iOS applications may use the SFSafariViewController class instead of app switching to Safari. Use of the WKWebView or UIWebView class is prohibited. I will add an handler type with this controller as example or into framework edit: 11424b643a8a043430e1c8f7341a6337d5810677
Author
Owner

@phimage commented on GitHub (Nov 19, 2015):

see b74da75
I add accessTokenBasicAuthentification and use in demo code for FitBit and Oauth2

<!-- gh-comment-id:158047868 --> @phimage commented on GitHub (Nov 19, 2015): see b74da75 I add `accessTokenBasicAuthentification` and use in demo code for FitBit and Oauth2
Author
Owner

@amruss commented on GitHub (Jan 26, 2016):

This was awesome, thank you!

<!-- gh-comment-id:175132858 --> @amruss commented on GitHub (Jan 26, 2016): This was awesome, thank you!
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/OAuthSwift#86
No description provided.