
Last updated: May 28, 2026
TL;DR: Quire OAuth 2.0 API를 사용하면 앱이 사용자의 비밀번호를 저장하지 않고도 사용자의 Quire 계정에서 작업할 수 있습니다. 등록된 OAuth 앱(클라이언트 ID, 보안 키, 리디렉션 URL), 4단계 인증 흐름(설정, 리디렉션, 응답 처리, 코드와 토큰 교환), 그리고 액세스 토큰이 1시간 후 만료되기 때문에 리프레시 토큰 루프가 필요합니다.
사용자의 Quire 데이터를 읽거나 수정하는 앱을 구축할 때 가장 먼저 결정해야 할 것은 사용자의 비밀번호를 직접 보지 않고 어떻게 인증할 것인가입니다. Quire API는 OAuth 2.0으로 이 문제를 해결합니다. 이 포스트에서는 OAuth 앱 설정, 4단계 인증 흐름, 액세스 토큰과 갱신 루프, 그리고 개발자들이 첫 번째 빌드에서 자주 실수하는 부분들을 살펴봅니다.
Quire의 OpenAPI 1.0.0은 2019년 10월에 출시된 이후 안정적으로 유지되고 있습니다. OAuth를 통해 사용자는 앱이 자신의 Quire 콘텐츠(업무, 프로젝트, 댓글, 담당자, 태그, 마감일)에 접근할 수 있도록 승인하며, 앱은 사용자의 자격 증명을 직접 다루지 않습니다. 사용자는 비밀번호를 변경하지 않고도 언제든지 해당 접근 권한을 취소할 수 있습니다. 이것이 바로 OAuth가 등장하기 전, 비밀번호를 저장하는 통합 방식이 보안상 문제가 있었던 이유입니다.
OAuth API를 연결하기 전에 API가 실제로 올바른 도구인지 먼저 확인하세요. 2026년 현재 Quire는 네 가지 통합 방식을 지원하며, 각각 서로 다른 문제를 해결합니다.
| 필요한 작업 | 사용 도구 | 이유 |
|---|---|---|
| 자체 앱에서 사용자를 대신해 Quire 데이터 읽기 또는 수정 | Quire OAuth API (이 포스트) | 사용자 승인, 전체 CRUD 접근, 폴링 불필요 |
| Quire 이벤트에 반응 (업무 생성, 상태 변경, 댓글 추가) | Quire 웹훅 | 푸시 기반, 폴링 오버헤드 없음, 간편한 설정 |
| Quire를 Claude 또는 다른 AI 에이전트에 연결 | Quire MCP 서버 | LLM 도구를 위한 표준 프로토콜, 사전 구축된 서버 제공 |
| Quire를 자동화 또는 BI 워크플로우에 연결 | OAuth API + n8n 또는 Power BI | 검증된 파이프라인, 커스텀 코드 최소화 |
일반적인 앱 통합(모바일 앱, 웹 대시보드, 동기화 서비스)을 구축하고 있다면 OAuth API가 적합합니다. 이 포스트의 나머지 부분은 그 경로를 선택했다는 가정 하에 진행됩니다.
Quire API를 사용하려면 OAuth 앱을 먼저 만들어야 합니다.
앱을 만들려면 Quire 계정에 로그인되어 있어야 합니다.
Quire 개발자 앱 콘솔로 이동하여 새 앱 만들기 버튼을 클릭합니다.

앱이 속할 Quire 조직을 선택합니다. 해당 조직의 멤버는 선택한 조직에 속한 모든 앱을 보거나 편집할 수 있습니다.

