> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rhinestone.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Accounts

> Install the embedded wallet SDK, initialize one client, and obtain a user's smart account.

export const CSS = ".rhinestone-1auth-demo .oa-demo {\n  margin: 1.5rem 0;\n  border: 1px solid #202127;\n  border-radius: 16px;\n  background: #0b0c0e;\n  overflow: hidden;\n}\n.rhinestone-1auth-demo .oa-demo-head {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 0.75rem;\n  min-height: 39px;\n  padding: 0.625rem 1rem;\n  border-bottom: 1px solid #191a1e;\n}\n.rhinestone-1auth-demo .oa-demo-title {\n  font-size: 0.8125rem;\n  font-weight: 500;\n  letter-spacing: -0.01em;\n  color: #e4e4e9;\n}\n.rhinestone-1auth-demo .oa-demo-status {\n  display: flex;\n  align-items: center;\n  gap: 0.4375rem;\n  flex: 0 0 auto;\n  font-size: 0.75rem;\n  color: #5e5e68;\n}\n.rhinestone-1auth-demo .oa-demo-dot {\n  width: 6px;\n  height: 6px;\n  border-radius: 999px;\n  background: #3f3f48;\n}\n.rhinestone-1auth-demo .oa-demo-dot[data-state=\"on\"] {\n  background: #22c55e;\n  box-shadow: 0 0 8px rgba(34, 197, 94, 0.5);\n}\n.rhinestone-1auth-demo .oa-demo-body {\n  display: flex;\n  flex-direction: column;\n  gap: 0.75rem;\n  padding: 1rem;\n}\n.rhinestone-1auth-demo .demo-container {\n  display: contents;\n}\n.rhinestone-1auth-demo .oa-demo-body > * > [style] {\n  margin: 0 !important;\n}\n.rhinestone-1auth-demo .oa-demo-body > * > div[style]:not([class]) {\n  padding: 0 !important;\n}\n.rhinestone-1auth-demo .oa-demo-body [style] {\n  text-align: left !important;\n}\n.rhinestone-1auth-demo .oa-demo-body [style*=\"justify-content: center\"] {\n  justify-content: flex-start !important;\n}\n.rhinestone-1auth-demo .demo-button {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  gap: 0.375rem;\n  height: 2.25rem;\n  padding: 0 0.875rem;\n  border: none;\n  border-radius: 10px;\n  background: #4f41ef;\n  color: #ffffff;\n  font-size: 0.875rem;\n  font-weight: 500;\n  cursor: pointer;\n  transition:\n    background 0.15s ease,\n    opacity 0.15s ease;\n}\n.rhinestone-1auth-demo .demo-button:hover:not(:disabled) {\n  background: #6355f5;\n}\n.rhinestone-1auth-demo .demo-button:disabled {\n  opacity: 0.6;\n  cursor: default;\n}\n.rhinestone-1auth-demo .demo-button-secondary {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  height: 2.25rem;\n  padding: 0 0.875rem;\n  border: 1px solid #2e2e36;\n  border-radius: 10px;\n  background: transparent;\n  color: #c8c8d0;\n  font-size: 0.875rem;\n  font-weight: 500;\n  cursor: pointer;\n  transition:\n    border-color 0.15s ease,\n    color 0.15s ease;\n}\n.rhinestone-1auth-demo .demo-button-secondary:hover:not(:disabled) {\n  border-color: #45454f;\n  color: #f2f2f5;\n}\n.rhinestone-1auth-demo .oa-demo-body > * > .demo-button, .rhinestone-1auth-demo .oa-demo-body > * > .demo-button-secondary {\n  align-self: flex-start;\n}\n.rhinestone-1auth-demo .oa-demo-body input[type=\"checkbox\"] {\n  accent-color: #4f41ef;\n}\n.rhinestone-1auth-demo .demo-result {\n  padding: 0.75rem 0.875rem;\n  border-radius: 10px;\n  background: #14151a;\n}\n.rhinestone-1auth-demo .demo-result-label {\n  font-size: 0.6875rem;\n  font-weight: 500;\n  letter-spacing: 0.08em;\n  text-transform: uppercase;\n  color: #6e6e78;\n}\n.rhinestone-1auth-demo .demo-result-value {\n  margin-top: 0.1875rem;\n  font-family: paperMono, ui-monospace, SFMono-Regular, Menlo, monospace;\n  font-size: 0.8125rem;\n  line-height: 1.5;\n  color: #e4e4e9;\n  overflow-wrap: anywhere;\n}\n.rhinestone-1auth-demo .demo-result-success .demo-result-label {\n  color: #4ade80;\n}\n.rhinestone-1auth-demo .demo-result-error .demo-result-label {\n  color: #f87171;\n}\n.rhinestone-1auth-demo .demo-result-error .demo-result-value {\n  color: #fca5a5;\n}\n.rhinestone-1auth-demo .demo-error {\n  margin: 0;\n  font-size: 0.8125rem;\n  color: #f87171;\n  overflow-wrap: anywhere;\n}\n.rhinestone-1auth-demo .oa-demo-skeleton {\n  display: block;\n  width: 7rem;\n  height: 2.25rem;\n  border-radius: 10px;\n  background: #16171c;\n  animation: rhinestone-1auth-demo-pulse 1.6s ease-in-out infinite;\n}\n@keyframes rhinestone-1auth-demo-pulse {\n  50% {\n    opacity: 0.45;\n  }\n}";

export const SOURCE_COMMIT = "e06ebe8add704e95f679eaddc38fd7ea88cb3de8";

export const SDK_VERSION = "0.10.1";

export const VIEM_VERSION = "2.55.0";

export const STORAGE_KEY = "rhinestone-docs-1auth-account";

export const PROD_BACKENDS = {
  auth: "https://passkey.1auth.app",
  sponsorship: "https://docs.1auth.app/api/sponsorship"
};

export const DEV_BACKENDS = {
  auth: "https://passkey.passkey-test.app",
  sponsorship: "https://docs.passkey-test.app/api/sponsorship"
};

export const PROD_DOCS_HOST = "docs.rhinestone.dev";

