이 문서는 카카오톡 인증 서비스의 K2220 로그인 축약서명 API 사용법을 안내합니다.
카카오톡 로그인 축약서명은 카카오톡 애플리케이션(이하 앱)을 통한 인증 로그인 후, 세션 유효시간 동안 반복적인 축약서명 기능을 제공하는 서비스입니다. 세션은 회원번호와 유효시간을 포함합니다.
세션은 사용자가 인증 로그인을 완료한 후 세션 정보 가져오기의 호출 결과로 Kakao SDK 내부에 생성됩니다. 세션의 유효시간은 전자서명 요청하기 호출 시 최소 6시간, 최대 48시간으로 설정할 수 있습니다.
임시 키 쌍은 카카오톡 로그인 축약서명 시 필요한 암호화 키로, Kakao SDK를 통해 생성 및 삭제할 수 있습니다. 임시 키 쌍은 공개 키와 개인 키로 이뤄져 있으며, 세션의 유효시간 동안만 사용할 수 있습니다. 각 키의 용도는 아래와 같습니다.
이용기관은 사용자 비교 및 검증 용도의 서명자 정보를 서명자 정보 가져오기로 제공받을 수 있습니다. 이밖에 카카오톡 인증 로그인 과정에서 사용자로부터 동의받은 개인정보 항목을 카카오로부터 제공받을 수 있습니다. 이를 통해 별도의 사용자 정보 입력 과정이나 서비스 약관 동의를 거치지 않고도 회원가입 및 로그인 처리를 할 수 있습니다. 개인정보제공 및 서비스 약관 동의 화면 구성을 참고합니다.
카카오톡 인증 서비스 API는 서버간 연동(Server to Server)을 원칙으로 합니다.
카카오톡 로그인 축약서명 서비스는 Kakao SDK를 통해 이용 가능하며, Android와 iOS 네이티브 앱만 지원합니다. Kakao SDK for Android(이하 Android SDK), Kakao SDK for iOS(이하 iOS SDK)의 Cert
모듈을 설치해 카카오톡 로그인 축약서명 서비스에 필요한 API를 사용할 수 있습니다. Kakao SDK 설치 및 설정 안내는 아래를 참고합니다.
아래 순서로 Android SDK 설치 및 설정을 완료합니다.
아래 순서로 iOS SDK 설치 및 설정을 완료합니다.
iOS SDK 설치 및 설정 완료 후, 아래와 같이 이용기관 앱에서 Cert
를 포함해 필요한 모듈을 사용하도록 설정해야 합니다.
import KakaoSDKCommon
import KakaoSDKAuth
import KakaoSDKUser
import KakaoSDKCert
카카오톡 로그인 축약서명의 진행 과정을 크게 세 단계로 나눠보면 아래와 같습니다.
1. 인증 로그인publicKey()
를 호출해 공개 키 가져오기를 합니다.tx_id
를 발급받습니다.tx_id
에 대한 세션 유효시간을 설정합니다. 필요한 서명자 정보를 identify_items
파라미터로 지정할 수 있습니다.tx_id
를 전달합니다.txId
로 Kakao SDK의 certLoginWithKakaoTalk()
을 호출해 인증 로그인을 요청합니다.txId
를 반환합니다.카카오톡 로그인 축약서명은 익명서명 방식으로, 전자서명 준비하기 호출 단계에서 이용기관이 카카오톡 인증 서비스에 사용자 정보를 전달하지 않습니다.
txId
를 전달하고 전자서명 검증을 요청합니다.txId
로 Kakao SDK의 sessionInfo()
를 호출해 세션 정보를 받습니다.sessionInfo()
에서 반환된 값으로 세션 정보를 업데이트합니다.reducedSign()
을 호출해 축약서명을 요청합니다.카카오톡 로그인 축약서명의 전자서명은 아래 두 종류로, 서명 원문의 구성과 검증 방식에 차이가 있습니다.
서비스의 인증 로그인 요청하기 후 사용자가 카카오톡에서 수행하는 서명입니다.
카카오톡 인증 로그인 시 전자서명 완료 후 사용자의 축약서명 필요 서비스 요청 시 이용기관에서 처리하는 서명입니다.
사용자가 이용기관 서비스에서 로그아웃할 경우, 로그아웃을 호출해야 합니다.
사용자가 이용기관 서비스에서 카카오 로그인 연동 해제 또는 탈퇴 시, 연결 끊기를 호출해 이용기관 앱과 사용자의 연결을 끊어야 합니다.
연결 끊기 호출 없이 이용기관 서비스에서의 연동 해제 처리만 이뤄질 경우, 사용자가 다시 카카오톡 인증 로그인을 수행할 때 개인정보제공 및 서비스 약관 동의 절차를 거치지 않아 이용에 불편을 겪거나 문제가 발생할 수 있습니다. 자세한 사항은 연결을 참고합니다.
로그아웃, 연결 끊기는 Kakao SDK를 사용해 요청할 수 있으며 임시 키 쌍, 세션 정보, txId
를 함께 삭제해야 합니다. 아래 예제를 참고합니다.
// 로그아웃
UserApiClient.instance.logout { error ->
if (error != null) {
Log.e(TAG, "로그아웃 실패. SDK에서 토큰 삭제 됨", error)
} else {
Log.i(TAG, "로그아웃 성공. SDK에서 토큰 삭제 됨")
}
// 로그아웃은 실패 시에도 Kakao SDK에 저장된 토큰 삭제
// 로그아웃 성공 여부와 관계 없이 임시 키 쌍, 세션 정보, txId도 함께 삭제해야 함
CertApiClient.instance.deleteKeyPair(CertType.K2220)
CertDemoClient.instance(context).deleteTxId(CertType.K2220)
}
// 연결 끊기
UserApiClient.instance.unlink { error ->
if (error != null) {
Log.e(TAG, "연결 끊기 실패", error)
} else {
Log.i(TAG, "연결 끊기 성공. SDK에서 토큰 삭제 됨")
// 연결 끊기 성공 시 임시 키 쌍, 세션 정보, txId도 함께 삭제해야 함
CertApiClient.instance.deleteKeyPair(CertType.K2220)
CertDemoClient.instance(context).deleteTxId(CertType.K2220)
}
}
val disposables = CompositeDisposable()
// 로그아웃
UserApiClient.rx.logout()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doFinally{
// 로그아웃은 실패 시에도 Kakao SDK에 저장된 토큰 삭제
// 로그아웃 성공 여부와 관계 없이 임시 키 쌍, 세션 정보, txId도 함께 삭제해야 함
CertApiClient.rx.deleteKeyPair(CertType.K2220)
CertDemoClient.instance(context).deleteTxId(CertType.K2220)
}
.subscribe({
Log.i(TAG, "로그아웃 성공. SDK에서 토큰 삭제 됨")
}, { error ->
Log.e(TAG, "로그아웃 실패. SDK에서 토큰 삭제 됨", error)
})
.addTo(disposables)
// 연결 끊기
UserApiClient.rx.unlink()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
Log.i(TAG, "연결 끊기 성공. SDK에서 토큰 삭제 됨")
// 연결 끊기 성공 시 임시 키 쌍, 세션 정보, txId도 함께 삭제해야 함
CertApiClient.rx.deleteKeyPair(CertType.K2220)
CertDemoClient.instance(context).deleteTxId(CertType.K2220)
}, { error ->
Log.e(TAG, "연결 끊기 실패", error)
})
.addTo(disposables)
// 로그아웃
UserApi.shared.logout {(error) in
if let error = error {
print(error)
}
else {
print("logout() success.")
}
// 로그아웃은 실패 시에도 Kakao SDK에 저장된 토큰 삭제
// 로그아웃 성공 여부와 관계 없이 임시 키 쌍, 세션 정보, txId도 함께 삭제해야 함
CertApi.shared.deleteKeyPair(certType: .K2220)
CertDemoApi.shared.deleteTxId(certType: .K2220)
}
// 연결 끊기
UserApi.shared.unlink {(error) in
if let error = error {
print(error)
}
else {
print("unlink() success.")
// 연결 끊기 성공 시 임시 키 쌍, 세션 정보, txId도 함께 삭제해야 함
CertApi.shared.deleteKeyPair(certType: .K2220)
CertDemoApi.shared.deleteTxId(certType: .K2220)
}
}
권한 | 사전 설정 | 카카오 로그인 | 동의항목 | 레퍼런스 |
---|---|---|---|---|
필요 | 플랫폼 등록 | - | - | Android SDKpublicKey() ReactiveX Android SDK publicKey() iOS SDK publicKey() |
Kakao SDK를 사용해 구현해야 하는 기능입니다.
임시 키 쌍을 생성하고, 공개 키 값을 조회합니다. publicKey()
를 호출합니다.
publicKey()
호출 시, 기존에 생성된 임시 키 쌍이 없다면 새로 생성합니다. 기존에 생성된 임시 키 쌍이 있다면 공개 키 값을 반환합니다. null
또는 nil
이 반환된 경우, 임시 키 쌍 삭제하기 호출 후 다시 공개 키 가져오기를 요청합니다.
공개 키는 이용기관 서버로 전송해 관리해야 합니다. 이용기관 서버는 공개 키를 전자서명 요청하기의 서명 원문, 전자서명 검증하기의 서명 값 검증에 사용합니다.
요청 실패 시 문제 해결을 참고합니다.
// 공개 키 가져오기
val publicKey = CertApiClient.instance.publicKey(CertType.K2220)
// 가져온 공개 키를 이용기관 서버로 전송
...
// 공개 키 가져오기
val publicKey = CertApiClient.rx.publicKey(CertType.K2220)
// 가져온 공개 키를 이용기관 서버로 전송
...
// 공개 키 가져오기
guard let publicKey = CertApi.shared.publicKey(certType: .K2220) else {
// 에러 처리
print("public key is nil")
return
}
// 가져온 공개 키를 이용기관 서버로 전송
...
메서드 | URL | 인증 방식 |
---|---|---|
POST |
https://cert-sign.kakao.com/sign/v2/prepare/${PRODUCT_CODE} |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | 플랫폼 등록 보안: 허용 IP 주소 |
- | - |
이용기관 서버에 구현해야 하는 기능입니다.
정산 ID인 settle_id
를 카카오톡 인증 서비스에 전달하고, 접수번호인 tx_id
를 발급받습니다. tx_id
를 사용해 다음 단계의 전자서명 요청하기, 인증 로그인, 전자서명 검증하기를 요청할 수 있습니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 POST
로 요청합니다. 요청 URL에 경로 변수(Path variable)로 상품 코드인 K2220
을 포함합니다. 쿼리 파라미터에 정산 ID를 포함해야 합니다. 카카오톡 로그인 축약서명은 익명서명 방식이므로 사용자 정보는 전달하지 않습니다.
요청 성공 시 응답은 tx_id
를 포함합니다. 요청 실패 시 문제 해결을 참고합니다.
이름 | 설명 | 필수 |
---|---|---|
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 |
상품 코드, K2220 전달 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
settle_id | String |
정산 ID | O |
이름 | 타입 | 설명 |
---|---|---|
tx_id | String |
전자서명 원문 접수번호 |
curl -X POST "https://cert-sign.kakao.com/sign/v2/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"
{
"tx_id": "ancb290af0-f72a-44dd-8f41-f73ed11879e3"
}
메서드 | URL | 인증 방식 |
---|---|---|
POST |
https://cert-sign.kakao.com/sign/v2/request |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | 플랫폼 등록 보안: 허용 IP 주소 |
- | - |
이용기관 서버에 구현해야 하는 기능입니다.
사용자가 전자서명할 서명 원문을 전달하고, 세션 유효시간을 설정합니다. 요청 성공 이후 사용자가 카카오톡에서 인증 로그인 및 전자서명할 수 있습니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 POST
로 요청합니다. 쿼리 파라미터에 정산 ID를 포함해야 합니다. 본문에 서명할 데이터와 전자서명 요청 정보를 JSON
형식으로 전달해야 합니다. 서명할 데이터는 공개 키와 세션 유효시간으로 구성합니다.
서명자 정보가 필요한 경우, identify_items
파라미터로 필요한 항목을 지정합니다. 카카오톡 인증 로그인 완료 후, 서명자 정보 가져오기로 서명자 정보를 제공받을 수 있습니다.
request_type
은 사용자가 카카오 인증서로 전자서명할 때 노출되는 [요청구분]의 문구입니다. 아래 이미지를 참고합니다.
요청 성공 시 응답은 tx_id
와 처리 결과인 result
를 포함합니다. tx_id
는 이용기관 클라이언트로 전달해 다음 단계인 인증 로그인에 사용합니다.
요청 실패 시 문제 해결을 참고합니다.
이름 | 설명 | 필수 |
---|---|---|
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 |
encrypted | Boolean |
서명할 데이터 암호화 여부, 암호화 예제 참고 (기본값: false ) |
X |
data | String |
서명할 데이터, 아래 항목 포함txId : 전자서명 요청 원문 접수번호, tx_id 와 같은 값data : data: 서명할 데이터, 공개 키와 공개 키의 유효시간을 포함한 전자서명 원문 JSON 문자열예제 참고 (최대: 300자) |
O |
delegate_info | JSON |
카카오 인증서로 전자서명 시 인증 정보 화면에 노출할 부가 정보, delegate_info: 사용자 인증 요청 안내문, 예제 참고 | |
identify_items | String[] |
서명자 정보 가져오기 응답으로 확인할 서명자 정보 목록 다음 중 하나 이상의 값 사용 가능 CI : 연계정보NAME : 이름BIRTHDAY : 생일PHONE_NUMBER : 전화번호GENDER : 성별 |
X |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
public_key | String |
공개 키 가져오기 시 반환받은 공개 키 값 | O |
start_at | String |
세션 유효시간의 시작 시각yyyy-mm-dd hh:MM:ss 형식 |
O |
end_at | String |
세션 유효시간의 종료 시각yyyy-mm-dd hh:MM:ss 형식start_at 으로부터 최소 6시간, 최대 48시간 이후의 시각이어야 함 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
request_type | String |
인증 정보 화면의 [요청구분] 문구 (최대: 40자, 공백 포함) |
O |
이름 | 타입 | 설명 |
---|---|---|
tx_id | String |
전자서명 원문 접수번호 |
result | String |
처리 결과Y : 접수 성공N : 접수 실패 |
curl -i -X POST "https://cert-sign.kakao.com/sign/v2/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 '{
"data": "{\"txId\": \"ancb290af0-f72a-44dd-8f41-f73ed11879e3\",\"data\": \"{\\\"public_key\\\":\\\"${PUBLIC_KEY}\\\",\\\"start_at\\\":\\\"2023-06-19 00:00:00\\\",\\\"end_at\\\":\\\"2023-06-19 06:00:00\\\"}\"}",
"delegate_info": {
"request_type": "증권 로그인"
},
"identify_items": ["CI", "NAME", "BIRTHDAY", "PHONE_NUMBER", "GENDER"]
}'
{
"tx_id": "ancb290af0-f72a-44dd-8f41-f73ed11879e3",
"result": "Y"
}
권한 | 사전 설정 | 카카오 로그인 | 동의항목 | 레퍼런스 |
---|---|---|---|---|
필요 | 플랫폼 등록 카카오 로그인 활성화 동의항목 OpenID Connect 활성화(선택) 간편가입(선택) |
필요 | 필요: 필수 동의항목 |
Android SDK 공통CertTokenInfo Android SDK certLoginWithKakaoTalk() ReactiveX Android SDK certLoginWithKakaoTalk() iOS SDK 공통 CertTokenInfo iOS SDK certLoginWithKakaoTalk() ReactiveX iOS SDK certLoginWithKakaoTalk() |
Kakao SDK를 사용해 구현해야 하는 기능입니다.
사용자 기기의 카카오톡을 실행하고 인증 로그인 및 전자서명을 요청합니다. certLoginWithKakaoTalk()
를 호출합니다.
호출 시 이용기관 서버로부터 전달받은 txId
, 정산 ID를 전달해야 합니다. CertType
은 K2220
으로 지정합니다. 이 외 파라미터 정보는 K2100: 인증 로그인을 참고합니다.
카카오톡 로그인 축약서명 서비스는 카카오톡 앱을 실행하고 전자서명 요청하는 앱투앱(App to app) 방식만 지원합니다. isKakaoTalkLoginAvailable()
를 호출해 카카오톡 실행 가능 여부를 먼저 확인할 수 있습니다. 예제를 참고합니다.
인증 로그인 요청 성공 시, 사용자는 카카오톡 앱에서 카카오 로그인, 카카오 인증서로 전자서명을 수행합니다. 카카오 로그인은 이용기관 서비스에 대한 개인정보제공 및 서비스 약관 동의를 포함합니다. 카카오 로그인 동의 화면은 사용자가 이용기관 서비스에 처음 카카오 로그인하는 경우에만 출력됩니다. (참고: 인가)
사용자가 전자서명을 완료하면 이용기관 클라이언트의 Kakao SDK에 인가 코드가 발급됩니다. Kakao SDK가 내부적으로 인가 코드를 사용해 토큰을 발급받고 인증 로그인을 완료합니다.
인증 로그인 완료 시 토큰과 txId
를 반환합니다.
반환받은 txId
는 이용기관 클라이언트에 별도 저장해 관리해야 합니다.txId
를 이용기관 서버에 전달한 후 전자서명 검증하기를 요청해야 합니다.
토큰은 사용자 정보 가져오기 API인 me()
를 요청하는 데 사용합니다. 사용자 정보 가져오기의 자세한 정보는 아래 문서에서 확인할 수 있습니다.
요청 실패 시 문제 해결을 참고합니다.
// 인증 로그인 요청하기
CertApiClient.instance.certLoginWithKakaoTalk(
context,
CertType.K2220,
txId = txId,
settleId = settleId
) { certTokenInfo, loginError ->
if (loginError != null) {
// 인증 로그인 요청에 실패한 경우
if (loginError is KakaoSdkError) {
// 에러 유형이 KakaoSdkError인 경우에는 기존 임시 키 쌍과 txId 삭제 후, 임시 키 쌍 생성하기부터 다시 요청해야 함
CertApiClient.instance.deleteKeyPair(CertType.K2220)
// txId 삭제 처리
...
} else {
// 에러 처리
...
}
} else {
// 인증 로그인 완료, txId 저장
Log.i(TAG, "인증 로그인 성공 ${certTokenInfo.token.accessToken} ${certTokenInfo.txId}")
...
}
}
val disposables = CompositeDisposable()
// 인증 로그인 요청하기
CertApiClient.rx.certLoginWithKakaoTalk(
context,
CertType.K2220,
txId = txId,
settleId = settleId
)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ certTokenInfo ->
// 인증 로그인 완료, txId 저장
Log.i(TAG, "인증 로그인 성공 ${certTokenInfo.token.accessToken} ${certTokenInfo.txId}")
...
}, { error ->
// 인증 로그인 요청에 실패한 경우
if (error is KakaoSdkError) {
// 에러 유형이 KakaoSdkError인 경우에는 기존 임시 키 쌍과 txId 삭제 후, 임시 키 쌍 생성하기부터 다시 요청해야 함
CertApiClient.rx.deleteKeyPair(CertType.K2220)
// txId 삭제 처리
...
} else {
// 에러 처리
...
}
})
.addTo(disposables)
// 인증 로그인 요청하기
CertApi.shared.certLoginWithKakaoTalk(certType: .K2220,
txId: "${TX_ID}",
settleId: "${SETTLE_ID}",
identifyItems: [.CI, .Name, .Birthday, .PhoneNumber]) { certTokenInfo, error in
if let error = error {
// 인증 로그인 요청에 실패한 경우
if let sdkError = error as? SdkError {
// 에러 유형이 SdkError인 경우에는 기존 임시 키 쌍과 txId 삭제 후, 임시 키 쌍 생성하기부터 다시 요청해야 함
CertApi.shared.deleteKeyPair(certType: .K2220)
// txId 삭제 처리
...
}
else {
// 네트워크 에러 등 기타 에러 처리
...
}
}
else {
// 인증 로그인 완료, txId 저장
if let txId = certTokenInfo?.txId {
...
}
}
}
let disposeBag = DisposeBag()
// 인증 로그인 요청하기
CertApi.shared.rx.certLoginWithKakaoTalk(certType: .K2220,
txId: "${TX_ID}",
settleId: "${SETTLE_ID}",
identifyItems: [.CI, .Name, .Birthday, .PhoneNumber])
.subscribe(onNext: { certTokenInfo in
// 인증 로그인 완료, txId 저장
if let txId = certTokenInfo?.txId {
...
}
}, onError: { error in
if let sdkError = error as? SdkError {
// 에러 유형이 SdkError인 경우에는 기존 임시 키 쌍과 txId 삭제 후, 임시 키 쌍 생성하기부터 다시 요청해야 함
CertApi.shared.deleteKeyPair(certType: .K2220)
// txId 삭제 처리
...
}
else {
// 네트워크 에러 등 기타 에러 처리
...
}
})
.disposed(by: disposeBag)
메서드 | URL | 인증 방식 |
---|---|---|
GET |
https://cert-sign.kakao.com/sign/v2/verify |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | 플랫폼 등록 보안: 허용 IP 주소 |
필요 | - |
이용기관 서버에 구현해야 하는 기능입니다.
완료된 전자서명을 검증하고 전자서명 데이터 전문을 가져옵니다. 사용자가 인증 로그인 시 수행한 전자서명만을 검증하며, 축약서명에 대한 검증을 지원하지 않습니다.
헤더(Header)에 이용기관 앱 REST API 키와 딜러사 앱 REST API 키를 담아 GET
으로 요청합니다. 쿼리 파라미터에 tx_id
와 정산 ID를 포함해야 합니다.
요청 성공 시 응답은 전자서명 검증 결과와 전자서명 데이터 전문을 포함합니다. 전자서명 데이터 전문은 사용자가 인증 로그인 시 전자서명한 결과인 서명 값입니다. 전자서명 데이터 전문이 전자서명 요청하기 시 전달한 서명 원문과 일치하는지 비교해 검증해야 합니다. 서명 값 검증 결과 이상이 없는 경우, 이용기관 서비스에서 사용자를 로그인 완료 처리합니다.
요청 실패 시 문제 해결을 참고합니다.
이름 | 설명 | 필수 |
---|---|---|
Authorization | Authorization: KakaoAK ${DEALER_REST_API_KEY} 인증 방식, 딜러사 앱의 REST API 키로 인증 요청 |
O |
Target-Authorization | Target-Authorization: KakaoAK ${PARTNER_REST_API_KEY} 인증 방식, 이용기관 앱 REST API 키로 인증 요청 |
O |
이름 | 타입 | 설명 | 필수 |
---|---|---|---|
tx_id | String |
전자서명 원문 접수번호 | O |
settle_id | String |
정산 ID | O |
이름 | 타입 | 설명 |
---|---|---|
status | String |
전자서명 상태REQUESTED : 사용자에게 전자서명을 요청함COMPLETED : 사용자가 전자서명을 완료함EXPIRED : 유효시간 이내에 사용자가 전자서명을 완료하지 않아 요청이 만료됨 |
data | JSON |
전자서명 검증 결과 data: 전자서명 검증 결과 참고 |
이름 | 타입 | 설명 |
---|---|---|
result | String |
전자서명 검증 결과Y : 검증 성공N : 실패 |
signed_data | String |
전자서명 데이터 전문 (참고: CMSSignedData) |
curl -i -X GET "https://cert-sign.kakao.com/sign/v2/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",
"data": {
"result": "Y",
"signed_data": "${CMSSignedData}" // 상단 설명 및 표 참고
}
}
메서드 | URL | 인증 방식 |
---|---|---|
GET |
https://cert-sign.kakao.com/sign/v2/identify |
REST API 키 |
권한 | 사전 설정 | 카카오 로그인 | 동의항목 |
---|---|---|---|
필요 | - | - | - |
이용기관 서버에 구현해야 하는 기능입니다.
서명자 정보받기 API는 서명을 완료한 서명자 정보를 제공합니다.
이 API는 완료된 전자서명 요청당 1회만 요청 가능하며, 사용자가 서명을 완료한 후, 일정시간(10분) 동안만 정상 응답합니다. 이후 요청에 대해서는 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 수신 시 응답에 미포함 |
sign_user_id | Long |
서명자 회원번호 |
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}",
"sign_user_id": "${SIGN_USER_ID}"
}
아래는 실제 서비스에서 고려해야 할 여러 요소(성능, 예외 처리, 동시성 등)가 반영되지 않은 참고용 예제입니다.
class IdentifySample {
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 callIdentify(txId: String): IdentifyResponse {
val uri = URI.create(createURI(txId))
val response: HttpResponse<String> = kakaoClient.send(createHttpRequest(uri), HttpResponse.BodyHandlers.ofString())
return mapper.readValue<IdentifyResponse>(response.body())
}
private fun createURI(txId: String): String {
val sb = StringBuilder()
sb.append("https://cert-sign.kakao.com/sign/v2/identify?settle_id=")
.append(settleId)
.append("&tx_id=")
.append(txId)
return sb.toString()
}
/**
* 실명인증된 CI가 있는 경우
* 서명자 정보 가져오기 API의 결과와 실명인증된 CI를 비교
* !!중요!! 서명자 정보 가져오기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 서명자 정보 가져오기 API 호출
fun compareCI(txId: String, ci: String): Boolean {
// 응답에 포함된 CI를 복호화
val encryptedCi = callIdentify(txId).ci
// 실명인증된 CI와 비교
val decryptedCI = decrypt(encryptedCi.decodeBase64())
return ci == decryptedCI
}
}
class IdentifySample {
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 IdentifyResponse callIdentify(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(), IdentifyResponse.class);
}
private String createURI(String txId) {
StringBuilder sb = new StringBuilder();
sb.append("https://cert-sign.kakao.com/sign/v2/identify?settle_id=")
.append(settleId)
.append("&tx_id=")
.append(txId);
return sb.toString();
}
/**
* 실명인증된 CI가 있는 경우
* 서명자 정보 가져오기 API의 결과와 실명인증된 CI를 비교
* !!중요!! 서명자 정보 가져오기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 서명자 정보 가져오기 API 호출
boolean compareCI(String txId, String ci) throws IOException, InterruptedException, InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
// 응답에 포함된 CI를 복호화
String encryptedCi = callIdentify(txId).getCi();
// 실명인증된 CI와 비교
String decryptedCI = decrypt(Base64.getDecoder().decode(encryptedCi));
return ci.equals(decryptedCI);
}
}
class IdentifySample {
private:
//카카오의 서명자 정보 가져오기 API를 호출.
json callIdentify(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/v2/identify?settle_id=" + settleId + "&tx_id=" + txId;
}
public:
/**
* 실명인증된 CI가 있는 경우
* 서명자 정보 가져오기 API의 결과와 실명인증된 CI를 비교
* !!중요!! 서명자 정보 가져오기 API 호출 및 CI 비교는 반드시 서버에서 수행
*/
// 서명자 정보 가져오기 API 호출
bool compareCI(const string& txId, const string& ci) {
// 응답에 포함된 CI를 복호화
string encryptedCi = callIdentify(txId)["ci"];
// 실명인증된 CI와 비교
string decryptedCI = decrypt(base64_decode(encryptedCi));
return ci == decryptedCI;
}
};
권한 | 사전 설정 | 카카오 로그인 | 동의항목 | 레퍼런스 |
---|---|---|---|---|
필요 | 플랫폼 등록 보안: 허용 IP 주소 |
필요 | - | Android SDKsessionInfo() ReactiveX Android SDK sessionInfo() iOS SDK sessionInfo() ReactiveX iOS SDK sessionInfo() |
Kakao SDK를 사용해 구현해야 하는 기능입니다.
인증 로그인 완료 후 생성된 세션 정보를 가져옵니다. sessionInfo()
를 호출합니다. 호출 시 txId
를 전달해야 합니다.
세션 정보 가져오기 요청이 성공하면 Kakao SDK가 카카오 인증 서버로부터 조회한 세션 정보를 내부에 저장합니다. Kakao SDK에 저장된 세션의 유효시간 동안 축약서명하기를 요청할 수 있습니다.
서버로부터 세션 정보를 응답받지 못한 경우, null
또는 nil
이 반환됩니다. 세션 정보 가져오기를 재요청하거나, 임시 키 쌍 삭제하기로 임시 키 쌍과 세션 정보를 삭제하고, 다시 처음부터 인증 로그인 과정을 진행합니다.
요청 시 txId
를 전달하지 않으면 Kakao SDK에 저장되어 있는 세션 정보를 조회하는 용도로 사용할 수 있습니다.
요청 실패 시 문제 해결을 참고합니다.
// 세션 정보 가져오기
CertApiClient.instance.sessionInfo(CertType.K2220, txId) { sessionInfo, error ->
if (error != null) {
// 에러 처리
Log.e(TAG, error)
...
return@sessionInfo
}
// 세션 정보 가져오기 성공, Kakao SDK에 세션 정보 저장됨
...
}
// txId 없이 sessionInfo 호출 시 세션 정보 조회 가능
val sessionInfo = CertApiClient.instance.sessionInfo(CertType.K2220)
...
val disposables = CompositeDisposable()
// 세션 정보 가져오기
CertApiClient.rx.sessionInfo(
certType = CertType.K2220,
txId = txId,
)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ sessionInfo ->
// 세션 정보 가져오기 성공, Kakao SDK에 세션 정보 저장됨
...
}, { error ->
// 에러 처리
Log.e(TAG, error)
})
.addTo(disposables)
// txId 없이 sessionInfo 호출 시 세션 정보 조회 가능
val sessionInfo = CertApiClient.rx.sessionInfo(CertType.K2220)
...
// 세션 정보 가져오기
CertApi.shared.sessionInfo(certType: .K2220, txId: txId) { sessionInfo, error in
if let error = error {
// 에러 처리
print(error)
...
}
else {
// 세션 정보 가져오기 성공, Kakao SDK에 세션 정보 저장됨
...
}
}
let disposeBag = DisposeBag()
CertApi.shared.rx.sessionInfo(certType: .K2220, txId: txId)
.subscribe(onSuccess:{ (sessionInfo) in
// 세션 정보 가져오기 성공, Kakao SDK에 세션 정보 저장됨
...
}, onFailure: {error in
// 에러 처리
print(error)
...
})
.disposed(by: disposeBag)
// txId 없이 sessionInfo 호출 시 세션 정보 조회 가능
if let sessionInfo = CertApi.shared.sessionInfo(certType: .K2220) {
// 세션 정보 처리
...
}
권한 | 사전 설정 | 카카오 로그인 | 동의항목 | 레퍼런스 |
---|---|---|---|---|
필요 | 플랫폼 등록 | - | - | Android SDKreducedSign() ReactiveX Android SDK reducedSign() iOS SDK reducedSign() ReactiveX iOS SDK reducedSign() |
Kakao SDK를 사용해 구현해야 하는 기능입니다.
세션이 유효한지 확인 후, 세션이 유효하다면 서명 원문에 개인 키로 축약서명합니다. reducedSign()
을 호출합니다. 호출 시 서명 원문에 포함할 데이터를 전달해야 합니다. 축약서명의 서명 원문은 축약서명 요청 시 전달된 데이터, 공개 키, 세션 유효시간으로 구성됩니다.
축약서명 성공 시, 이용기관 서버에 서명 값을 검증하도록 요청해야 합니다. 이용기관 서버에서 공개 키로 서명 값을 검증할 수 있습니다.
축약서명 시 세션이 유효하지 않은 경우, Kakao SDK에 저장된 임시 키 쌍과 세션 정보가 삭제됩니다.
요청 실패 시 문제 해결을 참고합니다.
// 축약서명하기
CertApiClient.instance.reducedSign(
certType = CertType.K2220,
data = signData,
) { signature, error ->
if (error != null) {
// 에러 처리
...
return@reducedSign
}
// 축약서명 성공
// 서버에 서명 값 검증 요청 필요
...
}
val disposables = CompositeDisposable()
// 축약서명하기
CertApiClient.rx.reducedSign(
certType = CertType.K2220,
data = signData,
)
.flatMap { signature ->
// 축약서명 성공
// 서버에 서명 값 검증 요청 필요
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ response ->
// 서명 값 검증 성공
}, { error ->
// 에러 처리
})
.addTo(disposables)
// 축약서명하기
CertApi.shared.reducedSign(certType: .K2220, data: "${SIGN_DATA}") { signature, error in
if let error = error {
// 축약서명 실패 에러 처리
print(error)
...
}
else {
if let signature = signature {
// 축약서명 성공
...
}
else {
// 에러 처리
print("signature is nil")
...
}
}
}
let disposeBag = DisposeBag()
// 축약서명하기
CertApi.shared.rx.reducedSign(certType: .K2220, data: "${SIGN_DATA}")
.subscribe (onSuccess:{ signature in
if let signature = signature {
// 축약서명 성공
...
}
else {
// 에러 처리
print("signature is nil")
...
}
}, onError: { error in
// 축약서명 실패 에러 처리
print(error)
...
})
.disposed(by: disposeBag)
권한 | 사전 설정 | 카카오 로그인 | 동의항목 | 레퍼런스 |
---|---|---|---|---|
필요 | 플랫폼 등록 | 필요 | - | Android SDKisValidSession() ReactiveX Android SDK isValidSession() iOS SDK isValidSession() |
Kakao SDK를 사용해 구현해야 하는 기능입니다.
세션이 유효한지 확인합니다. isValidSession()
를 호출합니다.
축약서명하기 요청 시에도 Kakao SDK에 저장된 세션이 유효한지 확인 후 축약서명이 진행되지만, 이용기관의 필요에 따라 별도로 세션 유효성을 확인할 수 있습니다.
세션 유효성 확인하기 요청 시, 서버로부터 세션 정보를 응답받지 못헸거나 세션이 유효하지 않으면 false
가 반환되고 Kakao SDK에 저장된 임시 키 쌍과 세션 정보가 삭제됩니다. 이 경우, 임시 키 쌍 삭제하기 후 다시 처음부터 인증 로그인 과정을 진행합니다.
요청 실패 시 문제 해결을 참고합니다.
// 세션 유효성 확인하기
if (CertApiClient.instance.isValidSession(CertType.K2220)) {
Log.i(TAG, "세션 유효함")
} else {
Log.i(TAG, "세션 정보가 없거나 만료됨")
}
// 세션 유효성 확인하기
if (CertApiClient.rx.isValidSession(CertType.K2220)) {
Log.i(TAG, "세션 유효함")
} else {
Log.i(TAG, "세션 정보가 없거나 만료됨")
}
// 세션 유효성 확인하기
if (CertApi.shared.isValidSession(certType: .K2220)) {
print("세션 유효함")
} else {
print("세션 정보가 없거나 만료됨")
}
권한 | 사전 설정 | 카카오 로그인 | 동의항목 | 레퍼런스 |
---|---|---|---|---|
필요 | 플랫폼 등록 | 필요 | - | Android SDKdeleteKeyPair() ReactiveX Android SDK deleteKeyPair() iOS SDK deleteKeyPair() |
Kakao SDK를 사용해 구현해야 하는 기능입니다.
Kakao SDK에 저장된 임시 키 쌍과 세션 정보를 삭제합니다.
카카오톡 로그인 축약서명 과정 중 Kakao SDK에서 에러가 발생한 경우, 임시 키 쌍과 txId
를 삭제하고 공개 키 가져오기부터 카카오톡 로그인 축약서명 과정을 다시 시작해야 합니다.
요청 실패 시 문제 해결을 참고합니다.
// 임시 키 쌍 삭제하기
CertApiClient.instance.deleteKeyPair(CertType.K2220)
// 임시 키 쌍 삭제하기
CertApiClient.rx.deleteKeyPair(CertType.K2220)
// 임시 키 쌍 삭제하기
CertApi.shared.deleteKeyPair(certType: .K2220)
축약서명 과정의 각 단계를 Kakao SDK의 샘플 앱에서 직접 실행해 볼 수 있습니다.
아래는 샘플 앱의 단계별 구현 예제로, 실제 이용기관 서비스 개발 시 참고합니다.
// 카카오톡으로 인증 로그인 할 수 없는 경우 에러 처리
if (!UserApiClient.instance.isKakaoTalkLoginAvailable(context)) {
Log.e(TAG, "kakaotalk is not available")
// 카카오톡 설치 호출 예시
// val uri = Uri.parse("market://launch?id=com.kakao.talk")
// startActivity(Intent(Intent.ACTION_VIEW, uri))
return
}
val publicKey = CertApiClient.instance.publicKey(CertType.K2220) ?: run {
Log.e(TAG, "public key is null")
return
}
// 이용기관 서버에서 전자서명 준비하기, 전자서명 요청하기를 통해 txId 발급 후 클라이언트에 전달
// 아래 샘플 앱 코드를 참고해 이용기관에서 직접 구현
CertDemoClient.instance(context).demoSign(publicKey) { txId, error ->
if (error != null) {
Log.e(TAG, error)
return@demoSign
}
// 인증 로그인 요청
CertApiClient.instance.certLoginWithKakaoTalk(
context,
CertType.K2220,
txId = txId!!,
settleId = ${settleId},
) { certTokenInfo, loginError ->
if (loginError != null) {
// 에러 유형이 KakaoSdkError인 경우에는 기존 임시 키 쌍과 txId 삭제 후, 임시 키 쌍 생성하기부터 다시 요청해야 함
if (loginError is KakaoSdkError) {
CertApiClient.instance.deleteKeyPair(CertType.K2220)
// txId 삭제 처리
...
} else {
// 네트워크 에러 등 기타 에러 처리
}
return@certLoginWithKakaoTalk
}
// 인증 로그인 완료, txId 저장
val txId = certTokenInfo!!.txId
// txId 저장
...
}
}
// 카카오톡으로 인증 로그인 할 수 없는 경우 에러 처리
if (!UserApiClient.instance.isKakaoTalkLoginAvailable(context)) {
Log.e(TAG, "kakaotalk is not available")
// 카카오톡 설치 호출 예시
// val uri = Uri.parse("market://launch?id=com.kakao.talk")
// startActivity(Intent(Intent.ACTION_VIEW, uri))
return
}
val publicKey = CertApiClient.rx.publicKey(CertType.K2220) ?: run {
Log.e(TAG, "public key is null")
return
}
// 이용기관 서버에서 전자서명 준비하기, 전자서명 요청하기를 통해 txId 발급 후 클라이언트에 전달
// 아래 샘플 앱 코드를 참고해 이용기관에서 직접 구현
RxCertDemoClient.instance(context).demoSign(publicKey)
.flatMap { txId ->
// 인증 로그인 요청
CertApiClient.rx.certLoginWithKakaoTalk(
context,
CertType.K2220,
txId = txId,
settleId = settleId
)
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ certTokenInfo ->
// 인증 로그인 완료, txId 저장
val txId = certTokenInfo!!.txId
// txId 저장
...
}, { error ->
// 에러 유형이 KakaoSdkError인 경우에는 기존 임시 키 쌍과 txId 삭제 후, 임시 키 쌍 생성하기부터 다시 요청해야 함
if (error is KakaoSdkError) {
CertApiClient.rx.deleteKeyPair(CertType.K2220)
// txId 삭제 처리
...
} else {
// 네트워크 에러 등 기타 에러 처리
}
})
.addTo(disposables)
// 카카오톡으로 인증 로그인 가능 여부 확인
if (UserApi.isKakaoTalkLoginAvailable()) {
guard let publicKey = CertApi.shared.publicKey(certType: .K2220) else {
print("public key is nil")
return
}
// 이용기관 서버에서 전자서명 준비하기, 전자서명 요청하기를 통해 txId 발급 후 클라이언트에 전달
// 아래 샘플 앱 코드를 참고해 이용기관에서 직접 구현
CertDemoApi.shared.demoSign(certType: .K2220, base64encodedDerPublicKey:publicKey, completion: { (txId, error) in
if let error = error {
// 서버 에러 처리
print(error)
}
else {
if let txId = txId {
// 인증 로그인 요청
CertApi.shared.certLoginWithKakaoTalk(certType: .K2220, txId: txId, settleId: "${SETTLE_ID}") { certTokenInfo, error in
if let error = error {
if let sdkError = error as? SdkError {
// 에러 유형이 SdkError인 경우에는 기존 임시 키 쌍과 txId 삭제 후, 임시 키 쌍 생성하기부터 다시 요청해야 함
CertApi.shared.deleteKeyPair(certType: .K2220)
// txId 삭제 처리
...
}
else {
// 네트워크 에러 등 기타 에러 처리
}
}
else {
// 인증 로그인 완료, txId 저장
if let txId = certTokenInfo?.txId {
// txId 저장
...
}
}
}
}
else {
// 인증 로그인 실패, 임시 키 쌍과 txId 삭제 후, 임시 키 쌍 생성하기부터 다시 요청해야 함
CertApi.shared.deleteKeyPair(certType: .K2220)
// txId 삭제
...
}
}
})
}
else {
// 카카오톡으로 인증 로그인 할 수 없는 경우 에러 처리
print("kakaotalk is not available")
...
// 카카오톡 설치 유니버설 링크 호출 예시
// UserApi.shared.loginWithKakaoTalk(launchMethod: .UniversalLink) { }
return
}
let disposeBag = DisposeBag()
// 카카오톡으로 인증 로그인 가능 여부 확인
if (UserApi.isKakaoTalkLoginAvailable()) {
guard let publicKey = CertApi.shared.publicKey(certType: .K2220) else {
print("public key is nil")
return
}
CertDemoApi.shared.rx.demoSign(certType: .K2220, base64encodedDerPublicKey: publicKey)
.flatMap { txId -> Observable<CertTokenInfo> in
CertApi.shared.rx.certLoginWithKakaoTalk(certType: .K2220, txId: txId, settleId: "${SETTLE_ID}")
}
.subscribe(onNext: { certTokenInfo in
// 인증 로그인 완료, txId 저장
if let txId = certTokenInfo?.txId {
// txId 저장
...
}
}, onError: { error in
if let sdkError = error as? SdkError {
// 에러 유형이 SdkError인 경우에는 기존 임시 키 쌍과 txId 삭제 후, 임시 키 쌍 생성하기부터 다시 요청해야 함
CertApi.shared.deleteKeyPair(certType: .K2220)
// txId 삭제 처리
...
}
else {
// 네트워크 에러 등 기타 에러 처리
}
})
.disposed(by: disposeBag)
}
else {
// 카카오톡으로 인증 로그인 할 수 없는 경우 에러 처리
print("kakaotalk is not available")
...
// 카카오톡 설치 유니버설 링크 호출 예시
// UserApi.shared.loginWithKakaoTalk(launchMethod: .UniversalLink) { }
return
}
UserApiClient.instance.me { user, error ->
if (error != null) {
// 서버 에러 처리
return@me
}
val userId = user?.id ?: run {
//user id 가져오기 에러
return@me
}
CertDemoClient.instance(context)
.demoVerify(txId, userId) { response, verifyError ->
if (verifyError != null) {
// 전자서명 검증하기 실패, 에러 처리
return@demoVerify
}
// 전자서명 검증하기 성공, 이용기관 서비스 로그인 완료 처리
}
}
val disposables = CompositeDisposable()
UserApiClient.rx.me()
.flatMap { user ->
val userId = user.id ?: throw IllegalStateException("user.id is null")
RxCertDemoClient.instance(context).demoVerify(txId, userId)
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ response ->
// 전자서명 검증하기 성공, 이용기관 서비스 로그인 완료 처리
},
{ error ->
// 전자서명 검증하기 실패, 에러 처리
}
)
.addTo(disposables)
UserApi.shared.me { user, error in
if let error = error {
// 서버 에러 처리
print(error)
}
else {
guard let userId = user?.id else {
//user id 가져오기 에러
print("[k2220]user.id is nil")
return
}
CertDemoApi.shared.demoVerify(certType: .K2220, txId: txId, appUserId: userId) { response, error in
if let error = error {
// 전자서명 검증하기 실패, 에러 처리
print(error)
}
else {
// 전자서명 검증하기 성공, 이용기관 서비스 로그인 완료 처리
}
}
}
}
let disposeBag = DisposeBag()
// txId 발급 상태 확인
guard let txId = CertDemoApi.shared.txId(certType: .K2220) else {
print("txId is nil. sign first.")
return
}
UserApi.shared.rx.me()
.asObservable()
.flatMap { user -> Observable<CertDemoResponse> in
guard let userId = user.id else {
//user id 가져오기 에러
print("[k2220]user.id is nil")
throw CertDemoError(msg: "user.id is nil")
}
return CertDemoApi.shared.rx.demoVerify(certType: .K2220, txId: txId, appUserId: userId)
}
.subscribe (onNext:{ response in
// 전자서명 검증하기 성공, 이용기관 서비스 로그인 완료 처리
}, onError: { error in
// 전자서명 검증하기 실패, 에러 처리
print(error)
})
.disposed(by: disposeBag)
// txId 발급 상태 확인
val txId = CertDemoClient.instance(context).getTxId(CertType.K2220) ?: run {
Log.e(TAG, "txId is null.")
return
}
// 서명 원문에 포함할 텍스트
val signData = "${SIGN_DATA}"
// 축약서명 요청하기
CertApiClient.instance.reducedSign(
certType = CertType.K2220,
data = signData,
) { signature, error ->
if (error != null) {
Log.e(TAG, "축약서명 실패 $error")
return@reducedSign
}
Log.i(TAG, "축약서명 성공 $signature")
// 이용기관 서버에 축약서명 검증 요청하기
CertDemoClient.instance(context).demoReducedSign(
txId = txId,
data = signData,
signature = signature!!,
certType = CertType.K2220,
) { response, signError ->
if (signError != null) {
// 축약서명 검증 실패, 에러 처리
Log.e(TAG, signError)
return@demoSign
}
// 축약서명 검증 성공
...
}
}
val disposables = CompositeDisposable()
// txId 발급 상태 확인
val txId = CertDemoClient.instance(context).getTxId(CertType.K2220) ?: run {
Log.e(TAG, "txId is null.")
return
}
val signData = "hello"
CertApiClient.rx.reducedSign(
certType = CertType.K2220,
data = signData,
)
.flatMap { signature ->
// 이용기관 서버에 축약서명 검증 요청하기
RxCertDemoClient.instance(context).demoReducedSign(
txId = txId,
data = signData,
signature = signature,
certType = CertType.K2220,
)
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ response ->
// 축약서명 검증 성공
}, { error ->
// 축약서명 검증 실패, 에러 처리
})
.addTo(disposables)
// txId 발급 상태 확인
guard let txId = CertDemoApi.shared.txId(certType: .K2220) else {
// txId가 없는 경우 에러 처리
print("txId is nil. login first.")
return
}
// 서명 원문에 포함할 텍스트
let signData = "${SIGN_DATA}"
// 축약서명 요청하기
CertApi.shared.reducedSign(certType: .K2220, data: signData, completion: { signature, error in
if let error = error {
// 축약서명 실패
print(error)
}
else {
guard let signature = signature else {
// 에러 처리
print("signature is nil")
return
}
// 이용기관 서버에 축약서명 검증 요청하기
CertDemoApi.shared.demoReducedSign(certType: .K2220, txId: txId, data: signData, signature: signature, completion:{ response, error in
if let error = error {
// 축약서명 검증 실패, 에러 처리
print(error)
}
else {
// 축약서명 검증 성공
}
})
}
})
let disposeBag = DisposeBag()
// txId 발급 상태 확인
guard let txId = CertDemoApi.shared.txId(certType: .K2220) else {
// txId가 없는 경우 에러 처리
print("txId is nil. login first.")
return
}
// 서명 원문에 포함할 텍스트
let signData = "${SIGN_DATA}"
// 축약서명 요청하기
CertApi.shared.rx.reducedSign(certType: .K2220, data: signData)
.asObservable()
.flatMap { signature -> Observable<CertDemoResponse> in
CertDemoApi.shared.rx.demoReducedSign(certType: .K2220, txId: txId, data: signData, signature: signature)
}
.subscribe (onNext:{ response in
// 축약서명 검증 성공
}, onError: { error in
// 축약서명 실패
print(error)
})
.disposed(by: disposeBag)