
最后更新:2026 年 5 月 28 日
TL;DR:Quire OAuth 2.0 API 让你的应用能够代表用户操作其 Quire 账户,而无需存储他们的密码。你需要一个已注册的 OAuth 应用(客户端 ID、密钥、重定向 URL)、四步授权流程(配置、重定向、处理响应、用授权码换取令牌),以及刷新令牌循环——因为访问令牌一小时后就会过期。
构建一个能读取或修改用户 Quire 数据的应用,首先要做一个决定:如何在不接触用户密码的情况下完成身份验证?Quire API 通过 OAuth 2.0 给出了答案。本文将逐步介绍 OAuth 应用配置、四步授权流程、访问令牌与刷新循环,以及开发者首次构建时常踩的坑。
Quire OpenAPI 1.0.0 版本于 2019 年 10 月发布,至今保持稳定。通过 OAuth,用户授权你的应用访问其 Quire 内容(任务、项目、评论、分配、标签、截止日期),而你无需接触他们的凭据。用户随时可以撤销授权,且无需更改密码——这正是为什么在 OAuth 普及之前,存储密码的集成方式是一种安全反模式。
在接入 OAuth API 之前,先确认 API 是否真的是最合适的工具。2026 年 Quire 提供四种受支持的集成方式,各自解决不同的问题。
| 如果你需要… | 使用 | 原因 |
|---|---|---|
| 在自己的应用中代表用户读取或修改 Quire 数据 | Quire OAuth API(本文) | 用户授权、完整 CRUD 访问、无需轮询 |
| 响应 Quire 中的事件(任务创建、状态变更、评论添加) | Quire Webhooks | 推送驱动、无轮询开销、配置轻量 |
| 将 Quire 连接到 Claude 或其他 AI 代理 | Quire MCP 服务器 | LLM 工具的标准协议,内置预构建服务器 |
| 将 Quire 数据接入自动化或 BI 工作流 | OAuth API 配合 n8n 或 Power BI | 成熟的数据管道,减少自定义代码 |
如果你正在构建典型的应用集成(移动应用、Web 仪表板、同步服务),OAuth API 就是你需要的。本文其余部分默认你走的是这条路。
使用 Quire API 之前,你需要先创建一个 OAuth 应用。
创建应用需要先登录你的 Quire 账户。
前往 Quire 开发者应用控制台,点击 Create new app 按钮。

选择应用所属的 Quire 组织,该组织的成员可以查看和编辑所有属于该组织的应用。

填写应用名称和重定向 URL,重定向 URL 的作用我们稍后会介绍。现在可以先填写以下 URL:
http://localhost:3000/callback
点击 Create new app 按钮,新创建的 OAuth 应用将显示在开发者控制台页面上,你可以在此进一步配置。

