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

@vulog/auth

v1.0.6

Published

Browser-only, framework-agnostic authentication for Vulog apps. Ships a Service Worker that owns the tokens and transparently injects the Bearer + refreshes it on AIMA/BO API calls.

Readme

@vulog/auth

Browser-only, framework-agnostic authentication for Vulog apps.

@vulog/auth ships a Service Worker that owns the tokens. The worker stores the access/refresh tokens in IndexedDB (never in localStorage, never in a JS variable the page can read), transparently injects Authorization: Bearer … (and X-API-Key) on your API calls, and refreshes the token silently — including a one-shot retry on a 401.

It supports the three Vulog authentication modes and, when a client has one enabled, the Service Worker handles token injection and refresh for every request to /boapi/proxy/ and /apiv5/ (configurable).

  • ropc — username/password login (grant_type=password) with optional 2FA.
  • oauth2 — OAuth2 Authorization Code + PKCE, refreshed silently via the httpOnly session cookie (no refresh token in the browser).
  • microsoft — Microsoft / Azure AD SSO.

Works with vanilla JS, React, or any other framework. Written in TypeScript, fully tested.


Why a Service Worker?

The tokens live inside the worker. The page asks the worker to log in, log out, or read the (token-free) auth state; it never touches the raw token itself. When the page fetch()es an API URL, the worker intercepts the request and attaches the credentials. This keeps tokens out of reach of most XSS payloads and centralizes refresh + retry in one place shared across all tabs.

   page (React / vanilla)                     Service Worker
   ─────────────────────                       ──────────────
   createAuthClient(...)  ── INIT ───────────▶ persist config
   client.loginRopc(...)  ── LOGIN ──────────▶ POST IDP, store tokens (IndexedDB)
                          ◀── AUTH_OK ───────── broadcast (claims only)

   fetch('/apiv5/user')   ─────────────────────▶ intercept:
                                                  + Authorization: Bearer …
                                                  + X-API-Key
                                                  on 401 → refresh + retry once

Install

npm install @vulog/auth

react and zustand are optional peer dependencies, needed only if you use the @vulog/auth/react bindings.

Serve the worker file

The package ships a pre-built, self-contained worker at @vulog/auth/auth-sw (→ node_modules/@vulog/auth/dist/auth-sw.js). Serve it from your app root and register it at scope /.

The server must send the Service-Worker-Allowed: / header for the root scope to be granted. With Vite, a small plugin serves it in dev/preview and emits it at the build root:

// vite.config.js
import path from 'path';
import fs from 'fs';

const vulogAuthWorkerPlugin = () => {
    const workerPath = path.resolve('node_modules/@vulog/auth/dist/auth-sw.js');
    const serve = (server) => {
        server.middlewares.use('/auth-sw.js', (_req, res) => {
            res.setHeader('Content-Type', 'application/javascript');
            res.setHeader('Service-Worker-Allowed', '/');
            res.setHeader('Cache-Control', 'no-cache');
            res.end(fs.readFileSync(workerPath));
        });
    };
    return {
        name: 'vulog-auth-worker',
        configureServer: serve,
        configurePreviewServer: serve,
        generateBundle() {
            this.emitFile({
                type: 'asset',
                fileName: 'auth-sw.js',
                source: fs.readFileSync(workerPath),
            });
        },
    };
};
// plugins: [vulogAuthWorkerPlugin(), ...]

For a static server / CDN: serve auth-sw.js from the root with Service-Worker-Allowed: / and no long cache. The full guides (getting-started, architecture, security) ship in the package's docs/ folder.


Quickstart (vanilla JS)

import { createAuthClient } from '@vulog/auth';

const auth = createAuthClient({
    serviceWorker: { scriptUrl: '/auth-sw.js' },
    config: {
        clientId: 'F0001_Secure',
        clientSecret: '…', // ROPC only
        apiKey: '…', // sent as X-API-Key
        tokenEndpoint: 'https://…/auth/realms/F0001/protocol/openid-connect/token',
        // interceptPrefixes defaults to ['/boapi/proxy/', '/apiv5/']
    },
});

// Register the SW + push the config. Call once at boot.
await auth.start();

// React to session changes (login / logout / refresh) from any tab.
auth.onEvent((event) => console.log('[auth]', event.type));