export const backends = () => {
  const host = typeof window === "undefined" ? "" : window.location.hostname;
  return host === PROD_DOCS_HOST ? PROD_BACKENDS : DEV_BACKENDS;
};

export const BACKEND_NOTE = "Only the production docs host talks to the production Rhinestone deployment. " + "Every other host — a Mintlify preview, a tunnel, localhost — uses dev, so " + "an unrecognised preview pattern fails towards dev rather than creating " + "passkey state against production.";

export const CDN = spec => "https://esm.sh/" + spec + (spec.startsWith("@rhinestone/1auth@") ? "?deps=viem@" + VIEM_VERSION + "&external=react" : "");

export const shareReact = () => {
  if (window.__OA_SHARED_REACT__) return;
  if (typeof HTMLScriptElement.supports !== "function" || !HTMLScriptElement.supports("importmap")) {
    throw new Error("This demo requires a browser with import-map support.");
  }
  window.__OA_REACT__ = React;
  const reserved = ["default", "import", "export", "class", "function", "const", "let", "var", "new", "delete", "typeof", "void", "in", "of", "do", "if", "else", "for", "while", "switch", "case", "break", "continue", "return", "this", "super", "throw", "try", "catch", "finally", "yield", "await", "enum", "null", "true", "false", "with", "debugger", "instanceof", "extends", "static"];
  const names = Object.keys(React).filter(name => (/^[A-Za-z_$][A-Za-z0-9_$]*$/).test(name) && !reserved.includes(name));
  const source = ["const R = globalThis.__OA_REACT__; export default R;", ...names.map(name => "export const " + name + " = R." + name + ";")].join(" ");
  const jsx = ["const R = globalThis.__OA_REACT__; export const Fragment = R.Fragment;", "export const jsx = (type, props, key) => R.createElement(type, key == null ? props : { ...props, key });", "export const jsxs = jsx; export const jsxDEV = jsx;"].join(" ");
  const dataUrl = value => "data:text/javascript," + encodeURIComponent(value);
  const script = document.createElement("script");
  script.type = "importmap";
  script.textContent = JSON.stringify({
    imports: {
      react: dataUrl(source),
      "react/jsx-runtime": dataUrl(jsx),
      "react/jsx-dev-runtime": dataUrl(jsx)
    }
  });
  document.head.appendChild(script);
  window.__OA_SHARED_REACT__ = true;
};

export const MODULE_SPECS = {
  sdk: () => CDN("@rhinestone/1auth@" + SDK_VERSION),
  viem: () => CDN("viem@" + VIEM_VERSION)
};

export const importModule = url => new Promise((resolve, reject) => {
  const key = "__oa_" + Math.random().toString(36).slice(2);
  window[key] = {
    resolve,
    reject
  };
  const script = document.createElement("script");
  script.type = "module";
  script.textContent = "import(" + JSON.stringify(url) + ").then(m => window[" + JSON.stringify(key) + "].resolve(m))" + ".catch(e => window[" + JSON.stringify(key) + "].reject(new Error(String(e))));";
  script.onerror = () => reject(new Error("failed to load " + url));
  document.head.appendChild(script);
  script.remove();
});

export const importModuleWithRetry = async url => {
  try {
    return await importModule(url);
  } catch (first) {
    await new Promise(r => setTimeout(r, 500));
    return importModule(url);
  }
};

export const loadDeps = async () => {
  shareReact();
  const specs = Object.entries(MODULE_SPECS).map(([name, spec]) => [name, spec()]);
  const cacheKey = "__OA_DEPS__" + specs.map(([, url]) => url).join("|");
  if (window[cacheKey]) return window[cacheKey];
  const loaded = await Promise.all(specs.map(([, url]) => importModuleWithRetry(url)));
  const deps = {
    React
  };
  specs.forEach(([name], i) => {
    deps[name] = loaded[i];
  });
  deps.motion = motionShim();
  window[cacheKey] = deps;
  return deps;
};

export const unreachable = call => "Sponsorship " + call + " never reached " + backends().sponsorship + ". The browser hides why: a rejected origin, a failed preflight and a network" + " error all look identical here. The failing request is in the console.";

export const sponsorship = {
  accessToken: async () => {
    let res;
    try {
      res = await fetch(backends().sponsorship + "/access-token", {
        method: "GET",
        credentials: "include"
      });
    } catch (e) {
      throw new Error(unreachable("access token"));
    }
    if (!res.ok) throw new Error("Sponsorship access token failed (" + res.status + ")");
    return (await res.json()).token;
  },
  getExtensionToken: async intentOp => {
    let res;
    try {
      res = await fetch(backends().sponsorship + "/extension-token", {
        method: "POST",
        credentials: "include",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({
          intentOp
        })
      });
    } catch (e) {
      throw new Error(unreachable("extension token"));
    }
    if (!res.ok) throw new Error("Sponsorship extension token failed (" + res.status + ")");
    return (await res.json()).token;
  }
};

export const motionShim = () => {
  const passthrough = Tag => React.forwardRef((props, ref) => {
    const rest = Object.fromEntries(Object.entries(props).filter(([k]) => !["initial", "animate", "exit", "transition", "variants", "whileHover", "whileTap", "layout", "layoutId"].includes(k)));
    return React.createElement(Tag, {
      ...rest,
      ref
    });
  });
  const cache = {};
  return {
    motion: new Proxy({}, {
      get: (_, tag) => {
        if (!cache[tag]) cache[tag] = passthrough(tag);
        return cache[tag];
      }
    }),
    AnimatePresence: ({children}) => React.createElement(React.Fragment, null, children),
    useReducedMotion: () => true
  };
};

export const AuthContext = React.createContext(null);

export const useAuthContext = () => React.useContext(AuthContext);

