콘텐츠로 이동

검증과 공유

발급(issuance)이 끝나면 조금 뒤에 서명된 크리덴셜(VC-JWT) 이 만들어집니다. 이 가이드는 그 크리덴셜을 어떻게 찾고, 어떻게 검증하고, 수령자와 어떻게 나누는지를 다룹니다. 검증 로직을 직접 구현할 일은 없습니다. 판정은 Kolleges 의 공개 검증 문이 내리고, API 는 그 문을 가리키는 포인터를 줍니다.

발급과 크리덴셜은 다른 순간입니다

섹션 제목: “발급과 크리덴셜은 다른 순간입니다”

POST /v2/clubs/{clubDomain}/issuances 가 200 을 돌려준 순간 발급 기록은 생겼지만, 서명된 크리덴셜은 잠시 뒤 백그라운드에서 구워집니다. 두 시각 사이에 크리덴셜을 요청하면 409 credential-pending 을 받습니다. 폴링 대신 이벤트를 기다리세요.

  1. 발급합니다. 응답의 results[].resourceId 가 issuance id 입니다.

  2. issuance.credential_issued 를 기다립니다. GET /v2/clubs/{clubDomain}/events 피드에 이 이벤트가 오면 서명 크리덴셜이 존재합니다. subject.id 가 issuance id 입니다.

  3. 크리덴셜을 읽습니다. GET /v2/clubs/{clubDomain}/issuances/{issuanceId}/credential{ id, format, jwt, payload } 를 돌려줍니다. jwt 는 compact JWT 원문, payload 는 디코드된 클레임입니다.

// GET /v2/clubs/acme/events
{
"data": [
{ "id": "", "type": "issuance.credential_issued", "occurredAt": "2026-09-03T06:12:41.000Z", "subject": { "type": "issuance", "id": "1450" } },
{ "id": "", "type": "issuance.issued", "occurredAt": "2026-09-03T06:12:38.000Z", "subject": { "type": "issuance", "id": "1450" } }
],
"meta": { "nextCursor": null }
}

GET /v2/clubs/{clubDomain}/issuances/{issuanceId}credential 은 크리덴셜을 가리키는 포인터입니다. 아직 구워지지 않았으면 null 입니다.

필드
id 크리덴셜 UUID. 크리덴셜 안의 id 와 같은 값
format OB3_VC_JWT
status valid · expired · revoked. 취소가 만료보다 우선. 서명은 검사하지 않습니다
issuedAt 크리덴셜이 만들어진 시각
shareUrl 수령자에게 보낼 공유·검증 페이지 (https://{clubDomain}.kolleges.net/credentials/{id})
verifyUrl 공개 검증 API. 인증 없이 JSON 판정을 돌려줍니다
jwtUrl 공개 JWT 엔드포인트. 인증 없이 서명 JWT 원문(text/plain)

목록 항목에는 achievementIdcredentialId 가 함께 옵니다. credentialIdnull 이면 아직 굽기 전입니다.

검증자, 지갑, LMS 처럼 파트너 키가 없는 쪽은 Open Badges 3.0 공개 표면을 바로 부릅니다. 레퍼런스는 Open Badges 3.0 · 공개 검증에 있습니다.

무엇을 주나
GET https://api.kolleges.net/open-badges/v3/achievements/{issuanceId}/verify isValid(서명 판정) · status · issuerVerified(기관 신뢰) · payload(디코드된 VC)
GET https://api.kolleges.net/open-badges/v3/credentials/{credentialId} 서명 JWT 원문 (text/plain)
GET https://api.kolleges.net/open-badges/v3/issuers/{domain}/did.json 발급기관 DID Document (공개키)
GET https://api.kolleges.net/open-badges/v3/issuers/{domain}/status-lists/revocation 취소 상태 목록 (Bitstring Status List)

verify 응답의 payload.vc.credentialSubject.achievement 에 발급 시점의 취득조건 서술(criteria.narrative), 스킬(tag, alignment), 각인 설명이 그대로 들어 있습니다. 이것이 역량 데이터에서 말한 동결 기록입니다.

// GET https://api.kolleges.net/open-badges/v3/achievements/1450/verify
{
"statusCode": 200,
"isValid": true,
"status": "valid",
"issuerVerified": true,
"payload": {
"iss": "did:web:api.kolleges.net:open-badges:v3:issuers:acme",
"vc": {
"credentialSubject": {
"achievement": {
"achievementType": "CertificateOfCompletion",
"criteria": { "narrative": "1. 12주 커리큘럼 이수\n2. 최종 프로젝트 발표 (https://acme.example/demo-day)" },
"tag": ["React", "TypeScript", "협업"]
}
}
}
}
}

isValid 는 크리덴셜에 대한 판정이고 issuerVerified 는 발급기관에 대한 상업적 신뢰 인증입니다. 별개 축이라 issuerVerifiedfalse 여도 서명은 유효할 수 있습니다.

shareUrl 을 수령자에게 보내면 됩니다. 그 페이지는 인증 없이 열리고, 크리덴셜의 현재 판정을 보여 주며, 수령자가 자기 지갑이나 SNS 로 가져가는 진입점입니다. 취소된 크리덴셜은 그 페이지에서도 취소로 보입니다.

GET /v1/achievements/{id}credential { id, shareUrl, verifyUrl } | null 이 같은 포인터입니다. 일괄 발급 응답의 issued[].id 로 곧바로 되읽을 수 있습니다. 서명 JWT 원문은 위의 공개 문 credentials/{credentialId} 에서 받습니다.