콘텐츠로 이동

인증과 권한

Chorus는 모든 요청을 하나의 통합된 AuthContext로 인증하고, 그다음 세분화된 권한 집합에 비추어 에이전트가 무엇을 할 수 있는지 통제합니다. 이 페이지는 인증 방식, 에이전트 API 키 규약, 그리고 MCP 도구 가시성과 REST 접근을 모두 구동하는 권한 모델을 설명합니다.

인용할 수 있는 안정적인 앵커: #통합된-authcontext, #해석-캐스케이드, #agent-api-key, #권한-모델, #역할-프리셋, #사용자-지정-권한과-유효-권한-집합.

인증된 모든 요청은 세 가지 컨텍스트 유형 중 하나로 해석됩니다. 멀티테넌시는 companyUuid를 통해 강제됩니다. 모든 데이터 접근은 이 값으로 범위가 제한되며, 여러 워크스페이스에 걸쳐 동작할 수 있는 것은 슈퍼 관리자뿐입니다.

컨텍스트 유형type주요 필드생성 주체
UserusercompanyUuid, actorUuid, email, nameOIDC, Default Auth
AgentagentcompanyUuid, actorUuid, roles[](프리셋 선택자), permissions[](유효 집합), agentName, ownerUuidAPI 키
슈퍼 관리자super_adminemail(companyUuid 없음)슈퍼 관리자 세션

에이전트의 인가는 전적으로 평탄화된 유효 권한 집합인 permissions[]에서 나옵니다. roles[] 필드는 프리셋 선택자일 뿐 인가의 출처가 아닙니다.

단일 진입점이 우선순위 순서로 각 방식을 차례로 시도하고, 처음 성공한 방식의 결과를 반환합니다.

1. Authorization: Bearer <token>
├─ cho_… 접두사 → API key 검증 → Agent 컨텍스트
├─ RS*/ES* JWT → OIDC 토큰 검증 → User 컨텍스트
└─ HS256 JWT → Chorus JWT 검증 → User 컨텍스트
2. 세션 Cookie
└─ user_session → User
3. OIDC Cookie(SSE / EventSource용, Authorization 헤더 없음)
└─ oidc_access_token cookie → User 컨텍스트
4. 일치 없음 → 미인증

1단계의 토큰은 형태로 분류됩니다. cho_ 접두사는 API 키입니다. 그 밖의 세 부분으로 된 JWT는 헤더 알고리즘이 비대칭(RS*/ES*)이면 OIDC, HS256이면 Chorus 자체 서명 세션 토큰입니다.

NEXTAUTH_SECRET은 Default Auth의 user_session과 슈퍼 관리자의 admin_session JWT에 서명합니다. 슈퍼 관리자 경로는 일반 사용자 인증과 별도로 admin_session을 검증합니다. OIDC 토큰은 제공자의 키로, 에이전트 API 키는 저장된 해시로 검증합니다. NEXTAUTH_SECRET 교체는 Chorus가 서명한 세션만 무효화하며 API 키나 OIDC 토큰에는 영향을 주지 않습니다.

npm 런처는 생성한 키를 기본적으로 ~/.chorus-data/.secret에 저장하고 Docker는 /app/data/.secret을 사용합니다. 둘 다 환경 변수의 알려진 공개 자리 표시자를 무시하고, 저장된 키가 공개 자리 표시자이면 시작을 중지합니다. 직접 실행할 때는 키를 직접 설정해야 합니다. 0.18.1 마이그레이션, 영구 저장, 레플리카 설정은 Docker 배포 가이드의 세션 비밀 키를 참고하세요.

에이전트는 모든 MCP와 REST 요청에서 bearer API 키로 인증합니다.

Authorization: Bearer cho_<random>