export const buildModules = deps => {
  const mods = {};
  mods.authctx = (() => {
    const DOCS_APP_ORIGIN_STORAGE_KEY = STORAGE_KEY;
    const useAuth = () => useAuthContext();
    return {
      DOCS_APP_ORIGIN_STORAGE_KEY,
      useAuth,
      clearDocsSession: () => {}
    };
  })();
  mods.constants = (() => {
    const DOCS_APP_ORIGIN_CLIENT_ID = "docs-app-origin";
    function docsAppOriginWebAuthn() {
      if (typeof window === "undefined" || window.location.protocol !== "https:") {
        return {
          mode: "app_origin"
        };
      }
      return {
        mode: "app_origin",
        rpId: window.location.hostname
      };
    }
    const DOCS_EXPERIMENTAL_CLEAR_SIGNING = true;
    const APP_ORIGIN_DEMO_CAPABILITIES = {
      payButton: true,
      eip1193Transactions: true,
      sendCalls: true,
      batchCalls: true,
      messageSigning: true,
      typedDataSigning: true,
      batchIntents: true,
      smartSessions: true,
      walletConnection: true,
      recovery: true
    };
    const DOCS_DIALOG_THEME = {
      mode: "dark",
      accent: "#ffffff",
      backdrop: {
        color: "#52525c",
        opacity: 0.5,
        blur: 12
      }
    };
    const MOCK_USD_ADDRESS = "0x2f6fdE5E2AeAB6335d8f978B4d8B2a9c1129AcFb";
    const RECIPIENT_ADDRESS = "0x180b791BD181DF1773E4e33cb0374b258936d186";
    const MOCK_RWA_ADDRESS = "0x5948C7E284174f6Df0f2505fb3CBFbd685154323";
    const MOCK_SWAP_ADDRESS = "0xf2DFDC35d46e62F6D026afa36Cc6e941174B67f1";
    const MOCK_NFT_V2_ADDRESS = "0x99CCb273351Cf13713F7Bf5A0716d7C2a3DD4712";
    const MOCK_NFT_LUIGI_ID = 1n;
    const NVDA_ICON_SVG = `<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="250" height="250" fill="#76B900"/><path d="M99.5748 98.4439V86.5224C100.752 86.4488 101.93 86.3752 103.107 86.3752C135.781 85.345 157.195 114.486 157.195 114.486C157.195 114.486 134.088 146.571 109.289 146.571C105.977 146.571 102.739 146.056 99.6484 145.026V108.82C112.379 110.365 114.955 115.958 122.535 128.689L139.534 114.413C139.534 114.413 127.097 98.1495 106.198 98.1495C103.99 98.0759 101.782 98.2231 99.5748 98.4439ZM99.5748 59V76.8086L103.107 76.5878C148.512 75.0425 178.168 113.824 178.168 113.824C178.168 113.824 144.17 155.181 108.773 155.181C105.683 155.181 102.666 154.887 99.6484 154.372V165.41C102.15 165.705 104.726 165.925 107.228 165.925C140.196 165.925 164.039 149.073 187.146 129.204C190.973 132.295 206.647 139.727 209.885 142.965C187.956 161.363 136.811 176.154 107.817 176.154C105.02 176.154 102.371 176.007 99.722 175.713V191.24H224.971V59L99.5748 59ZM99.5748 145.026V154.445C69.1088 149 60.646 117.283 60.646 117.283C60.646 117.283 75.2903 101.093 99.5748 98.4439V108.746H99.5012C86.7702 107.201 76.7621 119.122 76.7621 119.122C76.7621 119.122 82.4285 139.212 99.5748 145.026ZM45.4866 115.958C45.4866 115.958 63.516 89.3188 99.6484 86.5224V76.8086C59.6158 80.0465 25.0288 113.898 25.0288 113.898C25.0288 113.898 44.6036 170.561 99.5748 175.713V165.41C59.2478 160.406 45.4866 115.958 45.4866 115.958Z" fill="white"/></svg>`;
    const NVDA_ICON_DATA_URL = `data:image/svg+xml;utf8,${encodeURIComponent(NVDA_ICON_SVG)}`;
    const LUIGI_ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="none" viewBox="0 0 28 28"><rect width="28" height="28" fill="#32a742" rx="4"/><path fill="#101110" d="M13 5.4h.9a7 7 0 0 1 4 1.1q1.3 1 2 2.4l.3.5.5-.6L22 7.5q1-.9 2.2-1.3h.5l.4.3v.8a9 9 0 0 1-2.5 4.4l-.6.6q.6.7.2 1.7t-1.4 1.6l.2.8q.4 2-.5 3.6l-.4.5a8 8 0 0 1-5.7 2.1h-1l-1.8-.3-.5-.2-.9-.3q-1-.4-1.8-1.2-.6-.6-1-1.4a5 5 0 0 1 0-3.6q-.9-.3-1.3-.9-.5-.9-.1-2v-.1L3.8 10q-.9-1.3-1-2.8 0-.5.3-.6C4 6.6 6 8 6.8 8.8l.9.9q.4-1 1.1-2c1.2-1.5 2.3-2 4.2-2.3"/><path fill="#f7c30f" d="M8.5 14q1.1.7 2.4.5c1-.2 2.3-1 3.3-.9l1.6.4.3.1.6.2q1.6.4 2.8-.5l.2.2c.8 1.3 1.5 3.3 1 4.8l-.5 1c0 .2-.7.8-.9.9l-.3.2-.3.2q-.6.5-1.3.6a9 9 0 0 1-7.6-.4l-.5-.4-.6-.4-.6-.7-.4-.7c-.5-.8-.4-2.4-.1-3.2q.1-.8.6-1.4l.1-.2z"/><path fill="#fb9410" d="M17.7 20.8q0 .3.4.3h.6q-.6.5-1.3.6a9 9 0 0 1-7.6-.4q.5 0 .9-.3 3.4.9 6.7 0z"/><path fill="#e0051c" d="M17.6 20.2c.2-1.5 2.6-3 2.8-1.5h.3l-.5 1.1c0 .2-.7.8-.9.9l-.3.2-.3.2H18q-.3 0-.4-.3z"/><path fill="#870c0d" d="M17.6 20.2c.2-1.5 2.6-3 2.8-1.5h.3l-.5 1.1c0 .2-.7.8-.9.9l.4-.5q.6-.7.6-1.5l-.3-.1h-.8q-.6.4-1 1l-.4.4h-.1z"/><path fill="#fb99a0" d="m17.8 20 .3-.7c.4-.6 1.3-1.4 2-1l.2.4-.3-.1h-.8q-.6.4-1 1z"/><path fill="#fac550" d="M20.4 18.7h.3l-.5 1.1v-.2q.3-.5.2-.9"/><path fill="#870c0d" d="m17.6 20.2.1-.1q-.1.6.4.9h.6l.3-.1-.3.2H18q-.3 0-.4-.3z"/><path fill="#e0051c" d="M7.9 19q0-.7.7-.7c1 0 2.5 1.7 2 2.7q-.2.4-.8.3l-.5-.4-.6-.4-.6-.7-.4-.7z"/><path fill="#870c0d" d="M7.9 19q0-.7.7-.7c1 0 2.5 1.7 2 2.7q-.2.4-.8.3l-.5-.4c.4 0 .4.3 1 .2l.3-.3q0-.5-.2-.9l-.5-.6Q9 18.4 8 19l.2.9-.1-.2v.2l-.4-.7z"/><path fill="#fb99a0" d="M8 18.9q.2-.6.8-.5a3 3 0 0 1 1.7 1.5l-.6-.6Q9 18.4 8 19"/><path fill="#fac550" d="M7.7 19h.2q0 .4.2.6v.2z"/><path fill="#831218" d="m8 19.6.2.2q.4.3.5.7l-.6-.7z"/><path fill="#101110" d="M17.4 14.9h.7q1.2.8.6 2v.1q-.4.5-1 .6-.8-.2-1-.8-.3-.6 0-1.2t.7-.7"/><path fill="#f2f0ee" d="M17.3 15.2q.3 0 .5.2v.3q0 .3-.3.3-.4 0-.5-.2-.2-.5.3-.6"/><path fill="#fb9410" d="M8.5 14q1.1.7 2.4.5c1-.2 2.3-1 3.3-.9l1.6.4.3.1.6.2q1.6.4 2.8-.5l.2.2-.6.5-.7.3H18v.1h-.6c0-.2-.8-.2-1-.2q-1.3-.4-2.7-.6l-1.3.3c-1.8.5-2.3.7-4 0l-.1-.1z"/><path fill="#fac550" d="m8.3 14.3-.1.2h-.1z"/><path fill="#101110" d="m14.1 17.6.3.1a5 5 0 0 0 2.8.3l.6-.1.1.2c.1 1.7-1.6 2.1-3 1.8l-.8-.3-.4.1-.7.3-1.2-.1c-.7-.2-1.6-.9-1.3-1.7q0-.2.3 0 1.7.4 3.3-.6M10.2 15c1.6-.2 1.9 2.3.4 2.7l-.6-.1c-1.1-.5-1-2.4.2-2.6"/><path fill="#f2f0ee" d="M10.6 15.3q.3 0 .5.2v.4q0 .2-.3.2h-.2l-.3-.2q-.2-.5.3-.6"/><path fill="#101110" d="m14 17.2.3.1v.2q-.5 0-.4-.3"/><path fill="#008a4d" d="M8.4 10.7 8 10c-.1-.2.3-.9.4-1A6 6 0 0 1 11 6.3c1.5-.7 3.5-.8 5-.2q2.2.7 3.3 2.6.4.4.6 1l-.2.3-.5.8-.7 1.2-.7-.4 1 1.2-.6-.5a7 7 0 0 0-2.3-1q.7-1 .5-2t-1-1.5a3 3 0 0 0-4 .7c-.4.8-.4 2 .2 2.7l.2.2-1.5.6-.8.5v-.2l.3-.4.1-.3-.2.1-.4.4V12z"/><path fill="#80c491" d="M8.4 10.7 8 10c-.1-.2.3-.9.4-1A6 6 0 0 1 11 6.3c1.5-.7 3.5-.8 5-.2q2.2.7 3.3 2.6.4.4.6 1l-.2.3v-.2l-.7-.9q-.7-1-1.7-2a6 6 0 0 0-2.8-1 6 6 0 0 0-4.6 2c-.5.5-1.3 2-1.6 2.8"/><path fill="#064634" d="m19.7 9.8.1.2-.5.8-.7 1.2q-.4-.4-.7-.4l1 1.2-.6-.5-1-.5.1-.4q.3-.3 1-.4.9-.3 1.3-1.2"/><path fill="#80c491" d="M10 11.6h.3l-.4.3zm-.7.4.5-.3z"/><path fill="#008a4d" d="M9.6 12.9a7 7 0 0 1 6.8-1.2l1 .4a7 7 0 0 1 2 1.5c-.8.7-2 .5-2.8.3q-.6 0-1-.3c-1.4-.4-1.7-.5-3 0l-1.8.6a3 3 0 0 1-2.2-.5z"/><path fill="#064634" d="M17.3 12.1a7 7 0 0 1 2 1.5c-.7.7-1.8.5-2.7.3.8-.6 1-.7.7-1.8"/><path fill="#80c491" d="M9.6 12.9c.1.5-.1.5.4 1s2.3-.4 2.5-.3q-.8.4-1.7.6a3 3 0 0 1-2.2-.5z"/><path fill="#f2f0ee" d="M13.8 7.6q1 0 1.8.6 1.5 1.4.1 3a9 9 0 0 0-3.6.1q-.6-.5-.7-1.3.1-2.3 2.4-2.4"/><path fill="#008a4d" d="m13.6 8-.1 2h1.6v.8h-2.3V8z"/><path fill="#fb9410" d="m18.8 12.3.3-.7q1-1.7 2.4-3.2l.7-.7.2.3 1 2.4-3 2.9-.6.4-.8-1.3z"/><path fill="#f7c30f" d="m18.8 12.3.3-.7q1-1.7 2.4-3.2l.7-.7.2.3.3.8-.8.5-.7.5-1 1-.9.8z"/><path fill="#fbeca3" d="m18.8 12.3.3-.7q1-1.7 2.4-3.2l.7-.7.2.3-.3.3a14 14 0 0 0-2.5 2.9l-.3.4z"/><path fill="#fb9410" d="M5.4 8.1q2 1.5 3.3 3.6l.5.7-.1.2q-.6.5-.8 1.2l-.8-.5q-1.6-1.1-3-2.7l.7-2.1z"/><path fill="#f7c30f" d="M5.4 8.1q2 1.5 3.3 3.6l.5.7-.1.2H9l-.6-.8-1.5-1.6-.7-.5-1-.7H5z"/><path fill="#fbeca3" d="M5.4 8.1a14 14 0 0 1 3.4 3.7h-.1C8.2 11 6 8.9 5.3 8.5z"/><path fill="#fac550" d="m8.7 11.7.5.7-.1.2v-.3z"/><path fill="#064634" d="M21.7 12.5c.7 1.1 0 2.2-1 2.8l-.2-.3-.5-1zm-15.4.3 1.2.9.6.4-.5.9-.2.3q-.8-.3-1.2-1.1-.2-.8 0-1.4"/><path fill="#f2f0ee" d="M24.3 6.5h.4l-.5.4-1.5.9h-.2l-.1-.2a5 5 0 0 1 1.9-1.1M3.2 7a6 6 0 0 1 2 1v.2H5l-.8-.4L3 7.3z"/><path fill="#1f5e4c" d="m9.3 12.7.3-.4v.1z"/></svg>`;
    const LUIGI_ICON_DATA_URL = `data:image/svg+xml;utf8,${encodeURIComponent(LUIGI_ICON_SVG)}`;
    const MUSD_ICON_SVG = `<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0_4758_159829)"><g filter="url(#filter0_i_4758_159829)"><path d="M124.999 249.149C193.565 249.149 249.149 193.565 249.149 124.999C249.149 56.4325 193.565 0.848633 124.999 0.848633C56.4325 0.848633 0.848633 56.4325 0.848633 124.999C0.848633 193.565 56.4325 249.149 124.999 249.149Z" fill="white"/></g><path d="M101.7 211.35C101.7 214.25 99.3499 215.9 96.6499 215.05C59.0499 203 31.8999 167.85 31.8999 126.25C31.8999 84.7497 59.0499 49.5497 96.6999 37.4997C99.4999 36.6497 101.75 38.2997 101.75 41.1997V48.4497C101.75 50.3997 100.3 52.5997 98.4499 53.2997C68.6499 64.2497 47.4499 92.8497 47.4499 126.25C47.4499 159.7 68.6999 188.25 98.4499 199.1C100.3 199.8 101.75 202 101.75 203.95V211.35H101.7Z" fill="black"/><path d="M132.752 184.451C132.752 186.601 131.002 188.351 128.852 188.351H121.102C118.952 188.351 117.202 186.601 117.202 184.451V172.251C100.252 169.901 92.0016 160.501 89.7516 147.501C89.3516 145.251 91.1016 143.351 93.3516 143.351H102.202C104.052 143.351 105.602 144.701 106.002 146.451C107.652 154.101 112.102 160.051 125.702 160.051C135.702 160.051 142.852 154.401 142.852 146.101C142.852 137.751 138.702 134.551 123.952 132.151C102.202 129.251 91.9516 122.651 91.9516 105.651C91.9516 92.5512 101.952 82.2512 117.252 80.1512V68.1012C117.252 65.9512 119.002 64.2012 121.152 64.2012H128.902C131.052 64.2012 132.802 65.9512 132.802 68.1012V80.4012C145.302 82.6512 153.252 89.7012 155.902 101.551C156.402 103.801 154.652 105.801 152.302 105.801H144.152C142.402 105.801 140.952 104.651 140.452 103.001C138.202 95.5512 132.902 92.2512 123.552 92.2512C113.252 92.2512 107.952 97.2012 107.952 104.201C107.952 111.551 110.952 115.251 126.752 117.501C148.102 120.401 159.152 126.501 159.152 144.651C159.152 158.401 148.852 169.601 132.852 172.101V184.501H132.752V184.451Z" fill="black"/><path d="M153.3 214.997C150.5 215.847 148.25 214.197 148.25 211.297V204.047C148.25 201.897 149.5 199.897 151.55 199.197C181.25 188.347 202.55 159.697 202.55 126.347C202.55 92.897 181.3 64.347 151.55 53.497C149.7 52.797 148.25 50.597 148.25 48.647V41.397C148.25 38.497 150.6 36.847 153.3 37.697C190.95 49.547 218.1 84.747 218.1 126.247C218.1 167.847 190.95 202.997 153.3 214.997Z" fill="black"/></g><defs><filter id="filter0_i_4758_159829" x="0.848633" y="0.848633" width="248.3" height="248.3" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/><feOffset/><feGaussianBlur stdDeviation="41.5"/><feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/><feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/><feBlend mode="normal" in2="shape" result="effect1_innerShadow_4758_159829"/></filter><clipPath id="clip0_4758_159829"><rect width="250" height="250" fill="white"/></clipPath></defs></svg>`;
    const MUSD_ICON_DATA_URL = `data:image/svg+xml;utf8,${encodeURIComponent(MUSD_ICON_SVG)}`;
    const USDC_BASE_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
    const USDC_BASE_SEPOLIA_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
    const USDC_ARB_SEPOLIA_ADDRESS = "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d";
    const BASE_SEPOLIA_CHAIN_ID = 84532;
    const ARB_SEPOLIA_CHAIN_ID = 421614;
    const erc20Abi = [{
      name: "transfer",
      type: "function",
      stateMutability: "nonpayable",
      inputs: [{
        name: "to",
        type: "address"
      }, {
        name: "amount",
        type: "uint256"
      }],
      outputs: [{
        name: "",
        type: "bool"
      }]
    }, {
      name: "approve",
      type: "function",
      stateMutability: "nonpayable",
      inputs: [{
        name: "spender",
        type: "address"
      }, {
        name: "amount",
        type: "uint256"
      }],
      outputs: [{
        name: "",
        type: "bool"
      }]
    }, {
      name: "mint",
      type: "function",
      stateMutability: "nonpayable",
      inputs: [{
        name: "to",
        type: "address"
      }, {
        name: "amount",
        type: "uint256"
      }],
      outputs: []
    }, {
      name: "balanceOf",
      type: "function",
      inputs: [{
        name: "account",
        type: "address"
      }],
      outputs: [{
        name: "",
        type: "uint256"
      }],
      stateMutability: "view"
    }];
    const mockSwapAbi = [{
      name: "swap",
      type: "function",
      stateMutability: "nonpayable",
      inputs: [{
        name: "usdcIn",
        type: "uint256"
      }, {
        name: "minRwaOut",
        type: "uint256"
      }, {
        name: "recipient",
        type: "address"
      }],
      outputs: [{
        name: "rwaOut",
        type: "uint256"
      }]
    }, {
      name: "quote",
      type: "function",
      stateMutability: "view",
      inputs: [{
        name: "usdcIn",
        type: "uint256"
      }],
      outputs: [{
        name: "rwaOut",
        type: "uint256"
      }]
    }, {
      name: "getPrice",
      type: "function",
      stateMutability: "view",
      inputs: [],
      outputs: [{
        name: "price",
        type: "uint256"
      }]
    }, {
      name: "pricePerShare",
      type: "function",
      stateMutability: "view",
      inputs: [],
      outputs: [{
        name: "",
        type: "uint256"
      }]
    }, {
      name: "jitterRange",
      type: "function",
      stateMutability: "view",
      inputs: [],
      outputs: [{
        name: "",
        type: "uint256"
      }]
    }];
    const mockNftV2Abi = [{
      name: "buy",
      type: "function",
      stateMutability: "nonpayable",
      inputs: [{
        name: "id",
        type: "uint256"
      }, {
        name: "amount",
        type: "uint256"
      }, {
        name: "recipient",
        type: "address"
      }],
      outputs: [{
        name: "totalPrice",
        type: "uint256"
      }]
    }, {
      name: "priceOf",
      type: "function",
      stateMutability: "view",
      inputs: [{
        name: "id",
        type: "uint256"
      }],
      outputs: [{
        name: "",
        type: "uint256"
      }]
    }];
    return {
      docsAppOriginWebAuthn,
      DOCS_APP_ORIGIN_CLIENT_ID,
      DOCS_EXPERIMENTAL_CLEAR_SIGNING,
      APP_ORIGIN_DEMO_CAPABILITIES,
      DOCS_DIALOG_THEME,
      MOCK_USD_ADDRESS,
      RECIPIENT_ADDRESS,
      MOCK_RWA_ADDRESS,
      MOCK_SWAP_ADDRESS,
      MOCK_NFT_V2_ADDRESS,
      MOCK_NFT_LUIGI_ID,
      NVDA_ICON_DATA_URL,
      LUIGI_ICON_DATA_URL,
      MUSD_ICON_DATA_URL,
      USDC_BASE_ADDRESS,
      USDC_BASE_SEPOLIA_ADDRESS,
      USDC_ARB_SEPOLIA_ADDRESS,
      BASE_SEPOLIA_CHAIN_ID,
      ARB_SEPOLIA_CHAIN_ID,
      erc20Abi,
      mockSwapAbi,
      mockNftV2Abi
    };
  })();
  mods.appOriginDemo = (() => {
    const {useCallback, useEffect, useRef, useState} = deps.React;
    const {OneAuthClient} = deps.sdk;
    const {encodeFunctionData, parseUnits} = deps.viem;
    const {DOCS_APP_ORIGIN_STORAGE_KEY, useAuth} = mods.authctx;
    const {BASE_SEPOLIA_CHAIN_ID, DOCS_APP_ORIGIN_CLIENT_ID, DOCS_EXPERIMENTAL_CLEAR_SIGNING, MOCK_USD_ADDRESS, docsAppOriginWebAuthn, erc20Abi} = mods.constants;
    const ACCOUNT_STORAGE_KEY = DOCS_APP_ORIGIN_STORAGE_KEY;
    function AppOriginDemo() {
      const {sponsorship} = useAuth();
      const [client, setClient] = useState(null);
      const [actionState, setActionState] = useState(null);
      const [accountAddress, setAccountAddress] = useState(null);
      const mounted = useRef(false);
      const sessionGeneration = useRef(0);
      useEffect(() => {
        const authUrl = backends().auth;
        mounted.current = true;
        const restoreGeneration = ++sessionGeneration.current;
        const nextClient = new OneAuthClient({
          providerUrl: authUrl,
          clientId: DOCS_APP_ORIGIN_CLIENT_ID,
          webauthn: docsAppOriginWebAuthn(),
          experimental_clear_signing: DOCS_EXPERIMENTAL_CLEAR_SIGNING,
          recovery: {
            fallback: {
              type: "verified-identity"
            }
          },
          testnets: true,
          sponsorship
        });
        setClient(nextClient);
        if (window.localStorage.getItem(ACCOUNT_STORAGE_KEY)) {
          void nextClient.getSession().then(result => {
            if (!mounted.current || sessionGeneration.current !== restoreGeneration) return;
            const address = result.success ? result.session.accountAddress : null;
            if (address && (/^0x[0-9a-fA-F]{40}$/).test(address)) {
              setAccountAddress(address);
              window.localStorage.setItem(ACCOUNT_STORAGE_KEY, JSON.stringify({
                address
              }));
            } else {
              window.localStorage.removeItem(ACCOUNT_STORAGE_KEY);
              setAccountAddress(null);
            }
          }).catch(() => {
            if (!mounted.current || sessionGeneration.current !== restoreGeneration) return;
            window.localStorage.removeItem(ACCOUNT_STORAGE_KEY);
            setAccountAddress(null);
          });
        }
        return () => {
          mounted.current = false;
          sessionGeneration.current += 1;
        };
      }, [sponsorship]);
      const acceptAuthResult = useCallback((result, generation) => {
        if (!mounted.current || sessionGeneration.current !== generation || !result.success) return;
        const address = result.session.accountAddress;
        setAccountAddress(address);
        window.localStorage.setItem(ACCOUNT_STORAGE_KEY, JSON.stringify({
          address
        }));
      }, []);
      const runAction = useCallback(async action => {
        if (!client) return;
        const generation = ++sessionGeneration.current;
        setActionState({
          action,
          status: "pending"
        });
        try {
          let response;
          if (action === "create-account") {
            const result = await client.authenticate({
              flow: "create-account",
              oauthEnabled: false
            });
            acceptAuthResult(result, generation);
            response = result;
          } else if (action === "login") {
            const result = await client.authenticate({
              flow: "login"
            });
            acceptAuthResult(result, generation);
            response = result;
          } else if (action === "session") {
            const result = await client.getSession();
            acceptAuthResult(result, generation);
            response = result;
          } else if (action === "disconnect") {
            await client.disconnect();
            if (mounted.current && sessionGeneration.current === generation) {
              setAccountAddress(null);
              window.localStorage.removeItem(ACCOUNT_STORAGE_KEY);
            }
            response = {
              success: true,
              disconnected: true
            };
          } else {
            if (!accountAddress) throw new Error("Create or log in to an account first");
            const amount = parseUnits("0.1", 6);
            response = await client.sendIntent({
              accountAddress,
              targetChain: BASE_SEPOLIA_CHAIN_ID,
              calls: [{
                to: MOCK_USD_ADDRESS,
                data: encodeFunctionData({
                  abi: erc20Abi,
                  functionName: "mint",
                  args: [accountAddress, amount]
                }),
                label: "Claim mUSD",
                sublabel: "Clear-signing testnet demo"
              }],
              sponsorshipMode: "required",
              closeOn: "claimed"
            });
          }
          const succeeded = typeof response !== "object" || response === null || !Object.hasOwn(response, "success") || response.success !== false;
          if (mounted.current && sessionGeneration.current === generation) {
            setActionState({
              action,
              status: succeeded ? "success" : "error",
              response
            });
          }
        } catch (error) {
          if (mounted.current && sessionGeneration.current === generation) {
            setActionState({
              action,
              status: "error",
              response: {
                error: error instanceof Error ? error.message : String(error)
              }
            });
          }
        }
      }, [acceptAuthResult, accountAddress, client]);
      const busy = actionState?.status === "pending";
      const actions = [{
        action: "create-account",
        label: "Create account"
      }, {
        action: "login",
        label: "Log in"
      }, {
        action: "session",
        label: "Check session"
      }, {
        action: "disconnect",
        label: "Disconnect"
      }, {
        action: "send-intent",
        label: "Send test intent"
      }];
      return React.createElement("div", {
        className: "demo-container",
        "data-testid": "docs-app-origin-panel"
      }, React.createElement("div", {
        className: "demo-result"
      }, React.createElement("p", {
        className: "demo-result-label"
      }, "Account"), React.createElement("p", {
        className: "demo-result-value",
        "data-testid": "docs-app-origin-account"
      }, accountAddress ?? "Not connected")), React.createElement("div", {
        style: {
          display: "flex",
          flexWrap: "wrap",
          gap: "0.5rem",
          marginTop: "1rem"
        }
      }, actions.map(({action, label}) => React.createElement("button", {
        className: action === "send-intent" ? "demo-button" : "demo-button-secondary",
        "data-testid": `docs-app-origin-${action}`,
        disabled: !client || busy || action === "send-intent" && !accountAddress,
        key: action,
        onClick: () => void runAction(action)
      }, busy && actionState.action === action ? "Working\u2026" : label))), actionState && React.createElement("div", {
        className: `demo-result ${actionState.status === "success" ? "demo-result-success" : actionState.status === "error" ? "demo-result-error" : ""}`,
        "data-testid": `docs-app-origin-result-${actionState.action}`
      }, React.createElement("p", {
        className: "demo-result-label"
      }, actionState.action), React.createElement("p", {
        className: "demo-result-value",
        "data-testid": "docs-app-origin-result-status"
      }, actionState.status), actionState.response !== void 0 && React.createElement("pre", {
        className: "demo-result-value",
        style: {
          fontSize: "0.75rem",
          overflowWrap: "anywhere",
          whiteSpace: "pre-wrap"
        }
      }, JSON.stringify(actionState.response, null, 2))));
    }
    return {
      AppOriginDemo
    };
  })();
  return mods;
};

