Appearance
개발하기
1. 인가 코드 받기
SDK를 통해 연동해주세요.
사용자의 인증을 요청하고, 사용자가 인증에 성공하면 인가 코드를 메소드 응답으로 전달드려요.appLogin
함수를 사용해서 인가 코드(authorizationCode
)와 referrer
를 받을 수 있어요.
appLogin를 확인해 주세요.
- 샌드박스앱에서는
referrer
가sandbox
가 반환돼요 - 토스앱에서는
referrer
가DEFAULT
가 반환돼요
참고하세요
인가코드의 유효시간은 10분입니다.
토스 로그인을 처음 진행할 때
appLogin
함수를 호출하면 토스 로그인 창이 열리고, 앱인토스 콘솔에서 등록한 약관 동의 화면이 노출돼요.
사용자가 필수 약관에 동의하면 인가 코드가 반환돼요.
토스 로그인을 이미 진행했을 때
appLogin
함수를 호출하면 별도의 로그인 창 없이 바로 인가 코드가 반환돼요.
2. AccessToken 받기
사용자 정보 조회 API 를 사용하기 위한 접근 토큰을 발급합니다.
- Content-type : application/json
- Method :
POST
- URL :
/api-partner/v1/apps-in-toss/user/oauth2/generate-token
참고하세요
AccessToken 유효시간은 1시간이에요.
요청
이름 | 타입 | 필수값 여부 | 설명 |
---|---|---|---|
authorizationCode | string | Y | 인가코드 |
referrer | string | Y | referrer |
성공 응답
이름 | 타입 | 필수값 여부 | 설명 |
---|---|---|---|
tokenType | string | Y | bearer 로 고정 |
accessToken | string | Y | accessToken |
refreshToken | string | Y | refreshToken |
expiresIn | string | Y | 만료시간(초) |
scope | string | Y | 인가된 scope(구분) |
json
{
"resultType":"SUCCESS",
"success":{
"accessToken":"eyJraWQiOiJjZXJ0IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJtMHVmMmhaUmpJTnNEQTdLNHVuVHhMb3IwcWNSa2JNPSIsImF1ZCI6IjNlenQ2ZTF0aDg2b2RheTlwOWN1eTg0dTRvdm5nNnNzIiwibmJmIjoxNzE4MjU0ODM2LCJzY29wZSI6WyJ1c2VyX2NpIiwidXNlcl9iaXJ0aGRheSIsInVzZXJfbmF0aW9uYWxpdHkiLCJ1c2VyX25hbWUiLCJ1c2VyX3Bob25lIiwidXNlcl9nZW5kZXIiXSwiaXNzIjoiaHR0cHM6Ly9jZXJ0LnRvc3MuaW0iLCJleHAiOjE3MTgyNTg0MzYsImlhdCI6MTcxODI1NDgzNiwianRpIjoiMTJkYjYwZjYtMjEzYS00NWQ3LTllOTItODBjMzBdseY2JkMGQ3In0.W1cjoeMN8pd3Jqgh6h8YzSVQ1PUNldulJJgy6bgH1AoDbv5xFTlBLzz9Slb_u52zUpyZbhglwblQmNJs7GT6-us7XtfxSGxTUY3ORqIhF_PPGQ6soi_Qgsi-hmX165CCAilf8cltSTTuTt8xOiEbLuSTY-cecxo7SkPUonQ_0v4_Ik0kwOiOBuYZyuch3KmlYQZTqsJmxlwJAPB8M9tZTtDpLOv9MEPU35YS7CZyN0l7lwn1EKrDHJdzA5CnstqEdz2I0eREmMgZoG9mSEybgD4NtPmVJos6AJerUGgSmzP_TwwlybVATuGpnAUmH1idaZJ-MHZJhUhR82z4zTn3bw",
"refreshToken":"xNEYPASwWw0n1AxZUHU9KeGj8BitDyYo4wi8rpfkUcJwByVxpAdUzwtIaWGVL6vHdrXLCxIlHAQRPF9hHnFleTsHkqUXzc-_78sD_r1Uh5Ff9UCYfArx8LTn1Vk99dDb",
"scope":"user_ci user_birthday user_nationality user_name user_phone user_gender",
"tokenType":"Bearer",
"expiresIn":3599
}
}
실패 응답
인가 코드가 만료되었거나 동일한 인가 코드로 AccessToken 을 중복으로 요청할 경우
json
{
"error":"invalid_grant"
}
json
{
"resultType":"FAIL",
"error":{
"errorCode":"INTERNAL_ERROR",
"reason":"요청을 처리하는 도중에 문제가 발생했습니다."
}
}
3. AccessToken 재발급 받기
사용자 정보 조회 API 를 사용하기 위한 접근 토큰을 재발급합니다.
- Content-type : application/json
- Method :
POST
- URL :
/api-partner/v1/apps-in-toss/user/oauth2/refresh-token
참고하세요
refreshToken 유효시간은 14일이에요.
요청
이름 | 타입 | 필수값 여부 | 설명 |
---|---|---|---|
refreshToken | string | Y | 획득한 RefreshToken |
성공 응답
이름 | 타입 | 필수값 여부 | 설명 |
---|---|---|---|
tokenType | string | Y | bearer 로 고정 |
accessToken | string | Y | accessToken |
refreshToken | string | Y | refreshToken |
expiresIn | string | Y | 만료시간(초) |
scope | string | Y | 인가된 scope(구분) |
실패 응답
이름 | 타입 | 필수값 여부 | 설명 |
---|---|---|---|
errorCode | string | Y | 에러 코드 |
reason | string | Y | 에러 메시지 |
4. 사용자 정보 받기
사용자 정보를 조회합니다.
DI는 null 로 내려가며 횟수 제한없이 호출이 가능해요.
개인정보 보호를 위해 암호화된 형태로 제공합니다.
- Content-type : application/json
- Method :
GET
- URL :
/api-partner/v1/apps-in-toss/user/oauth2/login-me
요청 헤더
이름 | 타입 | 필수값 여부 | 설명 |
---|---|---|---|
Authorization | string | Y | AccessToken으로 인증 요청 Authorization: Bearer ${AccessToken} |
성공 응답
이름 | 타입 | 필수값 여부 | 암호화 여부 | 설명 |
---|---|---|---|---|
userKey | number | Y | N | 사용자 식별자 |
scope | string | Y | N | 인가된 scope(구분) |
agreedTerms | list | Y | N | 사용자가 동의한 약관 목록 |
policy | string | Y | N | OAuth 로그인 연동 동선 구분 = Login 으로 값 고정 필요 |
ci | string | N | Y | 사용자 CI |
name | string | N | Y | 사용자 이름 |
phone | string | N | Y | 사용자 휴대전화번호 |
gender | string | N | Y | 사용자 성별(MALE/FEMALE) |
nationality | string | N | Y | 사용자 내/외국인 여부(LOCAL/FOREIGNER) |
birthday | string | N | Y | 사용자 생년월일(yyyyMMdd) |
string | N | Y | 사용자 이메일(점유인증 하지 않은 이메일 정보) |
json
{
"resultType":"SUCCESS",
"success":{
"userKey":443731104,
"scope":"user_ci,user_birthday,user_nationality,user_name,user_phone,user_gender",
"agreedTerms":["terms_tag1","terms_tag2"],
"policy":"AUTO_SELECT",
"certTxId":"ad052b57-dc8f-4cdb-a6e2-7b494e28b5ec",
"name":"ENCRYPTED_VALUE",
"phone":"ENCRYPTED_VALUE",
"birthday":"ENCRYPTED_VALUE",
"ci":"ENCRYPTED_VALUE",
"di":null,
"gender":"ENCRYPTED_VALUE",
"nationality":"ENCRYPTED_VALUE",
"email":null
}
}
실패 응답
유효하지 않은 토큰을 사용할 경우, 현재 사용 중인 access_token의 유효시간을 확인하고 재발급을 진행해주세요.
json
{
"error":"invalid_grant"
}
서버 에러 응답 예시
errorCode | 설명 |
---|---|
INTERNAL_ERROR | 내부 서버 에러 |
USER_KEY_NOT_FOUND | 로그인 서비스에 접속한 유저 키 값을 찾을 수 없음 |
USER_NOT_FOUND | 토스 유저 정보를 찾을 수 없음 |
BAD_REQUEST_RETRIEVE_CERT_RESULT_EXCEEDED_LIMIT | 조회 가능 횟수 초과 동일한 토큰으로 /api/login/user/me/without-di API 조회하면 정상적으로 조회되나, di 필드는 null 값으로 내려감 |
json
{
"resultType":"FAIL",
"error":{
"errorCode":"INTERNAL_ERROR",
"reason":"요청을 처리하는 도중에 문제가 발생했습니다."
}
}
5. 사용자 정보 복호화하기
콘솔을 통해 이메일로 받은 복호화 키
와 AAD(Additional Authenticated DATA)
로 진행해주세요.
암호화 알고리즘
- AES 대칭키 암호화
- 키 길이 : 256비트
- 모드 : GCM
- AAD : 복호화 키와 함께 이메일로 전달드립니다.
데이터 교환방식
- 암호화된 데이터의 앞 부분에 IV/NONCE 값을 첨부하여 드립니다.
- 복호화할 때는 암호화된 데이터의 앞 부분에서 IV/NONCE 값을 추출하여 사용하시길 바랍니다.
복호화 샘플 코드
Kotlin 예제
kotlin
import java.util.Base64
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec
class Test {
fun decrypt(
encryptedText: String,
base64EncodedAesKey: String,
add: String,
): String {
val IV_LENGTH = 12
val decoded = Base64.getDecoder().decode(encryptedText)
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
val keyByteArray = Base64.getDecoder().decode(base64EncodedAesKey)
val key = SecretKeySpec(keyByteArray, "AES")
val iv = decoded.copyOfRange(0, IV_LENGTH)
val nonceSpec = GCMParameterSpec(16 * Byte.SIZE_BITS, iv)
cipher.init(Cipher.DECRYPT_MODE, key, nonceSpec)
cipher.updateAAD(add.toByteArray())
return String(cipher.doFinal(decoded, IV_LENGTH, decoded.size - IV_LENGTH))
}
}
PHP 예제
php
<?php
class Test {
public function decrypt($encryptedText, $base64EncodedAesKey, $add) {
$IV_LENGTH = 12;
$decoded = base64_decode($encryptedText);
$keyByteArray = base64_decode($base64EncodedAesKey);
$iv = substr($decoded, 0, $IV_LENGTH);
$ciphertext = substr($decoded, $IV_LENGTH);
$tag = substr($ciphertext, -16);
$ciphertext = substr($ciphertext, 0, -16);
$decrypted = openssl_decrypt(
$ciphertext,
'aes-256-gcm',
$keyByteArray,
OPENSSL_RAW_DATA,
$iv,
$tag,
$add
);
return $decrypted;
}
}
// 사용 예제
$test = new Test();
$encryptedText = "Encrypted Text"; // Encrypted Text 입력
$base64EncodedAesKey = "Key"; // Key 입력
$add = "TOSS";
$result = $test->decrypt($encryptedText, $base64EncodedAesKey, $add);
echo $result;
?>
JAVA 예제
java
public class Test {
public String decrypt(
String encryptedText,
String base64EncodedAesKey,
String add
) throws Exception {
final int IV_LENGTH = 12;
byte[] decoded = Base64.getDecoder().decode(encryptedText);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
byte[] keyByteArray = Base64.getDecoder().decode(base64EncodedAesKey);
SecretKeySpec key = new SecretKeySpec(keyByteArray, "AES");
byte[] iv = new byte[IV_LENGTH];
System.arraycopy(decoded, 0, iv, 0, IV_LENGTH);
GCMParameterSpec nonceSpec = new GCMParameterSpec(16 * Byte.SIZE, iv);
cipher.init(Cipher.DECRYPT_MODE, key, nonceSpec);
cipher.updateAAD(add.getBytes());
byte[] decrypted = cipher.doFinal(decoded, IV_LENGTH, decoded.length - IV_LENGTH);
return new String(decrypted);
}
}
6. 로그인 끊기
발급받은 AccessToken을 더 이상 사용하지 않거나 사용자의 요구에 의해 만료시킬 경우 토큰을 삭제(만료)해주세요.
- Content-type : application/json
- Method :
POST
- URL :
- accessToken 으로 연결 끊기 :
/api-partner/v1/apps-in-toss/user/oauth2/access/remove-by-access-token
- userKey 로 연결 끊기 :
/api-partner/v1/apps-in-toss/user/oauth2/access/remove-by-user-key
- accessToken 으로 연결 끊기 :
AccessToken 으로 로그인 연결 끊기
// 포맷
curl --request POST 'https://apps-in-toss-api.toss.im/api-partner/v1/apps-in-toss/user/oauth2/access/remove-by-access-token' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer $access_token'
// 예시
curl --request POST 'https://apps-in-toss-api.toss.im/api-partner/v1/apps-in-toss/user/oauth2/access/remove-by-access-token' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJraWQiOiJjZXJ0IizzYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJtMHVmMmhaUmpJTnNEQTdLNHVuVHhMb3IwcWNSa2JNPSIsImF1ZCI6IjNlenQ2ZTF0aDg2b2RheTlwOWN1eTg0dTRvdm5nNnNzIiwibmJmIjoxNzE4MjU0ODM2LCJzY29wZSI6WyJ1c2VyX2NpIiwidXNlcl9iaXJ0aGRheSIsInVzZXJfbmF0aW9uYWxpdHkiLCJ1c2VyX25hbWUiLCJ1c2VyX3Bob25lIiwidXNlcl9nZW5kZXIiXSwiaXNzIjoiaHR0cHM6Ly9jZXJ0LnRvc3MuaW0iLCJleHAiOjE3MTgyNTg0MzYsImlhdCI6MTcxODI1NDgzNiwianRpIjoiMTJkYjYwZjYtMjEzYS00NWQ3LTllOTItODBjMzBmY2JkMGQ3In0.W1cjoeMN8pd3Jqgh6h8YzSVQ1PUNldulJJgy6bgH1AoDbv5xFTlBLwk9Slb_u52zUpyZbhglwblQmNJs7GT6-us7XtfxSGxTUY3ORqIhF_PPGQ6soi_Qgsi-hmX165CCAilf8cltSTTuTt8xOiEbLuSTY-cecxo7SkPUonQ_0v4_Ik0kwOiOBuYZyuch3KmlYQZTqsJmxlwJAPB8M9tZTtDpLOv9MEPU35YS7CZyN0l7lwn1EKrDHJdzA5CnstqEdz2I0eREmMgZoG9mSEybgD4NtPmVJos6AJerUGgSmzP_TwwlybVATuGpnAUmH1idaZJ-MHZJhUhR82z4zTn3bw'
userKey 로 로그인 연결 끊기
참고하세요
userKey에 맵핑된 AccessToken이 많을 경우 readTimeout 이 발생할 수 있어요
readTimeout 은 3초 입니다
// 포맷
curl --request POST 'https://apps-in-toss-api.toss.im/api-partner/v1/apps-in-toss/user/oauth2/access/remove-by-user-key' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer $access_token' \
--data '{"userKey": $user_key}'
// 예시
curl --request POST 'https://apps-in-toss-api.toss.im/api-partner/v1/apps-in-toss/user/oauth2/access/remove-by-user-key' \
--header 'Content-Type: application/json' \
--data '{"userKey": 443731103}'
json
{
"resultType": "SUCCESS",
"success": {
"userKey": 443731103
}
}
7. 콜백을 통해 로그인 끊기
사용자가 토스앱 내에서 서비스와의 연결을 해제한 경우 가맹점 서버로 알려드려요.
서비스에서 연결이 끊긴 사용자에 대한 처리가 필요한 경우 활용할 수 있어요. 콜백을 받을 URL과 basic Auth 헤더는 콘솔에서 입력할 수 있어요.
서비스에서 직접 로그인 연결 끊기 요청을 호출한 경우 콜백이 호출되지 않아요.
GET 방식
- 요청 requestParam에
userKey
와referrer
을 포함합니다.
// 포맷
curl --request GET '$callback_url?userKey=$userKey&referrer=$referrer'
// 예시
curl --request GET '$callback_url?userKey=443731103&referrer=UNLINK'
POST 방식
- 요청 body에
userKey
와referrer
을 포함합니다.
// 포맷
curl --request POST '$callback_url' \
--header 'Content-Type: application/json' \
--data '{"userKey": $user_key, "referrer": $referrer}'
// 예시
curl --request POST '$callback_url' \
--header 'Content-Type: application/json' \
--data '{"userKey": 443731103, "referrer": "UNLINK"}'
referrer 은 연결 끊기 요청 경로에요.
referrer | 설명 |
---|---|
UNLINK | 사용자가 앱에서 연결 끊기 |
WITHDRAWAL_TERMS | 로그인 서비스 약관 철회 |
WITHDRAWAL_TOSS | 토스 회원 탈퇴 |
트러블슈팅
로컬 개발 중 인증 에러가 발생할 때
로컬에서 개발할 때 인증 에러가 발생하는 원인은 주로 두가지예요.
인증 토큰이 만료됨
기존에 발급받은 인증 토큰이 만료되었을 수 있어요. 새로운 토큰을 발급받아 다시 시도해보세요.개발자 로그인이 되지 않음 샌드박스 환경에서 개발자 계정으로 로그인하지 않은 상태일 수 있어요. 샌드박스 앱 다운로드를 참고해 로그인을 진행한 뒤 다시 시도해보세요.