ENGINE DEVELOPMENT NOTES

한국투자증권 API 토큰을 여러 실행기에서 안전하게 공유하기

계좌별 토큰 캐시와 오전 워밍업을 공유하면서 잘못된 계좌의 토큰 재사용과 불필요한 재발급을 막은 구현 기록입니다.

발행
수정
구현 상태
구현 확인

여러 실행기가 같은 인증을 사용할 때 생기는 문제

자동매매 시스템에는 주문 실행기만 있는 것이 아닙니다. 시세 수집기와 상태 확인 작업도 인증이 필요합니다. 각각 토큰을 따로 관리하면 같은 계좌의 토큰을 중복 발급하거나, 인증 정보를 교체한 뒤에도 이전 토큰을 읽을 수 있습니다. 다른 계좌의 캐시를 잘못 사용하는 문제도 막아야 합니다.

MediaMaak 엔진은 이 문제를 물리 계좌별 공유 캐시와 사전 워밍업으로 다룹니다. 오전에 준비한 토큰을 이후 실행기가 재사용하되, 파일이 있다는 이유만으로 유효하다고 판단하지 않습니다. 이 글은 2026년 10월 17일에 확인한 구현을 설명합니다. 최초 구현 날짜나 실제 장애 발생 날짜를 확정한 기록은 아닙니다.

캐시를 재사용하는 네 가지 조건

현재 구현은 캐시 형식 버전, 발급 날짜, 계좌 식별값, 인증 정보 식별값을 모두 비교합니다. 한 조건이라도 다르면 캐시를 재사용하지 않습니다.

확인 항목 확인하는 이유 불일치하면
캐시 형식 버전 다른 형식의 파일을 잘못 읽지 않기 위해 기존 값을 사용하지 않음
로컬 기준 발급 날짜 전날 캐시를 그대로 이어 쓰지 않기 위해 새 인증 절차로 진행
계좌 fingerprint 다른 물리 계좌의 캐시를 섞지 않기 위해 기존 값을 사용하지 않음
인증 정보 fingerprint API 키 또는 시크릿 교체를 감지하기 위해 이전 토큰을 사용하지 않음

fingerprint는 원본을 직접 파일 이름에 넣지 않고 비교하기 위한 해시 식별값입니다. 계좌 식별값은 계좌 범위를, 인증 정보 식별값은 접속 환경과 해당 계좌의 인증 정보 범위를 구분합니다. 인증 정보를 바꾸더라도 같은 물리 계좌의 캐시 위치를 유지하면서 내용을 교체합니다.

이 식별값이 캐시 내용을 암호화하지는 않습니다. 캐시에는 인증 토큰이 저장되므로 접근 권한이 제한된 운영 저장소에서 관리해야 합니다. 소스 저장소, 게시글, 진단 출력에는 실제 값을 넣지 않습니다.

동시에 실행되어도 발급은 한 곳에서

캐시가 없을 때 여러 실행기가 동시에 인증을 요청할 수 있습니다. 엔진은 계좌별 파일 잠금을 획득한 실행기만 발급 절차에 들어가게 합니다. 잠금을 얻은 뒤에는 캐시를 다시 읽습니다. 기다리는 동안 다른 실행기가 토큰을 저장했다면 새 발급 없이 그 결과를 사용합니다.

처리 순서는 다음과 같습니다.

  1. 현재 계좌의 캐시를 확인합니다.
  2. 재사용할 값이 없으면 계좌별 잠금을 얻습니다.
  3. 잠금 안에서 캐시를 다시 확인합니다.
  4. 여전히 사용할 값이 없을 때만 인증 API를 호출합니다.
  5. 임시 파일을 완성한 뒤 캐시 파일을 교체합니다.
  6. 잠금을 해제합니다.

파일 교체는 다른 실행기가 쓰다 만 JSON을 읽을 가능성을 줄입니다. 잠금을 제한 시간 안에 얻지 못하면 다른 실행기와 경쟁해서 토큰을 발급하지 않고 실패로 종료합니다.

오전 워밍업은 활성화된 실계좌 KRX 프로필을 순서대로 처리합니다. 실패한 계좌만 정해진 횟수 안에서 재시도하고, 성공한 계좌까지 처음부터 다시 발급하지 않습니다. 워밍업은 인증 API를 사용할 수 있지만 매매 상태를 읽거나 주문을 제출하는 작업은 하지 않습니다.

실제 계좌 없이 재사용 조건 살펴보기

다음 코드는 비교 규칙만 보여 주는 합성 예제입니다. 계좌·인증 정보 식별값도 설명용 표식이며, 실제 해시나 토큰은 없습니다. 네트워크 연결이나 파일 저장을 수행하지 않습니다.