export const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;

export const readStoredAddressFromJsonEnvelope = () => {
  try {
    const raw = window.localStorage.getItem(STORAGE_KEY);
    if (!raw) return null;
    const parsed = JSON.parse(raw);
    const address = parsed && typeof parsed === "object" ? parsed.address : null;
    return typeof address === "string" && ADDRESS_RE.test(address) ? address : null;
  } catch {
    return null;
  }
};

export const writeStoredAddressAsJsonEnvelope = address => {
  window.localStorage.setItem(STORAGE_KEY, JSON.stringify({
    address
  }));
};

export const useOneAuth = deps => {
  const [address, setAddress] = React.useState(null);
  const [client, setClient] = React.useState(null);
  const mounted = React.useRef(false);
  const sessionGeneration = React.useRef(0);
  React.useEffect(() => {
    if (!deps) return;
    mounted.current = true;
    const restoreGeneration = ++sessionGeneration.current;
    const {OneAuthClient} = deps.sdk;
    const nextClient = new OneAuthClient({
      providerUrl: backends().auth,
      clientId: "docs-app-origin",
      webauthn: {
        mode: "app_origin",
        rpId: window.location.hostname
      },
      theme: {
        mode: "dark",
        accent: "#ffffff",
        backdrop: {
          color: "#52525c",
          opacity: 0.5,
          blur: 12
        }
      },
      experimental_clear_signing: true,
      recovery: {
        fallback: {
          type: "verified-identity"
        }
      },
      testnets: true,
      prewarm: true,
      sponsorship,
      onDisconnect: () => {
        if (!mounted.current) return;
        sessionGeneration.current += 1;
        window.localStorage.removeItem(STORAGE_KEY);
        setAddress(null);
      }
    });
    setClient(nextClient);
    const stored = readStoredAddressFromJsonEnvelope();
    if (stored) {
      nextClient.getSession().then(result => {
        if (!mounted.current || sessionGeneration.current !== restoreGeneration) return;
        const account = result.success ? result.session.accountAddress : null;
        if (account && ADDRESS_RE.test(account)) {
          writeStoredAddressAsJsonEnvelope(account);
          setAddress(account);
        } else {
          window.localStorage.removeItem(STORAGE_KEY);
          setAddress(null);
        }
      }).catch(() => {
        if (!mounted.current || sessionGeneration.current !== restoreGeneration) return;
        window.localStorage.removeItem(STORAGE_KEY);
        setAddress(null);
      });
    }
    return () => {
      mounted.current = false;
      sessionGeneration.current += 1;
    };
  }, [deps]);
  const login = React.useCallback(async () => {
    if (!client) return null;
    const generation = ++sessionGeneration.current;
    const result = await client.authenticate({
      oauthEnabled: false
    });
    if (!result.success) {
      if (result.error?.code === "USER_CANCELLED") return null;
      throw new Error(result.error?.message ?? "Authentication failed");
    }
    const account = result.session.accountAddress;
    if (!ADDRESS_RE.test(account)) throw new Error("Authentication returned an invalid account address");
    if (!mounted.current || sessionGeneration.current !== generation) return null;
    writeStoredAddressAsJsonEnvelope(account);
    setAddress(account);
    return account;
  }, [client]);
  const logout = React.useCallback(() => {
    sessionGeneration.current += 1;
    window.localStorage.removeItem(STORAGE_KEY);
    if (mounted.current) setAddress(null);
    if (client?.disconnect) client.disconnect();
  }, [client]);
  return React.useMemo(() => ({
    address,
    isAuthenticated: !!address,
    client,
    sponsorship,
    login,
    logout
  }), [address, client, login, logout]);
};

