Skip to main content

Verifying Credentials with mwen.io

@mwen/js-sdk is the consumer-facing SDK for integrating "Sign in with mwen.io" into your application. This page covers what mwen.io provides to apps, the trust model, and the core concepts you need before writing any code.


What your app gets from mwen.io

When a user signs in with mwen.io, your app receives:

  1. A pseudonymous user identifier — a did:jwk string that is stable for your app and cryptographically unique to it. Use it as a primary key for the user in your database.
  2. Selectively disclosed claims — only the attributes the user consented to share (e.g. given_name, age_over_18, email). No attribute the user withheld.
  3. A cryptographic proof — an SD-JWT Verifiable Presentation that you can verify locally using standard JWT libraries. No call back to mwen.io.
  4. Access and refresh tokens — short-lived JWTs for session management.

What your app never receives

  • The user's 24-word identity phrase or any private key material.
  • Claims the user chose to hide or did not share.
  • Information about which other apps the same user has signed in to.
  • Linkable user data across apps — the did:jwk your app sees is cryptographically independent from what any other app sees.

This means you have zero KYC liability for identity data you never received.


The trust model

User's device                          Your app
──────────────────────────────────────────────────────────
BIP39 phrase Receives VP only
└── HKDF(phrase, "your-app.com")
└── P-256 private key User identifier:
└── did:jwk:...──────────did:jwk:... (stable)
└── SD-JWT-VC ────→ verify locally
(signed) (no mwen.io call)

Key properties:

  • Self-issued: The user signs the credential with their own key. There is no mwen.io signing service in the path.
  • Self-resolving: The did:jwk identifier encodes the public key directly. You extract the public key by base64url-decoding the DID string. No DNS lookup, no registry call.
  • Standards-based: SD-JWT-VC (IETF), did:jwk (W3C). Any standards-compliant JWT library can verify the presentation.

Authentication path

The SDK currently supports Path A: extension-based authentication.

The user must have the mwen.io Chrome extension installed. Your app calls authenticate(), the extension popup opens for user consent, and the resolved credential is returned as a Promise — in under 2 seconds.

If the extension is not installed, authenticate() throws MwenExtensionNotFoundError. Handle this case by directing users to install the extension.


The user identifier: did:jwk

Your app's stable user identifier is the did:jwk in VerifiedSession.appIdentity (also the JWT sub claim). It looks like:

did:jwk:eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6Ii4uLiIsInkiOiIuLi4ifQ

This is a base64url-encoded JSON Web Key (P-256 public key). To extract the public key:

const suffix = did.replace('did:jwk:', '');
const jwk = JSON.parse(atob(suffix.replace(/-/g, '+').replace(/_/g, '/')));
// jwk = { kty: 'EC', crv: 'P-256', x: '...', y: '...' }

The SDK and its server utility handle this for you. You should treat did:jwk as an opaque stable string for database keying — no parsing required.


Package structure

The SDK ships three entry points:

Import pathPurpose
@mwen/js-sdkCore types, MwenClient class, session utilities, error classes
@mwen/js-sdk/reactMwenProvider context + useMwen() hook
@mwen/js-sdk/serververifyAccessTokenFromHeader() for Node.js API routes