페이지 이동경로
  • 문서>
  • 카카오톡 인증 서비스>
  • K2220: 로그인 축약서명

카카오톡 인증 서비스

K2220: 로그인 축약서명

이 문서는 카카오톡 인증 서비스의 K2220 로그인 축약서명 API 사용법을 안내합니다.

시작하기 전에

기능 소개

카카오톡 로그인 축약서명은 카카오톡 애플리케이션(이하 앱)을 통한 인증 로그인 후, 세션 유효시간 동안 반복적인 축약서명 기능을 제공하는 서비스입니다. 세션은 회원번호와 유효시간을 포함합니다.

세션은 사용자가 인증 로그인을 완료한 후 세션 정보 가져오기의 호출 결과로 Kakao SDK 내부에 생성됩니다. 세션의 유효시간은 전자서명 요청하기 호출 시 최소 6시간, 최대 48시간으로 설정할 수 있습니다.

임시 키 쌍은 카카오톡 로그인 축약서명 시 필요한 암호화 키로, Kakao SDK를 통해 생성 및 삭제할 수 있습니다. 임시 키 쌍은 공개 키와 개인 키로 이뤄져 있으며, 세션의 유효시간 동안만 사용할 수 있습니다. 각 키의 용도는 아래와 같습니다.

  • 공개 키: 카카오톡 로그인 축약서명 서비스의 서명 원문을 구성하며, 이용기관 서버에서 축약서명 값 검증 시에도 사용
  • 개인 키: 축약서명 요청하기 호출 시 Kakao SDK가 축약서명을 수행하는 데 사용

이용기관은 사용자 비교 및 검증 용도의 서명자 정보서명자 정보 가져오기로 제공받을 수 있습니다. 이밖에 카카오톡 인증 로그인 과정에서 사용자로부터 동의받은 개인정보 항목을 카카오로부터 제공받을 수 있습니다. 이를 통해 별도의 사용자 정보 입력 과정이나 서비스 약관 동의를 거치지 않고도 회원가입 및 로그인 처리를 할 수 있습니다. 개인정보제공 및 서비스 약관 동의 화면 구성을 참고합니다.

카카오톡 인증 서비스 API는 서버간 연동(Server to Server)을 원칙으로 합니다.

Kakao SDK 설치

카카오톡 로그인 축약서명 서비스는 Kakao SDK를 통해 이용 가능하며, Android와 iOS 네이티브 앱만 지원합니다. Kakao SDK for Android(이하 Android SDK), Kakao SDK for iOS(이하 iOS SDK)의 Cert 모듈을 설치해 카카오톡 로그인 축약서명 서비스에 필요한 API를 사용할 수 있습니다. Kakao SDK 설치 및 설정 안내는 아래를 참고합니다.

Android SDK

아래 순서로 Android SDK 설치 및 설정을 완료합니다.

  1. 설치
  2. 플랫폼 등록
  3. 인터넷 사용 권한 설정
  4. Java 8 사용 설정
  5. 키 해시 등록
  6. Redirect URI 설정

iOS SDK

아래 순서로 iOS SDK 설치 및 설정을 완료합니다.

  1. 설치
  2. 플랫폼 등록
  3. 앱 실행 허용 목록 설정
  4. URL Schemes 설정
  5. 카카오톡으로 로그인을 위한 설정

iOS SDK 설치 및 설정 완료 후, 아래와 같이 이용기관 앱에서 Cert를 포함해 필요한 모듈을 사용하도록 설정해야 합니다.

import KakaoSDKCommon
import KakaoSDKAuth
import KakaoSDKUser
import KakaoSDKCert

로그인 축약서명 과정

카카오톡 로그인 축약서명의 진행 과정을 크게 세 단계로 나눠보면 아래와 같습니다.

  1. 인증 로그인
  2. 전자서명 검증
  3. 축약서명 및 검증

1. 인증 로그인
  1. 사용자가 이용기관에 로그인을 요청하면, 이용기관이 클라이언트에서 Kakao SDK의 publicKey()를 호출해 공개 키 가져오기를 합니다.
  2. 이용기관이 생성된 공개 키를 클라이언트에서 서버로 전달합니다.
  3. 이용기관이 서버에서 전자서명 준비하기를 호출해 tx_id를 발급받습니다.
  4. 이용기관이 서버에서 전자서명 요청하기를 호출해 tx_id에 대한 세션 유효시간을 설정합니다. 필요한 서명자 정보identify_items 파라미터로 지정할 수 있습니다.
  5. 이용기관이 서버에서 클라이언트로 tx_id를 전달합니다.
  6. 이용기관이 클라이언트에서 txId로 Kakao SDK의 certLoginWithKakaoTalk()을 호출해 인증 로그인을 요청합니다.
    1. 카카오 인증 서버가 카카오톡을 실행해 카카오 인증서로 전자서명을 요청합니다.
    2. 사용자가 카카오톡에서 카카오 인증서로 전자서명을 완료하면, 카카오 인증 서버가 Kakao SDK에 인가 코드를 반환합니다.
    3. 이용기관 클라이언트의 Kakao SDK가 인가 코드로 토큰 발급을 요청하면, 카카오 인증 서버가 토큰과 txId를 반환합니다.
