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

@varyarorg/water-auth

v0.1.1

Published

Drop VarYar VyAuth into any website — h2o CLI pulls your dev credentials automatically, WaterAuthButton() and WaterGetUserX() do the rest.

Readme

water-auth

Drop VarYar sign-in into any website. h2o (the CLI) pulls your dev credentials out of the browser automatically — you never copy-paste a key. WaterAuthButton() and WaterGetUserX() do the rest with basically no boilerplate.

npm install water-auth

1. Connect your project (one time)

npx h2o init

Creates h2o.sadx in your project root — this is where your VarYar org ID and secret key live. It's .env-shaped but a different filename on purpose, so generic .env* tooling doesn't accidentally slurp it up. h2o init also adds it to .gitignore for you if one exists.

npx h2o login

Opens accounts.varyar.com in your browser. Log in (or register a new dev org if you don't have one yet) — as soon as that finishes, your org ID and secret key are written into h2o.sadx automatically. You never see or copy-paste the raw key — it goes straight from VarYar's server, into your browser session, into a one-time local handoff to the CLI, into the file. Nothing prints to your terminal.

h2o.sadx
────────────────────────────────────────
WATER_ORG_ID=VYD-XXXXXXXX
WATER_SECRET_KEY=•••••••••••••••••••••••
WATER_BASE_URL=https://accounts.varyar.com
WATER_CALLBACK_URL=http://localhost:3000/api/water-auth/callback

Before deploying, update WATER_CALLBACK_URL to your real domain — it must exactly match the callback URL registered for this org in DevPit.

Other CLI commands:

| Command | What it does | |----------------|-------------------------------------------------| | h2o whoami | Shows what's currently configured | | h2o logout | Clears the stored org + key from h2o.sadx |


2. Mount the API routes (one file)

Next.js (App Router)

Create app/api/water-auth/[...water]/route.ts:

import { createWaterAuthRoutes } from "water-auth/next";

export const { GET, POST } = createWaterAuthRoutes();

That's it — it reads h2o.sadx itself. This one file gives you:

  • GET /api/water-auth/url — hands the button a fresh signed sign-in link
  • GET /api/water-auth/callback — where VarYar redirects back to; sets your app's own session cookie
  • GET /api/water-auth/me — the current logged-in user, or { user: null }
  • POST /api/water-auth/logout — clears the session

Express / other Node backends

import express from "express";
import cookieParser from "cookie-parser";
import { mountWaterAuthExpress } from "water-auth/express";

const router = express.Router();
mountWaterAuthExpress(router);
app.use(cookieParser());
app.use("/api/water-auth", router);

3. Use it in your UI — this is the whole integration

import { WaterAuthButton, WaterGetUserFirstName, WaterIsLoggedIn } from "water-auth/react";

export default function Navbar() {
  return (
    <header>
      {WaterIsLoggedIn() ? <span>Hey, {WaterGetUserFirstName()} 👋</span> : null}
      <WaterAuthButton />
    </header>
  );
}

No <WaterAuthProvider> to wrap your app in, no manual fetch("/api/water-auth/me"), no state wiring. The button and every WaterGetUserX() call share one small built-in store that fetches /api/water-auth/me once and keeps everything in sync after login.

Available in water-auth/react

<WaterAuthButton />                 // sign-in button, becomes "Signed in as ..." once logged in
<WaterAuthButton next="/dashboard"/> // where to land after sign-in
<WaterLogoutButton />

WaterGetUserFirstName()
WaterGetUserMiddleName()
WaterGetUserLastName()
WaterGetUserEmail()
WaterGetUserPhone()
WaterGetUserRegion()
WaterGetUserUID()
WaterIsLoggedIn()                   // boolean
WaterIsNewUser()                    // true right after their first-ever sign-up via this app

useWaterUser()                      // { loading, user, isLoggedIn } if you want everything at once

These WaterGetUserX() functions are hooks under the hood (they read the live store via useSyncExternalStore) — call them at the top level of a component's render, same as any other hook, not inside a loop/condition/ callback. Because they're named WaterGetX rather than useX, ESLint's react-hooks plugin won't flag misuse automatically — if you want lint coverage, useWaterUser() is the one that will get picked up, or alias: const useWaterFirstName = WaterGetUserFirstName;

Only first_name, email, etc. that your org is actually allowed to request (configured in DevPit → your app → Auth fields) will ever be non-empty — anything outside your allowed_info/optional_info scope comes back undefined, same as it would from the raw VyAuth payload.


4. What fields can I get?

Exactly what you selected for your app under DevPit → your app → Auth → Allowed / optional fields. water-auth doesn't add or remove scope — it's a thin, batteries-included wrapper around VarYar's existing VyAuth handshake (/vyauth, genhash, approve, validate on accounts.varyar.com).


How the pieces fit together

 h2o init        →  creates h2o.sadx (empty)
 h2o login        →  opens accounts.varyar.com/onboardingdev
                      (login or register org) → key auto-saved to h2o.sadx
                      via a one-shot localhost callback server — nothing is
                      ever typed or pasted by hand

 npm install      →  water-auth in your project
 route.ts         →  mounts /api/water-auth/{url,callback,me,logout}
                      using the org/key from h2o.sadx

 <WaterAuthButton/> → click → GET /url → redirect to accounts.varyar.com/vyauth
                    → user approves → VarYar redirects to /api/water-auth/callback
                    → your app's session cookie is set
                    → WaterGetUserX() everywhere now returns real values

No secret ever touches client-side JS. h2o.sadx and your session cookie are the only two places a key/token lives, and both stay server-side or httpOnly.


Where things go — quick reference

| File | What it's for | |----------------------------------------------------|--------------------------------------------------| | h2o.sadx (project root, gitignored) | Your org ID + secret key. Never commit this. | | app/api/water-auth/[...water]/route.ts (Next.js) | The four API routes. Copy-paste, done. | | Anywhere in your UI | import { WaterAuthButton, WaterGetUserX } from "water-auth/react" | | Any server code needing the raw VyAuth primitives | import { buildAuthUrl, verifyCallback } from "water-auth/server" |

That's the whole integration — one CLI login, one route file, one import.