U-net Docs
guide

Make your web app miniapp-ready

Use the same website in normal browsers and inside U-net as an unlisted or catalog-listed miniapp.

@union-networks/web-login@union-networks/server

Serve a miniapp manifest

U-net discovers unlisted miniapps from `/.well-known/unet-miniapp.json`. The manifest must be HTTPS, same-origin, and match a registered U-net service.

json.well-known/unet-miniapp.json
{
  "serviceId": "example-shop",
  "name": "Example Shop",
  "provider": "example-shop.com",
  "description": "A web app that can also run as a U-net miniapp.",
  "icon": "basket-outline",
  "launchUrl": "https://shop.example.com/app",
  "permissions": ["identity.scoped"]
}
Representation

U-net validates origin, launch URL, permissions, and service registration.

Login through the host bridge

When your site runs inside U-net, do not show a QR. Ask the host bridge for a scoped service session and verify the returned assertion on your server.

tsBridge login
type BridgeResponse<T> = {
  id: string;
  ok: boolean;
  result?: T;
  error?: string;
};

function callUnetHost<T>(action: string, payload = {}): Promise<T> {
  const bridge = window.ReactNativeWebView;
  if (!bridge) throw new Error('not_running_inside_unet');
  const id = crypto.randomUUID();

  return new Promise((resolve, reject) => {
    const onMessage = (event: MessageEvent<BridgeResponse<T>>) => {
      if (event.data?.id !== id) return;
      window.removeEventListener('message', onMessage as EventListener);
      event.data.ok
        ? resolve(event.data.result as T)
        : reject(new Error(event.data.error ?? 'unet_bridge_failed'));
    };
    window.addEventListener('message', onMessage as EventListener);
    bridge.postMessage(JSON.stringify({ id, action, payload }));
  });
}

const session = await callUnetHost<{
  scopedUserId: string;
  assertionJws: string;
}>('host.createServiceSession');

await fetch('/api/unet/session', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ assertionJws: session.assertionJws }),
});
Representation

Inside U-net: one tap consent, no QR. Browser: QR fallback.