참고: 익명서명

카카오톡 로그인 축약서명은 익명서명 방식으로, 전자서명 준비하기 호출 단계에서 이용기관이 카카오톡 인증 서비스에 사용자 정보를 전달하지 않습니다.

2. 전자서명 검증
  1. 이용기관이 클라이언트에서 서버로 txId를 전달하고 전자서명 검증을 요청합니다.
  2. 이용기관이 서버에서 전자서명 검증하기를 호출해 전자서명 데이터 전문을 받습니다.
  3. 이용기관이 서버에서 서명자 정보 가져오기를 호출해 서명자 정보를 받습니다.
  4. 이용기관이 서버에서 클라이언트로 검증 결과를 전달하고 로그인을 완료 처리합니다.

3. 축약서명 및 검증
  1. 사용자가 축약서명 필요 서비스 사용을 요청하면, 이용기관이 클라이언트에서 txId로 Kakao SDK의 sessionInfo()를 호출해 세션 정보를 받습니다.
    1. Kakao SDK는 sessionInfo()에서 반환된 값으로 세션 정보를 업데이트합니다.
    2. 세션이 유효하지 않다면 Kakao SDK는 임시 키 쌍을 삭제하고 에러를 반환합니다. 이 경우, 처음부터 다시 축약서명 과정을 진행해야 합니다.
  2. 세션이 유효할 경우, 이용기관이 축약서명 필요 시 reducedSign()을 호출해 축약서명을 요청합니다.
    1. Kakao SDK가 내부적으로 개인 키를 사용해 축약서명을 수행합니다.
  3. 이용기관이 축약서명 값을 클라이언트에서 서버로 전달합니다.
  4. 이용기관이 서버에서 공개 키로 축약서명 값을 검증합니다.
  5. 축약서명 값이 유효할 경우, 이용기관이 서버에서 클라이언트로 검증 결과를 전달하고 축약서명 필요 서비스를 제공합니다.

전자서명 검증

카카오톡 로그인 축약서명의 전자서명은 아래 두 종류로, 서명 원문의 구성과 검증 방식에 차이가 있습니다.

카카오톡 인증 로그인 시 전자서명

서비스의 인증 로그인 요청하기 후 사용자가 카카오톡에서 수행하는 서명입니다.

  • 서명 원문: 공개 키, 세션 유효시간으로 구성
  • 검증: 전자서명 검증하기 시 반환받은 전자서명 데이터 전문이 전자서명 요청하기 시 전달한 서명 원문과 일치하는지 비교해 검증, 서명 값 검증은 이용기관에서 직접 구현해야 함

축약서명

카카오톡 인증 로그인 시 전자서명 완료 후 사용자의 축약서명 필요 서비스 요청 시 이용기관에서 처리하는 서명입니다.

  • 서명 원문: 공개 키, 세션 유효시간, 요청 시 전달된 데이터로 구성
  • 검증: 축약서명 후 반환받은 서명 값을 이용기관 서버에서 공개 키로 검증, 서명 값 검증은 이용기관에서 직접 구현해야 함

로그아웃 및 연결 끊기

사용자가 이용기관 서비스에서 로그아웃할 경우, 로그아웃을 호출해야 합니다.

사용자가 이용기관 서비스에서 카카오 로그인 연동 해제 또는 탈퇴 시, 연결 끊기를 호출해 이용기관 앱과 사용자의 연결을 끊어야 합니다.

연결 끊기 호출 없이 이용기관 서비스에서의 연동 해제 처리만 이뤄질 경우, 사용자가 다시 카카오톡 인증 로그인을 수행할 때 개인정보제공 및 서비스 약관 동의 절차를 거치지 않아 이용에 불편을 겪거나 문제가 발생할 수 있습니다. 자세한 사항은 연결을 참고합니다.

로그아웃, 연결 끊기는 Kakao SDK를 사용해 요청할 수 있으며 임시 키 쌍, 세션 정보, txId를 함께 삭제해야 합니다. 아래 예제를 참고합니다.

Android
Kotlin
RxKotlin
// 로그아웃
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)
iOS
// 로그아웃
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 SDK
publicKey()
ReactiveX Android SDK
publicKey()
iOS SDK
publicKey()

