はじめに
皆さんは VC や VP という言葉を聞いたことがあるでしょうか?これらは W3C が標準化したデジタル認証の仕組み で、マイナンバーカードや卒業証明書、資格証明書などを"デジタルで安全に"扱うための技術です。
この記事を読むと…
- VC・VP とは何か
- 実際の JSON を見ながら構造を理解
- DID・OIDC との組み合わせ方
まで順を追って理解できるはずです。
現実世界のアナロジーから考える
まず日常の「紙の証明書」で考えてみましょう。
| 証明書 | 発行者 | 証明内容 | 改ざん防止 |
|---|---|---|---|
| 運転免許証 | 政府(公安委員会) | 運転できる | ICチップ・印刷 |
| 大学卒業証明書 | 大学 | 卒業した | 実印・割印 |
| 資格証明書 | 試験機関 | 合格した | 認定印 |
VC・VP はこれをそのままデジタル化したものです。発行者(Issuer)・保持者(Holder)・検証者(Verifier) の3者が登場します。
|
🏛️ Issuer(発行者) 市区町村・大学・試験機関 |
──── VC 発行 ────▶ |
🧑 Holder(保持者) あなた(ウォレット保管) |
──── VP 提示 ────▶ |
🏢 Verifier(検証者) 銀行・病院・EC サイト |
VC(Verifiable Credential)とは?
VC は「発行者が署名した、改ざん不可能なデジタル証明書」です。JSON-LD という形式で書かれており、以下の要素で構成されます。
| フィールド | 役割 |
|---|---|
@context |
W3C VC 標準への参照 URL |
type |
["VerifiableCredential", ...] |
issuer |
発行者の DID / URL |
issuanceDate |
発行日時(ISO 8601) |
credentialSubject |
証明される属性(名前・年齢など) |
proof |
発行者の電子署名(Ed25519 など) |
実例:年齢確認 VC の JSON
// 市区町村が発行した「18歳以上」証明 VC
{
"@context": [
"https://www.w3.org/2018/credentials/v1"
],
"type": ["VerifiableCredential", "AgeVerificationCredential"],
"issuer": "did:web:city.example.gov",
"issuanceDate": "2024-01-15T00:00:00Z",
"expirationDate": "2029-01-15T00:00:00Z",
"credentialSubject": {
"id": "did:key:z6Mk...",
"isAdult": true,
"verifiedAt": "2024-01-15"
},
"proof": {
"type": "Ed25519Signature2020",
"created": "2024-01-15T09:00:00Z",
"verificationMethod": "did:web:city.example.gov#key-1",
"jws": "eyJhbGci..."
}
}
proof フィールドに電子署名が入るため、内容を1文字でも書き換えると署名検証が失敗します。これが「Verifiable(検証可能)」の意味です。
VP(Verifiable Presentation)とは?
VP は「保持者が選んだ VC をまとめて提示するための封筒」です。1つ以上の VC を束ねて、保持者自身の署名を加えます。
なぜ VP が必要?
免許証を見せると生年月日も住所も氏名も全部バレますが、VP + 選択的開示(SD-JWT など)なら「18歳以上かどうか」だけを証明できます。プライバシーの最小化が実現できます。
実例:VP の JSON
// 保持者が「年齢だけ」提示する VP
{
"@context": ["https://www.w3.org/2018/credentials/v1"],
"type": ["VerifiablePresentation"],
"holder": "did:key:z6Mk...",
"verifiableCredential": [
{ /* 上の AgeVerificationCredential をそのまま埋め込む */ }
],
"proof": {
"type": "Ed25519Signature2020",
"challenge": "abc123",
"domain": "example-bar.com",
"jws": "eyJhbGci..."
}
}
challenge と domain を入れることで「この VP は example-bar.com 向けに今回だけ作った」ことを証明でき、使い回し攻撃(リプレイ攻撃)を防げます。
DID(Decentralized Identifier)との関係
DID は VC の「発行者と保持者の識別子」として使われます。did:web: や did:key: など複数のメソッドがあります。
| ── DID による VC 検証の全体像 ── | ||||
|
🏛️
Issuer発行者 (市区町村など) |
①VC発行 ▶ |
🧑
Holder保持者 (ウォレット) |
②VP提示 ▶ |
🏢
Verifier検証者 (銀行・病院) |
⬆ DID を持つdid:web:city.gov
|
⬆ DID を持つdid:key:z6Mk...
|
③DIDを解決して 公開鍵を取得・署名検証 ⬇ |
||
|
🌐 分散型台帳 / HTTPS / ブロックチェーン
(DID Document を格納・公開)
|
||||
| DID メソッド | 解決先 | 特徴 |
|---|---|---|
did:web |
HTTPS サーバ上の JSON | 既存インフラで導入しやすい。企業・政府向け |
did:key |
公開鍵そのものをエンコード | ブロックチェーン不要。テスト・個人利用向け |
did:ion |
Bitcoin ネットワーク上 | Microsoft が推進。高い耐改ざん性 |
did:ethr |
Ethereum スマートコントラクト | Web3 DApps との親和性が高い |
DID Document の例
// did:web:city.example.gov を解決すると取得できる DID Document
{
"@context": "https://www.w3.org/ns/did/v1",
"id": "did:web:city.example.gov",
"verificationMethod": [{
"id": "did:web:city.example.gov#key-1",
"type": "Ed25519VerificationKey2020",
"controller": "did:web:city.example.gov",
"publicKeyMultibase": "z6Mk..."
}]
}
検証者は以下の流れで VC の真正性を確認します:
- VC の
issuerDID を解決 - DID Document から公開鍵を取得
-
proof.jwsを公開鍵で検証
OIDC(OpenID Connect)との組み合わせ
VC/VP は単体でも使えますが、既存の認証システムである OIDC と組み合わせた OID4VC(OpenID for Verifiable Credentials) も急速に普及しています。
通常の OIDC では「Google や Microsoft などの IdP がユーザーを認証して ID Token を発行する」という中央集権的な構造です。OID4VC はこれを拡張し、ユーザー自身のウォレットが VC/VP を使って認証・属性証明できる仕組みを加えます。
| ── OID4VC の全体像(3プロトコルの関係) ── | |||||||
|
🏛️
Issuer発行機関 (自治体・大学) |
OID4VCI VC発行 ⇄ |
📱
Wallet保持者のウォレット (VC 保管・VP 生成) |
OID4VP VP提示 ⇄ |
🏢
RP / Verifier検証者 (銀行・病院) |
|||
|
|||||||
Wallet と IdP の関係について
上図の Wallet は「VC を保管し VP を生成する」役割です。通常は IdP とイコールではありません。 SIOPv2 を使った場合に限り、Wallet 自身が Self-Issued OpenID Provider(IdP)として振る舞い、外部の Google や Microsoft などに依存せず認証を完結できます。SIOPv2 を使わない OID4VP 単体のフローでは、Wallet は VP を提示するだけで、IdP は別途存在するか不要な構成になります。
RP(Relying Party)とは?
OIDC の用語で、「ユーザーの認証を外部の IdP(Identity Provider)に委託するサービス」のことです。わかりやすく言うと「ログインさせたい側のアプリ・サイト」です。例えば「Google でログイン」ボタンを設置している EC サイトが RP、Google が IdP にあたります。OID4VP の文脈では、RP が VP を受け取って検証する Verifier の役割も兼ねます。
OID4VC の3つのプロトコル
OID4VC は目的別に3つのプロトコルで構成されています。
1. OID4VCI(OpenID for Verifiable Credential Issuance)― VC を発行する
Issuer(発行機関)がユーザーのウォレットに VC を安全に届けるためのプロトコルです。
[ユーザー/ウォレット] [Issuer(発行機関)]
| |
|-- ① Credential Offer を受け取る -------->|
| |
|-- ② Authorization Request ------------->|
|<- ③ Authorization Code -----------------|
| |
|-- ④ Token Request (code交換) ----------->|
|<- ⑤ Access Token ------------------------|
| |
|-- ⑥ Credential Request ---------------->|
|<- ⑦ VC 発行(credentialレスポンス) ------|
- Issuer はまず Credential Offer(QR コードや deeplink)でウォレットを招待します
- ウォレットは通常の OAuth 2.0 フローでアクセストークンを取得し、VC を要求します
- 発行された VC はウォレット内に安全に保管されます
活用例: マイナンバーカードの読み取り → 自治体サーバーが VC を発行 → スマホのウォレットに保存
2. OID4VP(OpenID for Verifiable Presentations)― VP を提示する
ユーザーが RP(Verifier)に対して VP を提示して属性証明するためのプロトコルです。既存の OIDC の Authorization フローを拡張しており、vp_token という新しいレスポンスタイプを追加しています。
[ユーザー/ウォレット] [RP(Verifier)]
| |
|<- ① Authorization Request ------------|
| (presentation_definition 付き) |
| |
| ウォレットが条件に合う VC を選択 |
| VP を生成(holder の署名を付与) |
| |
|-- ② vp_token を返送 ---------------->|
| |
| RP が VP を検証 |
|<- ③ ログイン完了/属性情報を利用 --------|
Authorization Request の例(OID4VP)
GET /authorize?
response_type=vp_token
&client_id=https://hospital.example/callback
&presentation_definition={
"id": "age-check",
"input_descriptors": [{
"id": "age-credential",
"constraints": {
"fields": [{
"path": ["$.credentialSubject.isAdult"],
"filter": { "type": "boolean", "const": true }
}]
}
}]
}
&nonce=abc123
presentation_definition で「どんな VC が必要か」を宣言します。ウォレットはこの定義に合う VC を選んで VP にして返します。RP は受け取った vp_token を検証してログインを許可します。
nonce は毎回ランダムな値を使うことで、VP の使い回し(リプレイ攻撃)を防いでいます。
活用例: 病院サイトにログイン時、「成人であること」を VP で証明 → 氏名・生年月日は開示不要
3. SIOPv2(Self-Issued OpenID Provider v2)― ウォレット自身が IdP になる
通常の OIDC では Google や Microsoft などの外部 IdP が認証を担いますが、SIOPv2 では ユーザーのウォレット自体が IdP(OpenID Provider)として振る舞います。
通常の OIDC: ユーザー → RP → Google(外部 IdP) → RP
SIOPv2: ユーザー → RP → ウォレット(自己発行 IdP) → RP
- 外部 IdP への依存がゼロになり、完全に分散型の認証が実現します
- RP は
sub_jwk(ユーザーの公開鍵)を使って署名を検証します - OID4VP と組み合わせることで「ウォレットで認証しつつ VC も提示する」という強力なフローが組めます
活用例: 行政サービスへのログインで、Google アカウントなしにマイナンバー由来の VC だけで本人確認を完結させる
3つのプロトコルの使い分け
| やりたいこと | 使うプロトコル |
|---|---|
| 機関から VC をウォレットに取得したい | OID4VCI |
| VC の属性を RP に証明してログインしたい | OID4VP |
| 外部 IdP なしで分散認証したい | SIOPv2 |
| 上記すべてを組み合わせたい | OID4VCI + OID4VP + SIOPv2 |
実際のユースケース
eKYC(本人確認)
マイナンバーカードの VC をウォレットに保存し、銀行口座開設時に VP として提示。紙不要・即時確認が実現します。
学歴・資格証明
大学が発行した卒業証書 VC を企業の採用システムに VP 提示。偽造不可・即時検証が可能です。
ワクチン接種証明
EU Digital COVID Certificate はほぼ VC 相当の仕組みです。入国審査で QR スキャンして検証します。
年齢確認(SNS / EC サイト)
「18歳以上」だけを VP で提示。生年月日・名前は開示しないプライバシー保護設計が実現できます。
VC と従来の JWT / SAML との違い
| 特徴 | JWT(旧来) | SAML | VC/VP |
|---|---|---|---|
| 発行者管理 | 中央集権(IdP) | 中央集権(IdP) | 分散(DID) |
| 保持場所 | クライアント Cookie/Storage | SP セッション | ユーザーのウォレット |
| 選択的開示 | △ 基本不可 | ✗ 不可 | ✅ SD-JWT などで可能 |
| オフライン検証 | ✅ 可(公開鍵配布) | △ 要メタデータ | ✅ DID 解決で可能 |
| 相互運用性 | 高(RFC 7519) | 中(XML) | 高(W3C 標準) |
まとめ
- VC = 発行者が署名した「改ざん不可能なデジタル証明書」
- VP = 保持者が必要な情報だけ選んで提示する「封筒」
- DID = 発行者・保持者を分散的に識別する「識別子」
OID4VC により既存の OIDC エコシステムとも統合できるため、今後はパスポート・学位・医療記録など多くの場面で使われるようになるでしょう。
まずは did:key + @digitalbazaar/vc ライブラリでローカル動作を試してみることをおすすめします。
参考リンク・お試しライブラリ
仕様書
- W3C Verifiable Credentials Data Model v2.0
- OpenID for Verifiable Credential Issuance (OID4VCI)
- OpenID for Verifiable Presentations (OID4VP)
- DIF Presentation Exchange
ライブラリ
- @digitalbazaar/vc — Node.js 向けの VC ライブラリ
- veramo — TypeScript フルスタック VC フレームワーク
- Sphereon SDK — OID4VC 対応 SDK