MINARA
Minara 사용하기클라이언트 및 인터페이스메시징 플랫폼

Lark / Feishu

tenant_access_token을 통한 Lark IM 메시징. 선택적 AES-256-CBC 암호화 webhook 이벤트를 지원합니다.

🟡 아웃바운드 준비 완료, 인바운드 지원, 중국 본토 Feishu(open.feishu.cn)와 국제 Lark(open.larksuite.com) 모두 지원합니다. 인바운드 webhook은 Lark의 세 가지 보안 모드인 검증 토큰, 암호화, 서명된 HMAC를 모두 처리합니다.

제공 기능

  • POST /open-apis/im/v1/messages?receive_id_type=chat_id를 통한 아웃바운드 텍스트 메시징. tenant access token은 2시간 동안 캐시되며, 5분의 갱신 여유 시간이 있어 대용량 발신 시 앱별 token 속도 제한에 걸리지 않습니다.
  • /webhooks/lark에서의 인바운드 webhook 이벤트. Lark는 운영자가 세 가지 보안 모드(검증 토큰, 암호화 키, HMAC 서명)를 자유롭게 조합하여 선택할 수 있습니다. Minara는 개발자 콘솔에서 활성화된 모드를 모두 지원합니다.
  • 도메인 인식 라우팅. LARK_DOMAIN으로 중국 본토 Feishu 또는 국제 Lark를 선택합니다. 두 서비스는 동일한 API 구조를 공유합니다.
  • 현재 텍스트만 지원. 리치 카드, 이미지, 파일은 향후 추가 예정입니다. 현재는 tenant 토큰 캐시와 서명된 webhook 기반이 제공됩니다.
  • 30,000자 제한. 이를 초과하는 텍스트는 잘립니다.

설정

1. 앱 생성

  1. Lark 개발자 콘솔(또는 국제 Lark)에 로그인합니다.
  2. Custom App을 생성합니다. App ID(cli_로 시작)와 App Secret을 기록해 둡니다.
  3. "권한 및 범위"에서 im:message:send_as_bot을 부여하고, 인바운드의 경우 봇에 필요한 메시지 수신 범위(일반적으로 im:message)를 추가합니다.
  4. "이벤트 구독"에서 요청 URL을 https://<your-host>/webhooks/lark로 설정합니다. Verification Token과 (선택 사항) Encrypt Key를 복사합니다.

2. 기본 chat_id 찾기

대상 채팅(1:1 또는 그룹)에 메시지를 보낸 후, 개발자 콘솔에서 POST /open-apis/im/v1/messages/list를 호출하거나 tenant 토큰으로 curl을 실행하여 chat_id(oc_xxxxxxxxxxxxxxxx 형식)를 추출합니다. 이를 LARK_DEFAULT_CHAT_ID로 저장합니다.

3. Minara 설정

minara auth messaging add
# 목록에서 `lark`를 선택하고 app id, app secret, chat id,
# verification token(암호화를 활성화한 경우 encrypt key)을 입력합니다.

또는 프로젝트 루트의 .env 파일에 직접 작성합니다.

LARK_APP_ID=cli_xxxxxxxxxxxxxxxx
LARK_APP_SECRET=<opaque secret>
LARK_DEFAULT_CHAT_ID=oc_xxxxxxxxxxxxxxxx
LARK_VERIFICATION_TOKEN=<verification token>
LARK_ENCRYPT_KEY=<encrypt key, optional>
LARK_DOMAIN=open.feishu.cn          # or open.larksuite.com

4. 테스트

minara auth messaging test lark

인바운드 webhook

Lark 이벤트 구독 URL을 다음으로 설정합니다.

https://<your-host>/webhooks/lark

세 가지 보안 모드가 중첩 적용됩니다.

모드환경 변수동작
검증 토큰LARK_VERIFICATION_TOKEN디코딩된 페이로드의 최상위 token 필드가 일치해야 합니다. 평문 모드 및 복호화 이후에 사용됩니다.
암호화LARK_ENCRYPT_KEY (선택 사항)설정 시 본문이 {encrypt: "<base64>"} 형태로 수신되며, key = SHA256(encrypt_key), IV = 키의 첫 16바이트로 AES-256-CBC 복호화됩니다.
서명X-Lark-Signature 헤더 (항상 선택 사항)timestamp + nonce + encrypt_key + body에 대한 SHA-256 hex가 헤더로 전달됩니다. 추가 무결성 검사가 필요한 경우 콘솔에서 활성화합니다.

URL 검증 핸드셰이크: Lark가 {type:"url_verification", challenge:"..."}를 전송하면, Minara는 검증 토큰 확인 후 {challenge}로 응답합니다. 토큰이 일치하지 않으면 403을 반환합니다.

제한 사항 및 주의점

  • Tenant 토큰 속도 제한. Lark는 앱당 분당 약 100회의 토큰 발급 호출을 허용합니다. 2시간 캐시로 이 제한을 충분히 회피할 수 있습니다.
  • content는 JSON 인코딩 문자열이어야 합니다. Lark API의 특성상, 텍스트 메시지도 content: JSON.stringify({text: "..."})로 전송해야 합니다. Minara가 이를 자동으로 처리합니다.
  • 카드 인터랙션 미지원. 인터랙티브 카드의 버튼 클릭 콜백은 별도의 webhook 이벤트 타입으로 수신되며, 현재 파싱되지 않습니다.

문제 해결

"테스트 메시지에서 code 99991663 반환"

  • tenant access token 갱신에 실패한 것입니다. 개발자 콘솔에서 LARK_APP_IDLARK_APP_SECRET을 확인합니다.

"인바운드 webhook이 401 반환"

  • 콘솔에서 암호화 모드를 활성화했지만 LARK_ENCRYPT_KEY를 설정하지 않은 경우, 모든 인바운드 POST 요청에서 복호화가 실패합니다. 콘솔에서 암호화를 비활성화하거나 환경 변수를 설정합니다.
  • 서명 모드를 활성화한 경우, 저장한 LARK_ENCRYPT_KEY가 콘솔에 표시된 값과 일치하는지 확인합니다. 이 값은 서명 입력으로도 사용됩니다.

"content 필드 필수 (400)"

  • send_messagetext에 빈 문자열로 호출하고 있습니다. Lark는 빈 본문을 거부합니다.

참조

목차