npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sveltebase/auth

v2.0.1

Published

Session cookies, SvelteKit auth routes, reactive client state, and Google sign-in for Svelte 5 apps. Plays nicely with `@sveltebase/sync` for real-time session checks.

Readme

@sveltebase/auth

Session cookies, SvelteKit auth routes, reactive client state, and Google sign-in for Svelte 5 apps. Plays nicely with @sveltebase/sync for real-time session checks.

Install

bun add @sveltebase/auth

Peer deps: Svelte 5, SvelteKit. Install @sveltebase/sync if you use client verification or websocket auth.

How sessions work

A session is an HMAC-SHA256 JWT stored in an HTTP-only cookie (sf_session by default). The payload separates profile from claims:

{
  user: { id: "…", /* profile fields mirrored in verifyTable */ },
  claims: { activeRoleId?: "…", /* session-only state */ },
  exp?: number
}

Claims are for things that are not columns on the user row (active role, tenant, etc.). Profile refresh preserves claims. Keep the signing secret private and stable — rotating it logs everyone out. The cookie is signed, not encrypted, so don’t put secrets in the snapshot.

Entry points

| Import | What it’s for | | --- | --- | | @sveltebase/auth | JWT helpers, cookie parsing, shared errors | | @sveltebase/auth/server | createServerAuth | | @sveltebase/auth/sveltekit | Auth API routes (login, refresh, claims, google, tma) | | @sveltebase/auth/client | Reactive client auth (user + claims) | | @sveltebase/auth/sync | Websocket auth for sync (merges claims onto auth user) | | @sveltebase/auth/google | Google Identity Services UI + server verify | | @sveltebase/auth/telegram | Telegram Mini App verifyInitData + helpers |

Server setup

// src/lib/server/auth.ts
import { createServerAuth } from "@sveltebase/auth/server";
import type { User } from "$lib/types";

type Claims = { activeRoleId?: string };

export const auth = createServerAuth<User, Claims>({
  secret: process.env.JWT_SECRET!
  // cookieName: "sf_session",  // optional
  // cookieOptions: { secure: false }  // for local HTTP
});

Defaults: cookie sf_session, path: "/", httpOnly: true, secure: true, sameSite: "lax".

Methods

await auth.login(cookies, user, { claims: { activeRoleId }, maxAge: 60 * 60 * 24 * 30 });
const session = await auth.getSession(cookies); // { user, claims } | null
const user = await auth.getUser(cookies);       // profile only
await auth.setClaims(cookies, { activeRoleId: "…" });
await auth.refresh(cookies, user);              // preserves claims
auth.logout(cookies);
  • login — signs profile + claims, writes the cookie, returns { user, claims }
  • getSession / getUser / getClaims — verify the cookie
  • setClaims — update claims without reloading the profile
  • refresh — re-signs with a fresh profile; claims are preserved unless overridden
  • logout — deletes the cookie

SvelteKit routes

Mount auth actions at a dynamic route:

// src/routes/api/auth/[auth]/+server.ts
import { createAuthRoutes } from "@sveltebase/auth/sveltekit";
import { auth } from "$lib/server/auth";

export const { GET, POST } = createAuthRoutes({
  auth,

  login: async (credentials, event) => {
    const user = await verifyCredentials(credentials, event);
    if (!user) throw new Error("Invalid credentials");
    return user;
  },

  getUser: async (userId) => findUserById(userId),

  // optional Google login
  google: {
    clientId: env.GOOGLE_CLIENT_ID,
    getUser: async (profile, event) => findOrCreateFromGoogle(profile)
  }
});

| Action | Method | What it does | | --- | --- | --- | | /login | POST | Runs login, sets cookie, returns { user, claims } | | /logout | POST | Clears cookie (204) | | /refresh | POST | Reloads profile via getUser; preserves claims | | /claims | POST | Updates claims (setClaims callback optional) | | /google | POST | Verifies Google ID token, runs google.getUser | | /tma | POST | Verifies Telegram initData, runs tma.getUser |

Login callbacks may return a plain profile or { user, claims }.

Missing callbacks return 404 for that action. Request bodies are JSON (parse failures become {}).

Errors: SvelteKit HttpError keeps its status; app SerializableError subclasses return { code, message } with status 400; other errors are 500.

Client auth

// src/lib/auth.ts
import { createAuth } from "@sveltebase/auth/client";

export const auth = createAuth<User, Claims>({
  routesBase: "/api/auth",
  verifyTable: "users", // optional: sync table for live verification
  reconnect: "if-connected" // default — do not abort a first connect after login
});

Initialize from server load data in a root layout:

<script lang="ts">
  import { auth } from "$lib/auth";

  let { data } = $props();
  auth.init(() => data.user, () => data.claims);
  // Always attach the dynamic client (not only when .client exists):
  auth.setClient(app.sync);
