@ropean/sso-client v0.0.1
OAuth 2.0 + OIDC

One SSO library.
Every runtime.

Drop-in OAuth 2.0 + OIDC client for Node.js, Cloudflare Workers, Cloudflare Pages, and Vercel Edge — same API everywhere.

$ pnpm add @ropean/sso-client
🔐

PKCE S256 by default

Authorization Code + PKCE. No implicit flow. No secret leaks in redirect URIs.

🌐

Cross-runtime crypto

Built on Web Crypto API — works identically on Node 18+, CF Workers, Vercel Edge, and Deno.

🍪

HMAC-signed cookies

Session IDs signed with HMAC-SHA256. AES-256-GCM encrypted refresh tokens at rest.

🔄

Transparent token refresh

Silently rotates expired access tokens. Concurrent refresh handled with distributed locking.

📦

Pluggable session stores

SQLite (Node), Cloudflare KV (edge), or in-memory (testing). Bring your own store.

🔔

Backchannel logout

Handles OIDC backchannel logout tokens. Sessions revoked server-side in real time.

Quick start
import { createSso } from '@ropean/sso-client';
import { SqliteSessionStore } from '@ropean/sso-client/store/sqlite';
import { Hono } from 'hono';

const sso = createSso({
  env: process.env,
  store: new SqliteSessionStore('./data/sso.db'),
});

const app = new Hono();
app.route('/auth', sso.router);            // /auth/login  /auth/callback …
app.get('/me', sso.authenticate(), (c) => c.json(c.get('user')));
app.get('/admin', sso.authenticate({ admin: true }), (c) => c.text('ok'));
// functions/auth/[[path]].js
import { createSso } from '@ropean/sso-client';
import { KvStore } from '@ropean/sso-client/store/kv';

export async function onRequest({ request, env }) {
  const sso = createSso({ env, store: new KvStore(env.AUTH_KV) });
  return sso.handleAt(request, '/auth');
}
import { createSso } from '@ropean/sso-client';
import { KvStore } from '@ropean/sso-client/store/kv';

export default {
  async fetch(request, env) {
    const sso = createSso({ env, store: new KvStore(env.AUTH_KV) });
    const url = new URL(request.url);
    if (url.pathname.startsWith('/auth')) return sso.handle(request);
    const auth = await sso.resolveAuth(request);
    if (!auth) return new Response('Unauthorized', { status: 401 });
    return new Response(`Hello ${auth.user.name}`);
  },
};
How it works

Under the hood the library runs Authorization Code + PKCE S256 — no implicit flow, no tokens in the browser. Sessions are stored server-side (SQLite or Cloudflare KV); the cookie carries only an HMAC-signed session ID. Access tokens refresh transparently on every request, with a distributed lock to prevent thundering herd on edge runtimes. Backchannel logout lets the SSO provider force-revoke sessions across all clients in real time.

Full SSO flow reference →