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

sikaku-auth

v1.0.1

Published

OAuth 2.1 + PKCE (S256) authentication middleware for Node.js — secure, zero-dependency

Readme

sikaku-oauth

OAuth 2.1 + PKCE (S256) authentication module untuk SiKaKu — profesional, aman, bergaya Passport.js.

Tests Node License: MIT

Fitur

  • OAuth 2.1 + PKCE (S256) — standar keamanan terbaru
  • 🔒 Zero credential leakclientSecret disimpan di WeakMap + Symbol, tidak bisa diakses dari luar
  • ♻️ Auto-refresh token — middleware protect() otomatis refresh token yang expired
  • 🧩 Pluggable store — default InMemoryStore, bisa diganti Redis/DB custom
  • 📡 EventEmitter — observability via events (auth_success, token_refreshed, dll.)
  • 🔷 TypeScript ready — file .d.ts tersedia
  • Zero external dependency — hanya menggunakan Node.js built-in (crypto, https)

Instalasi

# Salin module ini ke project Anda, atau tambahkan sebagai dependency lokal
npm install express express-session

Penggunaan Cepat

1. Setup

const express     = require('express');
const session     = require('express-session');
const SikakuOAuth = require('sikaku-oauth');

const app = express();

// Wajib: express-session sebelum SikakuOAuth
app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: { secure: true, httpOnly: true, sameSite: 'lax' },
}));

// Inisialisasi OAuth
const oauth = new SikakuOAuth({
  clientId:     process.env.SIKAKU_CLIENT_ID,
  clientSecret: process.env.SIKAKU_CLIENT_SECRET,
  redirectUri:  process.env.SIKAKU_REDIRECT_URI,
  scope:        'openid profile', // default
});

2. Routes

// Redirect ke halaman login SiKaKu
app.get('/login', oauth.authenticate());

// Handle callback (setelah user login di SiKaKu)
app.get('/callback', oauth.callback(), (req, res) => {
  // req.sikakuToken berisi { access_token, refresh_token, expires_at, ... }
  res.redirect('/dashboard');
});

// Proteksi route — redirect ke /login jika tidak auth
// Token di-refresh otomatis jika expired
app.get('/dashboard', oauth.protect(), (req, res) => {
  res.json({ token: req.sikakuToken });
});

// Logout
app.get('/logout', oauth.logout({ redirectTo: '/' }));

Konfigurasi Lengkap

const oauth = new SikakuOAuth({
  // === WAJIB ===
  clientId:     'Sikaku-oauth.1854c4ba99b83d60a1f5a1b51f95948a',
  clientSecret: 'YOUR_CLIENT_SECRET',
  redirectUri:  'https://domain.dev/callback',

  // === OPSIONAL ===
  scope:        'openid profile',          // default
  sessionKey:   'sikaku_oauth',            // key di session
  authorizeUrl: 'https://api.sikaku.dev/oauth/authorize', // url api sikaku
  tokenUrl:     'https://api.sikaku.dev/oauth/token', // url token sikaku

  // Custom store (lihat seksi Pluggable Store)
  store: myRedisStore,

  // Callbacks opsional
  onSuccess: (req, res, next, token) => res.redirect('/dashboard'),
  onError:   (err, req, res, next)   => res.redirect('/error'),
});

Middleware API

oauth.authenticate([options])

Redirect user ke halaman login SiKaKu. Otomatis:

  • Generate PKCE code_verifier + code_challenge (S256)
  • Generate CSRF state token
  • Simpan keduanya di session (server-side only)
app.get('/login', oauth.authenticate({
  scope: 'openid profile email', // override scope
}));

oauth.callback([options])

Handle redirect callback dari SiKaKu. Otomatis:

  • Validasi CSRF state (timing-safe)
  • Tukar code dengan token via POST ke token endpoint
  • Simpan token di store
  • Set req.sikakuToken untuk handler berikutnya