def can_reuse(cache, *, day, account_mark, credential_mark):
    return (
        cache.get("schema_version") == 1
        and cache.get("issued_on") == day
        and cache.get("account_mark") == account_mark
        and cache.get("credential_mark") == credential_mark
    )

demo_cache = {
    "schema_version": 1,
    "issued_on": "2026-10-17",
    "account_mark": "synthetic-account-a",
    "credential_mark": "synthetic-key-v1",
}

assert can_reuse(
    demo_cache,
    day="2026-10-17",
    account_mark="synthetic-account-a",
    credential_mark="synthetic-key-v1",
)

# 인증 정보를 교체하면 같은 계좌여도 재사용하지 않습니다.
assert not can_reuse(
    demo_cache,
    day="2026-10-17",
    account_mark="synthetic-account-a",
    credential_mark="synthetic-key-v2",
)

이 예제는 실제 엔진의 캐시 형식이나 인증 클라이언트를 복사한 코드가 아닙니다. 날짜 또는 계좌 표식을 바꾸어 어느 조건에서 재사용이 차단되는지 확인하는 학습용 코드입니다.

유효한 날짜라도 인증이 거부될 수 있습니다

같은 날짜의 캐시라도 토큰이 취소되었을 수 있습니다. 현재 클라이언트는 읽기 요청인 GET에서 HTTP 401 또는 403을 받으면 해당 토큰을 무효화하고 인증을 한 번 다시 시도합니다. 캐시를 지울 때에는 계좌·인증 정보 식별값과 토큰 자체가 모두 일치하는지도 확인합니다. 다른 실행기가 이미 저장한 새 토큰을 이전 실패 처리에서 삭제하지 않기 위해서입니다.

이 인증 재시도는 주문 POST에 적용하지 않습니다. 주문 응답이 불확실할 때 다시 요청하면 중복 주문이 될 수 있기 때문입니다. 주문을 재시도할지 여부는 인증 캐시와 별개로 주문 접수 이력과 실행 조건을 확인하는 절차에서 결정해야 합니다.

어떤 검증이 코드에 포함되어 있나요?

현재 엔진에는 실제 증권사 연결 대신 가짜 응답과 임시 저장소를 사용하는 오프라인 테스트가 포함되어 있습니다.

검증 시나리오 확인하는 계약
API 시크릿 교체 같은 계좌의 캐시 위치를 유지하되 이전 토큰을 재사용하지 않음
서로 다른 계좌 인증 요청과 주문 요청의 계좌 범위가 섞이지 않음
워밍업 실행 매매 상태를 읽지 않고 주문 제출도 하지 않음
계좌 하나의 워밍업 실패 실패한 계좌만 재시도함
진단 출력 인증 키·시크릿·토큰으로 식별한 필드를 가림
캐시 토큰의 GET 인증 거부 읽기 요청을 한 번 다시 시도함

이 글에서는 해당 소스와 테스트의 검증 항목을 확인했습니다. 새로 실계좌 인증을 요청하거나 주문을 실행하지 않았으며, 이 글의 작성만으로 전체 엔진 테스트의 최신 통과 결과를 주장하지 않습니다.

적용 범위와 다음에 확인할 점

이 구현은 같은 운영 환경의 로컬 파일 시스템을 공유하는 실행기를 대상으로 합니다. 여러 서버 사이의 분산 잠금이나 암호화된 비밀 관리 서비스를 제공하는 구현은 아닙니다.

또한 현재 캐시 재사용 조건은 로컬 날짜를 기준으로 합니다. 토큰 응답의 남은 유효 시간을 계산한 결과와 동일하지 않습니다. 운영 환경의 시간대와 시계를 확인해야 하고, 캐시가 같은 날짜라는 사실만으로 인증 성공을 보장할 수 없습니다.

진단 출력의 필드 가리기도 모든 종류의 비밀정보 유출을 자동으로 막는 보장은 아닙니다. 새 로그 필드를 추가할 때에는 출력 내용을 별도로 검토해야 합니다. 인증 준비, 시세 조회, 주문 제출의 경계를 유지하는 것이 이 설계의 핵심입니다.

공식 참고 자료

한국투자증권은 Appkey와 App secret으로 토큰을 발급받아 REST API를 호출하는 흐름을 안내합니다. API의 현재 사용 조건과 요청 형식은 KIS Developers에서 확인할 수 있습니다.

한국투자증권 공식 Open API 예제 저장소도 함께 참고할 수 있습니다. 위의 캐시 공유·파일 잠금·워밍업 규칙은 MediaMaak의 구현 선택이며, 공식 API의 필수 규칙으로 해석하지 않습니다.

다시 읽고 싶은 기록이라면

공유 링크를 복사해 보관할 수 있습니다.