럭키박스
연동 안내서
Lucky Box Integration Guide
매체사 백엔드에서 럭키박스 서버로 이용자 정보를 전달해 일회성 접속 주소를 발급받고, 이를 매체사 앱의 브라우저에서 오픈하는 방식으로 동작합니다. 모든 인증 과정은 반드시 백엔드 간에 처리되어야 하며, 발급된 주소는 2분간만 유효합니다.
럭키박스 연동 흐름
API방식으로 럭키박스 연동은 아래와 같은 순서로 진행됩니다.
1~3번 과정은 반드시 백엔드 간에 이루어져야 합니다. 프론트에서 위의 작업을 수행 시 비밀정보 노출 등에 의해 보안사고가 발생할 수 있습니다.
API를 통해서 수신한 사이트 주소는 2분간만 유효합니다. 2분 경과 시 다시 위의 과정을 통해 사이트 주소를 재할당 받아야 하며, 매 접속 시마다 위의 과정을 항상 반복해야 합니다.
관리자 사이트
위의 관리자 사이트에 접속하실 수 있습니다.
앱목록 메뉴에서 등록된 앱을 확인하실 수 있으며, API방식 연동에 필요한 앱키·시크릿 등을 확인 가능하고, 제휴포인트·캐시백 등 연동을 위한 설정이 가능합니다.
접속 URI 획득 API
접속 URL 획득 API는 접속하는 이용자 정보를 럭키박스 시스템 백엔드에 전달하고 접속 주소를 획득하기 위한 목적입니다. 획득된 주소를 브라우저에 오픈해 주시면 됩니다.
| 파라메터명 | 설명 |
|---|---|
| appKey | 매체사 앱 등록 후 할당 받은 앱키 |
| userId | 매체사 이용자 식별자 |
| userName선택 | 접속하는 이용자의 별명생략 가능 — 생략 시 임의의 별명이 생성됩니다. |
| requesttime | YYYYMMDDhhmmss 형식, UTC 기준 요청 시점 시간 |
| hash | appKey + userId + requesttime 값을 sha256 알고리즘으로 해싱한 값 §4 예제 참조 |
| 필드명 | 타입 | 설명 |
|---|---|---|
| ret | number (int) | API 호출 결과 코드. 아래 ret 코드 상세 표 참조. |
| siteUrl | string | 주소 획득 성공(ret: 0)인 경우에만 포함됩니다. 획득된 주소를 프론트에 전달하고 웹브라우저에 오픈해 주시면 됩니다.※ 인증 정보는 2분간만 유효하며 한 번 사용 후 재사용 불가합니다. |
| 코드 | 상태 | 설명 |
|---|---|---|
| 0 | 성공 | 주소 획득 성공 |
| 1 | 오류 | 잘못된 요청 |
| 2 | 오류 | 앱키 오류 |
| 3 | 오류 | 해시 오류 |
| 5 | 오류 | 접속 차단 |
| 6 | 오류 | 인증 등록 실패 |
| 7 | 오류 | 매체사 인증 오류 |
| 8 | 오류 | 요청 시간 초과 |
| 9 | 오류 | 요청 시간 오류 |
| -1 | 오류 | 서버 오류 |
| 60 | 점검 | 사이트 점검 중 |
결제 문제로 인해 웹뷰에 적용 시 결제가 제대로 되지 않습니다. 웹뷰 연동을 원하시는 경우 PG사 앱 연동 가이드를 따라 추가적인 앱 및 웹뷰 설정이 필요합니다. → PG사 웹뷰 연동 가이드
{
"ret": 0,
"siteUrl": "https://box.../enter?token=eyJhbGci..."
}
{
"ret": 3
}
접속 파라메터의 해시 값 생성
요청의 유효성을 식별하기 위해서 sha256 알고리즘으로 해싱된 결과 값을 포함해야 합니다. 해시 값 생성을 위한 키는 앱 정보에서 확인이 가능하며, 비밀키를 외부에 노출할 경우 보안 문제가 발생할 수 있습니다.
const Crypto = require('crypto');
const appKey = '매체사할당된앱키';
const appSecret = '매체사에할당된앱시크릿';
const userId = '접속할이용자식별자';
const now = new Date();
const requesttime = now.getUTCFullYear().toString()
+ String(now.getUTCMonth() + 1).padStart(2, '0')
+ String(now.getUTCDate()).padStart(2, '0')
+ String(now.getUTCHours()).padStart(2, '0')
+ String(now.getUTCMinutes()).padStart(2, '0')
+ String(now.getUTCSeconds()).padStart(2, '0');
const getHash = (key, value) => {
return Crypto.createHmac('sha256', key)
.update(value, 'utf8').digest('hex');
};
// 비밀키로 sha256 해싱
const hash = getHash(appSecret,
`${appKey}${userId}${requesttime}`);
console.log('requesttime: ' + requesttime);
console.log('hash: ' + hash);
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
public class HashExample {
public static String getHash(String key, String value) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(
key.getBytes(StandardCharsets.UTF_8), "HmacSHA256"
);
mac.init(secretKey);
byte[] hash = mac.doFinal(value.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : hash) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
String appKey = "매체사할당된앱키";
String appSecret = "매체사에할당된앱시크릿";
String userId = "접속할이용자식별자";
String requesttime = ZonedDateTime.now(ZoneOffset.UTC)
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
String hash = getHash(appSecret, appKey + userId + requesttime);
System.out.println("requesttime: " + requesttime);
System.out.println("hash: " + hash);
}
}
<?php
$appKey = '매체사할당된앱키';
$appSecret = '매체사에할당된앱시크릿';
$userId = '접속할이용자식별자';
$requesttime = gmdate('YmdHis');
$hash = hash_hmac('sha256',
$appKey . $userId . $requesttime,
$appSecret);
echo 'requesttime: ' . $requesttime . "\n";
echo 'hash: ' . $hash . "\n";