이 문서는 카카오톡 인증 서비스의 K3100 출금동의 API 사용법을 안내합니다.
K3100 출금동의는 이름, 생년월일, 전화번호, CI로 자동이체 또는 자동납부 신청을 위한 출금동의를 제공하는 서비스입니다. 앱투앱(App to App) 또는 채널 메시지 방식으로 사용자에게 카카오톡을 통한 출금동의 전자서명을 요청할 수 있으며, 전자서명에 대한 검증을 통해 안전하게 출금동의를 완료할 수 있습니다.
카카오톡 인증 서비스 API는 서버간 연동(Server to Server)을 원칙으로 합니다.
아래는 카카오톡 출금동의의 전자서명 과정을 표현한 시퀀스 다이어그램(Sequence Diagram)입니다.
위 과정을 요약하면 다음과 같습니다.
tx_id
를 발급받습니다.tx_id
로 전자서명 요청하기 API를 호출해 사용자의 인증을 요청하면, 카카오톡 앱 실행 또는 카카오톡 메시지로 사용자에게 인증 요청이 전달됩니다.identify_items
파라미터에 CI
를 지정해 전자서명 요청 시 서명자 정보 가져오기 API로 연계정보(CI)가 포함된 개인정보를 전달받아야 합니다.tx_id
로 전자서명 상태 확인하기 API를 호출해 진행 상태를 확인합니다.tx_id
로 전자서명 검증하기 API를 호출해 전자서명 값을 전달받습니다.tx_id
로 서명자 정보 가져오기 API를 호출해 서명자 정보를 전달받습니다.카카오톡 인증 서비스는 전자서명 완료 후 이용기관에 자동납부 동의자료만 제공합니다. 자동납부 동의자료 금융결제원 제출, 자동이체 또는 자동납부 등록은 이용기관에서 직접 처리해야 합니다.
사용자는 다음과 같은 과정을 거쳐 출금동의 전자서명을 수행합니다.
카카오는 전자서명 준비하기 단계에서 개인정보, CI, 또는 CI와 전화번호를 함께 사용하여 인증을 요청할 사용자를 찾습니다. 대상 사용자가 확인되지 않거나 카카오 인증서를 발급받지 않은 경우, 카카오톡 출금동의가 불가능하여 전자서명 준비하기 API 호출 시 에러가 반환됩니다.
CI, 또는 CI와 전화번호를 함께 사용하는 확인 과정은 다음과 같습니다.
메서드 | URL | 인증 방식 |
---|---|---|
POST |
https://cert-sign.kakao.com/sign/doc/v1/prepare/${PRODUCT_CODE} |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | - | - | - |
전자서명 준비하기 API는 전자서명을 수행할 사용자의 정보를 카카오톡 인증 서비스에 전달하고 접수번호를 발급하는 API입니다. 이 API의 요청 결과로 받은 접수번호인 tx_id
를 사용해 다음 단계의 전자서명 요청하기, 상태 확인하기, 검증하기를 요청할 수 있습니다.
전자서명 준비하기 API는 요청 URL에 경로 변수(Path variable)로 상품 코드를 포함합니다. 예를 들어 K3110
상품 이용 시, 요청 URL의 마지막 부분에 /K3110
을 반드시 포함해야 합니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 POST
로 요청합니다. 본문에 사용자의 사용자 인증 방식과 개인정보를 JSON
형식으로 포함해야 합니다. 개인정보는 반드시 지정된 키로 암호화하여 전달해야 하며, 자세한 사항은 암호화 예제를 참고합니다.
요청 성공 시 응답은 tx_id
와 처리 결과인 result
값을 포함합니다. 요청 실패 시 문제 해결에서 에러 코드 정보를 확인합니다.
전자서명 준비하기 요청 시 사용자 개인정보인 이름, 전화번호, 생년월일과 서명할 데이터는 반드시 암호화 및 인코딩하여 전달해야 합니다. 다음 순서로 암호화와 인코딩을 처리합니다.
다음은 개인정보 암호화 및 인코딩 결과를 보여주는 예제입니다.
평문 | AES256 암호화 값 | Base64 인코딩 텍스트 |
---|---|---|
이름:홍길동 전화번호 : 01012345678 생년월일: 19950723 |
이름:[6a 33 59 45 34 35 6a 2b 74 67 2b 43] 전화번호: [55 74 36 35 4f 42 4a 31 61 62 55 74 75 45 59 3d] 생년월일: [4e 38 4d 6a 32 54 6f 3d] |
이름:ajNZRTQ1ait0ZytD 전화번호: VXQ2NU9CSjFhYlV0dUVZPQ== 생년월일: TjhNajJUbz0= |
이름 | 설명 | 필수 |
---|---|---|
Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY} 인증 방식, 딜러사 앱의 REST API 키로 인증 요청 |
O |
Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY} 인증 방식, 이용기관 앱 REST API 키로 인증 요청 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
PRODUCT_CODE | String |
상품 코드, 상품 상세 종류는 카카오톡 출금동의 상품 종류 참고 다음 중 이용하는 상품의 코드로 지정하여 요청: - K3110 - K3120 (예: K3110 상품 이용 시 요청 URL은 /sign/v2/prepare/K3110 ) |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
settle_id | String |
정산 ID | O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
type | String |
사용자 인증 방식 다음 중 하나의 값 선택: PERSONAL_INFO : 전화번호, 성명, 생년월일 사용CI_WITH_PHONE_NO : CI, 전화번호 사용CI : CI 사용(기본값: PERSONAL_INFO )주의: 기본값이 아닌 CI_WITH_PHONE_NO 또는 CI 사용자 인증 방식은 매 요청 시 값을 설정해야 함주의: CI 로 인증하는 경우, 지갑 채널을 통해서 채널 메시지가 발송되며 파트너 채널을 이용할 수 없음 |
X |
phone_no | String |
암호화된 01000000000 형식의 사용자 전화번호하이픈(-)을 제외한 숫자로만 구성 주의: type 이 PERSONAL_INFO 또는 CI_WITH_PHONE_NO 인 경우 필수 |
X |
name | String |
암호화된 사용자 성명 주의: type 이 PERSONAL_INFO 인 경우 필수 |
X |
birthday | String |
암호화된 YYYYMMDD 형식의 사용자 생년월일 주의: type 이 PERSONAL_INFO 인 경우 필수 |
X |
ci | String |
연계정보(Connecting Information, CI) 주의: type 이 CI_WITH_PHONE_NO 또는 CI 인 경우 필수 |
X |
enc_version | Integer |
암호화 및 복호화 키 버전1 로 고정 |
O |
이름 | 타입 | 설명 |
---|---|---|
tx_id | String |
전자서명 원문 접수번호 |
curl -i -X POST "https://cert-sign.kakao.com/sign/doc/v1/prepare/${PRODUCT_CODE}?settle_id=${SETTLE_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8" \
-d '{
"type": "PERSONAL_INFO",
"phone_no": "3BKX7CnJ4GhDFnw=",
"birthday": "3Rqf7CnL6m4=",
"name": "AJY7MrlsNc/t",
"enc_version": 1
}'
{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa"
}
메서드 | URL | 인증 방식 |
---|---|---|
POST |
https://cert-sign.kakao.com/sign/doc/v1/request |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | - | - | - |
전자서명 요청하기 API는 전자서명 준비하기 API를 통해 접수된 tx_id
에 해당하는 전자서명 요청을 실행합니다. 이 API의 요청 성공 결과로 사용자의 카카오톡에 전자서명 요청 또는 채널 메시지가 발송됩니다. 앱투앱 방식인 K3120
상품 이용 시, 이 API의 요청 성공 결과로 받은 scheme
값으로 카카오톡의 전자서명 요청 화면을 호출해야 합니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 POST
로 요청합니다. 본문에 서명 원문을 포함한 전자서명 요청 정보를 JSON
형식으로 전달해야 합니다. 서명 원문은 암호화된 자동출금 동의 자료입니다.
요청 성공 시 사용자에게 전자서명 요청이 보내지며, 응답은 tx_id
와 처리 결과인 result
값을 포함합니다.
사용자는 전자서명 요청의 남은 유효시간 이내에 채널 메시지의 [인증하기] 버튼을 눌러 전자서명을 진행할 수 있습니다. 이미 전자서명을 완료했거나 유효시간이 경과한 후에는 사용자가 [인증하기] 버튼을 눌렀을 때 에러 안내가 나타납니다.
다음과 같은 경우에는 전자서명 요청이 실패할 수 있습니다.
요청 실패 시 문제 해결에서 에러 코드 정보를 확인합니다.
전자서명 요청하기의 파라미터 값은 사용자 인증 요청 안내문에 사용됩니다. 아래 예시와 설명을 참고합니다.
영역 | 파라미터 | 설명 |
---|---|---|
🅐 요청구분 | delegate_info.request_type |
요청구분, 공백 포함 최대 40자 예: 자동이체 출금동의 |
🅑 요청기관 | - | 등록된 이용기관 이름 예: 서비스 이용기관 |
🅒 받는이 | delegate_info.receiver_name |
전자서명을 요청할 사용자 이름, 공백 포함 최대 80자 문구: 받는이 뒤에 receiver_name 의 값을 대입해 출력예: 김라연 |
🅓 유효일시 | - | 전자서명 요청 시각으로부터 5분(300초) 후의 시각 |
🅔 서비스 이용기관 고객센터 | - | 등록된 이용기관 고객센터 이름과 연락처 |
🅕 자동출금 동의 자료 | document |
자동출금 동의 자료, 인증 정보 화면에만 노출 예: 청구기관명: 요금청구기관, 출금은행: 테스트 은행, 계좌번호: 000-1111-222-3333, 예금주: 테스트 예금자명, 생년월일: 20000101, 서비스종류: CMS, 동의항목: 자동이체 출금에 동의함 |
🅖 커스텀 메시지 | extra_message |
이용기관에서 지정 가능한 상세 설명, 공백 포함 최대 500자 |
🅗 개인정보 제3자 제공 동의 | identify_items |
인증을 통해 이용기관에서 제공받을 서명자의 개인정보 동의항목 |
이름 | 설명 | 필수 |
---|---|---|
Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY} 인증 방식, 딜러사 앱의 REST API 키로 인증 요청 |
O |
Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY} 인증 방식, 이용기관 앱 REST API 키로 인증 요청 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
settle_id | String |
정산 ID | O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
return_url | String |
전자서명 후 사용자가 복귀할 파트너 서비스 URL 전자서명 요청이 완료됐거나 실패했을 때, 사용자가 파트너 서비스로 이동할 수 있도록 하기 위해 사용 (최대: 255자) 주의: 채널 메시지 방식에서 사용 불가 주의: URL에 스킴(Scheme) 지정 시 카카오톡 종료 스킴 사용 불가, 스킴 이름은 알파벳과 숫자만 사용 가능(예: kakaocert://xxxxx 사용 가능, kakao.cert://xxxxx 사용 불가) |
X |
expires_in | Integer |
처리 마감시간(단위: 초, 기본값: 600 , 최대값: 1200 ) |
X |
tx_id | String |
전자서명 원문 접수번호 | O |
document | Document |
서명할 데이터 암호화된 값으로 전달, 예제 참고 자동출금 동의 자료 항목의 키와 값 쌍으로 구성 (예: "{\"txId\":\"094f8bf9e2-5c41-4641-867a-4a89eb604330\",\"data\":\"{\\\"청구기관명\\\":\\\"청구 기관명\\\",\\\"출금은행\\\":\\\"이름\\\",\\\"계좌번호\\\":\\\"000-1111-222-3333\\\",\\\"예금주\\\":\\\"예금주 이름\\\",\\\"생년월일\\\":\\\"20000101\\\",\\\"서비스종류\\\":\\\"CMS\\\",\\\"동의항목\\\":\\\"자동이체 출금에 동의함\\\"}\"}" ) |
O |
document_type | String |
상세 서명 정보 화면에서 노출되는 서명 원문의 타입TEXT 로 고정 |
O |
delegate_info | JSON |
사용자에게 보여질 인증 요청 안내문, delegate_info: 사용자 인증 요청 안내문과 예제 참고 | O |
extra_message | String |
커스텀 메시지, 사용자에게 보여질 상세 설명, 사용자 인증 요청 안내문 참고 모든 문자 입력 가능, 공백 포함 최대 500자 주의: 카카오톡을 이용하여 메시지를 발송함에 있어 메시지 집행 가이드 및 발송 유의사항 가이드를 준수해야 하며, 위반 시 운영정책에 따라 서비스 이용이 제한될 수 있음 |
X |
identify_items | String[] |
서명자 정보 가져오기 응답으로 확인할 서명자 정보 목록 다음 중 하나 이상의 값 사용 가능 CI : 연계정보NAME : 이름BIRTHDAY : 생일PHONE_NUMBER : 전화번호GENDER : 성별 |
X |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
청구기관명 | String |
청구 기관 이름 | O |
출금은행 | String |
출금은행 이름 | O |
계좌번호 | String |
출금계좌번호 | O |
예금주 | String |
출금계좌 예금주명 | O |
생년월일 | String |
출금계좌 예금주 생년월일, YYYYMMDD 형식 |
O |
서비스종류 | String |
CMS , 펌뱅킹 , 지로 중 하나 |
X |
동의항목 | String |
자동이체 출금 동의 확인 문구 | X |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
receiver_name | String |
전자서명을 요청할 사용자 이름, 공백 포함 최대 80자 주의: 암호화 필수, 예제 참고 카카오계정의 이름과 다른 경우 E2002 에러 발생 |
O |
request_type | String |
요청 구분, 공백 포함 최대 40자 (기본값: 자동이체 출금동의 ) |
X |
* call_center_number, call_center_name, request_organization: Deprecated, 등록된 이용기관 정보를 사용하도록 변경
이름 | 타입 | 설명 |
---|---|---|
tx_id | String |
전자서명 원문 접수번호 |
result | String |
처리 결과Y : 정상 접수N : 접수 실패 |
scheme | String |
K3120 상품 이용 시에만 응답에 포함사용자가 카카오톡 앱을 실행해 전자서명을 수행할 수 있도록 하기 위한 커스텀 URL 스킴(Custom URL Scheme) 전자서명 요청하기 API 성공 응답을 통해 전달 받은 scheme 값을 사용해 사용자가 전자서명을 요청할 수 있도록 해야 함 |
curl -i -X POST "https://cert-sign.kakao.com/sign/doc/v1/request?settle_id=${SETTLE_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8" \
-d '{
"tx_id": "09c0fe5dd9-d201-41dc-ab59-50a3ac3cace6",
"expires_in": 1200,
"document_type": "TEXT",
"document": "lwHTplCd+mBTF3UxUxG4d7gke...",
"identify_items": ["CI", "NAME", "BIRTHDAY", "PHONE_NUMBER", "GENDER"],
"delegate_info": {
"receiver_name": "AJY7MrlsNc/t",
}
}'
{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa",
"result": "Y"
}
{
"tx_id": "02a05c5bfe-d89a-448b-a538-d80dc5b038fa",
"result": "Y",
"scheme": "kakaotalk://..."
}
메서드 | URL | 인증 방식 |
---|---|---|
GET |
https://cert-sign.kakao.com/sign/doc/v1/status |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | - | - | - |
전자서명 상태 확인하기 API는 카카오톡 출금동의(K3100) 상품을 통해 요청된 전자서명의 진행 상태를 확인합니다. 사용자는 카카오톡을 통해 인증을 수행하므로, 이용기관은 전자서명 상태 확인하기 API를 통해서만 인증 진행 상태를 확인할 수 있습니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 GET
으로 요청합니다. 본문에 상태를 확인할 전자서명 요청의 tx_id
와 정산 ID를 포함해야 합니다.
요청 성공 시 응답은 전자서명의 상태를 포함합니다. 전자서명의 상태는 요청(REQUESTED
), 완료(COMPLETED
), 만료(EXPIRED
) 세 가지로 각각 다음과 같이 조치합니다.
viewed_at
필드 값으로 확인 가능전자서명이 완료된 경우에는 사용자가 서명한 일시, 전자서명이 만료되는 일시를 비롯한 시간 정보들을 제공합니다. 이미 이용기관이 전자서명 검증하기 API를 통해 전자서명 값을 전달받았다면, 전자서명 값이 전달된 일시 정보를 제공합니다.
사용자의 인증서 상태에 따라 인증서를 발급 또는 재발급하거나 2차 본인인증(은행 계좌 확인)을 해야 할 수 있습니다. 이 경우, 추가 인증까지 모두 완료된 후 전자서명 상태가 완료로 변경됩니다.
요청 실패 시 문제 해결에서 에러 코드 정보를 확인합니다.
이름 | 설명 | 필수 |
---|---|---|
Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY} 인증 방식, 딜러사 앱의 REST API 키로 인증 요청 |
O |
Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY} 인증 방식, 이용기관 앱 REST API 키로 인증 요청 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
settle_id | String |
정산 ID | O |
tx_id | String |
전자서명 원문 접수번호 | O |
이름 | 타입 | 설명 |
---|---|---|
tx_id | String |
전자서명 원문 접수번호 |
status | String |
전자서명 상태, 다음 중 하나REQUESTED : 사용자에게 전자서명을 요청함, 사용자는 채널 메시지를 통해 전자서명 요청을 받음COMPLETED : 사용자가 전자서명을 완료함EXPIRED : 유효시간 이내에 사용자가 전자서명을 완료하지 않아 요청이 만료됨 |
created_at | String |
전자서명 요청 일시* |
viewed_at | String |
사용자가 전자서명 요청을 확인한 일시* |
completed_at | String |
사용자가 전자서명을 완료한 일시* |
expired_at | String |
전자서명 만료 일시* |
partner_notified_at | String |
이용기관이 전자서명 검증하기 API를 통해 전자서명 값을 전달받은 일시* |
* 시간은 yyyy-MM-dd'T'HH:mm:ss 형식, RFC3339 참고
curl -i -X GET "https://cert-sign.kakao.com/sign/doc/v1/status?settle_id=${SETTLE_ID}&tx_id=${TX_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8"
{
"status": "REQUESTED",
"tx_id": "d3a83f53-239d-4d7a-968d-25ec0969047e",
"created_at": "2021-06-18 13:53:36",
"viewed_at": null,
"completed_at": null,
"expired_at": "2021-06-18 14:03:36",
"partner_notified_at": null
}
메서드 | URL | 인증 방식 |
---|---|---|
GET |
https://cert-sign.kakao.com/sign/doc/v1/verify |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | - | - | - |
전자서명 검증하기 API는 완료된 전자서명을 검증하고 이용기관에 전자서명 데이터 전문을 제공합니다. 전자서명 데이터 전문은 자동이체 또는 자동납부 등록 시 필요한 자동출금 동의 자료를 포함합니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 GET
으로 요청합니다. 본문에 완료된 전자서명 요청의 tx_id
와 정산 ID를 포함해야 합니다. 전자서명 검증하기는 완료된 전자서명 요청당 1회만 요청 가능합니다.
요청 성공 시 응답은 전자서명의 상태와 전자서명 검증 결과를 포함합니다. 요청 실패 시 문제 해결에서 에러 코드 정보를 확인합니다.
이름 | 설명 | 필수 |
---|---|---|
Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY} 인증 방식, 딜러사 앱의 REST API 키로 인증 요청 |
O |
Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY} 인증 방식, 이용기관 앱 REST API 키로 인증 요청 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
settle_id | String |
정산 ID | O |
tx_id | String |
전자서명 원문 접수번호 | O |
이름 | 타입 | 설명 |
---|---|---|
status | String |
전자서명 상태, 전자서명 검증 시에는 전자서명이 완료된 상태인 COMPLETE 값만 제공되며, 이 외 상태인 경우 에러 응답 |
result | String |
전자서명 검증 결과Y : 성공N : 실패 |
ci | String |
연계정보(Connecting Information, CI) 카카오톡 출금동의 K3100 상품 이용 시 이용기관이 가진 권한 및 사용자 동의 여부에 따라, AES256(CTR) 방식으로 암호화된 CI 포함 비고: 전자서명 요청하기 요청의 identify_items 에 CI 포함 시 응답에 미포함 |
vid | String |
계약 시 ci 제공에 협의한 경우에만 제공사용자의 원본 CI(Base64 decoded CI)와 인증서 일련번호(Serial number byte array)로 구성된 SHA256 해시 값( sha256_hash ) |
signed_document | String |
Base64 인코딩된 DER 형식의 서명된 문서 (참고: CMSSignedData) |
curl -i -X GET "https://cert-sign.kakao.com/sign/doc/v1/verify?settle_id=${SETTLE_ID}&tx_id=${TX_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8"
{
"status": "COMPLETED",
"result": "Y",
"signed_document": "${CMSSignedData}" // 상단 설명 및 표 참고
}
{
"status": "COMPLETED",
"result": "Y",
"ci": "${CI}", // 상단 설명 및 표 참고
"vid": "${VID}", // 상단 설명 및 표 참고
"signed_document": "${CMSSignedData}" // 상단 설명 및 표 참고
}
아래는 실제 서비스에서 고려해야 할 여러 요소(성능, 예외 처리, 동시성 등)가 반영되지 않은 참고용 예제입니다.
class VerifySample {
val kakaoClient = HttpClient.newBuilder().build()
val mapper = ObjectMapper()
val settleId = "PARTNER_SETTLE_ID"
private val transformation = "AES/CTR/NoPadding"
private val secretKeySpec = SecretKeySpec("PARTNER_SECRET_KEY".decodeBase64(), "AES")
private val ivSpec = IvParameterSpec("PARTNER_IV".decodeBase64())
private fun decrypt(content: ByteArray): String =
Cipher.getInstance(transformation).run {
init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec)
String(doFinal(content))
}
private fun createHttpRequest(uri: URI): HttpRequest {
return HttpRequest.newBuilder()
.uri(uri)
.setHeader(AUTHORIZATION, DEALER_REST_API_KEY)
.setHeader(TARGET_AUTHORIZATION, PARTNER_REST_API_KEY)
.GET()
.build()
}
// 전자서명 검증하기 API
private fun callVerify(txId: String): VerifyResponse {
val uri = URI.create(createURI(txId))
val response: HttpResponse<String> = kakaoClient.send(createHttpRequest(uri), HttpResponse.BodyHandlers.ofString())
return mapper.readValue<VerifyResponse>(response.body())
}
private fun createURI(txId: String): String {
val sb = StringBuilder()
sb.append("https://cert-sign.kakao.com/sign/doc/v1/verify?settle_id=")
.append(settleId)
.append("&tx_id=")
.append(txId)
return sb.toString()
}
/**
* 이용기관에서 CI를 보유한 경우
* 전자서명 검증하기 API를 호출하여 보유한 CI와 비교
* !!중요!! 전자서명 검증하기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 전자서명 검증하기 API 호출
fun compareCI(txId: String): Boolean {
// 응답에 포함된 CI를 복호화
val encryptedCi = callVerify(txId).ci
// 이용기관에서 보유한 CI와 비교
val decryptedCI = decrypt(encryptedCi.decodeBase64())
return exist(decryptedCI)
}
/**
* 실명인증된 CI가 있는 경우
* 전자서명 검증하기 API의 결과와 실명인증된 CI를 비교
* !!중요!! 전자서명 검증하기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 전자서명 검증하기 API 호출
fun compareCI(txId: String, ci: String): Boolean {
// 응답에 포함된 CI를 복호화
val encryptedCi = callVerify(txId).ci
// 실명인증된 CI와 비교
val decryptedCI = decrypt(encryptedCi.decodeBase64())
return ci == decryptedCI
}
}
class VerifySample {
private final HttpClient kakaoClient = HttpClient.newBuilder().build();
private final SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode("PARTNER_SECRET_KEY"), "AES");
private final IvParameterSpec ivSpec = new IvParameterSpec(Base64.getDecoder().decode("PARTNER_IV"));
private final String settleId = "PARTNER_SETTLE_ID";
private String decrypt(byte[] content) throws NoSuchPaddingException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException {
String transformation = "AES/CTR/NoPadding";
Cipher cipher = Cipher.getInstance(transformation);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
return new String(cipher.doFinal(content));
}
private HttpRequest createHttpRequest(URI uri) {
return HttpRequest.newBuilder()
.uri(uri)
.setHeader(AUTHORIZATION, DEALER_REST_API_KEY)
.setHeader(TARGET_AUTHORIZATION, PARTNER_REST_API_KEY)
.GET()
.build();
}
private VerifyResponse callVerify(String txId) throws IOException, InterruptedException {
URI uri = URI.create(createURI(txId));
// 전자서명 검증하기 API
HttpResponse<String> response = kakaoClient.send(createHttpRequest(uri), HttpResponse.BodyHandlers.ofString());
return Mapper.getInstance().readValue(response.body(), VerifyResponse.class);
}
private String createURI(String txId) {
StringBuilder sb = new StringBuilder();
sb.append("https://cert-sign.kakao.com/sign/doc/v1/verify?settle_id=")
.append(settleId)
.append("&tx_id=")
.append(txId);
return sb.toString();
}
/**
* 이용기관에서 CI를 보유한 경우
* 전자서명 검증하기 API를 호출하여 보유한 CI와 비교
* !!중요!! 전자서명 검증하기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 전자서명 검증하기 API 호출
boolean compareCI(String txId) throws IOException, InterruptedException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
// 응답에 포함된 CI를 복호화
String encryptedCi = callVerify(txId).getCi();
// 이용기관에서 보유한 CI와 비교
String decryptedCI = decrypt(Base64.getDecoder().decode(encryptedCi));
return exist(decryptedCI);
}
/**
* 실명인증된 CI가 있는 경우
* 전자서명 검증하기 API의 결과와 실명인증된 CI를 비교
* !!중요!! 전자서명 검증하기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 전자서명 검증하기 API 호출
boolean compareCI(String txId, String ci) throws IOException, InterruptedException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
// 응답에 포함된 CI를 복호화
String encryptedCi = callVerify(txId).getCi();
// 실명인증된 CI와 비교
String decryptedCI = decrypt(Base64.getDecoder().decode(encryptedCi));
return ci.equals(decryptedCI);
}
}
class VerifySample {
private:
//카카오의 전자서명 검증하기 API를 호출.
json callVerify(const string& txId) {
string uri = createURI(txId);
auto response = kakaoClient.Get(uri.c_str());
return json::parse(response->body);
}
string createURI(const string& txId) {
return "https://cert-sign.kakao.com/sign/doc/v1/verify?settle_id=" + settleId + "&tx_id=" + txId;
}
public:
/**
* 이용기관에서 CI를 보유한 경우
* 전자서명 검증하기 API를 호출하여 보유한 CI와 비교
* !!중요!! 전자서명 검증하기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 전자서명 검증하기 API 호출
bool compareCI(const string& txId) {
// 응답에 포함된 CI를 복호화
string encryptedCi = callVerify(txId)["ci"];
// 이용기관에서 보유한 CI와 비교
string decryptedCI = decrypt(base64_decode(encryptedCi));
return exist(decryptedCI);
}
/**
* 실명인증된 CI가 있는 경우
* 전자서명 검증하기 API의 결과와 실명인증된 CI를 비교
* !!중요!! 전자서명 검증하기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 전자서명 검증하기 API 호출
bool compareCI(const string& txId, const string& ci) {
// 응답에 포함된 CI를 복호화
string encryptedCi = callVerify(txId)["ci"];
// 실명인증된 CI와 비교
string decryptedCI = decrypt(base64_decode(encryptedCi));
return ci == decryptedCI;
}
};
메서드 | URL | 인증 방식 |
---|---|---|
GET |
https://cert-sign.kakao.com/sign/v2/identify |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | - | - | - |
서명자 정보받기 API는 서명을 완료한 서명자 정보를 제공합니다.
이 API는 전자서명 검증하기 호출 후 요청 가능하며, 사용자 서명 완료 후 일정시간(10분)동안 1회만 요청 가능합니다. 이후 요청에 대해서는 E2017
에러가 발생합니다. 서명자의 개인정보 제공 동의 및 서명 완료 후, 개발 설계 오류, 네트워크 오류 등으로 인한 이용기관의 정보 수신 실패에 대해 카카오는 책임을 지지 않습니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 GET
으로 요청합니다. 본문에 완료된 전자서명 요청의 tx_id
와 정산 ID를 포함해야 합니다.
요청 성공 시 응답은 전자서명 요청하기의 identify_items
파라미터로 지정한 서명자 정보를 포함합니다. 요청 실패 시 문제 해결에서 에러 코드 정보를 확인합니다.
카카오톡 인증 서비스에서 제공하는 연계정보(CI)와 이름, 생년월일, 전화번호는 사용자 비교 및 검증 용도로만 사용할 수 있습니다. 서명자 정보 가져오기 API를 통해 제공받은 CI, 이름, 생년월일, 전화번호를 이용기관의 정보와 비교해 올바른 사용자인지 검증해야 합니다. 비교 및 검증은 반드시 이용기관 서버에서 수행해야 합니다.
이름 | 설명 | 필수 |
---|---|---|
Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY} 인증 방식, 딜러사 앱의 REST API 키로 인증 요청 |
O |
Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY} 인증 방식, 이용기관 앱 REST API 키로 인증 요청 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
settle_id | String |
정산 ID | O |
tx_id | String |
전자서명 원문 접수번호 | O |
이름 | 타입 | 설명 |
---|---|---|
name | String |
암호화된 서명자의 이름 |
phone_no | String |
암호화된 서명자의 카카오톡 전화번호 |
birthday | String |
암호화된 서명자의 생년월일 |
gender | String |
암호화된 서명자의 성별 |
ci | String |
암호화된 서명자의 CI(연계정보) 비고: 전자서명 검증하기로 CI 수신 시 응답에 미포함 |
vid | String |
암호화된 서명자의 CI 검증값 비고: 전자서명 검증하기로 CI 수신 시 응답에 미포함 |
curl -i -X GET "https://cert-sign.kakao.com/sign/v2/identify?settle_id=${SETTLE_ID}&tx_id=${TX_ID}" \
-H "Authorization: KakaoAK ${DEALER_REST_API_KEY}" \
-H "Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY}" \
-H "Content-Type: application/json;charset=UTF-8"
{
"name": "${NAME}",
"phone_no": "${PHONE_NO}",
"birthday": "${BIRTHDAY}",
"gender": "${GENDER}",
"ci": "${CI}",
"vid": "${VID}"
}