export const Frame = ({children, connected}) => <div className="oa-demo">
    <div className="oa-demo-head">
      <span className="oa-demo-title">Try a passkey account</span>
    </div>
    <div className="oa-demo-body">{children}</div>
  </div>;

export const AppOriginDemo = () => {
  const [deps, setDeps] = React.useState(null);
  const [loadError, setLoadError] = React.useState("");
  const [connecting, setConnecting] = React.useState(false);
  React.useEffect(() => {
    let cancelled = false;
    loadDeps().then(d => !cancelled && setDeps(d)).catch(e => !cancelled && setLoadError(String(e.message ?? e)));
    return () => {
      cancelled = true;
    };
  }, []);
  const mods = React.useMemo(() => deps ? buildModules(deps) : null, [deps]);
  const auth = {
    sponsorship
  };
  return <div className="not-prose rhinestone-1auth-demo" data-demo="app-origin">
      <style dangerouslySetInnerHTML={{
    __html: CSS
  }} />
      <AuthContext.Provider value={auth}>
        <Frame connected={auth.isAuthenticated}>
          {mods && auth.client && false && !auth.isAuthenticated ? <div>
              <button className="demo-button" disabled={connecting} onClick={async () => {
    setConnecting(true);
    setLoadError("");
    try {
      await auth.login();
    } catch (error) {
      setLoadError(String(error.message ?? error));
    } finally {
      setConnecting(false);
    }
  }}>{connecting ? "Signing in..." : "Sign in to try it"}</button>
              {loadError ? <p className="demo-error">{loadError}</p> : null}
            </div> : mods && (auth.client || true) ? React.createElement(mods.appOriginDemo.AppOriginDemo, {
    key: auth.address
  }) : loadError ? <p className="demo-error">{loadError}</p> : <span className="oa-demo-skeleton" />}
        </Frame>
      </AuthContext.Provider>
    </div>;
};

