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

@yannyours/auth-kit

v1.0.1

Published

Module d'authentification Node.js autonome — email/mot de passe + OAuth2 (Google, GitHub, générique) avec PKCE, JWT access/refresh avec rotation, adaptateur de stockage enfichable.

Readme

@yannyours/auth-kit

Module d'authentification Node.js autonome : e-mail/mot de passe + OAuth2 (Google, GitHub, ou n'importe quel fournisseur standard) avec PKCE, JWT access/refresh avec rotation, et un adaptateur de stockage enfichable.

Installation

npm install @yannyours/auth-kit

Ajouter uniquement le driver de votre base de données :

npm install better-sqlite3   # SQLite
npm install pg               # PostgreSQL
npm install mysql2           # MySQL / MariaDB
npm install mongodb          # MongoDB

Démarrage rapide

import express from "express";
import { AuthKit, SqliteStorageAdapter, createAuthRouter, requireAuth } from "@yannyours/auth-kit";
import type { AuthenticatedRequest } from "@yannyours/auth-kit";

const storage = await SqliteStorageAdapter.create("./auth.db");

const authKit = new AuthKit({
  storage,
  jwtSecret: process.env.JWT_SECRET!, // min 16 chars — variable d'env obligatoire
});

const app = express();
app.use(express.json());
app.use("/auth", createAuthRouter(authKit));

// Route protégée
app.get("/api/profile", requireAuth(authKit), (req: AuthenticatedRequest, res) => {
  res.json({ userId: req.auth!.userId, email: req.auth!.email });
});

app.listen(3000);

Variables d'environnement minimales (copier .env.example) :

JWT_SECRET=une-chaine-aleatoire-longue-min-32-chars

Endpoints exposés par createAuthRouter

| Méthode | Route | Accès | Description | |---------|-----------------------------|-------|-------------| | POST | /register | Public | { email, password, name? } → { user } | | POST | /login | Public | { email, password } → tokens | | POST | /refresh | Public | { refreshToken } → nouveaux tokens (rotation) | | POST | /logout | Public | { refreshToken } → révoque ce token | | GET | /me | Auth | Authorization: Bearer <token> → { user } | | GET | /oauth/:provider | Public | Redirige vers le fournisseur OAuth2 | | GET | /oauth/:provider/callback | Public | Échange le code, renvoie tokens |

OAuth2 (Google, GitHub, custom)

import { googleProvider, githubProvider, genericProvider } from "@yannyours/auth-kit";

const authKit = new AuthKit({
  storage,
  jwtSecret: process.env.JWT_SECRET!,
  oauthProviders: {
    google: googleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
      redirectUri: "https://monapp.com/auth/oauth/google/callback",
    }),
    github: githubProvider({
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      redirectUri: "https://monapp.com/auth/oauth/github/callback",
    }),
  },
});

Variables d'environnement supplémentaires :

GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=

Tout fournisseur OAuth2 standard (Microsoft Entra, GitLab, Okta…) peut être ajouté via genericProvider :

const microsoft = genericProvider({
  clientId: "...",
  clientSecret: "...",
  redirectUri: "https://monapp.com/auth/oauth/microsoft/callback",
  authorizeUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
  tokenUrl:     "https://login.microsoftonline.com/common/oauth2/v2.0/token",
  userInfoUrl:  "https://graph.microsoft.com/oidc/userinfo",
  scope: "openid email profile",
  mapProfile: (p) => ({ id: p.sub, email: p.email, name: p.name }),
});

Adaptateurs de stockage

@yannyours/auth-kit inclut quatre adaptateurs prêts à l'emploi. Seul express est une dépendance obligatoire — chaque adaptateur de base de données est une peer dependency optionnelle : installez uniquement ce que vous utilisez.

SQLite — single-instance, zéro infrastructure

npm install better-sqlite3
import { SqliteStorageAdapter } from "@yannyours/auth-kit";
const storage = await SqliteStorageAdapter.create("./auth.db");

Idéal pour un déploiement sur une seule machine (VPS, Raspberry Pi, container avec volume persistant). Pas adapté au multi-instance ou au serverless.


PostgreSQL

npm install pg
import { Pool } from "pg";
import { PostgresStorageAdapter } from "@yannyours/auth-kit";

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const storage = new PostgresStorageAdapter(pool);

Schéma à exécuter une fois (migration ou init script) :

