BringID Browser Extension v2 is a Chrome extension that enables users to prove legitimate ownership and activity on various online platforms through TLS notarization (MPC-TLS / zero-knowledge TLS proofs). The extension uses encrypted sessions with a notary server to generate cryptographic proofs that can be verified on blockchain without revealing sensitive personal data.
The extension provides zero-knowledge proof generation for user identity verification across multiple platforms:
- Uber: Prove at least 5 completed rides
- Apple Devices: Prove ownership of Apple devices
- Apple Subscriptions: Prove active paid subscriptions
- Binance KYC: Prove KYC verification status
- OKX KYC: Prove KYC verification status
- X/Twitter: Prove premium status and verified followers count
After successful verification, the extension returns a cryptographic proof (TLS notarization presentation) to the requesting web application via postMessage.
- Platform: Chrome Extension (Manifest V3)
- Language: TypeScript
- UI Framework: React 18
- State Management: Redux Toolkit
- Styling: Styled Components
- Blockchain: Ethers.js v6, Base chain (mainnet + Sepolia testnet)
- Privacy: Semaphore Protocol (zero-knowledge proofs)
- TLS Notarization:
bringid-tlsn-js(custom MPC-TLS library) - Worker Communication: Comlink
- Build: Webpack 5
┌────────────────────────────────────────────────────────┐
│ Web Application (Widget / Connect) │
│ Sends REQUEST_ZKTLS_VERIFICATION via │
│ chrome.runtime.sendMessage() │
└──────────────────┬─────────────────────────────────────┘
│
┌──────────────────▼─────────────────────────────────────┐
│ Content Script (content.tsx + index.tsx) │
│ Relays messages between page ↔ extension │
└──────────────────┬─────────────────────────────────────┘
│
┌──────────────────▼─────────────────────────────────────┐
│ Background Service Worker (background/index.tsx) │
│ Routes requests, manages sessions, opens side panel │
└──────────────────┬─────────────────────────────────────┘
│
┌──────────────────▼─────────────────────────────────────┐
│ Side Panel (side-panel/) │
│ ├── Task Verification UI │
│ ├── Request Recorder (captures HTTP requests) │
│ ├── Notarization Template (handler configs) │
│ └── TLSNotary (MPC-TLS proof generation) │
└──────────────────┬─────────────────────────────────────┘
│
┌──────────────────▼─────────────────────────────────────┐
│ External Services │
│ ├── Notary Server (api.bringid.org/v1/notary) │
│ ├── WebSocket Proxy (proxy.bringid.org/websockify) │
│ └── Target APIs (Uber, Apple, Binance, OKX, X) │
└────────────────────────────────────────────────────────┘
- Background Service Worker (
src/background/index.tsx): Handles external messages, manages side panel sessions, routes verification requests - Content Scripts:
src/content/content.tsx: Injected into widget pages, relays page messages to extensionsrc/content/index.tsx: Receives extension messages, sends results back to page viapostMessage
- Side Panel (
src/side-panel/): Main verification UI with React/Redux - Notarization Handlers (
src/side-panel/services/notarization/handlers/): Platform-specific verification configs - TLSNotary (
src/side-panel/services/tlsn/): MPC-TLS proof generation engine - Request Recorder (
src/side-panel/services/requests-recorder/): Captures HTTP requests using ChromewebRequestAPI - Configs (
src/configs/): Extension ID, API URLs, chain configs, task definitions
- Web application sends
REQUEST_ZKTLS_VERIFICATIONto extension viachrome.runtime.sendMessage(EXTENSION_ID, ...) - Background worker validates request and stores task in
chrome.storage.local - Background worker opens side panel UI
- Side panel displays verification steps to user
- User navigates to target service (e.g., Uber, Apple ID)
- Request Recorder captures relevant HTTP requests (cookies, headers, body)
- Extension replays the request through MPC-TLS notary to generate proof
- Response middleware validates the data (e.g., enough rides, KYC verified)
- TLS transcript is selectively disclosed (only specific JSON paths revealed)
- Cryptographic proof (presentation) is generated
- Result is sent back to the web application via
VERIFICATION_DATA_READYpostMessage
All postMessage communication flows between the extension and web applications hosted on BringID widget/connect domains.
Initiates a zero-knowledge TLS verification flow. Sent from the web application to the extension via chrome.runtime.sendMessage().
TypeScript Interface:
interface IRequestZktlsVerification {
type: 'REQUEST_ZKTLS_VERIFICATION';
requestId: string; // Unique request identifier
payload: {
task: string; // JSON stringified TTask object
origin: string; // Originating domain URL
};
}Example:
chrome.runtime.sendMessage('fjlmbkpfjmbjokokgmfcijlliceljbeh', {
type: 'REQUEST_ZKTLS_VERIFICATION',
requestId: 'unique-request-id-123',
payload: {
task: JSON.stringify({
id: '1',
title: 'Uber Rides',
service: 'Uber',
description: 'Prove that you had at least 5 uber trips',
permissionUrl: [
'https://riders.uber.com/graphql',
'https://riders.uber.com/trips',
],
groups: [{ points: 10, semaphoreGroupId: '0', credentialGroupId: '1' }],
steps: [
{ text: 'Visit website' },
{ text: 'Wait for request capture' },
{ text: 'MPC-TLS verification progress', notarization: true },
],
}),
origin: 'https://widget.bringid.org',
},
});Validation:
payload.taskis requiredpayload.originis requiredrequestIdis requiredsender.tab.idmust be present
Checks if the extension is installed and responsive.
TypeScript Interface:
interface IPing {
type: 'PING';
}Example:
chrome.runtime.sendMessage('fjlmbkpfjmbjokokgmfcijlliceljbeh', {
type: 'PING',
});Response: Returns true if extension is active.
All outgoing messages are sent via window.postMessage() from the content script to the web application page. Every message includes source: 'bringID extension'.
Sent when verification completes successfully with a valid TLS notarization proof.
TypeScript Interface:
interface IVerificationDataReady {
source: 'bringID extension';
type: 'VERIFICATION_DATA_READY';
requestId: string; // Matches the original request ID
payload: {
transcriptRecv: string; // Base64-encoded TLS transcript (received data)
presentationData: string; // Cryptographic proof / presentation
};
}Example:
// Received by web application via window.addEventListener('message', ...)
{
source: 'bringID extension',
type: 'VERIFICATION_DATA_READY',
requestId: 'unique-request-id-123',
payload: {
transcriptRecv: 'base64encodedtranscript...',
presentationData: 'cryptographicproof...'
}
}Note: The message is sent to the specific origin that initiated the request, not '*'.
Sent when verification fails or is cancelled by the user.
TypeScript Interface:
interface IVerificationDataError {
source: 'bringID extension';
type: 'VERIFICATION_DATA_ERROR';
requestId: string; // Matches the original request ID
payload: {
error: string; // Error code
};
}Error Codes (sent to widget):
| Error Code | Description |
|---|---|
USER_CANCELLED |
User closed the side panel before verification completed |
VERIFICATION_FAILED |
Notarization process failed |
Note: Additional error codes (e.g., uber_data_not_found, binance_kyc_not_verified, okx_kyc_not_verified, etc.) are used internally within the side panel UI but are not currently sent to the widget. These internal errors are mapped to VERIFICATION_FAILED before being communicated externally.
Example:
{
source: 'bringID extension',
type: 'VERIFICATION_DATA_ERROR',
requestId: 'unique-request-id-123',
payload: {
error: 'USER_CANCELLED'
}
}These messages flow between extension components (background worker, side panel, content scripts) and are not visible to external web applications.
// Register active verification session
{
type: 'REGISTER_SESSION',
tabId: number,
requestId: string,
origin: string
}// Unregister session on successful completion
{
type: 'UNREGISTER_SESSION',
requestId: string
}// Success result forwarded to content script for postMessage relay
{
type: 'VERIFICATION_DATA_READY',
payload: {
transcriptRecv: string,
presentationData: string,
requestId: string,
origin: string
}
}
// Error result forwarded to content script
{
type: 'VERIFICATION_DATA_ERROR',
payload: {
error: string,
requestId: string,
origin: string
}
}// Main thread → Worker
{ action: 'initWsMonitor' }
{ action: 'setWsMonitorConfig', config: WsMonitorConfig }
// Worker → Main thread
{
type: 'data',
payload: {
progress: number, // 0-100 percentage
eta: number, // Estimated seconds remaining
speed: string, // e.g., "512 KB/s"
quality: string, // Connection quality indicator
totalBytes: number,
remainingBytes: number,
elapsedSeconds: number
}
}Base URL: https://api.bringid.org
Authentication: API key via Zuplo gateway (zpka_...)
| Endpoint | Description |
|---|---|
GET /v1/notary |
Obtains a TLS notary session URL for MPC-TLS proof generation |
URL: wss://proxy.bringid.org/websockify
Purpose: Proxies TLS connections for MPC-TLS handshake between the extension and target servers.
These are the allowed origins for external communication:
| Domain | Purpose |
|---|---|
https://connect.bringid.org |
Main wallet connection interface |
https://dev.connect.bringid.org |
Development environment |
https://widget.bringid.org |
Embeddable widget |
https://staging.widget.bringid.org |
Staging widget |
These are the third-party services whose data is captured and notarized:
- Endpoint:
POST https://riders.uber.com/graphql - Server DNS:
riders.uber.com - Redirect URL:
https://riders.uber.com/trips - Cookies Used:
sid,csid - GraphQL Query:
{currentUser {uuid} activities {past(limit: 10) {activities {uuid, description}}}} - Disclosed Fields:
/data/currentUser/uuid,/data/activities/past/activities - Validation: At least 5 non-canceled rides required
- Endpoint:
GET https://appleid.apple.com/account/manage/security/devices - Server DNS:
account.apple.com - Redirect URL:
https://account.apple.com/account/manage/section/devices - Cookies Used:
aidsp - Disclosed Fields:
/devices - Validation: At least 1 device required
- Endpoint:
GET https://speedysub.apps.apple.com/subscription/v3/manage/list* - Server DNS:
speedysub.apps.apple.com - Redirect URL:
https://account.apple.com/account/manage/section/subscriptions - Cookies Used:
myacinfo,commerce-authorization-token,caw,caw-at,dslang,site - Disclosed Fields: Per subscription:
/active/{index}/subscriptionId,/active/{index}/status,/active/{index}/latestPlan/paidPrice - Validation: At least 1 active paid subscription required
- Endpoint:
POST https://www.binance.com/bapi/kyc/v2/private/certificate/user-kyc/current-kyc-status - Server DNS:
www.binance.com - Redirect URL:
https://www.binance.com/en/my/dashboard - Cookies Used:
aws-waf-token,p20t,bnc-uuid,d1og,logined,cr00,__cuid,BNC_FV_KEY,BNC_FV_KEY_T,BNC_FV_KEY_EXPIRE - Headers Forwarded:
csrftoken,bnc-uuid - Disclosed Fields:
/data/kycStatus,/data/currentKycLevel,/data/jumioStatus,/data/userId - Validation:
kycStatus === 1ANDjumioStatus === 'PASS'
- Endpoint:
GET https://www.okx.com/v3/users/security/profile* - Server DNS:
www.okx.com - Redirect URL:
https://www.okx.com/account/users - Cookies Used:
token,uid,ok-ses-id,devId,__cf_bm,locale,browserCheck - Headers Forwarded:
authorization,user-agent - Disclosed Fields:
/code,/data/kycLevel,/data/uuid - Validation:
code === 0ANDkycLevel >= 2
- Endpoint:
GET https://x.com/i/api/graphql/LwtiA7urqM6eDeBheAFi5w/AccountOverviewQuery?* - Server DNS:
x.com - Redirect URL:
https://x.com/i/account_analytics/overview - Cookies Used:
auth_token,ct0 - Headers Forwarded:
authorization,x-csrf-token - Disclosed Fields:
/data/viewer_v2/user_results/result/verified_follower_count,/data/viewer_v2/user_results/result/id - Validation: At least 10 verified followers required
- Score Groups: 20 points (1000+), 10 points (100+), 5 points (10+)
| Network | Chain ID | RPC URL | Explorer |
|---|---|---|---|
| Base Sepolia (testnet) | 84532 | https://base-sepolia.drpc.org |
https://sepolia.basescan.org |
| Base (mainnet) | 8453 | https://developer-access-mainnet.base.org |
https://basescan.org |
Registry Contracts:
- Testnet:
0x0b2Ab187a6FD2d2F05fACc158611838c284E3a9c - Mainnet:
0xFEA4133236B093eC727286473286A45c5d4443BC
Task definition that describes a verification type.
interface TTask {
id: string; // Task identifier
title: string; // Display name (e.g., "Uber Rides")
service: string; // Service name (e.g., "Uber", "Apple ID")
description: string; // Human-readable description
icon: string; // Icon URL
permissionUrl: string[]; // URLs requiring host permission
verificationType?: string; // e.g., "zktls"
additionalInfo?: {
// Optional info shown during verification
title: string;
text: string;
showBeforeStep: number;
};
groups: Array<{
points: number; // Score points for this group
semaphoreGroupId: string; // Semaphore group identifier
credentialGroupId: string; // Credential group identifier
checks?: Array<{
// Optional additional validation checks
key: string; // Field to check
type: string; // Comparison type (e.g., "gte")
value: string; // Threshold value
}>;
}>;
steps: Array<{
text: string; // Step description
notarization?: boolean; // Whether this is the notarization step
}>;
}Each verification type has a handler config defining how to capture, replay, and validate requests.
// Simple handler (single request)
interface SimpleHandlerConfig {
name: string;
request: { method: string; urlPattern: string };
redirect: string; // URL to open for user navigation
tlsnConfig: {
serverDns: string; // TLS server hostname
maxSentData: number; // Max bytes sent
maxRecvData: number; // Max bytes received
};
replayRequestCfg: {
url?: (req: Request) => string; // Optional URL transform
headers: {
custom: Record<string, string>; // Fixed headers
whitelist: string[]; // Headers to forward from capture
cookie: {
whitelist: string[]; // Cookies to forward from capture
};
};
customBody?: object; // Override request body
};
transcriptDisclose: string[]; // JSON pointers for selective disclosure
responseMiddleware?: ResponseMiddleware;
}
// Complex handler (multiple requests, custom middleware)
interface HandlerConfig {
name: string;
requests: Array<{ method: string; urlPattern: string }>;
redirect: string;
tlsnConfig: { serverDns: string; maxSentData: number; maxRecvData: number };
requestMiddleware?: (requests: Request[]) => Promise<Request>;
transcriptMiddleware: TranscriptMiddleware;
responseMiddleware?: ResponseMiddleware;
}- Extension ID:
fjlmbkpfjmbjokokgmfcijlliceljbeh - Manifest Version: 3
Required:
storage: Local/sync storage accesswebRequest: HTTP request interception for captureactiveTab: Current tab accesssidePanel: Side panel UI
Host Permissions (Required):
https://connect.bringid.org/*https://dev.connect.bringid.org/*https://widget.bringid.org/*https://staging.widget.bringid.org/*
Optional Host Permissions (User-Granted):
https://appleid.apple.com/*https://riders.uber.com/*https://account.apple.com/*https://www.binance.com/*https://www.okx.com/*https://speedysub.apps.apple.com/*https://apps.apple.com/*
PROXY_URL: WebSocket proxy URL (default:wss://proxy.bringid.org/websockify)
yarn dev # Development build with hot reload (watch mode)
yarn build # Production build
yarn lint # Run ESLint
yarn lint:fix # Fix ESLint issuesRequirements: Node.js 20+, Yarn
-
Extension Communication: Web applications communicate with the extension via
chrome.runtime.sendMessage(EXTENSION_ID, ...)for incoming requests, and receive results viawindow.postMessage()on the page. -
Externally Connectable: Only pages on
connect.bringid.org,dev.connect.bringid.org,widget.bringid.org, andstaging.widget.bringid.orgcan send messages to the extension. -
Content Scripts: Injected into all frames on the connectable domains. They relay messages bidirectionally between the page and the extension background.
-
Side Panel Sessions: The background worker tracks active sessions. If the user closes the side panel before completion, a
USER_CANCELLEDerror is sent to the originating tab. -
Selective Disclosure: TLS notarization proofs only reveal specific JSON paths (defined in
transcriptDisclose). All other response data remains hidden in the proof. -
Request Replay: The extension first captures a real request from the user's browser session, then replays it through the MPC-TLS notary with filtered headers/cookies to generate the proof.
-
Cookie Filtering: Each handler config defines a whitelist of cookies to include in the replayed request. This minimizes data exposure while maintaining authentication.
-
Semaphore Integration: Verification results can be used to join Semaphore groups on-chain (Base), enabling privacy-preserving proof of humanity.
-
Content Security Policy: Extension pages use
'wasm-unsafe-eval'for WebAssembly support (required bybringid-tlsn-js).