Embedded wallets give each user a passkey-controlled smart account for your application. The account has the same address on every supported EVM chain, but it is isolated from accounts the same person creates in other applications.

## Before you start

* Use Node.js and a browser application served over HTTPS. The hosted provider does not accept plain `http://localhost`; use local HTTPS for development.
* [Register your application and domains in the Dashboard](/home/resources/dashboard).
* [Configure sponsorship token endpoints](/transactions/sponsorship/set-up) before calling intent or asset methods. Authentication itself does not require a funded account.

## Install the SDK

<CodeGroup>
  ```bash npm theme={null}
  npm install @rhinestone/1auth
  ```

  ```bash pnpm theme={null}
  pnpm add @rhinestone/1auth
  ```

  ```bash yarn theme={null}
  yarn add @rhinestone/1auth
  ```
</CodeGroup>

The examples on this page are supported by the public `@rhinestone/1auth` `0.10.1` release.

## Initialize the client

Create one client and reuse it throughout your application:

```ts oneauth.ts {3} theme={null}
import { OneAuthClient } from "@rhinestone/1auth"

export const oneAuth = new OneAuthClient({
  providerUrl: "https://passkey.1auth.app",
  clientId: "my-app",
  sponsorship: {
    accessTokenUrl: "/api/sponsorship/access-token",
    extensionTokenUrl: "/api/sponsorship/extension-token",
  },
})
```

