카페24 공식 문서에는 “Header의 {base64_encode({client_id}:{client_Secret})} 부분은 {클라이언트 아이디}:{클라이언트 시크릿}을 Base64 방식으로 인코딩하여 입력하세요” 라고만 되어 있습니다.
파이썬으로 base64 문자열을 변환할 수 있어요. 다음 코드를 활용하세요.
import base64 # 여러분의 id, secret key을 입력 하세요 client_id ="my_client_id"client_secret ="my_client_secret_key"code =f"{client_id}:{client_secret}"encoded_code = base64.b64encode(code.encode('utf-8'))base64_encode_str = encoded_code.decode('utf-8')print(base64_encode_str)# 여기 코드를 복사해서 여러분의 id, secret_key를 넣고 실행한 결과값을 쓰세요 # 아래 값 복붙 하시면 작동하지 않습니다!
bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXRfa2V5
base64 encode 값 유출 주의!
base64 encode 값은 다시 해독하기 너무 쉬워요. 유출되면 client_id, client_secret이 함께 노출되는 것이니 주의하세요. 유출이 의심된다면 카페24 개발자 홈페이지에서 기존 id, secret을 삭제하고 새로 발급 받으시는 것을 추천합니다.
B. 최초 접속 코드 발급
Restful API로 요청하고 받는데 파이썬에서는 requests 패키지를 씁니다.
카페24 API 토큰 발급 경로: “https://{mall_id}.cafe24api.com/api/v2/oauth/token”
{..}는 변수로 정의한 내 쇼핑몰 id 값이 들어갈 거에요.
카페24 공식 문서 내용을 참고하여 작성한 파이썬 코드 입니다. 토큰 최초 발급 시에는 아래 함수를 1회 돌려요.
import requests, json # 내 쇼핑몰 변수 정의 code ="1분간 유효한 인증코드"redirect_uri ="인증코드 받을 때 사용한 경로"mall_id ="내 쇼핑몰 아이디"base64_encode_atr ="base64로 변환한 클라이언드 정보"def initiate_token(): code ="1분간 유효한 인증코드" url =f"https://{mall_id}.cafe24api.com/api/v2/oauth/token" payload =f"grant_type=authorization_code&code={code}&redirect_uri={redirect_uri}" headers = {'Authorization': f"Basic {base64_encode_str}",'Content-Type': "application/x-www-form-urlencoded" } response = requests.request("POST", url, data=payload, headers=headers)# API 콜 결과를 반환합니다: 200 이면 정상 print(response) tokens = response.json() access_token = tokens['access_token']# 'tokens.json' 파일에 토큰을 저장해요: 재활용 합니다 filename =f'tokens.json'withopen(filename, 'w') as json_file: json.dump(tokens, json_file, indent =4)return access_token
# 함수 실행하기 access_token = initiate_token()print(f'Access token: {access_token}')
토큰을 암호화하지 않고 저장하는 방법이기 때문에 제한된 접근으로 관리 가능한 로컬 컴퓨터나 클라우드에서만 사용하세요.
C. 발급된 토큰 형태
아래는 카페24 메뉴얼에서 복사한 샘플 데이터 입니다. Json 파일로 저장했기 때문에 파일을 코드 에디터로 열어보면 동일한 모습인 것을 볼 수 있어요. 아래 코드를 보면 각 토큰 유효기간 만료 시간이 발급된 시간으로부터 access_token 은 2시간 이후, refresh_token 이 14일 이후인 것을 알 수 있어요.
토큰 발급 자동화를 위해서는 현재 시간과 각 토큰의 유효기간 만료 시간을 비교해서 재발급 하면 됩니다. 이걸 “토큰 관리 Token Manager 라는 클래스로 정의해서 다양한 기능을 담을께요.
(모듈 1) 기존 토큰 불러오기
access_token 유효기간이 만료되지 않았다면: 저장된 토큰을 불러 옵니다.
import jsonfilename ="tokens.json"# 저장된 토큰 불러오는 함수 def _load_token(filename): try:withopen(filename, 'r') as json_file: return json.load(json_file)# 오류 발생 핸들링 exceptFileNotFoundError:raiseException(f"Token file '{filename}' not found.")except json.JSONDecodeError:raiseException("Token file is not properly formatted.")
# 함수 실행 확인하기 tokens = _load_token(filename) print(tokens)access_token = tokens['access_token']print(f"저장되었던 접속 코드: {access_token}")
리프레시 토큰 사용 시, 새로운 접속 코드가 풀세트로 발급되기 때문에 한 번 사용된 리프레시 코드는 더 이상 유효하지 않습니다. 따라서 새로 발급 받은 new_tokens 을 다시 json 파일에 저장해야 합니다. 저장 모듈을 먼저 준비할께요.
# 기존 정의한 파일과 동일하게 이름을 정의해야 덮어 써요. FILENAME ="tokens.json"def _save_tokens(new_tokens):"""토큰 파일을 업데이트합니다."""withopen(FILENAME, 'w') as json_file: json.dump(new_tokens, json_file, indent=4)
(모듈 3) 리프레시 토큰 사용하기
2시간 밖에 안 되는 접속 토큰 유효기간이 만료되기 일쑤라서 리프레시 토큰으로 전체 토큰 정보를 갱신해야 합니다. 아래와 같은 로직으로 진행합니다.
우선 리프레시 토큰 사용하는 모듈 입니다.
# 파일로 저장했던 걸 토큰 변수에 불러옵니다. filename ="sample_tokens.json"tokens = _load_token(filename) # 리프레시 토큰 활용 함수 def _refresh_access_token():# 리프레시 토큰을 사용하여 새 접속 토큰 세트를 발급 받아요 # 저장된 url =f"https://{mall_id}.cafe24api.com/api/v2/oauth/token" payload =f"grant_type=refresh_token&refresh_token={tokens['refresh_token']}" headers = {'Authorization': f"Basic {base64_encode}",'Content-Type': "application/x-www-form-urlencoded" }try: response = requests.post(url, data=payload, headers=headers) response.raise_for_status() # HTTP 상태 코드 확인# new_tokens 라는 새로운 변수에 새 접속 토큰 세트를 담아 둡니다 new_tokens = response.json()# 여기에 신규 토큰 저장 함수를 추가해요 # _save_tokens(new_tokens)return new_tokens['access_token']# 에러 발생 시 처리 except requests.RequestException as e:raiseException(f"Failed to refresh token: {e}")
(모듈 4) 유효기간 검토 + 토큰 관리 자동화
현재 시간을 확인합니다
로컬 위치에 따라 시간이 틀어질 수 있으니 같은 시간대인지 확인 합니다.
카페24 정보는 서울 기준시 (KST)로 주기 때문에 여기서는 시간 보정을 하지 않았어요.
접속 토큰과 리프레시 토큰의 유효기간과 현재 시간을 비교합니다
유효 여부에 따라 기존 코드를 꺼내 쓰거나 리프레시 토큰을 이용해서 새 토큰 세트를 발급 받아요
from datetime import datetime# 유효기간을 날짜형식으로 처리 def is_valid_datetime(value): try: ifisinstance(value, datetime):return valuereturn datetime.fromisoformat(value) # ISO 형식 문자열인 경우 변환exceptValueError:returnNone# 유효하지 않은 경우 None 반환def get_access_token():# 현재 시간을 저장합니다. now = datetime.now()# 기존 접속 토큰 유효성 확인 expires_at = is_valid_datetime(tokens.get('expires_at'))if expires_at and now < expires_at:return tokens['access_token']# 리프레시 토큰 유효성 확인 refresh_token_expires_at = is_valid_datetime(tokens.get('refresh_token_expires_at'))if refresh_token_expires_at and now < refresh_token_expires_at:return _refresh_access_token()# Both tokens are invalidraiseException("리프레시 코드도 만료되었어요. 응답코드 발급부터 다시 진행하세요.")
날짜형식 검토
파이썬에서 토큰을 저장할 때는 문자로 바뀌는 경향이 있어요. 그래서 위 코드에서는 날짜 형식인지 먼저 확인하고 날짜가 아닌 문자일 때(fromisoformat) datetime 으로 바꾸도록 추가 코드가 제공 되었습니다.
3. 토큰매니저로 통합한 최종본
최초 접속 토큰 발급 후 저장은 이 토큰 매니저가 아니라 1번의 initiate_token 함수로 실행하세요. 그래야 “tokens.json” 파일이 생깁니다. 토큰 파일을 생성한 이후에 아래 토큰매니저는 자동으로 작동합니다.
위 함수들을 모아서 TokenManager 라는 클래스로 묶어 줍니다. 모듈로 실행하기 위해서 self 라는 것이 추가 돼요. 위에 내용을 이해하셨다면 그냥 복붙하셔도 괜찮습니다.
# 필요한 패키지 import requests, json from datetime import datetime # 내 쇼핑몰 변수 정의 code ="1분간 유효한 인증코드"redirect_uri ="인증코드 받을 때 사용한 경로"mall_id ="내 쇼핑몰 아이디"base64_encode_atr ="base64로 변환한 클라이언드 정보"# 토큰 저장된 파일명; initiate_token()을 실행한 결과물 FILENAME ="tokens.json"# 통합한 토큰 매니저 class TokenManager: def__init__(self, mall_id=mall_id, base64_encode=base64_encode, filename=FILENAME):self.mall_id = mall_idself.base64_encode = base64_encodeself.filename = filenameself.tokens =self._load_tokens()def _load_tokens(self):"""토큰 파일을 로드합니다."""try:withopen(self.filename, 'r') as json_file:return json.load(json_file)exceptFileNotFoundError:raiseException(f"Token file '{self.filename}' not found.")except json.JSONDecodeError:raiseException("Token file is not properly formatted.")def _save_tokens(self):"""토큰 파일을 업데이트합니다."""withopen(self.filename, 'w') as json_file: json.dump(self.tokens, json_file, indent=4)def _refresh_access_token(self):"""리프레시 토큰을 사용하여 새 액세스 토큰을 발급받습니다.""" url =f"https://{self.mall_id}.cafe24api.com/api/v2/oauth/token" payload =f"grant_type=refresh_token&refresh_token={self.tokens['refresh_token']}" headers = {'Authorization': f"Basic {self.base64_encode}",'Content-Type': "application/x-www-form-urlencoded" }try: response = requests.post(url, data=payload, headers=headers) response.raise_for_status() # HTTP 상태 코드 확인 new_tokens = response.json()# 업데이트 토큰 정보 저장 self.tokens = new_tokensself._save_tokens()return new_tokens['access_token']except requests.RequestException as e:raiseException(f"Failed to refresh token: {e}")def _is_valid_datetime(self, value):"""입력값이 날짜 형식인지 확인하고 변환합니다."""try:ifisinstance(value, datetime):return valuereturn datetime.fromisoformat(value) # ISO 형식 문자열 변환exceptValueError:returnNone# 유효하지 않으면 None 반환def get_access_token(self):"""유효한 액세스 토큰을 반환하거나 새로 발급합니다.""" now = datetime.now()print(f"지금 시간: {now}")# 기존 접속 토큰 유효성 확인 expires_at =self._is_valid_datetime(self.tokens.get('expires_at'))if expires_at and now < expires_at:print("access token is valid.")returnself.tokens['access_token']# 리프레시 토큰 유효성 확인 refresh_token_expires_at =self._is_valid_datetime(self.tokens.get('refresh_token_expires_at'))if refresh_token_expires_at and now < refresh_token_expires_at:print("Using refresh token ...")returnself._refresh_access_token()# 두 조건 모두 실패 시 예외 처리raiseException("리프레시 토큰도 만료되었습니다. 새로운 인증을 진행하세요.")
(보너스) 토큰 매니저 실행 방법
여기까지 잘 따라 오셨나요? 이제 토큰 매니저를 실행해서 카페24에 토큰 매니저를 활용해 봐요. 데이터를 꺼내는 공통 모듈 함수는 아래와 같습니다. 기존 쇼핑몰 변수와 토큰 저장된 파일명, 패키지가 로드된 상태여야 합니다.
# API로 데이터 꺼내는 공통 모듈 함수# info 부분을 바꾸면서 다양한 정보를 읽거나 쓸 수 있어요. # 기본 모듈은 상품 수 추출로 정의되어 있습니다. def call_request(info='products/count'):# 토큰 매니저 활용! manager = TokenManager(mall_id, base64_encode) access_token = manager.get_access_token()# 유효한 토큰을 확인해요. print(f"access token: {access_token}") url =f'https://{mall_id}.cafe24api.com/api/v2/admin/{info}' headers = {'Authorization': f"Bearer {access_token}",'Content-Type': "application/json" } response = requests.request("GET", url, headers=headers) response_dict = response.json() first_key =list(response_dict.keys())[0] result = response_dict[first_key]return result
# 모듈 테스트: 등록 상품 추출product_count = call_request()print(f'Number of products: {product_count}')
코드가 정상적으로 작동해서 리프레시 토큰이 사용되었다면 다음과 같은 결과가 나올 거에요.
지금 시간: 2025-01-08 19:59:20.353054
access token expires at: 2025-01-08 19:53:36+00:00
Using refresh token ...
access token: WcRzDp3NEh5lNP--------
Number of products: 3742