@yescure/auth-node
v0.1.2
Published
Express/Fastify/plain-Node adapter for YesCure authentication
Downloads
52
Maintainers
Readme
@yescure/auth-node
Express-compatible adapter for YesCure authentication. One factory call wires up /login, /callback, /logout, /backchannel-logout, plus a middleware to protect routes.
Install
npm install @yescure/auth-node expressQuickstart
// auth.ts
import { yescureAuth } from "@yescure/auth-node";
export const auth = yescureAuth({
issuer: process.env.OIDC_ISSUER!,
clientId: process.env.OIDC_CLIENT_ID!,
clientSecret: process.env.OIDC_CLIENT_SECRET!,
redirectUri: process.env.OIDC_REDIRECT_URI!,
sessionSecret: process.env.SESSION_SECRET!,
backchannelLogoutSecret: process.env.YESCURE_BACKCHANNEL_LOGOUT_SECRET,
// Optional: persist users to your DB when they log in
onLogin: async ({ claims }) => {
const user = await db.upsertUser({
yescure_sub: claims.sub,
email: claims.email,
name: claims.preferred_username,
});
return { role: user.role }; // merged into the session cookie
},
// Optional: invalidate sessions when YesCure backchannel-logout fires
onBackchannelLogout: async ({ sub }) => {
await db.recordRevocation(sub);
},
isSessionRevoked: async (session) => {
return await db.isRevoked(session.sub, session.iat);
},
});// server.ts
import express from "express";
import { auth } from "./auth";
const app = express();
// Mounts /auth/login, /auth/callback, /auth/logout, /auth/backchannel-logout
app.use("/auth", auth.router());
// Protect any route
app.get("/dashboard", auth.required(), (req, res) => {
res.json({ user: req.user });
});
// JSON API style — 401 instead of redirect
app.get("/api/me", auth.required({ mode: "api" }), (req, res) => {
res.json({ user: req.user });
});
app.listen(3000);That's the whole integration. Your /auth/login link sends users to YesCure; YesCure redirects back to /auth/callback; you get a signed session cookie; req.user is populated on protected routes.
Configuration reference
| Option | Required | Description |
|--------|----------|-------------|
| issuer | ✓ | YesCure issuer URL |
| clientId | ✓ | From yescure-admin |
| clientSecret | confidential clients only | From yescure-admin |
| redirectUri | ✓ | Must match what you registered |
| sessionSecret | ✓ | openssl rand -hex 32, ≥32 chars |
| backchannelLogoutSecret | recommended | Shared secret YesCure sends in x-yescure-logout-token |
| scopes | | Default: "openid profile email" |
| sessionCookieName | | Default: "yescure_session" |
| sessionMaxAgeSeconds | | Default: 28800 (8 h) |
| cookieSecure | | Default: true in production |
| cookieDomain | | Set to ".example.com" for cross-subdomain SSO |
| defaultReturnTo | | Default: "/" |
| onLogin | | Persist user, return extra session fields |
| onBackchannelLogout | | Record revocation in DB |
| isSessionRevoked | | Block sessions revoked by backchannel logout |
What's mounted
app.use("/auth", auth.router()) adds:
GET /auth/login→ generates PKCE + state + nonce, redirects to YesCureGET /auth/callback→ verifies state, exchanges code, verifies id_token, firesonLogin, sets session cookieGET /auth/logoutandPOST /auth/logout→ clears the session cookiePOST /auth/backchannel-logout→ verifies the shared secret, callsonBackchannelLogout
You can override any of these paths via auth.router({ paths: { login: "/sign-in" } }).
Middleware
auth.required() // browser pages — redirects to login
auth.required({ mode: "api" }) // JSON APIs — returns 401
auth.getSession(req) // returns SessionUser | null (no enforcement)Drop-in access to the OIDC client
If you need lower-level control (refresh tokens, revoke, custom callback handling), auth.client is the underlying YescureClient from @yescure/auth-core.