CREATE TABLE IF NOT EXISTS auth_users (
  id            TEXT        PRIMARY KEY,
  email         TEXT UNIQUE NOT NULL,
  password_hash TEXT,
  name          TEXT,
  providers     JSONB       NOT NULL DEFAULT '{}',
  created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS auth_refresh_tokens (
  token      TEXT   PRIMARY KEY,
  user_id    TEXT   NOT NULL REFERENCES auth_users(id) ON DELETE CASCADE,
  expires_at BIGINT NOT NULL,
  revoked    BOOLEAN NOT NULL DEFAULT FALSE
);

CREATE INDEX IF NOT EXISTS idx_art_user    ON auth_refresh_tokens(user_id);
CREATE INDEX IF NOT EXISTS idx_art_revoked ON auth_refresh_tokens(revoked) WHERE NOT revoked;

L'adaptateur tire parti du type JSONB natif de Postgres : findUserByProvider utilise l'opérateur ->> (accès direct au sous-champ) sans scan complet. linkProvider utilise jsonb_set — atomique, pas de read-modify-write.


MySQL / MariaDB

npm install mysql2
import mysql from "mysql2/promise";
import { MysqlStorageAdapter } from "@yannyours/auth-kit";

const pool = mysql.createPool({ uri: process.env.DATABASE_URL });
const storage = new MysqlStorageAdapter(pool);

Schéma :

CREATE TABLE IF NOT EXISTS auth_users (
  id            VARCHAR(36)  PRIMARY KEY,
  email         VARCHAR(320) UNIQUE NOT NULL,
  password_hash TEXT,
  name          VARCHAR(128),
  providers     JSON         NOT NULL DEFAULT ('{}'),
  created_at    DATETIME(3)  NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
);

CREATE TABLE IF NOT EXISTS auth_refresh_tokens (
  token      VARCHAR(128) PRIMARY KEY,
  user_id    VARCHAR(36)  NOT NULL,
  expires_at BIGINT       NOT NULL,
  revoked    TINYINT(1)   NOT NULL DEFAULT 0,
  CONSTRAINT fk_art_user FOREIGN KEY (user_id)
    REFERENCES auth_users(id) ON DELETE CASCADE,
  INDEX idx_art_user    (user_id),
  INDEX idx_art_revoked (revoked)
);

Requiert MySQL ≥ 8.0 ou MariaDB ≥ 10.6 pour les fonctions JSON_EXTRACT / JSON_SET utilisées par findUserByProvider et linkProvider.


MongoDB

npm install mongodb
import { MongoClient } from "mongodb";
import { MongoStorageAdapter } from "@yannyours/auth-kit";

const client = new MongoClient(process.env.MONGODB_URI!);
await client.connect();
const storage = await MongoStorageAdapter.create(client.db("myapp"));

Les collections auth_users et auth_refresh_tokens sont créées automatiquement au premier appel de create(), avec :

  • Index unique sur email
  • Index sur providers pour les lookups OAuth2
  • TTL index sur expiresAtDate : MongoDB purge automatiquement les refresh tokens expirés (vérification toutes les 60 s)

Adapter personnalisé (Prisma, Drizzle, Sequelize…)

Implémentez l'interface StorageAdapter et passez-la à AuthKit :

import type { StorageAdapter } from "@yannyours/auth-kit";

class MonPrismaAdapter implements StorageAdapter {
  async findUserByEmail(email: string) { return prisma.authUser.findUnique({ where: { email } }); }
  async findUserById(id: string)       { return prisma.authUser.findUnique({ where: { id } }); }
  // … 7 autres méthodes
}

const authKit = new AuthKit({ storage: new MonPrismaAdapter(), jwtSecret: "…" });

Sécurité — ce qui est déjà géré

  • bcrypt (12 rounds) — mots de passe jamais stockés en clair.
  • JWT access token courte durée (15 min par défaut) + refresh token opaque longue durée, stocké et révocable côté serveur.
  • Rotation des refresh tokens — chaque /refresh invalide l'ancien token ; un token volé rejoué après usage légitime est automatiquement rejeté.
  • PKCE S256 sur tous les flux OAuth2 — protection contre l'interception du code d'autorisation, y compris avec les providers qui ne l'exigent pas.
  • State OAuth2 généré et vérifié côté serveur, expiré à 10 min — anti-CSRF sans cookie.
  • Rate limiting intégré sur /login (IP + email, 10 req/15 min) et /register (IP, 5 req/h), configurable ou désactivable :
createAuthRouter(authKit, {
  rateLimit: {
    login: { windowMs: 10 * 60 * 1000, max: 5 },
    register: false, // déjà géré en amont
  },
});
  • Validation des inputs — format email vérifié, mot de passe limité à 1024 chars (protection DoS bcrypt), name tronqué à 128 chars.

Limitations connues

Multi-instance / serverless : les états OAuth en attente (pendingOAuth) sont stockés en mémoire. Dans une architecture avec plusieurs réplicas ou en serverless, le callback OAuth peut atterrir sur une instance différente de celle qui a initié le flux, causant un rejet légitime. Pour ce cas d'usage, externaliser l'état OAuth dans Redis ou une base partagée, et implémenter un OAuthStateStore dédié.

Développement local

git clone https://github.com/YannYours/auth-kit
cd auth-kit
npm install
cp .env.example .env   # renseigner JWT_SECRET au minimum
npm run dev            # serveur de démo sur http://localhost:3000
npm run build          # compile src/ → dist/
npm run typecheck      # vérification TypeScript sans émettre

Licence

MIT — voir LICENSE.