app.get('/callback', oauth.callback(), (req, res) => {
  console.log(req.sikakuToken.access_token);
  res.redirect('/dashboard');
});

oauth.protect([options])

Proteksi route — redirect ke login jika tidak terautentikasi. Otomatis:

  • Cek token di session/store
  • Auto-refresh jika token expired (menggunakan refresh_token)
  • Set req.sikakuToken jika valid
app.get('/api/data', oauth.protect({ redirectTo: '/login' }), handler);

oauth.logout([options])

Hapus session dan token dari store.

app.get('/logout', oauth.logout({ redirectTo: '/' }));

await oauth.isAuthenticated(req)

Cek status autentikasi tanpa redirect.

const isAuth = await oauth.isAuthenticated(req);

await oauth.getToken(req)

Ambil token data secara langsung dari store.

const token = await oauth.getToken(req);
// { access_token, refresh_token, expires_in, token_type, expires_at }

Events

oauth.on('auth_success',        ({ tokenKey }) => { /* ... */ });
oauth.on('auth_fail',           ({ error })    => { /* ... */ });
oauth.on('token_refreshed',     ({ tokenKey }) => { /* ... */ });
oauth.on('token_refresh_failed',({ error })    => { /* ... */ });
oauth.on('authorize_redirect',  ({ url })      => { /* ... */ });
oauth.on('logout',              ()             => { /* ... */ });
oauth.on('error',               (err)          => { /* ... */ });

Pluggable Store

Default menggunakan InMemoryStore. Untuk production (multi-instance), gunakan custom store:

const { validateStoreInterface } = require('sikaku-oauth');

// Custom store (contoh: Redis)
const redisStore = {
  async set(key, data, ttlSeconds) { await redis.setex(key, ttlSeconds, JSON.stringify(data)); },
  async get(key)    { const d = await redis.get(key); return d ? JSON.parse(d) : null; },
  async delete(key) { await redis.del(key); },
  async has(key)    { return (await redis.exists(key)) === 1; },
};

// Validasi interface
validateStoreInterface(redisStore);

const oauth = new SikakuOAuth({
  // ...
  store: redisStore,
});

Keamanan

| Mekanisme | Implementasi | |-----------|-------------| | clientSecret protection | WeakMap + Symbol — tidak bisa diakses dari luar instance | | CSRF protection | State token + crypto.timingSafeEqual() | | PKCE | S256: BASE64URL(SHA256(verifier)) | | Token storage | Server-side store, bukan di cookie client | | Immutability | Object.freeze() pada semua token data | | Session security | httpOnly, sameSite, secure cookie |


Environment Variables

Salin .env.example.env:

SIKAKU_CLIENT_ID=Sikaku-oauth.1854c4ba99b83d60a1f5a1b51f95948a
SIKAKU_CLIENT_SECRET=YOUR_CLIENT_SECRET_HERE
SIKAKU_REDIRECT_URI=https://domain.dev/callback
SESSION_SECRET=random-long-string

Menjalankan Tests

npm test           # Run + coverage report
npm run test:watch # Watch mode
npm run test:verbose

Error Classes

const {
  SikakuAuthError,       // Base error
  StateValidationError,  // CSRF state mismatch
  TokenExchangeError,    // Gagal tukar code → token
  TokenExpiredError,     // Token expired, tidak ada refresh_token
  TokenRefreshError,     // Gagal refresh token
  ConfigurationError,    // Konfigurasi tidak valid
  UnauthorizedError,     // Tidak terautentikasi
} = require('sikaku-oauth');

app.use((err, req, res, next) => {
  if (err instanceof StateValidationError) {
    return res.status(403).json({ error: 'CSRF detected' });
  }
  if (err instanceof TokenExpiredError) {
    return res.redirect('/login');
  }
  next(err);
});

Contoh Lengkap

Lihat examples/express-basic/index.js

cd examples/express-basic
npm install express express-session dotenv
node index.js
# Buka http://localhost:3000