🔖

didkit-wasm, Next.jsでVerifiable Credentialsを検証してみる

2023/12/28に公開1

はじめに

DIDKitを使って、Verifiable Credentialsをブラウザで検証してみます。

didkit-wasmを使います。
https://www.spruceid.dev/didkit/didkit-packages/javascript

バージョン

nextjs: 14.0.4
@spruceid/didkit-wasm: 0.2.1

Next.jsプロジェクトを用意する

以下のように用意したNext.jsを使います。

hide@hidenoMacBook-Pro didkit-examples % npx create-next-app@latest
✔ What is your project named? … with-nextjs
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
Creating a new Next.js app in /Users/hide/hid3h/didkit-examples/with-nextjs.

Using npm.

Initializing project with template: app-tw 


Installing dependencies:
- react
- react-dom
- next

Installing devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom
- autoprefixer
- postcss
- tailwindcss
- eslint
- eslint-config-next


added 362 packages, and audited 363 packages in 15s

128 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Initialized a git repository.

Success! Created with-nextjs at /Users/hide/hid3h/didkit-examples/with-nextjs

didkit-wasmを用意する

yarn add @spruceid/didkit-wasm

didkit-wasmはWebAssemblyを用います。
Next.jsで使用できるようにするためには設定が必要です。

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config) => {
    config.experiments = {
      asyncWebAssembly: true,
      layers: true,
    };
    return config;
  },
};

module.exports = nextConfig;

検証部分のコンポーネントを用意します。

app/Verification.tsx
"use client";

export const Verification = () => {
  const verify = async () => {
    console.log("検証スタート");
    // didkit-wasmをサーバー側でimportしようとするとエラーになるので、
    // クライアント側でimportするようにする
    const didkit = await import("@spruceid/didkit-wasm");
    const result = await didkit.verifyCredential("{}", "{}");
    console.log(result);
  };

  return (
    <div>
      <button onClick={verify}>検証する</button>
    </div>
  );
};

以下のようにdidkit-wasmをimportしようとするとエラーになるので、上記ではconst verify()の中でimportしています。

app/Verification.tsx
"use client";

import didkit from "@spruceid/didkit-wasm";

export const Verification = () => {
  const verify = async () => {
    console.log("検証スタート");
    const result = await didkit.verifyCredential("{}", "{}");
    console.log(result);
  };

  return (
    <div>
      <button onClick={verify}>検証する</button>
    </div>
  );
};
Unhandled Runtime Error
Error: Element type is invalid. Received a promise that resolves to: undefined. Lazy element type must resolve to a class or function.

このコンポーネントを読み込むようにして、サーバを起動してブラウザで開いてみると、

app/page.tsx
import { Verification } from "./Verification";

export default function Home() {
  return <Verification />;
}

となり、

「検証する」を押すとdidkitで検証できるようになりました。

VCを検証してみる

VCはsampleとして、
https://zenn.dev/hid3/articles/9782e9b1fb17ca#vc署名
で署名したものを使ってみます。

app/Verification.tsx
"use client";

export const Verification = () => {
  const signedSampleVc = {
    "@context": "https://www.w3.org/2018/credentials/v1",
    id: "urn:uuid:86a109aa-a3f6-4374-b46f-92c58fcb16a1",
    type: ["VerifiableCredential"],
    credentialSubject: {
      id: "did:example:my-data-subject-identifier",
    },
    issuer: "did:key:z6Mkv2hGUtUdKdEVdqc7esowafyriuqPvxQFnVTrRqjMknj2",
    issuanceDate: "2023-01-08T18:23:56Z",
    proof: {
      type: "Ed25519Signature2018",
      proofPurpose: "assertionMethod",
      verificationMethod:
        "did:key:z6Mkv2hGUtUdKdEVdqc7esowafyriuqPvxQFnVTrRqjMknj2#z6Mkv2hGUtUdKdEVdqc7esowafyriuqPvxQFnVTrRqjMknj2",
      created: "2023-01-08T07:43:50.818Z",
      jws: "eyJhbGciOiJFZERTQSIsImNyaXQiOlsiYjY0Il0sImI2NCI6ZmFsc2V9..jyR9O8nb-ino0TXSCAhUdP2Z9iBc0E-aX7tyTHcFuOzOGd_uWpwHhA4gTOX961SUHB0un34e2YV41qc2lk0nCw",
    },
  };

  const verify = async () => {
    console.log("検証スタート");
    // didkit-wasmをサーバー側でimportしようとするとエラーになるので、
    // クライアント側でimportするようにする
    const didkit = await import("@spruceid/didkit-wasm");

    const proofOptions = {};
    const result = await didkit.verifyCredential(
      JSON.stringify(signedSampleVc),
      JSON.stringify(proofOptions)
    );
    console.log(result);
  };

  return (
    <div>
      <button onClick={verify}>検証する</button>
    </div>
  );
};

「検証する」ボタンを押してみると、

{"checks":["proof"],"warnings":[],"errors":[]}

ブラウザでVCの検証ができていることが確認できました。

改ざんの検知も確認してみます。
VCの一部を変更してみます。

credentialSubject: {
  id: "did:example:my-data-subject-identifier-fix",
},

{"checks":["proof"],"warnings":[],"errors":["signature error: Verification equation was not satisfied"]}

検証に失敗しており、改ざんを検知できることも確認できました。

おわりに

サンプルコードを以下に用意しています。
https://github.com/hid3h/didkit-examples/tree/main/with-nextjs

Discussion

ruharuha

大変参考になりました。おかげでDidikitへの理解も深まりました。本当にありがとうございます。