커넥트 API 연동 가이드
AI Market 밖에서 운영하는 서비스가 접속한 사용자가 그 서비스를 구독 중인지 확인하고, 토큰·크레딧 사용량을 기록하는 방법을 순서대로 설명합니다. 사용자를 AI Market 승인 화면으로 보내 연동을 승인받고, 발급된 토큰으로 구독 상태를 조회합니다.
개요
커넥트 API는 OAuth 2.0 인가 코드 방식(PKCE 지원)을 따릅니다. 전체 흐름은 다음 5개의 요청으로 이루어집니다.
1 브라우저 GET /connect/authorize?client_id&redirect_uri&service_id&state → 로그인 후 승인
2 브라우저 → {redirect_uri}?code=nxac_…&state=… (거절 시 ?error=access_denied)
3 서버 POST /api/v1/connect/token grant_type=authorization_code → 접근 토큰·갱신 토큰
4 서버 GET /api/v1/connect/subscription Authorization: Bearer nxa_… → 실시간 구독 확인
5 서버 POST /api/v1/connect/usage {"amount": n} → 사용량 보고(월 제공량이 있는 서비스)
준비물은 3가지입니다. 크리에이터 계정(크리에이터 모드), 연동할 서비스(테스트 키는 임시저장 상태도 가능), 그리고 클라이언트 시크릿을 안전하게 보관하고 토큰을 교환할 서버입니다. 클라이언트 시크릿이 필요한 요청은 브라우저나 모바일 앱에서 직접 보내지 않습니다.
코드를 작성하기 전에 샌드박스에서 테스트 키로 전체 흐름을 실행해 보세요. 실제 요청·응답 형식과 오류 코드를 바로 확인할 수 있습니다.
1. API 키 발급
개발자 센터 › API 키에서 발급합니다. 계정마다 운영 키 한 쌍과 테스트 키 한 쌍이 발급됩니다.
연동할 서비스는 키가 아니라 승인 요청의 service_id로 지정합니다.
| 키 | 형식 | 용도 |
|---|---|---|
| 운영 키 | nxc_… / 시크릿 nxs_… | 실제 구매자의 구독 상태와 남은 보유량을 확인합니다. 판매 중인 서비스(활성 상태)만 승인할 수 있습니다. |
| 테스트 키 | nxc_test_… / 시크릿 nxs_test_… | 서비스 심사 전 연동을 만들고 검증합니다. 크리에이터 본인 계정으로만 승인됩니다. 실제 구독 없이 ‘구독 중’으로 응답하며, 사용량은 테스트 잔액에만 기록됩니다. |
client_id는 공개되어도 되는 식별자입니다.client_secret은 발급 직후 한 번만 표시되므로 서버 설정에 바로 저장하세요.
창을 닫으면 다시 확인할 수 없으며, 분실한 경우 [시크릿 재발급]으로 새 시크릿을 발급받습니다.
재발급 즉시 기존 시크릿은 사용할 수 없으며,client_id와 사용자 토큰은 유지됩니다.- [비활성화]는 승인, 토큰 발급, 구독 확인을 일시 정지하는 기능입니다. 다시 활성화하면 기존 연동을 그대로 사용할 수 있습니다.
시크릿이나 토큰이 유출된 경우에는 [시크릿 재발급]과 [연동 전체 해제](발급된 모든 사용자 토큰을 영구 폐기)를 함께 실행하세요.
2. 리다이렉트 URI 등록
승인 후 사용자를 돌려보낼 리다이렉트 URI를 API 키마다 등록합니다.
API 키 화면의 각 키 카드에서 한 줄에 하나씩, 최대 10개까지 입력할 수 있습니다.
- 요청의
redirect_uri는 등록한 값과 정확히 일치해야 합니다. 프로토콜, 포트, 슬래시, 대소문자까지 모두 일치해야 합니다. http://또는https://로 시작하는 절대 주소만 등록할 수 있으며, 프래그먼트(#)는 사용할 수 없습니다. 개발 단계인 경우에는http://localhost:3000/callback과 같은 로컬 주소도 등록할 수 있습니다.- 샌드박스에서 사용하는 콜백 주소 (
https://ai-market.co.kr/developer/sandbox/callback)는
승인 화면을 처음 열 때 테스트 키에 자동으로 등록됩니다.
3. 연동할 서비스 ID
API 키 화면 아래의 ‘연동할 서비스 ID’ 표에서 서비스 ID(UUID)를 복사하여
승인 요청의 service_id 값으로 전달합니다.
- 운영 키는 활성 상태인 서비스만, 테스트 키는 삭제되지 않은 모든 서비스
(임시저장, 검토 중 포함)를 승인할 수 있습니다. - 서비스가 여러 개인 경우 승인과 토큰은 서비스별로 각각 관리됩니다.
토큰은 승인한 서비스에 연결되므로 다른 서비스의 구독은 조회할 수 없습니다. - 기존에 발급된 키는
service_id없이도 발급 당시 선택한 서비스를 기준으로 동작합니다.
신규 코드에는service_id를 반드시 포함하세요.
4. 승인 요청
서비스에서 로그인 또는 구독 확인이 필요한 경우, 사용자를 아래 주소로 이동시킵니다.
로그인 상태가 아닌 경우 로그인 후 자동으로 승인 화면으로 이동합니다.
GET https://ai-market.co.kr/connect/authorize
?client_id=nxc_xxxxx
&redirect_uri=https%3A%2F%2Fmyservice.com%2Fcallback
&service_id=68f5f1e7-…
&state=임의의_문자열
&code_challenge=…&code_challenge_method=S256 # PKCE(선택)
| 파라미터 | 필수 | 설명 |
|---|---|---|
client_id | 필수 | 발급받은 클라이언트 ID(운영 키 또는 테스트 키) |
redirect_uri | 필수 | 등록한 리다이렉트 URI와 정확히 일치하는 값(URL 인코딩) |
service_id | 필수 | 연동할 서비스의 ID(3절) |
state | 권장 | CSRF 방지용 임의 값. 콜백에 그대로 돌아오므로 보낸 값과 같은지 확인합니다 |
code_challenge | 선택 | PKCE 챌린지(S256). base64url 43~128자. 보냈다면 5절에서 code_verifier가 필수입니다 |
code_challenge_method | 선택 | S256만 지원합니다. plain은 거절됩니다 |
PKCE 값 만들기
Node.js 예제: verifier, challenge, state 생성과 리다이렉트
import crypto from 'node:crypto';
const verifier = crypto.randomBytes(48).toString('base64url'); // 64자, 세션에 보관
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
const state = crypto.randomBytes(18).toString('base64url'); // 세션에 보관
const url = new URL('https://ai-market.co.kr/connect/authorize');
url.search = new URLSearchParams({
client_id: process.env.NEXA_CLIENT_ID,
redirect_uri: 'https://myservice.com/callback',
service_id: process.env.NEXA_SERVICE_ID,
state,
code_challenge: challenge,
code_challenge_method: 'S256',
}).toString();
res.redirect(url.toString());
콜백 처리
사용자가 승인하면 등록한 리다이렉트 URI로 code와 state가 전달됩니다.
거절하거나 취소한 경우 error=access_denied가 전달됩니다.
https://myservice.com/callback?code=nxac_xxxxx&state=보낸_값 # 승인
https://myservice.com/callback?error=access_denied&state=보낸_값 # 거절
- 콜백으로 전달된
state가 세션에 저장한 값과 일치하지 않는 경우 요청 처리를 중단하세요. - 인가 코드는 10분 동안 유효하며 한 번만 사용할 수 있습니다.
발급받은 인가 코드를 사용해 서버에서 토큰을 발급받으세요.
client_id, redirect_uri, service_id가 유효하지 않은 경우 오류 화면이 표시되며 리다이렉트는 진행되지 않습니다.
콜백이 전달되지 않는 경우 redirect_uri가 등록된 값과 정확히 일치하는지, service_id가 올바른 서비스의 ID인지 확인하세요. 운영 키는 활성 상태인 서비스에만 사용할 수 있습니다.
오류 코드는 API 레퍼런스에서 확인할 수 있습니다.
5. 토큰 교환
인가 코드를 사용해 접근 토큰을 발급받습니다. client_secret이 필요하므로 요청은 반드시 서버에서 전송해야 합니다.
요청 본문은 application/x-www-form-urlencoded 형식입니다.
curl -X POST https://ai-market.co.kr/api/v1/connect/token \
-d grant_type=authorization_code \
-d code=nxac_xxxxx \
-d client_id=nxc_xxxxx \
-d client_secret=nxs_xxxxx \
-d redirect_uri=https://myservice.com/callback \
-d code_verifier=… # PKCE를 사용한 경우에만
{
"access_token": "nxa_...",
"token_type": "Bearer",
"expires_in": 2592000,
"refresh_token": "nxr_..."
}
redirect_uri는 승인 요청에 전달한 값과 정확히 일치해야 합니다.- 접근 토큰은 30일, 갱신 토큰은 180일 동안 유효합니다.
토큰은 연동한 서비스와 승인한 사용자 기준으로 구분되므로 사용자별로 안전하게 보관하세요. - 요청에 실패한 경우
{"error", "error_description"}형식으로 오류가 반환됩니다.invalid_grant는 인가 코드 만료·재사용,redirect_uri불일치 또는 PKCE 검증 실패 시 발생할 수 있습니다. 해당 오류가 발생한 경우 승인 요청 단계부터 다시 시도하세요.
Node.js 예제: 콜백 라우트에서 토큰 교환
app.get('/callback', async (req, res) => {
const { code, state, error } = req.query;
if (error || state !== req.session.nexaState) return res.status(400).send('approval failed');
const r = await fetch('https://ai-market.co.kr/api/v1/connect/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
client_id: process.env.NEXA_CLIENT_ID,
client_secret: process.env.NEXA_CLIENT_SECRET,
redirect_uri: 'https://myservice.com/callback',
code_verifier: req.session.nexaVerifier,
}),
});
if (!r.ok) return res.status(400).json(await r.json()); // { error, error_description }
const token = await r.json(); // access_token · refresh_token · expires_in
await saveTokensForUser(req.user.id, token);
res.redirect('/');
});
Python 예제: requests
import requests
r = requests.post('https://ai-market.co.kr/api/v1/connect/token', data={
'grant_type': 'authorization_code',
'code': code,
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'redirect_uri': 'https://myservice.com/callback',
'code_verifier': verifier, # PKCE를 사용한 경우에만
}, timeout=10)
r.raise_for_status()
token = r.json() # access_token, refresh_token, expires_in
6. 구독 확인
구독 확인에는 접근 토큰만 필요하며 별도의 파라미터는 없습니다.
토큰은 연동한 서비스와 승인한 사용자 기준으로 구분되므로 다른 사용자의 구독 정보는 조회할 수 없습니다.
curl https://ai-market.co.kr/api/v1/connect/subscription \
-H "Authorization: Bearer nxa_..."
{
"active": true,
"status": "ACTIVE",
"mode": "live",
"user": { "id": "22270e30-...", "email": "user@example.com", "name": "홍길동", "nickname": "gildong" },
"service": { "id": "68f5f1e7-...", "title": "내 AI 서비스" },
"subscription": {
"id": "741171b0-...", "planId": "40413c13-...", "planName": "프로 플랜", "priceKrw": 29000,
"startedAt": "2026-08-08T02:31:12+09:00", "nextBillingAt": "2026-09-08T02:31:12+09:00",
"cancelledAt": null, "graceUntil": null
},
"usage": null,
"checkedAt": "2026-08-08T03:02:44+09:00"
}
active 값만으로 기본적인 구독 상태를 판단할 수 있습니다.
상태별 처리가 필요한 경우 아래 5가지 status 값을 참고하세요.
| status | active | 의미 | 권장 처리 |
|---|---|---|---|
ACTIVE | true | 정상 구독 중 | 정상 이용 |
PAST_DUE | true | 결제 실패 후 유예 중graceUntil까지 결제 재시도 | 이용 허용, 결제 수단 확인 안내 |
CANCEL_SCHEDULED | true | 해지 신청됨. nextBillingAt까지 유효 | 이용 허용, 종료 예정일 안내 |
EXPIRED | false | 과거 구독은 있으나 지금은 유효하지 않음 | 차단, 재구독 안내 ( subscription에 마지막 구독 정보) |
NONE | false | 이 서비스를 구독한 이력 없음 | 차단, 구독 안내 |
- 구독 상태는 요청 시점에 실시간으로 판정되며, 해지와 연체 상태도 즉시 반영됩니다.
로그인 시점에 확인하고, 세션 유지 중에는 주기적으로(예: 1시간마다) 재확인하는 것을 권장합니다. - 요청 한도는 분당 300회입니다. 구독 상태 조회 결과는 일정 시간 캐시하여 사용할 수 있습니다.
해지 등 상태 변경이 발생할 수 있으므로 캐시된 결과는 주기적으로 갱신하세요. - 시간은 ISO 8601 형식이며 KST 오프셋(
+09:00)을 포함합니다.nextBillingAt은ACTIVE상태에서 다음 결제일을,CANCEL_SCHEDULED상태에서 이용 종료일을 의미합니다. 구독은 월 단위입니다. - [단건 판매] 서비스는 항상
NONE으로 응답합니다.
구독 확인은 구독형(월 결제) 서비스에만 적용됩니다.
Node.js 예제: 401이면 갱신하고, 갱신도 실패하면 재승인
async function checkSubscription(userId) {
let tokens = await loadTokensForUser(userId);
let r = await fetch('https://ai-market.co.kr/api/v1/connect/subscription', { headers: { Authorization: `Bearer ${tokens.access_token}` } });
if (r.status === 401) {
tokens = await refreshTokens(tokens.refresh_token); // 8절 — 실패하면 null
if (!tokens) return { active: false, reauthorize: true }; // 4절부터 다시
r = await fetch('https://ai-market.co.kr/api/v1/connect/subscription', { headers: { Authorization: `Bearer ${tokens.access_token}` } });
}
const sub = await r.json();
return { active: sub.active, status: sub.status, usage: sub.usage };
}
7. 사용량 조회와 보고
월 제공량(토큰·크레딧)을 설정한 구독형 서비스는 구매자의 실제 사용량을 서버에서 전송하면 AI Market의 잔액에 반영됩니다.
구독 확인과 동일한 접근 토큰을 사용하며, 월 제공량을 설정하지 않은 서비스는 400 usage_not_enabled로 응답합니다.
조회
curl https://ai-market.co.kr/api/v1/connect/usage \
-H "Authorization: Bearer nxa_..."
보고
amount는 이번 요청의 사용량이며, 1 이상의 정수여야 합니다. 중복 요청 가능성이 있는 경우 idempotencyKey(100자 이하)를 포함하세요. 동일한 키는 중복 차감 없이 현재 잔액만 반환합니다(report.duplicate: true).
curl -X POST https://ai-market.co.kr/api/v1/connect/usage \
-H "Authorization: Bearer nxa_..." -H "Content-Type: application/json" \
-d '{"amount": 150, "idempotencyKey": "req-20260922-0001", "memo": "chat"}'
{
"active": true, "status": "ACTIVE", "mode": "live",
"report": { "amount": 150, "fromAllowance": 150, "fromTopup": 0, "overage": 0, "duplicate": false, "recordedAt": "2026-09-22T19:30:02+09:00" },
"usage": {
"unit": "크레딧", "monthlyTokens": 1000,
"period": { "start": "2026-09-22T19:20:11+09:00", "end": "2026-10-22T19:20:11+09:00", "used": 150 },
"totalTokens": 2000, "totalUsed": 150, "remaining": 1850,
"allowanceRemaining": 850, "topupRemaining": 1000, "lastReportedAt": "2026-09-22T19:30:02+09:00"
},
"checkedAt": "2026-09-22T19:30:02+09:00"
}
| 필드 | 의미 |
|---|---|
totalUsed | 전체 사용량. 이 구독에서 현재까지 집계된 사용량 |
totalTokens | 전체 보유량. 이번 결제 기간의 사용 가능량(월 제공량 + 이월된 추가 구매분 + 기간 중 추가 구매분) |
remaining | 남은 보유량. 월 제공 잔여량(allowanceRemaining) + 추가 구매 잔여량(topupRemaining) |
period | 이번 결제 기간과 해당 기간의 사용량. 월 제공량은 결제일마다 갱신되며 이월되지 않고, 추가 구매분만 다음 결제 기간으로 이월됩니다. |
- 차감 순서는 월 제공량 → 추가 구매분입니다. 잔여량을 초과하여 전송된 사용량도 처리되지만, 잔여량은 0으로 유지되며 초과분은
report.overage로 반환됩니다.
잔여량이 0인 경우 서비스 이용 여부는 각 서비스의 정책에 따라 처리합니다. - 추가 구매(팩)는 구매자 계정의 AI Market › 마이페이지 › 내 구독에서 구매할 수 있습니다.
잔여량이 부족한 경우 해당 화면으로 안내하세요. - 월 제공량과 단위는 구독 시점을 기준으로 고정됩니다.
이후 플랜의 제공량을 변경해도 기존 구독에는 반영되지 않습니다. - 폼 인코딩(
amount=150&idempotencyKey=...) 형식도 지원합니다.
요청 한도는 조회와 보고 각각 분당 300회입니다.
8. 토큰 갱신과 폐기
갱신: 접근 토큰이 만료되어 401 invalid_token이 반환된 경우 갱신 토큰을 사용해 새 접근 토큰과 갱신 토큰을 발급받습니다.
갱신 시 기존 접근 토큰과 갱신 토큰은 즉시 무효화되므로 새로 발급된 토큰을 저장하세요.
curl -X POST https://ai-market.co.kr/api/v1/connect/token \
-d grant_type=refresh_token \
-d refresh_token=nxr_... \
-d client_id=nxc_xxxxx \
-d client_secret=nxs_xxxxx
폐기: 사용자가 서비스에서 로그아웃하거나 연결을 해제하는 경우 토큰을 폐기합니다. 접근 토큰 또는 갱신 토큰 중 하나만 전달하면 두 토큰이 모두 폐기됩니다.
이미 폐기되었거나 확인할 수 없는 토큰을 전달해도 200 OK로 응답합니다.
curl -X POST https://ai-market.co.kr/api/v1/connect/revoke \
-d token=nxa_... \
-d client_id=nxc_xxxxx \
-d client_secret=nxs_xxxxx
9. 테스트 키와 샌드박스
검토 중이거나 임시저장 상태인 서비스도 테스트 키를 사용해 전체 흐름(승인 → 토큰 발급 → 구독 확인 → 사용량 처리)을 테스트할 수 있습니다.
- 승인 화면은 키를 발급한 크리에이터 계정으로 로그인한 경우에만 사용할 수 있습니다.
다른 계정으로 로그인한 경우test_owner_only오류 화면이 표시됩니다. - 승인 화면에는 ‘테스트 연동’ 표시가 추가되며, 이후 응답에는
"mode": "test"가 포함됩니다.
테스트 토큰은nxa_test_…/nxr_test_…형식으로 발급되어 로그에서 운영 토큰과 구분할 수 있습니다. - 구독 확인은 항상
active: true,status: "ACTIVE"로 응답합니다.
플랜 정보는 해당 서비스의 첫 번째 플랜을 기준으로 하며,nextBillingAt은 승인 시점으로부터 1개월 뒤로 설정됩니다. - 사용량은 테스트 잔액에만 반영됩니다. 월 제공량은 첫 번째 플랜의 설정을 따르며, 설정되지 않은 경우
usage_not_enabled로 응답합니다.
테스트 모드에서는 추가 구매 잔액이 제공되지 않으며,topupRemaining은 0으로 반환됩니다. 승인 시점으로부터 1개월 후 다음 기간이 자동으로 시작됩니다. 초기 상태부터 다시 테스트하려면 [테스트 데이터 초기화]를 실행하세요.
샌드박스 사용법
샌드박스에서는 전체 연동 흐름을 별도의 코드 작성 없이 브라우저에서 테스트할 수 있습니다.
- 테스트 키가 없는 경우 샌드박스에서 바로 발급할 수 있습니다.
client_secret은 발급 시 한 번만 표시되며, 샌드박스 이용에는 필요하지 않습니다. - 연동할 서비스를 선택하면 승인 요청 URL이 실시간으로 생성됩니다.
생성된 URL을 복사하여 작성한 코드와 비교할 수 있습니다. - [승인 화면 열기]를 선택하면 실제 승인 화면이 팝업으로 표시됩니다.
승인 완료 후 인가 코드가 샌드박스로 전달되며, 콜백 주소는 테스트 키에 자동으로 등록됩니다. - 인가 코드가 전달된 후 [토큰 발급]을 선택합니다.
이후 [구독 확인]과 사용량 조회·보고를 실행합니다. - [구독 확인], [사용량 조회], [사용량 보고], [토큰 갱신], [토큰 폐기]는 브라우저에서 Bearer 토큰을 사용해 실제 공개 API로 요청을 전송합니다.
오른쪽 콘솔에서 상태 코드, 응답 JSON,curl을 확인할 수 있습니다.
10. 운영 전환 체크리스트
-
client_id와client_secret을 운영 키로 교체하고, 응답의mode가live인지 확인합니다.
테스트 키로는 실제 구매자를 검증할 수 없습니다. - 연동할 서비스는 판매 중(활성) 상태여야 합니다. 운영 키는 활성 서비스만 승인할 수 있습니다.
- 운영 도메인의
redirect_uri를 운영 키에 등록했으며, 등록된 값과 요청 값이 정확히 일치합니다. -
client_secret은 서버의 환경 변수 또는 보안 저장소에만 보관합니다. 브라우저, 모바일 앱, 공개 저장소에는 포함하지 않습니다. -
state를 생성하여 요청에 포함하고, 콜백으로 반환된 값이 요청 시 전달한 값과 일치하는지 확인합니다. - 구독 확인 결과는 일정 시간 동안 임시 저장해 사용합니다.
401응답 시 토큰을 갱신하고, 갱신에 실패한 경우 재승인을 요청합니다. - 월 제공량이 있는 서비스는 사용 시점마다 사용량을 서버에서 전송하며,
remaining값을 기준으로 이용 가능 여부를 판단합니다. - 사용자가 로그아웃하거나 연결 해제를 선택한 경우 토큰을 폐기합니다.
11. 문제 해결
| 증상 | 원인과 조치 |
|---|---|
| 콜백이 전달되지 않고 AI Market 오류 화면이 표시됨 | redirect_uri 불일치(invalid_redirect), service_id 누락·서비스 불일치·비활성 서비스(invalid_service), 비활성 키(invalid_client)를 확인하세요.오류 코드는 API 레퍼런스에서 확인할 수 있습니다. |
테스트 키인데 test_owner_only가 표시된다 | 테스트 키 연동은 키를 발급한 크리에이터 본인 계정으로만 승인할 수 있습니다. 다른 계정(구매자 테스트 계정 등)으로 로그인한 상태인지 확인하세요. |
invalid_grant | 인가 코드 만료(10분) 또는 재사용, redirect_uri 불일치, PKCE 검증 실패, 갱신 토큰 만료 또는 이미 갱신된 경우 발생합니다.해당 오류가 발생한 경우 승인 요청 단계부터 다시 시도하세요. |
invalid_client(401) | client_id와 client_secret이 일치하지 않거나 키가 비활성 상태인 경우 발생합니다.시크릿을 재발급한 경우 기존 시크릿은 즉시 무효화됩니다. 보안상 정확한 원인은 구분하여 제공하지 않습니다. |
invalid_token(401) | 접근 토큰이 만료·폐기·갱신되었거나, 키가 비활성 상태이거나, 사용자 계정이 정지 또는 탈퇴한 경우 발생합니다. 토큰 갱신을 요청하고, 실패한 경우 재승인을 요청하세요. |
usage_not_enabled(400) | 이 서비스에는 월 제공량이 설정되어 있지 않습니다. 서비스 등록 폼의 토큰 항목에서 제공량을 설정하세요. 테스트 키는 첫 번째 플랜을 기준으로 합니다. |
subscription_inactive(403) | 사용량 API는 유효한 구독이 있는 경우에만 동작합니다. 구독 확인의 status 값을 확인하여 구독 상태에 맞게 안내하세요. |
| 429 | 요청 한도를 초과한 경우 발생합니다(토큰 분당 30회, 구독 확인과 사용량 분당 300회). 결과를 일정 시간 임시 저장해 사용하고, 재시도 간격을 충분히 확보하세요. |
temporarily_unavailable(503) | 테스트 키에서만 발생하는 오류입니다. 테스트 잔액 생성에 필요한 서비스 정보를 일시적으로 불러올 수 없는 경우 발생합니다. 잠시 후 다시 요청하세요. |
12. 보안 권장 사항
client_secret은 서버에서만 보관해야 합니다. 프런트엔드 번들, 모바일 앱, 공개 저장소에는 포함하지 않으며, 로그에도 기록하지 않습니다.state는 요청마다 새로 생성하여 세션에 저장하고, 콜백으로 반환된 값이 요청 시 전달한 값과 일치하는지 확인합니다. 가능하면 PKCE(S256)도 함께 사용하세요.- 사용자별 토큰은 암호화하여 저장하고, 사용자가 연결을 해제한 경우
/revoke요청으로 토큰을 폐기하세요. - 시크릿이나 토큰 유출이 의심되는 경우 API 키 화면에서 [시크릿 재발급]과 [연동 전체 해제]를 함께 실행하세요.
비활성화만으로는 토큰이 폐기되지 않으므로, 다시 활성화한 경우 기존 토큰을 사용할 수 있습니다. - 구독 상태 판정과 접근 제어는 서버에서 처리해야 합니다.
브라우저에 전달된 판정 결과는 변조될 수 있습니다.