该问题的答案实际上是我在客户端使用授权代码授予流。.这是导致阻塞错误的原因。
在下面检查功能验证OAUTH2隐式授予Fitbit API。
我正在针对Fitbit API执行OAuth2身份验证。全部使用授权码授予流程。因此,首先获取身份验证代码,将其重定向到我的应用程序,然后将其交换为访问令牌,并使用此令牌获取数据。
从“ post_request.html”页面上的主页开始,按“ fitbit”按钮,将用户重定向到Fitbit的授权端点。我正在使用Node.js构建本地服务器来托管应用程序,并能够进行重定向而没有任何问题。
在重定向后,我检索了授权代码并发出AJAX POST请求以将授权代码换成访问令牌。然后,我发出此POST请求,但出现以下错误。
{"errors":[{"errorType":"invalid_client","message":"Invalid authorization header format. The header was not recognized to be a valid header for any of known implementations or a client_id was not specified in case of a public client Received header = BasicdW5kZWZpbmVk. Visit https://dev.fitbit.com/docs/oauth2 for more information on the Fitbit Web API authorization process."}],"success":false}
我认为在对client_id和client_secret进行编码的网址中可能存在错误。或者在我设置标题。但是我看不到它。谁能帮我吗?
我的HTML文件如下。
<body>
<button onclick="fitbitAuth()">Fitbit</button>
<!-- action = route, method = method -->
<form action="/" method="POST" id="form">
<h3>Email Address:</h3>
<input type="email">
<br>
<h3>Password:</h3>
<input type="password">
<br>
<br>
<button type="submit">Send Request</button>
</form>
</body>
</html>
我的脚本如下,它包含3个功能。 -base64编码功能 -用于启动OAuth2进程的onclick函数 -以身份验证代码交换访问令牌的功能
// run this script upon landing back on the page with the authorization code
// specify and/ or calculate parameters
var url_terug = window.location.search;
var auth_code = url_terug.substr(6);
var granttype = "authorization_code";
var redirect_uri = "http://localhost:3000/fitbit";
var client_id = "xxxxx";
var client_secret = "xxxxxxxxxxxx";
var stringto_encode = client_id + ":" + client_secret;
var encoded_string = "";
console.log("auth code = " + auth_code);
function baseEncode(stringto_encode){
encoded_string = btoa(stringto_encode);
console.log(encoded_string);
}
function getTokenFitBit(){
baseEncode();
// execute a POST request with the right parameters
var request = new XMLHttpRequest();
request.open('POST', "https://api.fitbit.com/oauth2/token?client_id=" + client_id + "&grant_type=" + granttype + "&redirect_uri=" + redirect_uri + "&code=" + auth_code);
request.setRequestHeader('Authorization', 'Basic'+ encoded_string);
request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
// Setup our listener to process completed requests
request.onload = function () {
// Process our return data
// status code between 200 and 300 indicates success
if (request.status >= 200 && request.status < 300) {
console.log('success!', request);
console.log(request.responseText);
// continue with API calls..
// you could set up a broader response handling if there is a use case for it
} else {
console.log('The current token request failed!');
}
};
request.send();
}
getTokenFitBit();
// get the access token out of the JSON response
// execute a GET request on the API endpoint
// handle the data
// upon clicking fitbit button, starting off the oauth2 authentication
function fitbitAuth() {
window.location.href = 'https://www.fitbit.com/oauth2/authorize?client_id=xxxxx&response_type=code&scope=activity&redirect_uri=http://localhost:3000/fitbit&prompt=consent';
}
答案 0 :(得分:1)
在上面的示例中,您似乎缺少“ Basic”标头与其在此行中的值之间的分隔符:
//check if there's a hardware on the device, then lunch the camera app on click
if (hasCamera()) {
//---
snapFab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
requestPermission();
}
});
//---
} else {
snapFab.setEnabled(false);
Toast.makeText(this, "You don't have a hardware to handle camera events", Toast.LENGTH_LONG).show();
}
假设您正在构建基于Web的应用程序,那么您可能也想使用“隐式”流程进行研究:https://oauth.net/2/grant-types/implicit/
答案 1 :(得分:0)
以下代码起作用并使用隐式授予流。它与FitBit API,Node.js一起重定向到应用程序,然后再进行客户端身份验证。
Node.js本地服务器模块的代码
// PROJECT authenticating Fitbit OAuth2 Implicit Grant
const express = require("express");
const app = express();
const filesys = require("fs");
const path = require("path");
// body parser module parses form data into server
const body_parse = require("body-parser");
// middleware to encrypt folder structure for users : can look into DevTools
app.use('/public', express.static(path.join(__dirname, 'static')));
// allows us to parse url encoded forms
app.use(body_parse.urlencoded({extended: false}));
// using readstream with chunks in buffer with security on the path
app.get("/fitbit", (req, res) => {
const readStream = filesys.createReadStream(path.join(__dirname,'static','post_request.html'));
readStream.on('error', function(){
/*handle error*/
res.write("there is an error authenticating against fitbit api endpoint");
});
res.writeHead(200, {'Content-type' : 'text/html'});
readStream.pipe(res);
});
// bodyparser parses data and adds to the body of the request
app.get("/", (req, res, err) => {
const readStream = filesys.createReadStream(path.join(__dirname,'static','start_page.html'));
res.writeHead(200, {'Content-type' : 'text/html'});
readStream.pipe(res);
});
app.listen(3000);
起始页的HTML文件,仅带有一个按钮即可启动OAuth2进程。
<body>
<button onclick="fitbitAuth()">Fitbit</button>
<script>
// define variables
var cli_id = "xxxxx";
var res_typ = "token";
var scope_typ = "activity";
var redirect = "http://localhost:3000/fitbit";
var expires = "31536000";
var prompt_var = "consent";
// upon clicking fitbit button, starting off the oauth2 authentication
function fitbitAuth() {
window.location.href = "https://www.fitbit.com/oauth2/authorize?client_id=" + cli_id + "&response_type=" + res_typ + "&scope=" + scope_typ + "&redirect_uri=" + redirect + "&expires_in=" + expires + "&prompt=" + prompt_var;
}
</script>
</body>
</html>
重定向页面,在同意使用他/她的数据后,用户将被发送回该页面。仅需一个按钮即可启动有关生命周期活动统计信息的API调用。
<body>
<!-- action = route, method = method -->
<button type="submit" onclick="getActivityData()">Send Request</button>
<script>
// get out the accesstoken from the provided data
var url_terug = window.location.href;
var split_after = "access_token=";
var split_before = "&user_id";
var after_string = url_terug.split(split_after).pop();
var accesstoken = after_string.slice(0, after_string.indexOf(split_before));
console.log(accesstoken);
// getActivityData();
function getActivityData(){
// execute a POST request with the right parameters
var request = new XMLHttpRequest();
request.open('GET', "https://api.fitbit.com/1/user/-/activities.json");
request.setRequestHeader('Authorization', 'Bearer '+ accesstoken);
// Setup our listener to process completed requests
request.onload = function () {
// Process our return data
// status code between 200 and 300 indicates success
if (request.status >= 200 && request.status < 300) {
console.log('success!', request);
console.log(request.responseText);
// continue with API calls..
// you could set up a broader response handling if there is a use case for it
} else {
console.log('The current token request failed!');
}
};
request.send();
}
</script>
</body>