> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blursec.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Replit

# Replit integration

`@blursec/replit` is the official Replit adapter for `@blursec/sdk` —
zero-config credential & session leak protection for apps hosted on Replit.

The core SDK is already isomorphic and runs on Replit without any adapter.
This package layers on the Replit-specific wiring that is tedious to do by
hand:

| Export                      | What it does                                                                                                                      |
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `createBlursecFromReplit()` | Reads `BLURSEC_API_KEY` from Replit Secrets, tags outbound traffic with your Repl owner/slug/id, validates `BLURSEC_ENVIRONMENT`. |
| `blursecSession()`          | Express middleware that verifies the inbound session cookie/Bearer token against the live stealer-log feed on every request.      |
| `blursecLogin()`            | Express middleware for `POST /login` that runs email+password through Blursec **before** bcrypt.                                  |
| `blursecReplitIdentity()`   | Parses the `X-Replit-User-*` headers Replit's edge proxy injects into a typed `ReplitAuthIdentity` on `req.blursec.identity`.     |
| `replitAuthHeaders(req)`    | Standalone version of the above — call it from any framework.                                                                     |

Like everything else in the Blursec ecosystem it **fails open** on outages,
adds \~50 ms to a login, and runs on every Replit-supported runtime
(Node 18+, Bun, Deno).

## Install

```bash theme={null}
npm i @blursec/sdk @blursec/replit
```

`@blursec/sdk` is a **peer dependency**, so the adapter and the SDK version
independently — bring any SDK >= 1.0.0.

## Quick start (Replit + Express)

1. Open your Repl's **Secrets** pane (lock icon in the left sidebar).
2. Add a secret named `BLURSEC_API_KEY` with your Blursec API key.
3. Drop this into `index.ts`:

```ts theme={null}
import express from "express";
import { createBlursecFromReplit } from "@blursec/replit";
import { blursecLogin, blursecSession } from "@blursec/replit/express";

const app = express();
app.use(express.json());

const blursec = createBlursecFromReplit();

// Per-request session verification (every authenticated request).
app.use(blursecSession(blursec, { cookieName: "sid" }));

// Login-time credential check (before bcrypt).
app.post("/login", blursecLogin(blursec), async (req, res) => {
  // Your normal password verification only runs if the credential
  // is not known-compromised (or if Blursec failed open).
  res.json({ ok: true });
});

app.listen(3000);
```

Both middlewares fail open on Blursec outages — your login flow keeps
working even if the API is unreachable.

## `createBlursecFromReplit(overrides?)`

Env-aware constructor. Every field of `BlursecClientConfig` may be
overridden via the `overrides` argument.

| Env var               | Purpose                                                  |
| --------------------- | -------------------------------------------------------- |
| `BLURSEC_API_KEY`     | API key from Replit Secrets (required unless overridden) |
| `BLURSEC_ENVIRONMENT` | `production` (default) / `staging` / `local`             |
| `REPL_OWNER`          | Repl owner — tagged on outbound headers                  |
| `REPL_SLUG`           | Repl slug — tagged on outbound headers                   |
| `REPL_ID`             | Repl id — tagged on outbound headers                     |

Throws `BlursecValidationError` when `BLURSEC_API_KEY` is missing.

## `blursecSession(blursec, options?)`

Express middleware. Verifies the inbound session token against the
stealer-log feed.

| Option            | Default             | Notes                                      |
| ----------------- | ------------------- | ------------------------------------------ |
| `cookieName`      | `"session"`         | Forwarded to `extractSessionToken`.        |
| `header`          | `"authorization"`   | Header to read instead of `Authorization`. |
| `dryRun`          | `false`             | Observe-only mode — never blocks.          |
| `failOpen`        | `true`              | Inherited from the SDK.                    |
| `timeoutMs`       | `1500`              | Inherited from the SDK.                    |
| `resetPath`       | `"/auth/reset"`     | Set `null` to respond `403 JSON` instead.  |
| `onResult`        | —                   | Fires for every result (audit logging).    |
| `onBlock`         | —                   | Override the default `401 JSON`.           |
| `contextBuilder`  | `{ ip, userAgent }` | Custom `RequestContext` builder.           |
| `severityActions` | SDK default         | Per-severity action overrides.             |

Decision matrix:

| `recommendedAction`             | Default response                                         |
| ------------------------------- | -------------------------------------------------------- |
| `allow`                         | pass through                                             |
| `monitor`                       | pass through, fires `onResult`                           |
| `force_reset` / `kill_sessions` | `302 → resetPath` (or `403 JSON` when `resetPath: null`) |
| `block`                         | `401 JSON` (or `onBlock`)                                |

When the SDK fails open (timeout, network, 5xx, circuit open) the
middleware passes through unchanged.

## `blursecLogin(blursec, options?)`

Express middleware for `POST /login`. Runs `body[emailField]` +
`body[passwordField]` through `blursec.checkCredential` before returning
control to your password-verification handler.

| Option           | Default             | Notes                            |
| ---------------- | ------------------- | -------------------------------- |
| `emailField`     | `"email"`           | `req.body` field name.           |
| `passwordField`  | `"password"`        | `req.body` field name.           |
| `resetPath`      | `"/auth/reset"`     | Set `null` for `403 JSON`.       |
| `dryRun`         | `false`             | Observe-only.                    |
| `failOpen`       | `true`              | Inherited from the SDK.          |
| `onResult`       | —                   | Fires for every result.          |
| `onBlock`        | —                   | Override default `403 JSON`.     |
| `contextBuilder` | `{ ip, userAgent }` | Custom `RequestContext` builder. |

The decision matrix matches `blursecSession`, except `block` responds
`403 JSON` by default.

## Replit Auth identity

`blursecReplitIdentity()` attaches a typed identity parsed from the
`X-Replit-User-*` headers to `req.blursec.identity`. It never
short-circuits the response — pair it with your own logic for routes that
require Replit Auth.

`replitAuthHeaders(req)` is the framework-agnostic version: it accepts any
`RequestLike` (WHATWG `Request`, Node `IncomingMessage`, Express `req`, or
bare `{ headers }`) and returns an unauthenticated identity
(`isAuthenticated: false`) when no headers are present.

## TypeScript: augmenting `Request.blursec`

The Express adapters attach state to `req.blursec`. For type completion in
your handlers, add this to a `*.d.ts` in your project:

```ts theme={null}
declare module "express-serve-static-core" {
  interface Request {
    blursec?: import("@blursec/replit/express").BlursecRequestState;
  }
}
```

## Dry-run rollout (recommended)

Pass `dryRun: true` for the first 1–2 weeks so you can dashboard the real
signal without enforcing:

```ts theme={null}
app.use(blursecSession(blursec, { dryRun: true, onResult: logToDatadog }));
app.post("/login", blursecLogin(blursec, { dryRun: true, onResult: logToDatadog }));
```

`recommendedAction` will always be `"allow"`; the would-be action is
surfaced via `result.enforcedAction`. Flip `dryRun` off when your
dashboards are clean.

See the runnable example in
[examples/replit-express.ts](https://github.com/blur-sec/blursec-sdk/blob/main/packages/replit/examples/replit-express.ts)
and the error model in [errors](/docs/errors).