</script>

State

auth.user;            // profile User | null
auth.claims;          // Claims (e.g. { activeRoleId })
auth.session;         // { user, claims } | null
auth.sessionUser;     // flattened User & Claims | null
auth.isReady;         // finished startup
auth.isVerifying;     // refresh or sync check in progress
auth.isAuthenticated; // ready && user != null

Actions

await auth.login({ email, password }, { reconnect: false });
await auth.loginWithGoogle(credential);
await auth.loginWithTma({ initData, domain });
await auth.setClaims({ activeRoleId }, { reconnect: true });
await auth.refresh();
await auth.logout(); // clears cookie + IDB + disconnects sync

If a sync client is attached, login/refresh wait for a matching row in verifyTable (profile only). When that row disappears or verification fails, the client clears the session, runs onInvalidSession / onLogout, wipes local tables, and disconnects.

Useful options

createAuth({
  routesBase: "/api/auth",
  syncClient,                    // enable table verification
  verifyTable: "users",
  verifyUser: (session, row) => String(session.id) === String(row.id),
  onInvalidSession: () => goto("/login"),
  refreshWhenChanged: true,      // re-refresh if synced row differs from session
  errorClasses: [MyAuthError]    // restore custom error types from the API
});

Dynamic sync client

If the sync client is created later from context:

<script lang="ts">
  import { auth } from "$lib/auth";
  import { sync } from "$lib/sync-client.svelte";

  let { data } = $props();

  sync.setContext(() => ({ orgId: data.org.id }));
  auth.setClient(sync);
</script>

Custom errors

Throw structured errors from login callbacks and restore them on the client:

import { SerializableError } from "@sveltebase/auth";

export class TranslatedError extends SerializableError {
  static readonly code = "TranslatedError";
  constructor(message: string) {
    super(message);
  }
}
// server
if (!user) throw new TranslatedError("auth.invalid_credentials");

// client
createAuth({ errorClasses: [TranslatedError] });

Only code and message travel over the wire.

Sync websocket auth

import { sessionCookieAuth } from "@sveltebase/auth/sync";
import { createSyncAppWorker, SyncEngine } from "@sveltebase/sync/cloudflare";

export default createSyncAppWorker(app, {
  handlers,
  auth: sessionCookieAuth<User>(),
  allowUnauthenticated: false
});

export { SyncEngine };

Options (all optional):

  • secret / secretBinding — signing key (default binding: JWT_SECRET)
  • cookieName — default sf_session
  • identity — defaults to user.id for the user:… topic

Telegram Mini App

import { verifyInitData } from "@sveltebase/auth/telegram";
// or mount a first-class route:
createAuthRoutes({
  auth,
  tma: {
    getBotToken: async (event, body) => findBotToken(body.domain),
    getUser: async (initData, event, body) => {
      // map verified initData.user → your profile + claims
      return { user, claims: { activeRoleId } };
    },
    maxAgeSeconds: 86_400
  }
});
// client
await auth.loginWithTma({ initData: Telegram.WebApp.initData, domain });

verifyInitData uses Web Crypto HMAC (works on Cloudflare Workers). It checks signature, auth_date age, and returns a typed payload.

Google sign-in

Wrap the app (or login page) in the provider, then drop in a button:

<script lang="ts">
  import {
    GoogleLogin,
    GoogleOAuthProvider
  } from "@sveltebase/auth/google";
  import { auth } from "$lib/auth";

  const clientId = "your-google-client-id";
</script>

<GoogleOAuthProvider {clientId}>
  <GoogleLogin
    onSuccess={(response) => {
      if (response.credential) {
        auth.loginWithGoogle(response.credential);
      }
    }}
  />
</GoogleOAuthProvider>

Also available:

  • GoogleOneTapLogin — One Tap prompt on load
  • createGoogleLogin() — OAuth2 access-token / auth-code flow (not for loginWithGoogle; that needs an ID token)
  • googleLogout() — clears Google auto-select only; still call auth.logout()
  • verifyIdToken({ credential, clientId }) — server-side ID token verification (RS256, Google JWKS)
  • decodeCredentials(credential) — decode only, no verification — never use alone for auth

Common button props: theme, size, text, shape, width, locale, useOneTap, onError.

Low-level JWT helpers

Usually you go through createServerAuth. If you need them directly:

import {
  signJWT,
  verifyJWT,
  signSessionPayload,
  verifySessionPayload,
  getUserFromCookie,
  getUserFromRequest,
  parseCookies
} from "@sveltebase/auth";

Security checklist

  • Keep secrets and Google client config on the server
  • Never trust decodeCredentials without verifyIdToken
  • Don’t put sensitive data in the signed user snapshot
  • Authorize data in sync handlers — topics are delivery only
  • Clear client sync data on logout / invalid session

License

ISC