// Log in with a password.
const result = await auth.loginRopc({ username, password });
if (!result.ok && result.code === 'TWO_FA_REQUIRED') {
    const pin = await promptUser(result.details.pinCodeFormat);
    await auth.check2fa({ pin, url: result.details.url, sessionId: result.details.sessionId });
}

// From now on, just fetch — the worker attaches the token.
const user = await fetch('/apiv5/user').then((r) => r.json());

await auth.logout();

Microsoft SSO

// URLs come from discovery (`.well-known/method`).
await auth.loginMicrosoft({ loginUrl, refreshUrl, logoutUrl }); // logoutUrl optional (server-side logout)

OAuth2 Authorization Code + PKCE

// On the login page — generates PKCE + redirects to the IDP:
await auth.startOAuth2Login();
// On your redirect/callback page (config.redirectUri):
const result = await auth.completeOAuth2Login(); // reads ?code&state, exchanges it

Discover which modes a tenant has enabled with auth.discoverAuthMethods(methodsDiscoveryUrl(baseUrl, realm, clientId)).


Quickstart (React)

import { createAuthClient } from '@vulog/auth';
import { AuthProvider, useAuth, useLogout } from '@vulog/auth/react';

const auth = createAuthClient({
    serviceWorker: { scriptUrl: '/auth-sw.js' },
    config: { clientId: 'F0001_Secure', tokenEndpoint: '…', apiKey: '…' },
});

function App() {
    return (
        <AuthProvider client={auth}>
            <Home />
        </AuthProvider>
    );
}

function Home() {
    const view = useAuth();
    const { logout } = useLogout();
    if (view.isPreInit) return <Spinner />;
    if (!view.isAuthed) return <LoginForm />;
    return <button onClick={() => logout()}>Sign out ({String(view.claims.sub)})</button>;
}

The React hooks are useAuth, useLogout, useAuthMethods, and the useAuthStore observer — see the docs/ folder in the package.


API surface

| Import | What | | --------------------- | ------------------------------------------------------------------------------------------------- | | @vulog/auth | createAuthClient, low-level client pieces, PKCE + OIDC URL helpers, the typed message protocol. | | @vulog/auth/react | AuthProvider, useAuth, useLogout, useAuthMethods, useAuthStore. | | @vulog/auth/auth-sw | The pre-built Service Worker to serve at your app root. |


Configuration (AuthConfig)

| Field | For | Description | | ------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | clientId | all | OAuth2 client id. | | clientSecret | ropc | Confidential-client secret. Omit for public/PKCE clients. | | apiKey | optional | Value for the X-API-Key header on intercepted requests. | | interceptPrefixes | optional | Prefixes to intercept. Default ['/boapi/proxy/', '/apiv5/']. Path prefixes match same-origin pathname; http(s) prefixes match the full URL. | | tokenEndpoint | ropc | grant_type=password / refresh_token endpoint. | | logoutEndpoint | optional (ropc) | Best-effort IDP logout. | | oauth2AuthorizeEndpoint | oauth2 | Authorize endpoint (same-origin proxy for silent refresh). | | oauth2TokenEndpoint | oauth2 | Code-exchange endpoint (falls back to tokenEndpoint). | | endSessionEndpoint | optional (oauth2) | End-session redirect target for logout. | | redirectUri | oauth2 | Registered redirect URI. |

Documentation

The full guides — getting started, vanilla, react, architecture, and the security model — ship in the package's docs/ folder (node_modules/@vulog/auth/docs/).

Development

npm install
npm run type-check   # tsc --noEmit
npm run lint         # eslint
npm test             # vitest run
npm run test:coverage
npm run build        # tsdown → dist/{index,react,auth-sw}.js

Releasing

Publishing to the npm registry is maintainer-only, enforced by GitLab:

  1. Bump the version + update CHANGELOG.md, merge to main.
  2. A maintainer creates a protected tag vX.Y.Z (protected tags: Allowed to create = Maintainers).
  3. The CI publish job (manual, on the protected npm environment, using the protected+masked NPM_TOKEN) is triggered by a maintainer.

See the header of .gitlab-ci.yml for the exact project settings that lock this down.

License

MIT © Vulog.