본문으로 건너뛰기

커스텀 연령 게이트

이 가이드는 사전 구축된 위젯을 사용하지 않고 k-ID API를 직접 사용하여 커스텀 연령 게이트를 구현하는 방법을 안내합니다. 이 접근 방식은 k-ID가 규정 준수 로직을 처리하는 동안 사용자 인터페이스를 완전히 제어할 수 있게 해줍니다.

필수 권한으로 간소화된 통합

이 가이드는 Compliance Studio에서 모든 권한을 필수로 구성하는 간소화된 통합 패턴을 보여줍니다. 이 구성에서는 세션이 생성되면(직접 또는 부모 동의 후) 모든 기능을 즉시 사용할 수 있으며, 세션 업그레이드 플로우가 필요하지 않습니다.

커스텀 연령 게이트란?

커스텀 연령 게이트는 사용자가 구축하고 제어하는 연령 확인 인터페이스이며, k-ID의 API가 백그라운드에서 규정 준수 로직을 처리합니다. 이 접근 방식은 다음과 같은 경우에 이상적입니다:

  • 완전한 UI 제어: 브랜드와 사용자 경험에 맞는 연령 게이트 설계
  • 플랫폼 통합: 모바일 앱이나 게임 엔진을 위한 네이티브 경험 구축
  • 커스텀 워크플로우: 더 큰 온보딩 플로우의 일부로 연령 확인 구현

사전 요구 사항

시작하기 전에 다음이 필요합니다:

  1. k-ID 제품: k-ID Compliance Studio에서 제품을 생성하고 구성
  2. 필수 권한 구성: 제품의 권한 설정에서 모든 권한을 "필수"로 구성
  3. API 키: Compliance Studio의 제품 개발자 설정 페이지에서 API 키 생성
  4. 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이 관할권에서 허용되는 연령 수집 방법
연령 게이트가 필요하지 않은 경우

shouldDisplayfalse인 경우, 연령 게이트를 건너뛰고 /age-gate/get-default-permissions를 호출하여 해당 관할권의 기본 세션 권한을 가져옵니다.

2단계: 연령 게이트 UI 구축

응답에 따라 승인된 수집 방법을 사용하여 연령 게이트 인터페이스를 구축합니다:

  • date-of-birth: 전체 생년월일 입력(YYYY-MM-DD)
  • age-slider: 연령 범위 또는 슬라이더 선택
  • platform-account: 기존 플랫폼 계정 연령 데이터 사용
UX 가이드라인

연령 슬라이더 동작, 날짜 선택기 요구 사항, 접근성 고려 사항을 포함한 자세한 디자인 권장 사항은 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 가이드라인

레이아웃 예시 및 구현 팁을 포함한 신뢰할 수 있는 성인 동의 흐름에 대한 자세한 디자인 권장 사항은 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가 포함됩니다. 다음을 수행해야 합니다:

  1. 세션 권한 가져오기: 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"
}
  1. 저장된 챌린지를 세션으로 교체: challengeId를 지우고 대신 sessionId를 저장합니다. 이는 사용자가 이제 권한이 부여된 활성 세션을 가지고 있음을 나타냅니다.
// 보류 중인 챌린지를 지우고 활성 세션 저장
user.challengeId = null;
user.sessionId = data.sessionId;
  1. 권한 적용: 세션 응답의 권한을 사용하여 애플리케이션에서 기능을 활성화하거나 비활성화합니다.

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 엔드포인트가 다음을 수신하도록 구성되어 있는지 확인하세요:

Webhook 서명 확인에 대한 정보는 Webhooks를 참조하세요.

다음 단계

이제 커스텀 연령 게이트를 구현했으므로 다음 리소스를 탐색하여 통합을 강화하세요:

k-ID의 커스텀 연령 게이트 통합을 통해 k-ID가 복잡한 관할권 로직과 부모 동의 플로우를 처리하는 동안 완전히 브랜드화된 규정 준수 경험을 구축할 수 있습니다.