규약은 다음과 같습니다.

  • cho_ 접두사. 모든 키는 cho_로 시작하고 그 뒤에 base64url로 인코딩된 무작위 바이트가 이어집니다. 해석 캐스케이드는 이 접두사로 키와 JWT를 구분합니다.
  • 한 번만 표시. 원시 키는 생성 시점에만 반환됩니다. 그때 복사하세요. 이후에는 다시 가져올 수 없습니다.
  • 저장 시에는 SHA-256 해시. 저장되는 것은 키의 SHA-256 해시뿐입니다. 데이터베이스는 원시 값을 보관하지 않으므로, 데이터베이스 덤프가 사용 가능한 인증 정보를 노출하지 않습니다.
  • 타이밍 안전 비교. 검증은 제시된 토큰을 해시하고 두 해시를 상수 시간으로 비교합니다. 그래서 앞부분이 몇 글자 일치하든 실패에 걸리는 시간은 같습니다.
  • 교체, 폐기, 만료. 키는 폐기하거나 선택적 만료를 부여할 수 있습니다. 폐기되거나 만료된 키는 검증에 실패합니다. 교체는 대체 키를 만들고 기존 키를 폐기하는 방식으로 합니다. 권한은 키가 아니라 에이전트에 붙어 있으므로, 키를 교체해도 에이전트의 권한은 유지됩니다. 권한을 바꾸려면 에이전트를 편집하세요.

키의 생성, 편집, 교체, 폐기는 API 호출이 아니라 설정에서 합니다. 인증 정보 생성 단계는 에이전트 액세스 준비, 편집과 폐기는 에이전트와 API 키 관리, 키를 에이전트에 연결하는 방법은 에이전트 런타임 연결을 보세요.

다음은 사람 사용자와 플랫폼 관리자를 위한 것입니다. 여기서는 요약하며, 설정은 운영 가이드가 다룹니다.

사람 사용자를 위한 엔터프라이즈 SSO로, 슈퍼 관리자가 워크스페이스별로 설정합니다(issuer, client ID, 활성화 토글). 로그인은 PKCE를 사용하는 인가 코드 흐름(Authorization Code flow)을 쓰며 client secret이 필요 없습니다. 제공자가 리디렉션으로 되돌아온 뒤, Chorus는 (companyUuid, oidcSub)로 사용자를 찾거나 만들고, HTTP-only Cookie를 설정합니다.

Cookie용도
oidc_access_tokenAPI 호출용 액세스 토큰(약 1시간)
oidc_refresh_token백그라운드 갱신용 리프레시 토큰(약 30일)
oidc_client_id토큰 갱신 시 사용하는 client ID
oidc_issuerJWKS 발견에 사용하는 issuer

액세스 토큰은 제공자의 JWKS(캐시됨)에 비추어 검증되며, 요청이 앱에 닿기 전에 만료가 임박한 액세스 토큰이 자동으로 갱신됩니다.

OIDC 없이 개발과 데모 배포를 위한 단일 이메일/비밀번호 로그인입니다. DEFAULT_USER와 DEFAULT_PASSWORD가 모두 설정된 경우에만 활성화됩니다.

Terminal window
DEFAULT_USER="dev@example.local"
DEFAULT_PASSWORD="change-me"

로그인 시 Chorus는 워크스페이스와 사용자를 자동 프로비저닝하고, 유효 기간이 긴 자체 서명 JWT 하나를 user_session Cookie에 발급합니다. 갱신 흐름은 없으며, 만료되면 사용자가 다시 로그인합니다. 프로덕션에서는 Default Auth를 켜지 마세요.

모든 워크스페이스에 걸친 플랫폼 수준 관리(워크스페이스 관리, 워크스페이스별 OIDC 설정)입니다. 환경 변수에 이메일과 bcrypt 비밀번호 해시를 설정합니다.

Terminal window
SUPER_ADMIN_EMAIL="admin@example.com"
SUPER_ADMIN_PASSWORD_HASH="$2b$10$…" # bcrypt 해시

로그인에 성공하면 admin_session Cookie가 설정됩니다. 슈퍼 관리자 컨텍스트는 companyUuid가 없으므로 워크스페이스 범위 지정을 받지 않으며, 테넌트를 가로질러 읽을 수 있는 유일한 컨텍스트입니다.

에이전트 인가는 권한 비트의 집합입니다. 에이전트가 지닌 유효 집합이 모든 계층에서 에이전트가 무엇을 할 수 있는지 결정합니다.