Replace `my-app` with the client ID of your registered application. The sponsorship URLs are same-origin backend endpoints; follow [Sponsorship setup](/transactions/sponsorship/set-up) to implement them.

## Authenticate and obtain an account

```ts {3,9} theme={null}
import { oneAuth } from "./oneauth"

const auth = await oneAuth.authenticate()

if (!auth.success) {
  throw new Error(auth.error.message)
}

const accountAddress = auth.session.accountAddress
console.log(accountAddress)
```

`accountAddress` is a typed `0x${string}` address. Authentication creates an account when the verified identity has none in your application's namespace, or signs in to the existing account.

To restore a current wallet session without opening the dialog, call `getSession()`:

```ts theme={null}
const session = await oneAuth.getSession()
const accountAddress = session.success
  ? session.session.accountAddress
  : undefined
```

## Account isolation

Passkeys are created and used on your application's domain. By default, each hostname has its own passkey and account namespace, even when the user verifies the same email or OAuth identity. Funding and recovery configuration remain isolated to that namespace.

See [Passkeys and domains](/wallets/embedded-wallets/passkeys-and-domains) before sharing accounts across subdomains or changing your production hostname. Changing the RP ID selects a different account; existing balances do not move automatically.

## Account management

Build account management in your application. Account-management popups, redirect signing, inline-embed signing, and `openAccountDialog()` are not supported for these wallets and return `APP_ORIGIN_FLOW_UNSUPPORTED`.

## Try an account

Create or use a passkey for this docs hostname, then check the session or send a test transaction. The test intent mints 0.1 mUSD on Base Sepolia with sponsored fees. It uses clear signing: review the prepared action before approving the passkey prompt.

<AppOriginDemo />