앱 이름과 리디렉션 URL을 입력합니다. 리디렉션 URL의 역할은 나중에 설명합니다. 지금은 다음 URL을 사용하세요:
http://localhost:3000/callback
새 앱 만들기 버튼을 클릭하면 새로 만든 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';사용자를 Quire의 OAuth 엔드포인트 URI로 리디렉션할 인증 URL을 생성합니다. 이 URL은 로그인한 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(Cross-Site Request Forgery) 공격을 방지하기 위한 임의의 문자열입니다. 무작위 문자열을 생성해야 하며, 3단계에서 변경 없이 앱으로 다시 전달됩니다. 앱에서 이 값을 반드시 검증해야 합니다. 선택 사항이지만, 이 파라미터를 포함하는 것을 강력히 권장합니다.
샘플 URL:
https://quire.io/oauth?client_id=your-client-ID&redirect_uri=your-redirect-uri&state=lpcl9v94zOAuth 2.0 서버는 redirect_uri에 지정된 URL을 사용하여 앱의 접근 요청에 응답합니다.
사용자가 접근 요청을 승인하면 응답에 인증 코드가 포함됩니다. 사용자가 요청을 거부하면 응답에 오류 메시지가 포함됩니다. 웹 서버로 반환되는 인증 코드 또는 오류 메시지는 아래와 같이 쿼리 문자열에 나타납니다:
오류 응답:
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 | {인증 코드} |
| client_id | {클라이언트 ID} |
| client_secret | {클라이언트 보안 키} |
| redirect_uri | 2단계에서 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를 호출할 수 있습니다.
요청 헤더에 액세스 토큰을 베어러 토큰으로 전달하여 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의 중요한 보안 메커니즘입니다. 인증 코드 부여 흐름을 사용할 때 액세스 토큰의 기본 유효 시간은 1시간입니다.
액세스 토큰이 만료되면 HTTP 401 오류가 반환됩니다:
{
code: 401,
message: 'Invalid or expired 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. 클라이언트 보안 키를 클라이언트 측 코드에 저장하는 것. 클라이언트 보안 키는 말 그대로 비밀입니다. 모바일 앱 바이너리나 브라우저 번들에 포함되면 누구든 추출하여 앱을 가장할 수 있습니다. 보안 키는 직접 제어하는 서버에만 저장해야 합니다. 순수 클라이언트 측 앱(SPA, 모바일)이라면 보안 키를 포함하는 대신 OAuth 2.0 PKCE 흐름을 사용하세요.
2. state 파라미터 검증을 생략하는 것. state 파라미터는 CSRF 공격을 방지하기 위해 존재합니다. 콜백에서 검증을 건너뛰면 악의적인 사이트가 Quire 계정을 공격자의 앱 세션에 몰래 연결하는 데 악용할 수 있는 허점이 생깁니다. 요청마다 state를 생성하고, 세션에 저장하며, 반환된 state가 일치하지 않는 모든 콜백을 거부하세요.
3. 액세스 토큰을 영구적인 것으로 취급하는 것. 액세스 토큰은 1시간 후 만료됩니다. 토큰을 저장하고 갱신하지 않는 앱은 첫째 날은 잘 작동하다가 둘째 날 조용히 멈춥니다. 사용자 불만이 생기면 고치겠다는 식이 아니라, 배포 전에 리프레시 토큰 루프를 먼저 구축하세요.
4. 변경 사항을 감지하기 위해 API를 폴링하는 것. 폴링은 속도 제한, 지연 시간, 배터리를 낭비합니다. Quire의 변경 사항에 반응해야 한다면 웹훅을 사용하세요. 웹훅은 이벤트를 즉시 전달하므로, 해당 이벤트를 감지하기 위한 API 호출 자체가 필요 없어집니다.
5. 리디렉션 URL 허용 목록을 건너뛰는 것. 모든 OAuth 앱 등록은 리디렉션 URL 목록을 허용합니다. 와일드카드를 사용하거나 정확하게 설정하지 않으면 공격자가 자신의 콜백을 리디렉션 대상으로 등록하여 인증 코드를 가로챌 수 있습니다. 앱에서 실제로 사용하는 정확한 URL만 추가하세요.
처음으로 API를 구축한다면, n8n 커넥터와 같은 기존 통합을 포크하고 인증, 갱신, 오류 처리 방식을 공부하는 것이 패턴을 익히는 가장 빠른 방법입니다.
대신 다른 통합 방식을 선택해야 하는 세 가지 패턴이 있습니다.
위의 경우에 해당하지 않는다면 OAuth API가 적합한 도구입니다.
아니요. Quire API는 무료 티어를 포함한 모든 플랜에서 사용할 수 있습니다. 모든 플랜에 속도 제한이 적용됩니다. 현재 앱별 제한은 API 문서에서 확인하세요.
API는 JSON 요청 및 응답 본문을 사용하는 HTTP 기반이므로, HTTP 클라이언트와 JSON 파서가 있는 모든 언어에서 작동합니다. 이 포스트의 예시는 JavaScript로 작성되었지만, 동일한 흐름이 Python, Go, Ruby, PHP 등 모든 언어에서 동일하게 작동합니다. 공식 클라이언트 라이브러리는 없습니다. API 범위가 충분히 작아서 언어의 HTTP 클라이언트를 얇게 래핑하는 것이 일반적인 패턴입니다.
액세스 토큰은 기본적으로 1시간 후에 만료됩니다. 리프레시 토큰은 더 오래 유지되며, 사용자에게 다시 승인을 요청하지 않고도 새 액세스 토큰을 얻는 데 사용할 수 있습니다. 처음부터 앱에 리프레시 토큰 루프를 구축해 두세요.
네. OAuth 스코프를 사용하면 앱에 필요한 권한만 요청할 수 있습니다. 앱이 업무만 읽는 경우에는 읽기 스코프만 요청하면 됩니다. Quire 사용자는 인증 페이지에서 요청된 스코프를 확인하고 요청이 과도하다고 느끼면 거부할 수 있으므로, 필요 이상의 권한을 요청하면 전환율이 낮아집니다.
API는 사용자를 대신해 Quire 데이터를 읽거나 수정하려는 모든 앱을 위한 범용 REST 인터페이스입니다. MCP 서버는 Claude 및 기타 LLM 에이전트를 위해 특별히 설계된 것으로, 인증을 처리하고 표준 도구 스키마를 제공하므로 OAuth 코드를 직접 작성할 필요가 없습니다. 전통적인 앱 통합에는 API를, LLM 에이전트 통합에는 MCP를 사용하세요.
지금까지 Quire API의 전체 OAuth 2.0 흐름을 살펴보았습니다: OAuth 앱 설정, 4단계 인증, 액세스 토큰 사용, 그리고 갱신 루프까지. 잘 작동하는 통합을 구축했다가 이틀 후에 멈추는 가장 흔한 이유는 리프레시 루프를 나중에 고칠 문제로 미루는 것입니다. 처음부터 구축해 두세요.
Quire 개발자 앱 콘솔에서 시작하거나 전체 API 레퍼런스를 확인하세요. OAuth 코드를 직접 작성하고 싶지 않다면 Quire MCP 서버가 인증을 대신 처리해 주며, LLM 에이전트 통합에 적합한 선택입니다. 이벤트 기반 통합의 경우 대부분의 첫 번째 API 통합이 결국 사용하게 되는 폴링 패턴보다 웹훅이 더 나은 선택입니다.