Kakao SDK를 사용해 구현해야 하는 기능입니다.

임시 키 쌍을 생성하고, 공개 키 값을 조회합니다. publicKey()를 호출합니다.

publicKey() 호출 시, 기존에 생성된 임시 키 쌍이 없다면 새로 생성합니다. 기존에 생성된 임시 키 쌍이 있다면 공개 키 값을 반환합니다. null 또는 nil이 반환된 경우, 임시 키 쌍 삭제하기 호출 후 다시 공개 키 가져오기를 요청합니다.

공개 키는 이용기관 서버로 전송해 관리해야 합니다. 이용기관 서버는 공개 키를 전자서명 요청하기의 서명 원문, 전자서명 검증하기의 서명 값 검증에 사용합니다.

요청 실패 시 문제 해결을 참고합니다.

예제

Android
Kotlin
RxKotlin
// 공개 키 가져오기
val publicKey = CertApiClient.instance.publicKey(CertType.K2220)

// 가져온 공개 키를 이용기관 서버로 전송 
...
// 공개 키 가져오기
val publicKey = CertApiClient.rx.publicKey(CertType.K2220)

// 가져온 공개 키를 이용기관 서버로 전송
...
iOS
// 공개 키 가져오기
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
data: 서명할 데이터
이름 타입 설명 필수
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
delegate_info: 사용자 인증 요청 안내문
이름 타입 설명 필수
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를 전달해야 합니다. CertTypeK2220으로 지정합니다. 이 외 파라미터 정보는 K2100: 인증 로그인을 참고합니다.

참고: 카카오톡 설치 여부 확인

카카오톡 로그인 축약서명 서비스는 카카오톡 앱을 실행하고 전자서명 요청하는 앱투앱(App to app) 방식만 지원합니다. isKakaoTalkLoginAvailable()를 호출해 카카오톡 실행 가능 여부를 먼저 확인할 수 있습니다. 예제를 참고합니다.

인증 로그인 요청 성공 시, 사용자는 카카오톡 앱에서 카카오 로그인, 카카오 인증서로 전자서명을 수행합니다. 카카오 로그인은 이용기관 서비스에 대한 개인정보제공 및 서비스 약관 동의를 포함합니다. 카카오 로그인 동의 화면은 사용자가 이용기관 서비스에 처음 카카오 로그인하는 경우에만 출력됩니다. (참고: 인가)

사용자가 전자서명을 완료하면 이용기관 클라이언트의 Kakao SDK에 인가 코드가 발급됩니다. Kakao SDK가 내부적으로 인가 코드를 사용해 토큰을 발급받고 인증 로그인을 완료합니다.

인증 로그인 완료 시 토큰txId를 반환합니다.

반환받은 txId는 이용기관 클라이언트에 별도 저장해 관리해야 합니다.txId를 이용기관 서버에 전달한 후 전자서명 검증하기를 요청해야 합니다.

토큰은 사용자 정보 가져오기 API인 me()를 요청하는 데 사용합니다. 사용자 정보 가져오기의 자세한 정보는 아래 문서에서 확인할 수 있습니다.

요청 실패 시 문제 해결을 참고합니다.

예제

Android
Kotlin
RxKotlin
// 인증 로그인 요청하기
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)
iOS
Swift
RxSwift
// 인증 로그인 요청하기
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: 전자서명 검증 결과 참고
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}"
}
언어별 예제

아래는 실제 서비스에서 고려해야 할 여러 요소(성능, 예외 처리, 동시성 등)가 반영되지 않은 참고용 예제입니다.

Kotlin
Java
C++
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 SDK
sessionInfo()
ReactiveX Android SDK
sessionInfo()
iOS SDK
sessionInfo()
ReactiveX iOS SDK
sessionInfo()

Kakao SDK를 사용해 구현해야 하는 기능입니다.

인증 로그인 완료 후 생성된 세션 정보를 가져옵니다. sessionInfo()를 호출합니다. 호출 시 txId를 전달해야 합니다.

세션 정보 가져오기 요청이 성공하면 Kakao SDK가 카카오 인증 서버로부터 조회한 세션 정보를 내부에 저장합니다. Kakao SDK에 저장된 세션의 유효시간 동안 축약서명하기를 요청할 수 있습니다.

서버로부터 세션 정보를 응답받지 못한 경우, null 또는 nil이 반환됩니다. 세션 정보 가져오기를 재요청하거나, 임시 키 쌍 삭제하기로 임시 키 쌍과 세션 정보를 삭제하고, 다시 처음부터 인증 로그인 과정을 진행합니다.

