커스텀 연령 게이트
이 가이드는 사전 구축된 위젯을 사용하지 않고 k-ID API를 직접 사용하여 커스텀 연령 게이트를 구현하는 방법을 안내합니다. 이 접근 방식은 k-ID가 규정 준수 로직을 처리하는 동안 사용자 인터페이스를 완전히 제어할 수 있게 해줍니다.
이 가이드는 Compliance Studio에서 모든 권한을 필수로 구성하는 간소화된 통합 패턴을 보여줍니다. 이 구성에서는 세션이 생성되면(직접 또는 부모 동의 후) 모든 기능을 즉시 사용할 수 있으며, 세션 업그레이드 플로우가 필요하지 않습니다.
커스텀 연령 게이트란?
커스텀 연령 게이트는 사용자가 구축하고 제어하는 연령 확인 인터페이스이며, k-ID의 API가 백그라운드에서 규정 준수 로직을 처리합니다. 이 접근 방식은 다음과 같은 경우에 이상적입니다:
- 완전한 UI 제어: 브랜드와 사용자 경험에 맞는 연령 게이트 설계
- 플랫폼 통합: 모바일 앱이나 게임 엔진을 위한 네이티브 경험 구축
- 커스텀 워크플로우: 더 큰 온보딩 플로우의 일부로 연령 확인 구현
사전 요구 사항
시작하기 전에 다음이 필요합니다:
- k-ID 제품: k-ID Compliance Studio에서 제품을 생성하고 구성
- 필수 권한 구성: 제품의 권한 설정에서 모든 권한을 "필수"로 구성
- API 키: Compliance Studio의 제품 개발자 설정 페이지에서 API 키 생성
- Webhook 엔드포인트(권장): 챌린지 및 세션 이벤트를 수신하기 위한 보안 HTTPS 엔드포인트 설정. 자세한 내용은 Webhooks 참조.
1단계: 연령 게이트 요구 사항 가져오기
연령 게이트를 표시하기 전에 /age-gate/get-requirements를 호출하여 사용자의 관할권에 따라 표시해야 할 내용을 결정합니다.
구현에서 모든 API 호출은 API 키가 클라이언트 측 코드에 노출되지 않도록 서버 간 호출이어야 합니다.
요청 예시
GET /api/v1/age-gate/get-requirements?jurisdiction=US-CA
Authorization: Bearer your-api-key
응답 예시
{
"shouldDisplay": true,
"ageAssuranceRequired": false,
"digitalConsentAge": 13,
"civilAge": 18,
"minimumAge": 0,
"approvedAgeCollectionMethods": [
"date-of-birth",
"age-slider",
"platform-account"
]
}
응답 필드
| 필드 | 설명 |
|---|---|
shouldDisplay | 연령 게이트를 표시해야 하는지 여부 |
ageAssuranceRequired | 이 관할권에서 연령 확인이 필요한지 여부 |
digitalConsentAge | 디지털 동의를 위한 최소 연령(이 연령 미만의 사용자는 부모 동의 필요) |
civilAge | 사용자가 법적 성인으로 간주되는 연령 |
minimumAge | 제품에 접근하기 위한 최소 연령(Compliance Studio에서 구성) |
approvedAgeCollectionMethods | 이 관할권에서 허용되는 연령 수집 방법 |
shouldDisplay가 false인 경우, 연령 게이트를 건너뛰고 /age-gate/get-default-permissions를 호출하여 해당 관할권의 기본 세션 권한을 가져옵니다.
2단계: 연령 게이트 UI 구축
응답에 따라 승인된 수집 방법을 사용하여 연령 게이트 인터페이스를 구축합니다:
date-of-birth: 전체 생년월일 입력(YYYY-MM-DD)age-slider: 연령 범위 또는 슬라이더 선택platform-account: 기존 플랫폼 계정 연령 데이터 사용
연령 슬라이더 동작, 날짜 선택기 요구 사항, 접근성 고려 사항을 포함한 자세한 디자인 권장 사항은 UX 가이드라인을 참조하세요.
연령 게이트 UI 예시
<div id="age-gate">
<h2>생년월일을 입력해 주세요</h2>
<form id="age-gate-form">
<label for="dob">생년월일</label>
<input type="date" id="dob" name="dob" required />
<button type="submit">계속</button>
</form>
</div>
3단계: API로 연령 확인
사용자가 연령을 제출하면 수집한 연령 정보와 관할권을 사용하여 /age-gate/check를 호출합니다. 사용한 연령 수집 방법에 따라 dateOfBirth 또는 age를 전달할 수 있습니다.
생년월일을 사용한 요청 예시
날짜 선택기를 사용하여 전체 생년월일을 수집한 경우:
POST /api/v1/age-gate/check
Content-Type: application/json
Authorization: Bearer your-api-key
{
"jurisdiction": "US-CA",
"dateOfBirth": "2015-04-15"
}
연령을 사용한 요청 예시
연령 슬라이더를 사용하여 사용자의 연령을 수집한 경우:
POST /api/v1/age-gate/check
Content-Type: application/json
Authorization: Bearer your-api-key
{
"jurisdiction": "US-CA",
"age": 9
}
가능한 응답
API는 세 가지 상태 중 하나를 반환합니다:
PASS: 사용자가 진행할 수 있음
사용자의 연령으로 즉시 접근이 허용됩니다. 모든 권한이 있는 세션이 생성됩니다.
{
"status": "PASS",
"session": {
"sessionId": "608616da-4fd2-4742-82bf-ec1d4ffd8187",
"ageStatus": "LEGAL_ADULT",
"dateOfBirth": "2005-04-15",
"jurisdiction": "US-CA",
"permissions": [...],
"status": "ACTIVE"
}
}
조치: sessionId를 저장하고 사용자가 진행할 수 있도록 합니다.
PROHIBITED: 사용자가 차단됨
사용자의 연령이 제품에 구성된 최소 연령보다 낮습니다.
{
"status": "PROHIBITED"
}
조치: 연령에 적합한 메시지를 표시하고 접근을 방지합니다.
CHALLENGE: 부모 동의 필요
사용자의 연령에 검증 가능한 부모 동의(VPC)가 필요합니다. 신뢰할 수 있는 성인이 승인할 수 있는 챌린지가 생성됩니다.
{
"status": "CHALLENGE",
"challenge": {
"challengeId": "683409f1-2930-4132-89ad-827462eed9af",
"oneTimePassword": "PP5BUS",
"type": "CHALLENGE_PARENTAL_CONSENT",
"url": "https://family.k-id.com/authorize?otp=PP5BUS"
}
}
조치: challengeId를 저장하고 신뢰할 수 있는 성인 챌린지 화면을 표시합니다(4단계 참조).
4단계: 신뢰할 수 있는 성인 챌린지 화면 구축
CHALLENGE 응답을 받으면 사용자가 동의를 위해 신뢰할 수 있는 성인에게 연락할 수 있는 화면을 표시합니다. 챌린지 응답에는 필요한 모든 것이 포함되어 있습니다.
레이아웃 예시 및 구현 팁을 포함한 신뢰할 수 있는 성인 동의 흐름에 대한 자세한 디자인 권장 사항은 UX 가이드라인의 보호자 동의를 참조하세요.
챌린지 화면 옵션
챌린지 화면은 신뢰할 수 있는 성인이 동의를 완료할 수 있는 세 가지 옵션을 제공해야 합니다:
옵션 1: 이메일 알림
사용자가 신뢰할 수 있는 성인의 이메일 주소를 입력할 수 있도록 합니다. 제출되면 /challenge/send-email을 호출하여 동의 요청 이메일을 보냅니다.
POST /api/v1/challenge/send-email
Content-Type: application/json
Authorization: Bearer your-api-key
{
"challengeId": "683409f1-2930-4132-89ad-827462eed9af",
"email": "parent@example.com"
}
옵션 2: QR 코드
challenge.url 필드에서 생성된 QR 코드를 표시합니다. 신뢰할 수 있는 성인은 휴대폰으로 이를 스캔하여 동의 포털에 직접 접근할 수 있습니다.
// 챌린지 URL에서 QR 코드 생성
const qrCodeUrl = challenge.url;
// QR 코드 라이브러리를 사용하여 렌더링: "https://family.k-id.com/authorize?otp=PP5BUS"
옵션 3: 수동 코드 입력
challenge.oneTimePassword를 표시하고 신뢰할 수 있는 성인에게 asktoplay.com을 방문하여 코드를 입력하도록 안내합니다.
챌린지 화면 구현 예시
<div id="challenge-screen">
<h2>신뢰할 수 있는 성인에게 도움을 요청하세요</h2>
<p>
신뢰할 수 있는 성인에게 다음 방법 중 하나를 사용하여 설정을 완료해 달라고
요청하세요.
</p>
<div class="options-container">
<!-- 옵션 1: 이메일 -->
<div class="option">
<h3>옵션 1</h3>
<p>신뢰할 수 있는 성인의 이메일 입력</p>
<form id="email-form">
<label for="email">이메일</label>
<input type="email" id="email" placeholder="이메일 주소" required />
<button type="submit">제출</button>
</form>
</div>
<!-- 옵션 2: QR 코드 -->
<div class="option">
<h3>옵션 2</h3>
<p>신뢰할 수 있는 성인에게 QR 코드를 스캔하거나 클릭하도록 요청하세요.</p>
<div id="qr-code">
<!-- challenge.url에서 QR 코드 렌더링 -->
</div>
</div>
<!-- 옵션 3: 수동 코드 -->
<div class="option">
<h3>옵션 3</h3>
<p>
<a href="https://asktoplay.com">asktoplay.com</a>으로 이동하여 아래
코드를 입력하세요.
</p>
<div class="code-display">
<span id="otp-code">PP5BUS</span>
<button onclick="copyCode()">복사</button>
</div>
</div>
</div>
<button id="do-later">나중에 하기</button>
</div>
챌린지 저장
동의를 기다리는 동안 challengeId를 저장합니다. 로컬 스토리지, 사용자 계정과 연결된 데이터베이스 또는 플랫폼에 적합한 다른 영구 저장소에 저장할 수 있습니다. 동의가 부여되기 전에 사용자가 앱으로 돌아오면 /challenge/get을 사용하여 챌린지를 검색하고 챌린지 화면을 복원합니다.
// 챌린지 생성 시 저장 (localStorage를 사용한 예시)
localStorage.setItem("pendingChallenge", challengeId);
// 앱 재시작 시 보류 중인 챌린지 확인
const pendingChallenge = localStorage.getItem("pendingChallenge");
if (pendingChallenge) {
// 챌린지 세부 정보를 가져와 챌린지 화면 표시
const challenge = await fetchChallenge(pendingChallenge);
showChallengeScreen(challenge);
}
5단계: Webhook 이벤트 처리
챌린지 상태가 변경되거나 세션이 삭제될 때 이벤트를 수신하도록 webhook 엔드포인트를 구성합니다.
Challenge.StateChange 이벤트
이 이벤트는 신뢰할 수 있는 성인이 동의 요청을 승인하거나 거부할 때 발생합니다.
{
"eventType": "Challenge.StateChange",
"data": {
"id": "683409f1-2930-4132-89ad-827462eed9af",
"productId": 42,
"status": "PASS",
"dob": "2015-04-15",
"sessionId": "0ad1641f-c154-4c2-8bb2-74dbd0de7723",
"approverEmail": "parent@example.com",
"kuid": "7a1f2c3d-4e5f-6789-abcd-ef0123456789"
}
}
| 상태 | 설명 | 조치 |
|---|---|---|
PASS | 동의가 부여됨 | sessionId를 저장하고 접근 허용 |
FAIL | 동의가 거부됨 | 적절한 메시지 표시, 사용자 진행 불가 |
IN_PROGRESS | 챌린지가 여전히 보류 중 | 계속 대기 |
성공적인 동의 처리
PASS 상태를 받으면(웹훅 또는 폴링을 통해) 응답에 sessionId가 포함됩니다. 다음을 수행해야 합니다:
- 세션 권한 가져오기:
sessionId를 사용하여/session/get을 호출하여 권한을 포함한 전체 세션 세부 정보를 검색합니다.
GET /api/v1/session/get?id=0ad1641f-c154-4c2-8bb2-74dbd0de7723
Authorization: Bearer your-api-key
응답 예시:
{
"session": {
"ageStatus": "DIGITAL_MINOR",
"dateOfBirth": "2015-04-15",
"etag": "6d9d24fccd428f845b355122799948dd0a52fc5d",
"jurisdiction": "US-CA",
"kuid": "7a1f2c3d-4e5f-6789-abcd-ef0123456789",
"permissions": [
{
"enabled": true,
"managedBy": "GUARDIAN",
"name": "text-chat-private"
},
{
"enabled": false,
"managedBy": "GUARDIAN",
"name": "voice-chat"
}
],
"sessionId": "0ad1641f-c154-4c2-8bb2-74dbd0de7723",
"status": "ACTIVE"
},
"status": "PASS"
}
- 저장된 챌린지를 세션으로 교체:
challengeId를 지우고 대신sessionId를 저장합니다. 이는 사용자가 이제 권한이 부여된 활성 세션을 가지고 있음을 나타냅니다.
// 보류 중인 챌린지를 지우고 활성 세션 저장
user.challengeId = null;
user.sessionId = data.sessionId;
- 권한 적용: 세션 응답의 권한을 사용하여 애플리케이션에서 기능을 활성화하거나 비활성화합니다.
Session.Delete 이벤트
이 이벤트는 세션이 삭제될 때(예: 부모가 Family Connect를 통해 접근을 취소할 때) 발생합니다.
{
"eventType": "Session.Delete",
"data": {
"id": "0ad1641f-c154-4c2-8bb2-74dbd0de7723",
"productId": 42
}
}
조치: 저장된 세션을 제거하고 사용자가 연령 게이트 플로우를 다시 완료하도록 요구합니다.
Webhook 핸들러 예시
app.post("/webhook/k-id", (req, res) => {
const { eventType, data } = req.body;
switch (eventType) {
case "Challenge.StateChange":
if (data.status === "PASS") {
// 접근 허용 - 사용자의 sessionId 저장
grantAccess(data.sessionId, data.kuid);
} else if (data.status === "FAIL") {
// 접근 거부
denyAccess(data.id);
}
break;
case "Session.Delete":
// 접근 취소 - 사용자가 연령 게이트를 다시 완료해야 함
revokeSession(data.id);
break;
}
res.status(200).send("OK");
});
폴링을 대체 수단으로 사용
Webhook을 사용할 수 없는 경우 /challenge/get-status를 폴링하여 챌린지 상태를 확인할 수 있습니다:
GET /api/v1/challenge/get-status?id=683409f1-2930-4132-89ad-827462eed9af
Authorization: Bearer your-api-key
폴링할 때 요청 사이에 최소 5초를 기다려야 합니다. 너무 자주 폴링하면 API가 HTTP 429를 반환할 수 있습니다.
Webhook 구성
커스텀 연령 게이트 플로우의 경우 webhook 엔드포인트가 다음을 수신하도록 구성되어 있는지 확인하세요:
Challenge.StateChange: 부모 동의가 승인되거나 거부될 때 알림Session.Delete: 부모가 세션을 삭제할 때 알림
Webhook 서명 확인에 대한 정보는 Webhooks를 참조하세요.
다음 단계
이제 커스텀 연령 게이트를 구현했으므로 다음 리소스를 탐색하여 통합을 강화하세요:
- UX 가이드라인: 연령 슬라이더, 날짜 선택기, 동의 흐름에 대한 디자인 권장 사항
- API 참조 문서: 연령 게이트 및 챌린지 API의 상세 문서
- Webhooks 설정: 프로덕션 시스템을 위한 강력한 webhook 처리 구현
- 모범 사례: 보안과 안정적인 사용자 경험을 보장하기 위한 모범 사례 구현
- 테스트: 테스트 모드 API로 통합 테스트
- 출시 전 체크리스트: 출시 전 요구 사항 검토
k-ID의 커스텀 연령 게이트 통합을 통해 k-ID가 복잡한 관할권 로직과 부모 동의 플로우를 처리하는 동안 완전히 브랜드화된 규정 준수 경험을 구축할 수 있습니다.