모의투자용 App Key를 준비해도 시세 조회에 바로 사용할 수는 없습니다. App Key와 Secret으로 Access Token을 먼저 발급하고, 조회 요청에 그 토큰을 전달해야 합니다. 이 글에서는 토큰을 화면에 노출하지 않으면서 발급 성공과 만료일을 확인하는 방법을 보여줍니다.
핵심
토큰 발급은 /oauth2/token에 POST로 요청합니다. HTTP 상태와 키움 응답의 return_code를 모두 확인하고, 응답의 expires_dt로 만료일을 확인합니다. 토큰 폐기는 만료와 다른 작업이므로 필요할 때만 요청합니다.
모의투자와 실전투자 주소
인증 요청의 경로와 본문 구조는 같지만 서버 주소와 인증정보를 서로 맞춰야 합니다.
- 모의투자:
https://mockapi.kiwoom.com과 모의투자용 App Key·Secret을 사용합니다. - 실전투자:
https://api.kiwoom.com과 실전투자용 App Key·Secret을 사용합니다. - 공통 경로: 토큰 발급은
/oauth2/token, 폐기는/oauth2/revoke입니다.
아래 코드는 모의투자 주소만 사용합니다. 실전투자 주소로 자동 전환되지 않으며, 모의투자용 키를 실전 서버에 보내지 않습니다. 키움의 서비스 이용안내에서도 두 환경의 App Key를 별도로 관리한다고 설명합니다.
.env에 인증정보 넣기
Python 코드와 같은 작업 폴더에 .env 파일을 만들고 다음 변수명을 적습니다. 등호 오른쪽에는 각각 모의투자용 App Key와 Secret 값을 넣습니다. 실제 값은 다른 사람에게 공유하거나 Git에 올리지 않습니다.
KIWOOM_APP_KEY=
KIWOOM_SECRET_KEY=
이 글의 Python 코드는 python-dotenv로 .env를 읽습니다. .gitignore에는 .env를 추가해 공개 저장소에서 제외합니다. 필요한 패키지는 별도로 설치합니다.
pip install requests python-dotenv
Access Token 발급 코드
다음은 import부터 결과 확인까지 한 번에 실행할 수 있는 모의투자 예제입니다. 기본값인 REVOKE_AFTER_CHECK = False에서는 토큰을 발급한 뒤 바로 폐기하지 않습니다. 폐기 요청까지 확인하려면 그 값을 True로 바꾸고 실행합니다.
"""키움 REST API 모의투자 토큰 발급과 선택적 폐기."""
import os
import requests
from dotenv import load_dotenv
MOCK_BASE_URL = "https://mockapi.kiwoom.com"
REQUEST_HEADERS = {"Content-Type": "application/json;charset=UTF-8"}
REVOKE_AFTER_CHECK = False
load_dotenv(".env")
app_key = os.getenv("KIWOOM_APP_KEY")
secret_key = os.getenv("KIWOOM_SECRET_KEY")
if not app_key or not secret_key:
raise SystemExit(".env에 KIWOOM_APP_KEY와 KIWOOM_SECRET_KEY를 설정해 주세요.")
def request_auth_api(endpoint, request_body):
response = requests.post(
MOCK_BASE_URL + endpoint,
headers=REQUEST_HEADERS,
json=request_body,
timeout=15,
)
response.raise_for_status()
response_data = response.json()
return_code = response_data.get("return_code")
if str(return_code) != "0":
raise RuntimeError(f"키움 인증 요청 실패: return_code={return_code}")
return response_data
token_response_data = request_auth_api(
"/oauth2/token",
{"grant_type": "client_credentials", "appkey": app_key, "secretkey": secret_key},
)
access_token = token_response_data.get("token")
expires_dt = str(token_response_data.get("expires_dt") or "")
if not access_token or len(expires_dt) != 14 or not expires_dt.isdigit():
raise RuntimeError("토큰 또는 만료일 필드를 확인할 수 없습니다.")
print("모의투자 Access Token 발급 확인: return_code=0")
print(f"토큰 유형: {token_response_data.get('token_type')}, 만료일: {expires_dt}")
if REVOKE_AFTER_CHECK:
request_auth_api(
"/oauth2/revoke",
{"appkey": app_key, "secretkey": secret_key, "token": access_token},
)
print("Access Token 폐기 확인: return_code=0")
grant_type은 공식 명세의 client_credentials입니다. au10001은 토큰 발급 기능의 API ID이지만, 일반 시세 조회와 달리 발급 요청 헤더에 api-id를 넣지 않습니다. 공식 Python 예제도 토큰 발급 헤더에 Content-Type만 사용합니다. 폐기 기능의 API ID는 au10002이며, 폐기 본문에는 App Key·Secret과 폐기할 토큰이 필요합니다.
응답에서 확인할 값
모의투자 발급 요청에서는 HTTP 200과 return_code=0을 확인했습니다. 발급 응답에는 token, token_type, expires_dt가 있으며, 폐기 요청에서는 return_code=0을 확인했습니다. 아래는 공개해도 되는 항목만 남긴 응답 형태입니다.
return_code: 0
token_type: Bearer
expires_dt: [14자리 만료일]
token: [마스킹]
키움 공식 예시의 token_type은 bearer로 표기되지만, 모의투자 응답에서는 Bearer로 왔습니다. 대소문자를 고정해서 검사하기보다 return_code, 토큰 존재 여부와 만료일 형식을 확인합니다. 토큰 원문은 출력하지 않습니다.
만료될 때와 폐기할 때
키움 서비스 이용안내는 Access Token 유효기간을 24시간으로 안내합니다. expires_dt를 확인해 만료된 토큰을 재사용하지 않고, 다시 필요하면 App Key와 Secret으로 /oauth2/token을 요청합니다. 공식 토큰 발급 본문에는 refresh token 필드가 없습니다.
폐기는 토큰을 더 이상 사용하지 않겠다는 별도 요청입니다. 위 예제에서 REVOKE_AFTER_CHECK를 True로 바꾸면 /oauth2/revoke를 호출하므로, 그 토큰을 이후 조회에 쓰려면 기본값인 False를 유지합니다. 폐기 후 다시 조회하려면 새 토큰을 발급받습니다.
발급이 실패하면 .env에 두 변수가 모두 들어 있는지, 키가 모의투자용인지, 사용 IP가 등록되어 있는지를 먼저 확인합니다. HTTP 오류와 return_code 오류를 구분하되, 요청 본문 전체나 토큰 원문을 디버깅 화면에 출력하지 않습니다.
이미 공개된 데이터 저장 예제가 필요하다면 키움 REST API 일봉을 SQLite에 저장하는 글을 참고할 수 있습니다. 토큰 발급·폐기의 URL, 필수 필드와 응답 구조는 키움 REST API 가이드에서 확인할 수 있습니다.
이 글은 API 인증 구조를 설명하기 위한 자료입니다. 실제 거래와 투자 판단에는 별도의 검증이 필요하며 그 책임은 투자자 본인에게 있습니다.