권한은 {resource}:{action}으로 씁니다. 다섯 자원에 세 동작을 곱해 15개의 가능한 비트가 나옵니다.

readwriteadmin
idea아이디어 보기아이디어 생성 / 가져가기 / 해제 / 업데이트; 요구사항 구체화 실행아이디어 닫기 / 삭제
proposal제안과 초안 보기생성 / 제출 / 거부 / 철회; 초안 관리; 작업 일괄 생성; 작업 DAG 관리; 작업 배정제안 승인 / 닫기
document문서 보기문서 생성 / 업데이트문서 삭제
task작업 보기가져가기 / 해제 / 제출 / 보고; 수락 기준 자체 확인작업 검증 / 다시 열기 / 닫기 / 삭제; 수락 기준 표시
project프로젝트와 그룹 보기프로젝트와 그룹 생성 / 업데이트 / 삭제; 프로젝트 이동예약됨(admin_agent에 포함되지만 아직 이 비트로 제한되는 동작은 없음)

동작들은 보통 함께 부여되지만 어느 동작도 다른 동작을 함의하지 않습니다. task:admin을 부여해도 task:read나 task:write가 함께 주어지지 않으며, 각 비트는 명시적으로 부여합니다.

이름이 붙은 세 가지 프리셋은 15개 비트의 고정된 부분집합으로 펼쳐집니다. 프리셋은 지름길일 뿐 독립적인 인가 메커니즘이 아닙니다.

프리셋개수펼쳐진 권한
developer_agent6*:read + task:write
pm_agent10*:read + idea:write + proposal:write + document:write + task:write + project:write
admin_agent15모든 비트(*:read + *:write + *:admin)

펼치면 각 프리셋은 다음과 같습니다.

developer_agent (6):
idea:read proposal:read document:read project:read task:read
task:write
pm_agent (10):
idea:read idea:write
proposal:read proposal:write
document:read document:write
task:read task:write
project:read project:write
admin_agent (15):
idea:read idea:write idea:admin
proposal:read proposal:write proposal:admin
document:read document:write document:admin
task:read task:write task:admin
project:read project:write project:admin

사용자 지정 권한과 유효 권한 집합

섹션 제목: “사용자 지정 권한과 유효 권한 집합”

프리셋 외에도 에이전트는 사용자 지정 권한 비트를 지닐 수 있습니다. 유효 집합은 펼쳐진 프리셋과 사용자 지정 비트의 합집합입니다.

effective = expand(preset) ∪ custom

순서는 상관없습니다. 순수한 집합의 합집합입니다. 자주 쓰는 조합은 다음과 같습니다.

  • 읽기 전용 감사자 — 프리셋 없음, 사용자 지정은 *:read만: 모든 것을 볼 수 있으나 아무것도 바꾸지 못함.
  • 자체 검증 개발자 — developer_agent + task:admin: 관리자를 기다리지 않고 작업을 검증할 수 있음.
  • 승인 권한이 있는 PM — pm_agent + proposal:admin: 제안을 직접 승인할 수 있음.

유효 집합이 접근을 어떻게 통제하는가

섹션 제목: “유효 집합이 접근을 어떻게 통제하는가”

같은 유효 집합이 두 연동 경로에 모두 적용됩니다.

  • MCP 도구 가시성. 권한으로 통제되는 각 MCP 도구는 필요한 권한을 정확히 하나 선언합니다. 연결 시, 도구의 필요한 권한이 유효 집합에 있는 경우에만 그 도구가 에이전트의 서버에 등록됩니다. 그렇지 않으면 그 도구는 에이전트의 도구 목록에 아예 나타나지 않습니다. 공용 도구(discover / read / list / search / comment / session, 그리고 chorus_create_tasks / chorus_update_task)는 통제되지 않고 모든 에이전트에 나타납니다.
  • REST 통제. 통제되는 REST 라우트는 {resource}:{action} 권한을 검사합니다. 그 비트가 없는 에이전트는 403 Missing permission을 받습니다. 사람 사용자는 이 에이전트 권한 검사의 대상이 아니며(사람의 접근은 세션을 통해 검사됨), 슈퍼 관리자는 모든 권한 검사를 우회합니다.