외부 서비스 인증과 Cloud Secrets
플러그인 source와 .mplg에는 비밀 값이 들어가지 않습니다. package는 필요한 Credential·Connector·
Secret ID만 선언하고 실제 값은 사용자 Connection 또는 조직의 Cloud Secret에 저장합니다.
선택 기준
사용자 token을 Cloud Secret으로 공유하거나 조직 secret을 Instance settings에 복사하지 않습니다.
Manifest 선언
OAuth 계정:
{
"credentials": [
{
"id": "notion_account",
"label": "Notion 계정",
"description": "공유한 페이지를 읽습니다.",
"kind": "oauth_access_token",
"required": true,
"oauth_provider": "notion",
"allow_multiple": true
}
],
"connectors": [
{
"id": "notion_cloud",
"kind": "oauth",
"label": "Notion Cloud",
"description": "Notion 공식 OAuth 연결",
"credential_id": "notion_account",
"cloud_connection_id": "notion"
}
]
}
조직 Secret:
{
"cloud_project_id": "00000000-0000-4000-8000-000000000000",
"required_secrets": [
{
"id": "EXAMPLE_API_KEY",
"label": "Example API key",
"description": "서버 간 API 호출에 사용합니다.",
"required": true
}
],
"connectors": [
{
"id": "example_api",
"kind": "api_key",
"label": "Example API",
"description": "조직 API 연결",
"cloud_secret_id": "EXAMPLE_API_KEY"
}
]
}
cloud_project_id는 Developer Project에 연결할 때 발급된 실제 UUID를 사용합니다.
Developer Platform 설정
- 조직을 선택하고 Plugin Project를 엽니다.
- Secrets에서 manifest의
required_secrets.id와 같은 ID를 등록합니다. - Connections에서
cloud_connection_id와 같은 provider 설정을 만듭니다. - OAuth authorize URL, token URL, client ID, client secret, redirect URI를 공급자 문서와 맞춥니다.
- 필요한 header/content type과 PKCE 지원 여부를 명시합니다.
- source를 sync하고 새 Deployment를 build합니다.
Secret 값은 저장 후 다시 평문으로 표시되거나 source ZIP, MCP 응답, build log에 포함되면 안 됩니다. 변경은 새 값으로 덮어쓰고 필요한 경우 provider에서 기존 값을 폐기합니다.
사용자 연결 흐름
설치·활성화
→ 필요한 Connection 없음
→ 설정에서 “계정 연결”
→ Host가 state와 redirect를 생성
→ provider 승인
→ Host callback에서 state 검증과 token 교환
→ 암호화 저장
→ default Instance에 Connection 연결
allow_multiple: true이면 같은 default Instance 안에 여러 Connection을 만들고 사용자가 표시 이름으로
선택합니다. 같은 package root Instance를 복제해 계정을 추가하지 않습니다.
OAuth state와 redirect URI는 필수입니다. PKCE는 공급자 호환 설정에 따라 사용하지만 state 검증을 대체하지 않습니다. callback이 성공하기 전에 연결 완료로 표시하지 않습니다.
실행과 갱신
Capability는 connector_id만 참조합니다. Host는 선택된 Connection의 token을 요청 직전에 주입하고
응답과 로그에서 제거합니다. credential 거부가 명확하고 provider가 refresh를 지원하면 한 번 갱신한
뒤 전체 요청을 재시도합니다. 반복 실패는 “다시 연결” 상태로 전환합니다.
Connection 상태를 구분합니다.
ready: 필요한 credential과 runtime이 준비됨not_configured: 필수 Connection/Secret이 없음unavailable: provider, 암호화, dependency, network runtime을 사용할 수 없음- 만료·거부: 사용자 재연결 필요
연결 해제와 삭제
Instance Connection 삭제는 해당 연결 row의 encrypted credential, 진행 중 OAuth state, 관련 pending Host action을 로컬에서 정리하고 generation을 갱신합니다. 이 API를 provider token revoke가 완료됐다는 증거로 사용하지 않습니다.
기존 default credential 해제 API는 provider에 revocation endpoint가 있으면 먼저 revoke하고 성공한
경우에만 local credential을 삭제합니다. provider 오류가 나면 암호화된 credential을 유지하고 오류를
반환하므로 사용자가 다시 시도할 수 있습니다. Plugin 전체 삭제는 remote revoke를 가능한 범위에서
시도한 뒤 data_policy: retain이어도 local credential과 OAuth state를 보존하지 않습니다.
운영 점검
- authorize 요청마다 새로운 state가 생성되는가
- redirect URI가 등록값과 정확히 일치하는가
- token URL과 content type이 provider 요구와 맞는가
- client secret과 access token이 로그·MCP·artifact에 없는가
- 여러 Connection의 token과 표시 이름이 섞이지 않는가
- token 만료 후 한 번 갱신하고, 실패 시 재연결을 안내하는가
- Connection 삭제 후 해당 연결의 실행이 즉시 차단되고 local credential이 제거되는가
- provider revoke가 제품 요구사항이면 공급자 console에서도 token 폐기를 별도로 확인했는가
- 플러그인 삭제 후 local credential과 OAuth state가 남지 않는가
Notion의 실제 구성은 Notion 플러그인을 참고하세요.