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

weegloo-service-user

v1.1.0

Published

Weegloo ServiceLogin SDK for browser apps — Google OAuth 2.0 sign-in for app-managed members of a Weegloo Space. Pure vanilla JavaScript, zero dependencies.

Readme

weegloo-service-user

Vanilla-JavaScript browser SDK for Weegloo ServiceLogin — the per-Space, app-managed member sign-in feature of Weegloo. Zero runtime dependencies. Ships UMD, ESM, and minified builds.

  • Drives the full Google OAuth 2.0 flow: redirect → callback → token exchange → refresh → logout.
  • Stores tokens in sessionStorage (or localStorage, or a custom adapter).
  • Auto-refreshes the accessToken before it expires.
  • Removes exchangeToken from the address bar before the network call (success, failure, or reload — never leaks).
  • Auto-injects Authorization: Bearer … for ACMA / ACDA calls.

The Bearer Token issued by ServiceLogin is valid only against acma.weegloo.com / acda.weegloo.com. It is not valid against cma.weegloo.com / cda.weegloo.com.


Install

Option A. npm + bundler (Vite, Webpack, Next.js, …)

npm install weegloo-service-user
import WeeglooServiceLogin from 'weegloo-service-user';

const auth = WeeglooServiceLogin.init({ spaceId: 'YOUR_SPACE_ID' });

Option B. <script> tag (static sites, Weegloo WebHosting)

After publishing, jsDelivr and unpkg serve the same file automatically:

<!-- Latest patch of the major version (auto-updates within v1.x) -->
<script src="https://cdn.jsdelivr.net/npm/weegloo-service-user@1/dist/service-login.min.js"></script>
<!-- or -->
<script src="https://unpkg.com/weegloo-service-user@1/dist/service-login.min.js"></script>
<script>
  const auth = WeeglooServiceLogin.init({ spaceId: 'YOUR_SPACE_ID' });
</script>

The library exposes a global WeeglooServiceLogin when loaded via <script>.

Pinning to an immutable revision

Each release also ships content-addressed copies whose bytes never change for a given hash, suitable for integrity="sha384-…" pinning and aggressive CDN caching. Pick the build you want and append .<hash> before the file extension:

<script
  src="https://cdn.jsdelivr.net/npm/[email protected]/dist/service-login.<hash>.min.js"
  integrity="sha384-…"
  crossorigin="anonymous"></script>

The exact hash and SRI value for the version you installed are recorded in dist/manifest.json (require('weegloo-service-user/manifest') from Node, or the same path on jsDelivr).


Minimal example

<button id="login">Login</button>
<button id="logout">Logout</button>
<button id="load">Load via ACDA</button>

<script src="https://cdn.jsdelivr.net/npm/weegloo-service-user@1/dist/service-login.min.js"></script>
<script>
  const SPACE_ID = 'YOUR_SPACE_ID';
  const auth = WeeglooServiceLogin.init({ spaceId: SPACE_ID });

  // On the callback page, complete the OAuth handshake.
  if (location.search.includes('exchangeToken=')) {
    auth.handleCallback().catch(console.error);
  }

  document.querySelector('#login').onclick  = () => auth.login();
  document.querySelector('#logout').onclick = () => auth.logout();
  document.querySelector('#load').onclick   = async () => {
    const res  = await auth.fetch(`https://acda.weegloo.com/v1/spaces/${SPACE_ID}/contents`);
    console.log(await res.json());
  };
</script>

API

WeeglooServiceLogin.init(options) → instance

| Option | Type | Default | Description | |---|---|---|---| | spaceId | string | — (required) | Your Weegloo Space ID. | | provider | string | 'google' | OAuth provider path segment. | | authBaseUrl | string | 'https://auth.weegloo.com' | Base URL of the auth server. | | storage | 'session' \| 'local' \| object | 'session' | Token storage. The 'session' default uses sessionStorage and is the recommended security posture. A custom adapter { getItem, setItem, removeItem } is also accepted. | | storageKey | string | weegloo:serviceLogin:<spaceId> | Key used in storage. | | autoRefresh | boolean | true | If true, getAccessToken() will refresh automatically when the access token is near expiry. | | refreshLeewaySeconds | number | 60 | Refresh fires N seconds before expiresAt. |

Calling init() multiple times with the same spaceId | authBaseUrl pair returns the same cached instance.

Instance methods

| Method | Returns | Description | |---|---|---| | login(opts?) | void | Redirects the browser to the OAuth login page. | | handleCallback(opts?) | Promise<tokens> | Call on the callback page. First strips exchangeToken from the address bar, then exchanges it for tokens and stores them. | | isLoggedIn() | boolean | true if accessToken is unexpired or a valid refreshToken exists. | | getAccessToken() | Promise<string \| null> | Returns the access token, auto-refreshing if necessary. Returns null if the user is not logged in or refresh failed. | | getTokens() | tokens \| null | Returns the stored token bundle. | | refresh() | Promise<tokens> | Forces a refresh (POST /oauth/refresh). | | logout() | Promise<true> | Calls DELETE /oauth/token with the stored refreshToken and clears local storage. | | fetch(input, init?) | Promise<Response> | A fetch wrapper that injects Authorization: Bearer <accessToken> and avoids forcing Accept: application/json (Weegloo serves a vendor media type). | | onChange(cb) | () => void | Subscribe to lifecycle events: 'login' \| 'refresh' \| 'logout' \| 'set' \| 'clear' \| 'refresh-failed'. Returns an unsubscribe function. |


