Observed since 20 Oct, 22:03 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
0account web integration library
Browser-native OAuth2/OIDC authentication widget for 0account.
Drop in a <zero-account> element — it handles PKCE, QR code, SSE polling, and redirects.
npm install @0account/web
Or via CDN (no build step):
<script type="module" src="https://unpkg.com/@0account/web/dist/0account-web.js"></script>
The widget covers the full auth flow for you. Add the element, listen for one event.
<zero-account
app-id="YOUR_APP_ID"
redirect-uri="https://yourapp.com/callback"
finalize-uri="https://yourapp.com/api/auth/finalize"
scope="openid profile email"
with-button
></zero-account>
import "@0account/web";
document.querySelector("zero-account")
.addEventListener("0account-authenticated", (e) => {
// Code exchange was handled by finalize-uri — you're done.
console.log("logged in", e.detail);
});
Your finalize-uri backend receives { code, code_verifier, state, nonce, redirect_uri } as JSON.
Exchange the code with 0account's /oauth/token endpoint there.
Add mode="redirect" and the widget navigates to redirect-uri automatically:
<zero-account
app-id="YOUR_APP_ID"
redirect-uri="https://yourapp.com/callback"
finalize-uri="https://yourapp.com/api/auth/finalize"
mode="redirect"
with-button
></zero-account>
The callback URL includes the auth code as a query param and the session token in the hash:
https://yourapp.com/callback?code=…&state=…#za_session_token=…
| Attribute | Required | Description |
|---|---|---|
app-id | ✅ | Your OAuth2 application ID |
redirect-uri | ✅ | OAuth redirect URI |
finalize-uri | Your backend endpoint that receives the auth code and completes the exchange | |
scope | OAuth scopes, space-separated (default: openid profile) | |
mode | redirect — navigate to redirect-uri automatically after login | |
environment | development points to staging API | |
theme | light / dark | |
embedded | Render inline instead of as a modal | |
state | Optional OAuth state parameter | |
with-button | Show a pre-built trigger button | |
label-* | Override any UI label (e.g. label-sign-in-to) |
All events fire on the <zero-account> element with bubbles: true, composed: true.
| Event | When | event.detail |
|---|---|---|
0account-authenticated | Auth completes | { code, state, nonce, sessionToken, redirectUri } |
0account-pending | An approval is being confirmed — typically as the user returns from the mobile app | { reason: "confirming" } |
0account-error | The login cannot continue | { reason } — see below |
0account-logout | Server sends logout event | { action: "logout" } |
0account-trigger-open | Widget opens | — |
0account-trigger-close | Widget closes | — |
0account-error reasonsreason | Meaning | Suggested handling |
|---|---|---|
network_unavailable | The request never reached your backend. The user's approval is still good; only the trip failed. | Offer a retry — this is not a rejected login |
finalize_failed | Your finalize-uri answered with a non-2xx status | Treat as a failed login |
session_expired | The session lapsed. Attach mode only (session-id set), where the widget cannot mint a replacement. | Restart the OIDC flow |
no_session_data | The PKCE verifier was missing from sessionStorage — blocked storage, or already consumed | Restart the login |
not_configured | app-id or redirect-uri was missing when the widget was opened | Fix the integration |
In the default widget flow an expired session is not reported as an error: the widget quietly mints a fresh one so the user can simply tap again.
Dispatch 0account-trigger-open / 0account-trigger-close on document to open/close the widget from anywhere:
document.dispatchEvent(new Event("0account-trigger-open"));
In mode="redirect", the callback page needs the PKCE verifier to exchange the code.
Read it with ZeroAccount.getSessionData() — this clears the value from sessionStorage on first call.
import { ZeroAccount } from "@0account/web";
const params = new URLSearchParams(location.search);
const code = params.get("code");
const data = ZeroAccount.getSessionData("YOUR_APP_ID"); // { verifier, nonce }
// Exchange the code on your backend
await fetch("/api/auth/finalize", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
code,
code_verifier: data.verifier,
state: params.get("state"),
nonce: data.nonce,
redirect_uri: "https://yourapp.com/callback",
}),
});
When redirecting a user to a different subdomain that also has the <zero-account> widget, include the session token in the URL hash — the widget reads and clears it automatically:
window.location.href = `https://app2.yoursite.com/dashboard#za_session_token=${encodeURIComponent(sessionToken)}`;
All types are included. Key exports:
import {
ZeroAccount, // Custom Element class
ZeroAccountEvents, // Event name constants
} from "@0account/web";
MIT
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 1.7.0Registry latest | 26 Aug 2026 | 5 | |
| 1.6.0 | 23 Aug 2026 | 5 | |
| 1.5.1 | 23 Aug 2026 | 5 | |
| 1.5.0 | 23 Aug 2026 | 5 | |
| 1.4.0 | 23 Aug 2026 | 5 | |
| 1.3.9 | 23 Aug 2026 | 5 | |
| 1.3.8 | 23 Aug 2026 | 5 | |
| 1.3.7 | 3 Aug 2026 | 5 | |
| 1.3.6 | 3 Aug 2026 | 6 | |
| 1.3.5 | 3 Aug 2026 | 6 | |
| 1.3.4 | 13 May 2026 | 6 | |
| 1.3.3 | 12 May 2026 | 6 | |
| 1.3.2 | 11 May 2026 | 6 | |
| 1.3.1 | 9 May 2026 | 6 | |
| 1.3.0 | 28 Apr 2026 | 6 | |
| 1.2.9 | 26 Apr 2026 | 6 | |
| 1.2.8 | 26 Apr 2026 | 6 | |
| 1.2.7 | 25 Apr 2026 | 6 | |
| 1.2.6 | 19 Apr 2026 | 6 | |
| 1.2.5 | 19 Apr 2026 | 6 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 22:03 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:adb78903d61ad9965950e894284034f46b0111b90feed40ffb019a48d16de4c5