A comprehensive OAuth 2.0 SDK for Node.js applications supporting both Express.js and Koa.js frameworks with middleware patterns.
Build a secure serverβrendered web app using BlitzWare OAuth 2.0 Authorization Code flow with automatic route management and session handling.
- A BlitzWare OAuth application (Client ID, Client Secret, Redirect URI)
- Node.js 18+
- HTTPS in production
Get your application keys from the BlitzWare dashboard. You will need:
- Client ID
- Client Secret
- A Redirect URI added to your application's Redirect URIs list (under Security)
If the redirect URI is not configured, authentication will fail.
Run this in your project directory:
npm install blitzware-node-sdk express express-session dotenv
# or
# yarn add blitzware-node-sdk express express-session dotenvCreate a .env file with your credentials:
BLITZWARE_CLIENT_ID=your-client-id
BLITZWARE_CLIENT_SECRET=your-client-secret
BLITZWARE_REDIRECT_URI=http://localhost:3000/callback
SESSION_SECRET=replace-with-a-strong-secret
# Optional: override auth base (self-hosted/staging)
# Optional managed auth domain shown in the BlitzWare dashboard
# BLITZWARE_AUTH_BASE_URL=https://acme.auth.blitzware.xyz/api/auth/
Create server.js (or app.js):
const path = require("path");
require("dotenv").config({ path: path.join(__dirname, "../.env") });
const express = require("express");
const session = require("express-session");
const { expressAuth, expressRequiresAuth } = require("../dist");
const app = express();
const port = process.env.PORT || 3000;
// BlitzWare configuration
const config = {
authRequired: false, // Don't require auth for all routes
clientId: process.env.BLITZWARE_CLIENT_ID || "your-client-id",
clientSecret: process.env.BLITZWARE_CLIENT_SECRET || "your-client-secret",
redirectUri:
process.env.BLITZWARE_REDIRECT_URI || `http://localhost:${port}/callback`,
secret: process.env.SESSION_SECRET || "LONG_RANDOM_STRING",
// authBaseUrl: process.env.BLITZWARE_AUTH_BASE_URL, // Optional managed auth domain
};
// Session middleware (required for auth middleware)
app.use(
session({
secret: config.secret,
resave: false,
saveUninitialized: false,
})
);
// Parse JSON bodies
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// BlitzWare auth router attaches /login, /logout, and /callback routes
app.use(expressAuth(config));
// Home route - req.session.user is provided from the auth router
app.get("/", (req, res) => {
res.send(`
<html>
<head><title>BlitzWare Express Example</title></head>
<body>
<h1>BlitzWare Express Example</h1>
${
req.session.user
? `
<p>β
<strong>Logged in as ${req.session.user.username}</strong></p>
<p><a href="/profile">View Profile</a></p>
<p><a href="/logout">Logout</a></p>
`
: `
<p>β Not logged in</p>
<p><a href="/login">Login</a></p>
`
}
</body>
</html>
`);
});
// Protected profile route - expressRequiresAuth() middleware
app.get("/profile", expressRequiresAuth(), (req, res) => {
res.send(`
<html>
<head><title>Profile</title></head>
<body>
<h1>Profile</h1>
<pre>${JSON.stringify(req.session.user, null, 2)}</pre>
<p><a href="/">β Back to Home</a></p>
</body>
</html>
`);
});
app.listen(port, () => {
console.log(`
π BlitzWare Express Example running at http://localhost:${port}
π Routes:
β’ GET / - Home page
β’ GET /profile - Protected profile page
β’ GET /login - Login (automatic)
β’ GET /logout - Logout (automatic)
π Setup:
1. Set BLITZWARE_CLIENT_ID and BLITZWARE_CLIENT_SECRET in .env
2. Visit http://localhost:${port}/login to authenticate
`);
});
module.exports = app;Run:
node server.jsThen visit http://localhost:3000.
Create a Koa app (example):
const path = require("path");
require("dotenv").config({ path: path.join(__dirname, "../.env") });
const Koa = require("koa");
const Router = require("@koa/router");
const KoaSession = require("koa-session");
const session = KoaSession && KoaSession.default ? KoaSession.default : KoaSession;
const bodyParser = require("koa-bodyparser");
const { koaAuth, koaRequiresAuth } = require("../dist");
const app = new Koa();
const router = new Router();
const port = process.env.PORT || 3001;
// BlitzWare configuration
const config = {
authRequired: false, // Don't require auth for all routes
clientId: process.env.BLITZWARE_CLIENT_ID || "your-client-id",
clientSecret: process.env.BLITZWARE_CLIENT_SECRET || "your-client-secret",
redirectUri:
process.env.BLITZWARE_REDIRECT_URI || `http://localhost:${port}/callback`,
secret: process.env.SESSION_SECRET || "LONG_RANDOM_STRING",
// authBaseUrl: process.env.BLITZWARE_AUTH_BASE_URL, // Optional managed auth domain
};
// Koa requires signing keys for sessions
app.keys = [config.secret];
// Session middleware
app.use(session(app));
app.use(bodyParser());
// BlitzWare auth router attaches /login, /logout, and /callback routes
app.use(koaAuth(config));
// Home route - ctx.session.user is provided from the auth router
router.get("/", async (ctx) => {
ctx.type = "html";
ctx.body = `
<html>
<head><title>BlitzWare Koa Example</title></head>
<body>
<h1>BlitzWare Koa Example</h1>
${
ctx.session.user
? `
<p>β
<strong>Logged in as ${ctx.session.user.username}</strong></p>
<p><a href="/profile">View Profile</a></p>
<p><a href="/logout">Logout</a></p>
`
: `
<p>β Not logged in</p>
<p><a href="/login">Login</a></p>
`
}
</body>
</html>
`;
});
// Protected profile route - koaRequiresAuth() middleware
router.get("/profile", koaRequiresAuth(), async (ctx) => {
ctx.type = "html";
ctx.body = `
<html>
<head><title>Profile</title></head>
<body>
<h1>Profile</h1>
<pre>${JSON.stringify(ctx.session.user, null, 2)}</pre>
<p><a href="/">β Back to Home</a></p>
</body>
</html>
`;
});
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(port, () => {
console.log(`
π BlitzWare Koa Example running at http://localhost:${port}
π Routes:
β’ GET / - Home page
β’ GET /profile - Protected profile page
β’ GET /login - Login (automatic)
β’ GET /logout - Logout (automatic)
π Setup:
1. Set BLITZWARE_CLIENT_ID and BLITZWARE_CLIENT_SECRET in .env
2. Visit http://localhost:${port}/login to authenticate
`);
});- PKCE + state: The SDK generates a
stateand PKCE verifier/challenge.statedefends against CSRF- PKCE protects the code exchange
When you use expressAuth() or koaAuth(), the following routes are created automatically:
GET /login- Initiates OAuth login flowGET /logout- Logs out user and clears sessionGET /callback- OAuth callback handler
The SDK provides middleware to protect routes and enforce authorization:
expressRequiresAuth()/koaRequiresAuth()- Ensures a user is logged in before accessing a route. Redirects to/loginif not authenticated.
Express Example:
app.get("/profile", expressRequiresAuth(), (req, res) => {
res.json({ user: req.session.user });
});Koa Example:
router.get("/profile", koaRequiresAuth(), async (ctx) => {
ctx.body = { user: ctx.session.user };
});expressRequiresRole(role)/koaRequiresRole(role)- Ensures a user has a specific role. Returns 403 Forbidden if the user doesn't have the required role.
Express Example:
const { expressRequiresAuth, expressRequiresRole } = require("blitzware-node-sdk");
// Admin-only route
app.get("/admin",
expressRequiresAuth(),
expressRequiresRole("admin"),
(req, res) => {
res.send("Admin Dashboard");
}
);Koa Example:
const { koaRequiresAuth, koaRequiresRole } = require("blitzware-node-sdk");
// Admin-only route
router.get("/admin",
koaRequiresAuth(),
koaRequiresRole("admin"),
async (ctx) => {
ctx.body = "Admin Dashboard";
}
);Note: These middleware functions check for roles stored in user.roles array. They do not perform token introspection by default.
The SDK performs a front-channel logout: it serves a small HTML page that POSTs to the auth service (so auth-service cookies are sent) and then redirects back to your app.
If you need additional features β token introspection on each request, automatic refresh using session.refreshToken, or other behavior β open an issue or PR and I can add an opt-in option such as requiresAuth({ validateToken: true }).
authBaseUrl is optional. Omit it to keep using https://auth.blitzware.xyz/api/auth/; set it to the managed auth domain shown in the BlitzWare dashboard, such as https://acme.auth.blitzware.xyz/api/auth/.
If Google, Microsoft, Discord, or another social provider is enabled, add the managed-domain callback URL in that provider's settings before switching users to the managed domain. This option does not require JWKS, ID tokens, or OIDC discovery configuration.
License: MIT