요청 시 txId를 전달하지 않으면 Kakao SDK에 저장되어 있는 세션 정보를 조회하는 용도로 사용할 수 있습니다.

요청 실패 시 문제 해결을 참고합니다.

예제

Android
Kotlin
RxKotlin
// 세션 정보 가져오기
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)
...
iOS
Swift
RxSwift
// 세션 정보 가져오기
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 SDK
reducedSign()
ReactiveX Android SDK
reducedSign()
iOS SDK
reducedSign()
ReactiveX iOS SDK
reducedSign()

Kakao SDK를 사용해 구현해야 하는 기능입니다.

세션이 유효한지 확인 후, 세션이 유효하다면 서명 원문에 개인 키로 축약서명합니다. reducedSign()을 호출합니다. 호출 시 서명 원문에 포함할 데이터를 전달해야 합니다. 축약서명의 서명 원문은 축약서명 요청 시 전달된 데이터, 공개 키, 세션 유효시간으로 구성됩니다.

축약서명 성공 시, 이용기관 서버에 서명 값을 검증하도록 요청해야 합니다. 이용기관 서버에서 공개 키로 서명 값을 검증할 수 있습니다.

축약서명 시 세션이 유효하지 않은 경우, Kakao SDK에 저장된 임시 키 쌍과 세션 정보가 삭제됩니다.

요청 실패 시 문제 해결을 참고합니다.

예제

Android
Kotlin
RxKotlin
// 축약서명하기
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)
iOS
Swift
RxSwift
// 축약서명하기
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 SDK
isValidSession()
ReactiveX Android SDK
isValidSession()
iOS SDK
isValidSession()

Kakao SDK를 사용해 구현해야 하는 기능입니다.

세션이 유효한지 확인합니다. isValidSession()를 호출합니다.

축약서명하기 요청 시에도 Kakao SDK에 저장된 세션이 유효한지 확인 후 축약서명이 진행되지만, 이용기관의 필요에 따라 별도로 세션 유효성을 확인할 수 있습니다.

세션 유효성 확인하기 요청 시, 서버로부터 세션 정보를 응답받지 못헸거나 세션이 유효하지 않으면 false가 반환되고 Kakao SDK에 저장된 임시 키 쌍과 세션 정보가 삭제됩니다. 이 경우, 임시 키 쌍 삭제하기 후 다시 처음부터 인증 로그인 과정을 진행합니다.

요청 실패 시 문제 해결을 참고합니다.

예제

Android
Kotlin
RxKotlin
// 세션 유효성 확인하기
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, "세션 정보가 없거나 만료됨")
}
iOS
// 세션 유효성 확인하기
if (CertApi.shared.isValidSession(certType: .K2220)) {
    print("세션 유효함")
} else {
    print("세션 정보가 없거나 만료됨")
}

임시 키 쌍 삭제하기

기본 정보
권한 사전 설정 카카오 로그인 동의항목 레퍼런스
필요 플랫폼 등록 필요 - Android SDK
deleteKeyPair()
ReactiveX Android SDK
deleteKeyPair()
iOS SDK
deleteKeyPair()

Kakao SDK를 사용해 구현해야 하는 기능입니다.

Kakao SDK에 저장된 임시 키 쌍과 세션 정보를 삭제합니다.

카카오톡 로그인 축약서명 과정 중 Kakao SDK에서 에러가 발생한 경우, 임시 키 쌍과 txId를 삭제하고 공개 키 가져오기부터 카카오톡 로그인 축약서명 과정을 다시 시작해야 합니다.

요청 실패 시 문제 해결을 참고합니다.

예제

Android
Kotlin
RxKotlin
// 임시 키 쌍 삭제하기
CertApiClient.instance.deleteKeyPair(CertType.K2220)
// 임시 키 쌍 삭제하기
CertApiClient.rx.deleteKeyPair(CertType.K2220)
iOS
// 임시 키 쌍 삭제하기
CertApi.shared.deleteKeyPair(certType: .K2220)

예제

축약서명 과정의 각 단계를 Kakao SDK의 샘플 앱에서 직접 실행해 볼 수 있습니다.

아래는 샘플 앱의 단계별 구현 예제로, 실제 이용기관 서비스 개발 시 참고합니다.

인증 로그인

Android
Kotlin
RxKotlin
// 카카오톡으로 인증 로그인 할 수 없는 경우 에러 처리
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)
iOS
Swift
RxSwift
// 카카오톡으로 인증 로그인 가능 여부 확인
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
}

전자서명 검증

Android
Kotlin
RxKotlin
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)
iOS
Swift
RxSwift
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)

축약서명 및 검증

Android
Kotlin
RxKotlin
// 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)
iOS
Swift
RxSwift
// 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)

더 보기