# Node.js (Traditional Web App)

Build a secure server‑rendered web app using BlitzWare OAuth 2.0 Authorization Code + PKCE with the BlitzWare Node SDK.

{% hint style="info" %}
This tutorial is based on the [example app](https://github.com/LanderDK/blitzware-node-web-sdk/tree/master/examples).
{% endhint %}

1. [**Configure BlitzWare**](#configure-blitzware)
2. [**Install the BlitzWare Node Web SDK**](#id-2-install-the-blitzware-node-web-sdk)
3. [**Configure environment**](#id-3-configure-environment)
4. [**Express setup**](#id-4-express-setup)
5. [**Koa setup**](#id-5-koa-setup)
6. [**How it works**](#id-6-how-it-works)

## 1) Configure BlitzWare <a href="#configure-blitzware" id="configure-blitzware"></a>

### Get Your Application Keys <a href="#get-your-application-keys" id="get-your-application-keys"></a>

You will need some details about your application to communicate with BlitzWare. You can get these details from the Application Settings section in the BlitzWare dashboard.

<figure><img src="/files/2wZRoRqdmWpuTXY4PW2j" alt=""><figcaption></figcaption></figure>

You need the **Client ID** and **Client Secret** (given when app was created).

### Configure Redirect URIs

A redirect URI is a URL in your application where BlitzWare redirects the user after they have authenticated. The redirect URI for your app must be added to the **Redirect URIs** list in your **Application Settings** under the **Security** tab. If this is not set, users will be unable to log in to the application and will get an error.

## 2) Install the BlitzWare Node Web SDK

Run the following command within your project directory to install the [BlitzWare Node Web SDK](https://www.npmjs.com/package/blitzware-node-web-sdk):

{% code title="npm" overflow="wrap" lineNumbers="true" %}

```
npm install blitzware-node-web-sdk
```

{% endcode %}

{% code title="yarn" lineNumbers="true" %}

```
yarn add blitzware-node-web-sdk
```

{% endcode %}

## 3) Configure environment

Create a `.env` file:

```bash
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)
# BLITZWARE_BASE_URL=https://auth.blitzware.xyz/api/auth
```

## 4) Express setup

{% code lineNumbers="true" %}

```javascript
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("blitzware-node-web-sdk");

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",
  // baseUrl: process.env.BLITZWARE_BASE_URL, // Optional: custom auth server
};

// 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;
```

{% endcode %}

## 5) Koa setup

{% code lineNumbers="true" %}

```javascript
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("blitzware-node-web-sdk");

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",
  // baseUrl: process.env.BLITZWARE_BASE_URL, // Optional: custom auth server
};

// 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
  `);
});
```

{% endcode %}

### 6) How it works

* PKCE + state: The SDK generates a `state` and PKCE verifier/challenge.
  * `state` defends against CSRF
  * PKCE protects the code exchange

#### Automatic Routes

When you use `expressAuth()` or `koaAuth()`, the following routes are created automatically:

* `GET /login` - Initiates OAuth login flow
* `GET /logout` - Logs out user and clears session
* `GET /callback` - OAuth callback handler

#### Protection

The SDK provides middleware to protect routes and enforce authorization:

**Authentication Middleware**

* `expressRequiresAuth()` / `koaRequiresAuth()` - Ensures a user is logged in before accessing a route. Redirects to `/login` if not authenticated.

**Express Example:**

```js
app.get("/profile", expressRequiresAuth(), (req, res) => {
  res.json({ user: req.session.user });
});
```

**Koa Example:**

```js
router.get("/profile", koaRequiresAuth(), async (ctx) => {
  ctx.body = { user: ctx.session.user };
});
```

**Role-Based Authorization Middleware**

* `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:**

```js
const { expressRequiresAuth, expressRequiresRole } = require("blitzware-node-sdk");

// Admin-only route
app.get("/admin", 
  expressRequiresAuth(), 
  expressRequiresRole("admin"), 
  (req, res) => {
    res.send("Admin Dashboard");
  }
);
```

**Koa Example:**

```js
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.

#### Logout (front-channel)

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 })`.

***

License: MIT


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.blitzware.xyz/oauth/quickstart/webapp/node.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
