Browser SDK for logi (1pass) — OAuth 2.0 + OIDC PKCE for SPAs. Zero dependencies, ~3 KB minified.
npm install @logi-auth/browserimport { LogiAuth } from "@logi-auth/browser";
const auth = new LogiAuth({
clientId: "logi_xxx",
redirectUri: window.location.origin + "/auth/callback",
// scopes: ["openid", "profile:basic", "email"], // default
// issuer: "https://api.1pass.dev", // default
});loginButton.addEventListener("click", () => {
auth.signIn({ returnTo: location.pathname });
// → redirects to https://api.1pass.dev/oauth/authorize
});if (auth.hasPendingCallback()) {
try {
const tokens = await auth.handleCallback();
// tokens.accessToken — Bearer token for your API
// tokens.refreshToken — store securely (preferably HttpOnly cookie via your backend)
// tokens.idToken — OIDC identity (decode for UI hints only)
// tokens.returnTo — what you passed to signIn({ returnTo })
// tokens.expiresAt — ms epoch
location.replace(tokens.returnTo ?? "/");
} catch (err) {
if (err instanceof LogiAuthError) {
console.error(err.code, err.message, err.details);
}
}
}const fresh = await auth.refresh(savedRefreshToken);
// fresh.refreshToken is the rotated token — persist the new value.const claims = auth.parseIdToken<{ sub: string; email?: string }>(tokens.idToken!);
// ⚠️ No signature verification. Don't make authorization decisions client-side.Browser PKCE flow is small but easy to get wrong:
- Generating the
code_verifier+ SHA-256code_challenge - Persisting
verifier+stateacross the IdP redirect - Validating returned
stateto defeat CSRF - Distinguishing
error=callbacks from missing-codecases - Cleaning up
sessionStorageon every exit path (success or failure)
This SDK does all of that in ~250 LOC, zero deps, ESM-only.
- Zero dependencies. Uses
crypto.subtleandfetchdirectly. - Public client. Never sends
client_secret. Token endpoint must acceptnoneauth (logi PKCE clients do). - No signature verification. ID token claims are decoded for UI only; your backend is the trust root and re-verifies via
/.well-known/jwks.json. - sessionStorage by default. Pending handoff is wiped on tab close. Override via
storage:option. - TTL on pending handoff. Stale handoffs (default 10 min) are rejected with
expired_handoff.
- Secure context.
crypto.subtleis undefined on plainhttp://(excepthttp://localhost). Serve your SPA over HTTPS. - Modern browsers. Chromium 92+, Safari 15.4+, Firefox 90+ (anything with
crypto.subtle.digest("SHA-256")andfetch). - Node ≥ 18 if you import this from a server-side test harness or SSR layer.
LogiAuthError with one of:
storage_unavailable—signIn()couldn't persist the PKCE handoff (Safari ITP, iOS private browsing, corp policy). Thrown before redirecting to the IdP so the user doesn't waste a round-trip.no_pending_handoff—handleCallback()called without a priorsignIn()in this tabstate_mismatch— returnedstate≠ persisted (CSRF attempt or stale callback)missing_code— callback URL had nocodeparameterauthorization_server_error— IdP returned?error=...token_exchange_failed—/oauth/tokenPOST failed (HTTP status + truncated body indetails)network_error—fetchrejected (offline, DNS, CORS, TLS)expired_handoff— pending older thanpendingTtlMs
details.bodymay include server payloads. We truncate to 2 KB but logging it to Sentry/Datadog without scrubbing could leak tokens that the IdP echoed in a 4xx response.
- Multi-tab race. Concurrent
signIn()calls in multiple tabs sharesessionStorageper origin, so only the most-recent handoff completes; the older tab'shandleCallback()will fail withstate_mismatch. State-keyed storage is on the v0.2.0 roadmap. - No automatic refresh. Call
auth.refresh(savedRefreshToken)yourself beforeexpiresAt. A token-manager wrapper (@logi-auth/react) is planned.
This SDK only handles the browser. Your backend should:
- Validate
accessTokenagainst/.well-known/jwks.jsonon every protected request - Store
refreshTokenserver-side (HttpOnly cookie) — don't keep it inlocalStorage
For Node.js servers, use a generic OIDC library pointed at https://api.1pass.dev/.well-known/openid-configuration. logi advertises a full discovery document so oauth4webapi, openid-client, next-auth, auth.js all auto-configure.
MIT © Seunghan Kim