{"_id":"@canton-vc/credential","_rev":"3-9186331f886bd4c9aa08b043ecf2ea2e","name":"@canton-vc/credential","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@canton-vc/credential","version":"0.1.0","keywords":["canton","canton-network","kyc","oauth","oidc","verifiable-credentials","vc","selective-disclosure","trustless-verification"],"author":{"url":"https://github.com/Farukest","name":"Abdullah Faruk Özden","email":"abdullahfarukozden@gmail.com"},"license":"Apache-2.0","_id":"@canton-vc/credential@0.1.0","maintainers":[{"name":"0xflydev","email":"0xflydev@gmail.com"}],"homepage":"https://github.com/Farukest/canton-vc/tree/main/packages/credential#readme","bugs":{"url":"https://github.com/Farukest/canton-vc/issues"},"dist":{"shasum":"b7263b94a706f863e92a524540efd8005016f521","tarball":"https://registry.npmjs.org/@canton-vc/credential/-/credential-0.1.0.tgz","fileCount":10,"integrity":"sha512-y/gOWg6BXbzO5CKHElB5MnGemTxl5Nj+skBjQsVlR77QITRyuyREBSJGB+jGcB00qaVdCP7pu/iETHM8Et5c+w==","signatures":[{"sig":"MEQCIEuxD1jxfLVx39xx4LfeU5Wk2x3mgQBoAMIFqyvsal+eAiACs/+nkmFivgZmZpiLuh/ZCI/nGrMhh4+ihimS6sznvw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51956},"main":"./src/index.ts","type":"module","_from":"file:canton-vc-credential-0.1.0.tgz","types":"./src/index.ts","engines":{"node":">=18"},"exports":{".":{"types":"./src/index.ts","default":"./src/index.ts"}},"scripts":{"lint":"biome check src","test":"vitest run","clean":"rm -rf .turbo dist","typecheck":"tsc --noEmit"},"_npmUser":{"name":"0xflydev","email":"0xflydev@gmail.com"},"_resolved":"C:\\Users\\FARUKE~1\\AppData\\Local\\Temp\\bc520c0af6b6e137ea3037c496b91b3d\\canton-vc-credential-0.1.0.tgz","_integrity":"sha512-y/gOWg6BXbzO5CKHElB5MnGemTxl5Nj+skBjQsVlR77QITRyuyREBSJGB+jGcB00qaVdCP7pu/iETHM8Et5c+w==","repository":{"url":"git+https://github.com/Farukest/canton-vc.git","type":"git","directory":"packages/credential"},"_npmVersion":"11.6.2","description":"High-level OAuth 2.0 / OIDC client + on-chain disclosure verification helper for Canton-issued verifiable credentials. Wraps the issuer's /oauth/authorize + /oauth/token + /oauth/userinfo endpoints and exposes verifyDisclosure() so any firm running their ","directories":{},"sideEffects":false,"_nodeVersion":"24.12.0","dependencies":{"@canton-vc/core":"0.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"2.1.8","typescript":"5.6.3","@types/node":"22.10.2"},"_npmOperationalInternal":{"tmp":"tmp/credential_0.1.0_1779586291436_0.42088559274346804","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@canton-vc/credential","version":"0.2.0","keywords":["canton","canton-network","kyc","oauth","oidc","verifiable-credentials","vc","selective-disclosure","trustless-verification"],"author":{"url":"https://github.com/Farukest","name":"Abdullah Faruk Özden","email":"abdullahfarukozden@gmail.com"},"license":"Apache-2.0","_id":"@canton-vc/credential@0.2.0","maintainers":[{"name":"0xflydev","email":"0xflydev@gmail.com"}],"homepage":"https://github.com/Farukest/canton-vc/tree/main/packages/credential#readme","bugs":{"url":"https://github.com/Farukest/canton-vc/issues"},"dist":{"shasum":"bb84fbc69ab82b2844e2bb651eed3162e5c836ef","tarball":"https://registry.npmjs.org/@canton-vc/credential/-/credential-0.2.0.tgz","fileCount":11,"integrity":"sha512-0VOTlOmzkeHW5nvnZcnvUMKyQN/vbHEuS3E1UKkoXf3OKmpuLqZheLreotAHMzus5dxoy46blCg7NQz7zk3+NA==","signatures":[{"sig":"MEQCIA5cHr/H04ya8YtdSs/tQsdVWWfA7LBMYvbnpN5sTOviAiBUTR8QSfha706Yc+YcF/qynCElJJP0zl4502C50Rq88g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":56765},"main":"./src/index.ts","type":"module","_from":"file:canton-vc-credential-0.2.0.tgz","types":"./src/index.ts","engines":{"node":">=18"},"exports":{".":{"types":"./src/index.ts","default":"./src/index.ts"}},"scripts":{"lint":"biome check src","test":"vitest run","clean":"rm -rf .turbo dist","typecheck":"tsc --noEmit"},"_npmUser":{"name":"0xflydev","email":"0xflydev@gmail.com"},"_resolved":"C:\\Users\\FARUKE~1\\AppData\\Local\\Temp\\4fe94674a33d77b7d3fc92c07a9ea473\\canton-vc-credential-0.2.0.tgz","_integrity":"sha512-0VOTlOmzkeHW5nvnZcnvUMKyQN/vbHEuS3E1UKkoXf3OKmpuLqZheLreotAHMzus5dxoy46blCg7NQz7zk3+NA==","repository":{"url":"git+https://github.com/Farukest/canton-vc.git","type":"git","directory":"packages/credential"},"_npmVersion":"11.6.2","description":"High-level OAuth 2.0 / OIDC client + on-chain disclosure verification helper for Canton-issued verifiable credentials. Wraps the issuer's /oauth/authorize + /oauth/token + /oauth/userinfo endpoints and exposes verifyDisclosure() so any firm running their ","directories":{},"sideEffects":false,"_nodeVersion":"24.12.0","dependencies":{"@canton-vc/core":"0.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"2.1.8","typescript":"5.6.3","@types/node":"22.10.2"},"_npmOperationalInternal":{"tmp":"tmp/credential_0.2.0_1779984346992_0.38143848623975773","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@canton-vc/credential","version":"0.3.0","description":"High-level OAuth 2.0 / OIDC client + on-chain disclosure verification helper for Canton-issued verifiable credentials. Wraps the issuer's /oauth/authorize + /oauth/token + /oauth/userinfo endpoints and exposes verifyDisclosure() so any firm running their ","license":"Apache-2.0","type":"module","main":"./src/index.ts","types":"./src/index.ts","exports":{".":{"types":"./src/index.ts","default":"./src/index.ts"}},"sideEffects":false,"engines":{"node":">=18"},"dependencies":{"@noble/hashes":"^2.2.0","@canton-vc/core":"0.3.0"},"devDependencies":{"@types/node":"22.10.2","typescript":"5.6.3","vitest":"2.1.8"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/Farukest/canton-vc.git","directory":"packages/credential"},"keywords":["canton","canton-network","kyc","oauth","oidc","verifiable-credentials","vc","selective-disclosure","trustless-verification"],"author":{"name":"Abdullah Faruk Özden","email":"abdullahfarukozden@gmail.com","url":"https://github.com/Farukest"},"homepage":"https://github.com/Farukest/canton-vc/tree/main/packages/credential#readme","bugs":{"url":"https://github.com/Farukest/canton-vc/issues"},"scripts":{"lint":"biome check src","typecheck":"tsc --noEmit","test":"vitest run","clean":"rm -rf .turbo dist"},"_id":"@canton-vc/credential@0.3.0","_integrity":"sha512-Us06gXTUEOOx0OnaKf4rmugIo5mEY9soiB5IP23nnd6NCT6hW8bjyIMmR47jwbjDKIe9uISKU1M9y/NDwHFRlQ==","_resolved":"C:\\Users\\FARUKE~1\\AppData\\Local\\Temp\\8269f9ff8ed5b22f3d9aaf6b5107bc71\\canton-vc-credential-0.3.0.tgz","_from":"file:canton-vc-credential-0.3.0.tgz","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-Us06gXTUEOOx0OnaKf4rmugIo5mEY9soiB5IP23nnd6NCT6hW8bjyIMmR47jwbjDKIe9uISKU1M9y/NDwHFRlQ==","shasum":"2d58be4f21ac331ae0edafd72a3485d7e27bb53d","tarball":"https://registry.npmjs.org/@canton-vc/credential/-/credential-0.3.0.tgz","fileCount":11,"unpackedSize":56213,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIB/ep56ceQuJWhDA+uyzoMavhEGDEuXfPR22AAURP2DmAiAuoilfJqWE3pLOBPidqvbsJRD9EamB3MhHd8zEBQoEJQ=="}]},"_npmUser":{"name":"0xflydev","email":"0xflydev@gmail.com"},"directories":{},"maintainers":[{"name":"0xflydev","email":"0xflydev@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/credential_0.3.0_1780019783043_0.20234450866392728"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-24T01:31:31.227Z","modified":"2026-05-29T01:56:23.327Z","0.1.0":"2026-05-24T01:31:31.571Z","0.2.0":"2026-05-28T16:05:47.195Z","0.3.0":"2026-05-29T01:56:23.201Z"},"bugs":{"url":"https://github.com/Farukest/canton-vc/issues"},"author":{"name":"Abdullah Faruk Özden","email":"abdullahfarukozden@gmail.com","url":"https://github.com/Farukest"},"license":"Apache-2.0","homepage":"https://github.com/Farukest/canton-vc/tree/main/packages/credential#readme","keywords":["canton","canton-network","kyc","oauth","oidc","verifiable-credentials","vc","selective-disclosure","trustless-verification"],"repository":{"type":"git","url":"git+https://github.com/Farukest/canton-vc.git","directory":"packages/credential"},"description":"High-level OAuth 2.0 / OIDC client + on-chain disclosure verification helper for Canton-issued verifiable credentials. Wraps the issuer's /oauth/authorize + /oauth/token + /oauth/userinfo endpoints and exposes verifyDisclosure() so any firm running their ","maintainers":[{"name":"0xflydev","email":"0xflydev@gmail.com"}],"readme":"# @canton-vc/credential\n\nOAuth 2.0 + OpenID Connect client SDK for Canton-VC compatible KYC issuers.\n\nWorks in modern browsers, Node.js 18+, Bun and Deno. Zero runtime dependencies — backed by the Web Crypto API and the platform `fetch`.\n\n## Install\n\n```bash\nnpm install @canton-vc/credential\n# or\npnpm add @canton-vc/credential\n```\n\n## Browser usage — redirect flow\n\n```ts\nimport { CantonVcClient, CantonVcOauthError, isCantonVcOauthError } from '@canton-vc/credential';\n\nconst client = new CantonVcClient({\n  clientId: 'crv_oauth_live_xxxxxxxxxxxxx',\n  redirectUri: 'https://your.app/oauth/callback',\n});\n\n// On your \"Verify identity\" button click:\ndocument.querySelector('#verify')?.addEventListener('click', () => {\n  client.authorize({ scope: ['openid', 'kyc'] });\n});\n```\n\nOn your `/oauth/callback` page:\n\n```ts\nimport { CantonVcClient, isCantonVcOauthError } from '@canton-vc/credential';\n\nconst client = new CantonVcClient({\n  clientId: 'crv_oauth_live_xxxxxxxxxxxxx',\n  redirectUri: 'https://your.app/oauth/callback',\n});\n\ntry {\n  const { code, codeVerifier } = await client.handleCallback();\n  // Forward { code, codeVerifier } to your backend — never exchange\n  // a code from the browser unless this is a public (PKCE-only) client.\n  await fetch('/api/finish-signup', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({ code, codeVerifier }),\n  });\n} catch (err) {\n  if (isCantonVcOauthError(err)) {\n    console.error(err.code, err.description);\n  }\n}\n```\n\n## Server-side — code exchange\n\n```ts\nimport { CantonVcClient } from '@canton-vc/credential';\n\nconst client = new CantonVcClient({\n  clientId: process.env.CANTON_VC_CLIENT_ID!,\n  clientSecret: process.env.CANTON_VC_CLIENT_SECRET!,\n  redirectUri: 'https://your.app/oauth/callback',\n});\n\n// inside your /api/finish-signup handler:\nconst tokens = await client.exchangeCode({ code, codeVerifier });\nconst claims = await client.getUserinfo(tokens.access_token);\n\nif (claims.identity_verified !== true) throw new Error('KYC required');\nreturn { userId: claims.sub };\n```\n\n## Public clients (SPAs / native)\n\nPublic clients authenticate with PKCE alone — no `client_secret`. The SDK handles this automatically when `clientSecret` is omitted:\n\n```ts\nconst client = new CantonVcClient({\n  clientId: 'crv_oauth_live_public_spa_xxxx',\n  redirectUri: 'https://your.app/oauth/callback',\n});\n\nawait client.authorize({ scope: ['openid', 'kyc'] });\n// …later…\nconst { code, codeVerifier } = await client.handleCallback();\nconst tokens = await client.exchangeCode({ code, codeVerifier });\n```\n\n## Custom storage\n\nThe SDK needs to persist the PKCE verifier + state between the authorize redirect and the callback. The default storage is `sessionStorage` with an in-memory fallback. Override with your own implementation when `sessionStorage` isn't available (React Native, extensions, encrypted stores):\n\n```ts\nimport { CantonVcClient, type SdkStorage } from '@canton-vc/credential';\n\nconst storage: SdkStorage = {\n  getItem: async (k) => mySecureStore.read(k),\n  setItem: async (k, v) => mySecureStore.write(k, v),\n  removeItem: async (k) => mySecureStore.delete(k),\n};\n\nconst client = new CantonVcClient({ clientId, redirectUri }, storage);\n```\n\n## Error handling\n\nEvery failure throws a `CantonVcOauthError` with a `.code` matching the OAuth 2.0 / RFC 9700 vocabulary:\n\n| code | meaning |\n|---|---|\n| `access_denied` | User rejected the consent screen |\n| `state_mismatch` | CSRF token from storage did not match the callback query |\n| `missing_verifier` | Storage was cleared before the callback (user came back on a new tab?) |\n| `invalid_grant` | Server refused the code — expired, reused, or wrong client |\n| `invalid_client` | Wrong `client_secret` or unknown `client_id` |\n| `pkce_invalid` | The verifier doesn't match the original challenge |\n| `network_error` | Underlying `fetch` rejected |\n\nUse `isCantonVcOauthError(err)` to type-narrow.\n\n## API reference\n\n### `new CantonVcClient(options, storage?)`\n\n- `options.clientId` — required.\n- `options.redirectUri` — required, exact match against the value registered in the issuer dashboard.\n- `options.clientSecret` — required for confidential clients, must NOT be set in the browser.\n- `options.issuer` — full origin of the issuer deployment. Defaults to `https://issuer.example`; set this to the URL of the issuer you're integrating with.\n- `options.fetch` — override the global `fetch`.\n\n### `client.buildAuthorizeUrl({ scope, nonce?, redirectUri?, uiLocales? })`\n\nReturns `{ url, state, codeVerifier, nonce? }` without navigating. Useful for SSR and testing.\n\n### `client.authorize({ scope, ... })`\n\nBrowser convenience — builds the URL and navigates the current tab. Returns a `Promise<never>`.\n\n### `client.handleCallback(input?)`\n\nParses the callback URL (default: `window.location`), validates state, returns `{ code, codeVerifier, redirectUri, state }`.\n\n### `client.exchangeCode({ code, codeVerifier, redirectUri? })`\n\nExchanges the code for a token response `{ access_token, token_type, expires_in, scope, id_token? }`.\n\n### `client.getUserinfo(accessToken)`\n\nFetches the userinfo claim set.\n\n## License\n\nApache 2.0 — see [LICENSE](../../LICENSE) at the repository root.\n","readmeFilename":"README.md"}