总结一下,你需要记录以下三项信息:
http://localhost:3000/callback
在应用中存储配置信息。
const clientId = ':wJoMEodI4fSSR54pfNwIuIzLnaJ';
const clientSecret = 'eb8faf4nyd1wbeconw060e9ejui8zg6w8p1hyoex';
const redirectURI = 'http://localhost:3000/callback';
const authorizationUrl = 'https://quire.io/oauth';
const tokenUrl = 'https://quire.io/oauth/token';
const apiUrl = 'https://quire.io/api';生成授权 URL,将用户重定向到 Quire 的 OAuth 端点。用户登录 Quire 后,将看到一个页面,可在此授权你的应用访问其内容。
示例 URL:
https://quire.io/oauth?client_id=your-client-ID&redirect_uri=your-redirect-uri授权链接的实现示例如下:
var http = require('http');
var url = require('url');
var server = http.createServer(function (req, res) {
var uri = url.parse(req.url, true);
if (uri.pathname == '/') {
//..
} else if (uri.pathname == "/install") {
var authUrl = authorizationUrl
+ '?client_id=' + clientId
+ '&redirect_uri=' + encodeURIComponent(redirectURI);
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write(
'<html><body>'
+ '<a href="' + authUrl + '">Connect Quire</a>'
+ '</body></html>');
res.end();
} else if (uri.pathname == "/callback") {
//...
}
});
server.listen(3000);state 参数是一个随机字符串,用于防止跨站请求伪造(CSRF)攻击。你应该随机生成该字符串,它将在第三步原封不动地回传给你的应用,应用需要验证该值。虽然此参数是可选的,但我们强烈建议包含它。
示例 URL:
https://quire.io/oauth?client_id=your-client-ID&redirect_uri=your-redirect-uri&state=lpcl9v94zOAuth 2.0 服务器会通过 redirect_uri 中指定的 URL 响应你的应用访问请求。
如果用户批准了访问请求,响应中将包含一个授权码。如果用户拒绝,响应中将包含错误信息。返回给 Web 服务器的授权码或错误信息会出现在查询字符串中,如下所示:
错误响应:
http://localhost:3000/callback?error=access_denied授权码响应:
http://localhost:3000/callback?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7回调处理示例:
//...
} else if (uri.pathname == "/callback") {
var result = uri.query;
var message = 'Auth fail';
if (result["error_description"] != null) {
message = result["error_description"];
if (result["error"] == 'access_denied') {
//display reject message
}
messageView(res, message);
} else if (result["code"] != null) {
return exchangeAccessToken(result["code"])
.then(function(data) {
var token = data['access_token'];
message = token != null ? 'Success': 'Fail';
messageView(res, message);
});
}
}当用户被重定向回你的应用 redirect_uri 时,查询字符串参数中也会包含 code 和 state 参数。state 是你的 CSRF 防伪令牌,用于验证请求的合法性。
从查询字符串参数中提取 code 和 state,此时可以验证 state 的值。
验证示例:
} else if (result["code"] != null) {
if (result["state"] != stateFromSession(res))
return messageView(res, 'invalid state');
return exchangeAccessToken(result["code"])
.then(function(data) {
var token = data['access_token'];
message = token != null ? 'Success': 'Fail';
messageView(res, message);
});
}你的应用需要向令牌端点发起 POST 请求,携带提取到的授权码以及以下请求参数。
| 参数 | 值 |
|---|---|
| grant_type | authorization_code |
| code | {your-authorization-code} |
| client_id | {your-client-ID} |
| client_secret | {your-client-secret} |
| redirect_uri | 如果你在第二步中指定了 redirect_uri,则此参数为必填项,且值必须与第二步中使用的完全一致。 |
请求访问令牌的示例:
var request = require('request');
function exchangeAccessToken(code) {
return new Promise(function(resolve, reject){
request.post({
url: tokenUrl,
form: {
grant_type: 'authorization_code',
code: code,
client_id: clientId,
client_secret: clientSecret,
redirect_uri: redirectURI
}
},
function (error, httpResponse, body) {
if (error) {
return reject(error);
}
resolve(JSON.parse(body))
});
});
}响应中返回的访问令牌为 JSON 格式。
响应示例:
{
"access_token":"ACCESS_TOKEN",
"token_type": "bearer",
"expires_in":2592000,
"refresh_token":"REFRESH_TOKEN"
}请妥善且永久保存该令牌,因为访问每一个 Quire API 都需要用到它。
你的应用现在已经拥有访问令牌,可以代表用户发起 API 调用了。
在请求头中以 bearer token 的形式传入访问令牌来发起 API 调用。
API 调用示例:
function getCurrentUser(token) {
return new Promise(function(resolve, reject){
request.get({
url: apiUrl + '/user/id/me',
headers: {
"Authorization": "Bearer " + token
}
},
function (error, httpResponse, body) {
if (error) {
return reject(error);
}
resolve(JSON.parse(body))
});
});
}响应示例:
{
"email": "john@gmail.cc",
"website": "https://coolwebsites.com",
"id": "My_ID",
"description": "This is *cool*!",
"url": "https://quire.io/u/My_ID",
"nameText": "My Name",
"nameHtml": "My Name",
"descriptionText": "This is cool!",
"descriptionHtml": "This is <i>cool</i>!",
"image": "https://quire.s3.amazonaws.com/oid/image.jpg",
"iconColor": "37",
"name": "My Name",
"oid": "Dyh2YkFcu9uLgLFIeN1kB4Ld"
}访问令牌本身就是为短期使用而设计的,这是 OAuth 2.0 的重要安全机制。使用授权码授权流程时,访问令牌默认有效期为一小时。
访问令牌过期后,将返回 HTTP 401 错误:
{
code: 401,
message: 'Invalid or expired token.'
}
Your application will need to refresh the access token.
function refreshToken(refreshToken) {
return new Promise(function(resolve, reject){
request.post({
url: tokenUrl,
form: {
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: clientId,
client_secret: clientSecret
}
},
function (error, httpResponse, body) {
if (error) {
return reject(error);
}
resolve(JSON.parse(body))
});
});
}或者,你也可以将用户重定向回身份验证流程。
观察各团队基于 Quire API 的开发过程,同样的五个问题反复出现。这些问题都不难发现,也完全可以避免。
1. 将客户端密钥存储在客户端代码中。 客户端密钥本就是机密信息。如果它出现在移动应用的二进制文件或浏览器打包文件中,任何人都可以提取并冒充你的应用。密钥只应存在于你控制的服务器上。如果你的应用是纯客户端应用(单页应用、移动应用),应使用 OAuth 2.0 PKCE 流程,而不是内嵌密钥。
2. 忘记验证 state 参数。 state 参数的存在是为了防止 CSRF 攻击。如果你在回调时跳过验证,就留下了一个漏洞,恶意网站可以利用它将 Quire 账户静默关联到攻击者的应用会话。每次请求都要生成新的 state,将其存储在会话中,并拒绝任何返回 state 不匹配的回调。
3. 将访问令牌视为永久有效。 访问令牌一小时后过期。那些存储令牌后从不刷新的应用,第一天运行正常,第二天就会悄然失效。在上线之前就构建好刷新令牌循环,不要等用户投诉后再亡羊补牢。
4. 通过轮询 API 获取变更。 轮询会消耗频率限制、增加延迟、耗尽电量。如果你需要响应 Quire 中的变更,请改用 webhooks。Webhook 会即时将事件推送给你,原本需要发起的 API 调用根本不需要发生。
5. 跳过重定向 URL 白名单配置。 每个 OAuth 应用注册时都要填写允许的重定向 URL 列表。如果你使用通配符或配置不够精确,攻击者就可以将自己的回调注册为你的重定向目标,从而截获授权码。只添加你的应用实际使用的精确 URL。
如果你是第一次对接 API,最快的学习方式是 fork 一个现有集成(比如 n8n 连接器)并研究它如何处理身份验证、刷新和错误状态。
以下三种场景应该选择其他集成方式。
如果以上都不适用,OAuth API 就是你的工具。
不需要。Quire API 在所有计划中均可使用,包括 Free 层。所有计划均有频率限制;请查阅 API 文档了解当前每个应用的具体限制。
该 API 基于 HTTP,使用 JSON 格式的请求和响应体,因此任何支持 HTTP 客户端和 JSON 解析器的语言都可以使用。本文示例使用 JavaScript,但相同的流程同样适用于 Python、Go、Ruby、PHP 及其他任何语言。目前没有官方客户端库;常见的做法是在你所用语言的 HTTP 客户端上封装一个薄层。
访问令牌默认在一小时后过期。刷新令牌的有效期更长,可用于在不重新提示用户的情况下获取新的访问令牌。从第一天起就将刷新令牌循环内置到你的应用中。
可以。OAuth 作用域允许你只申请应用所需的权限。如果你的应用只读取任务,则申请读取作用域即可。Quire 用户在授权页面上会看到所请求的作用域,如果权限申请过多,他们可以拒绝,因此过度申请权限会影响转化率。
API 是一个通用 REST 接口,适用于任何需要代表用户读取或修改 Quire 数据的应用。MCP 服务器专为 Claude 和其他 LLM 代理设计:它处理身份验证、提供标准工具模式,意味着你无需自己编写 OAuth 代码。传统应用集成使用 API;LLM 代理集成使用 MCP。
以上就是 Quire API 的完整 OAuth 2.0 流程:OAuth 应用配置、四步授权、访问令牌使用,以及刷新循环。开发者最常遇到的情况是——集成上线时运行正常,两天后突然失效——根本原因就是把刷新循环当成"以后再说"的事,而不是从第一天起就内置进去。
前往 Quire 开发者应用控制台开始,或阅读完整的 API 参考文档。如果你根本不想写 OAuth 代码,Quire MCP 服务器会为你处理身份验证,是 LLM 代理集成的最佳选择。对于事件驱动的集成,webhooks 通常比大多数首次 API 集成最终依赖的轮询模式更合适。