Security notes

  • exchangeToken is removed from the URL before any network request. Even if the token-exchange call fails, hangs, or the user reloads mid-flight, the token never lingers in window.location, the session-history stack, or outgoing Referer headers.
  • The default sessionStorage discards tokens when the tab closes. Use storage: 'local' only when persistent sign-in is a deliberate UX choice.
  • The Bearer Token authorizes ACMA and ACDA only. Do not send it to CMA, CDA, or Upload — the server will reject it.
  • The library never sets Accept: application/json on its outgoing requests because Weegloo APIs negotiate the vendor media type application/vnd.com.weegloo.v1+json.

What is ServiceLogin?

ServiceLogin is the per-Space, app-managed member directory of a Weegloo Space. It is separate from Weegloo Console accounts (which manage the Space itself). Use it to add member sign-up / sign-in to a product you ship on top of a Weegloo Space — for example, a members-only board, a paid-content portal, or any community where readers must sign in.

Resource model

  • ServiceLogin — the Space's per-product login configuration (enabled OAuth providers, callback URL, default role).
  • ServiceUserRole — the permission rule set assigned to app-managed members. Defines what they may read or write through ACMA / ACDA.
  • ServiceUser — one record per app-managed member. May carry an optional roleOverride (a different ServiceUserRole for that specific member) and an optional isAdmin: true (adds delete of other members' resources, scoped to the role's permissions).

A successful sign-in returns a Bearer Token tied to the corresponding ServiceUser. That token authorizes ACMA and ACDA only.


Setup checklist (one-time)

1. Configure the OAuth client in Google Cloud

  1. In Google Cloud Console → "Google Auth Platform" → create an OAuth Client.
  2. Add https://auth.weegloo.com to Authorized JavaScript origins.
  3. Add https://auth.weegloo.com/v1/spaces/{spaceId}/login/oauth2/code/google to Authorized redirect URIs, where {spaceId} is the Weegloo Space ID hosting the ServiceLogin.

Note: the /login/oauth2/code/{provider} path is the redirect URI that Google calls Weegloo at — it is different from the URL the SDK navigates the browser to (/login/oauth2/{provider}, no code segment).

2. Configure ServiceLogin in the Weegloo Console

  1. In the target Space, create a ServiceLogin record.
  2. Set clientId / clientSecret to the values issued by Google Cloud above.
  3. Set defaultRole to a Refer of a ServiceUserRole you have created in advance with the appropriate permissions. Per-member overrides are possible later via ServiceUser.roleOverride.
  4. Set callbackUrl to a URL on your own product that the SDK can intercept — Weegloo will redirect the browser there with ?exchangeToken=... after a successful Google sign-in. The SDK's handleCallback() consumes this parameter to obtain a Bearer Token usable against ACMA / ACDA.

OAuth flow (for reference)

The SDK encapsulates all of this; you only need to read it if you are debugging or porting the flow elsewhere.

  1. Navigate the browser to:
    GET https://auth.weegloo.com/v1/spaces/{spaceId}/login/oauth2/google
    The user signs in through Google.
  2. Weegloo redirects the browser to the configured callbackUrl with ?exchangeToken=… appended.
  3. Exchange the exchangeToken for tokens:
    POST https://auth.weegloo.com/v1/spaces/{spaceId}/oauth/token
    Content-Type: application/json
    { "exchangeToken": "abc" }
    Response:
    {
      "accessToken": "XXXXXX",
      "tokenType": "Bearer",
      "scope": ["App"],
      "createdAt":  "2026-04-16T12:12:21.602Z",
      "expiresAt":  "2026-06-16T12:12:21.602Z",
      "refreshToken": "YYYYYYYY",
      "refreshExpiresAt": "2026-04-23T12:12:21.602Z"
    }
  4. Send Authorization: Bearer <accessToken> to ACMA / ACDA.
  5. Before expiresAt, refresh the access token:
    POST https://auth.weegloo.com/v1/spaces/{spaceId}/oauth/refresh
    { "refreshToken": "YYYYYYYY" }
  6. To sign out:
    DELETE https://auth.weegloo.com/v1/spaces/{spaceId}/oauth/token
    { "refreshToken": "YYYYYYYY" }
    Sending the refreshToken is strongly recommended so the server can invalidate it — calling without a body is permitted but leaves the refresh token usable until natural expiry.

Builds

Each build ships in two flavours: a mutable "latest" alias that auto-updates with patch releases, and a content-addressed immutable revision safe for SRI pinning.

| Format | Latest alias | Immutable revision | Use case | |---|---|---|---| | UMD | dist/service-login.js | dist/service-login.<hash>.js | <script> tag, CommonJS require, AMD | | ES Module | dist/service-login.esm.js | dist/service-login.<hash>.esm.js | Modern bundlers, import | | UMD (minified) | dist/service-login.min.js | dist/service-login.<hash>.min.js | Production <script> / CDN |

dist/manifest.json records each build's <hash> (sha256, first 8 hex chars), byte size, and the sha384 SRI integrity string ready to drop into <script integrity="…">.

The single source of truth is src/service-login.js. Run npm run build to regenerate the dist/ outputs from it.

License

MIT