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

@ruvyxa/auth

v1.1.5

Published

Secure sessions and provider-driven authentication for Ruvyxa applications.

Readme


import { createClient } from 'redis'
import {
  createAuth,
  google,
  nodeRedisCommandPort,
  redisAuthStore,
  redisRateLimitStore,
} from '@ruvyxa/auth'

const redis = nodeRedisCommandPort(await createClient({ url: process.env.REDIS_URL }).connect())

export const auth = createAuth({
  secret: process.env.AUTH_SECRET!,
  origin: 'https://app.example.com',
  store: redisAuthStore(redis),
  rateLimitStore: redisRateLimitStore(redis),
  providers: {
    email: {
      type: 'credentials',
      authorize: ({ email, password }, request) => verifyUser(email, password),
    },
    google: google({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
  },
})

Mount the endpoints with one route handler file under basePath (/__ruvyxa/auth by default). The same file serves them on every host — ruvyxa dev/start, and every deployed build through the adapters' request handler — so nothing changes between a self-hosted process and a serverless function. auth.handle(request) is the same dispatch for an application that mounts the endpoints itself.

// app/__ruvyxa/auth/[...path]/route.ts
import { auth } from '../../../_server/auth.js'

export const { GET, POST } = auth.handlers

createAuth() refuses the memory stores when NODE_ENV is production (RUV3105): the process that would keep sessions in its own memory is the one that must not start.

Stores. AuthStore.take() and AuthRateLimitStore.consume() must be atomic: a read-then-write in the application process lets two concurrent requests both claim one single-use token, or both pass one rate-limit slot. redisAuthStore(port) and redisRateLimitStore(port) run each as a single Lua script on the server, so several instances behind one load balancer share one truth. The package pins no Redis client: build the port with nodeRedisCommandPort(client) for node-redis or ioredisCommandPort(client) for ioredis, or hand in any object with get, set, del, and eval. The included memory stores are for tests and development, require { development: true }, and are refused by production builds with RUV3105.

The session cookie is opaque, HttpOnly, SameSite, and Secure on HTTPS. Session and one-time token keys are HMAC-derived. OAuth state is additionally bound to an HttpOnly browser cookie, protocol parameters cannot be overridden, and non-local provider endpoints must use HTTPS.

Account identity is session.user.idgoogle:${sub}, github:${id} — and never session.user.email. An address is a claim the identity provider may or may not stand behind, so session.user.emailVerified records which it was: true from Google only when the profile carried email_verified: true, and true from GitHub because its /user email is selected from the addresses GitHub confirmed. Absent means the provider said nothing. Do not link an OAuth login to an existing account, grant a role from an address domain, or authorize anything on user.email unless user.emailVerified is true — an unverified address is an address the person signing in chose.

Set onError(error, request) to send full server-side failures to application observability. Public 500 responses remain generic even if that hook fails.

WebAuthn challenge generation and signature/attestation verification are deliberately delegated to a standards-compliant adapter because correct verification depends on RP ID, origin, authenticator policy, and credential persistence. Successful verification enters the same session pipeline.