securenow 4.0.2 → 4.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTO-BODY-CAPTURE.md +409 -0
- package/BODY-CAPTURE-FIX.md +258 -0
- package/BODY-CAPTURE-QUICKSTART.md +147 -0
- package/CUSTOMER-GUIDE.md +23 -0
- package/EASIEST-SETUP.md +339 -0
- package/FINAL-SOLUTION.md +332 -0
- package/NEXTJS-BODY-CAPTURE-COMPARISON.md +320 -0
- package/NEXTJS-BODY-CAPTURE.md +368 -0
- package/NEXTJS-GUIDE.md +10 -0
- package/NEXTJS-QUICKSTART.md +1 -1
- package/NEXTJS-WRAPPER-APPROACH.md +411 -0
- package/QUICKSTART-BODY-CAPTURE.md +287 -0
- package/REDACTION-EXAMPLES.md +481 -0
- package/REQUEST-BODY-CAPTURE.md +575 -0
- package/SOLUTION-SUMMARY.md +309 -0
- package/cli.js +1 -1
- package/examples/instrumentation-with-auto-capture.ts +38 -0
- package/examples/nextjs-api-route-with-body-capture.ts +51 -0
- package/examples/nextjs-middleware.js +34 -0
- package/examples/nextjs-middleware.ts +34 -0
- package/nextjs-auto-capture.js +204 -0
- package/nextjs-middleware.js +178 -0
- package/nextjs-wrapper.js +155 -0
- package/nextjs.js +204 -14
- package/package.json +20 -2
- package/postinstall.js +117 -22
- package/tracing.js +154 -1
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# ✅ Next.js Body Capture - Non-Invasive Wrapper Approach
|
|
2
|
+
|
|
3
|
+
## 🎯 The Problem with Middleware
|
|
4
|
+
|
|
5
|
+
**Middleware runs BEFORE your handlers** and can:
|
|
6
|
+
- ❌ Conflict with NextAuth and other middleware
|
|
7
|
+
- ❌ Block requests from reaching handlers
|
|
8
|
+
- ❌ Cause "Response body disturbed or locked" errors
|
|
9
|
+
- ❌ Interfere with routing
|
|
10
|
+
|
|
11
|
+
## ✅ The Solution: Handler Wrappers
|
|
12
|
+
|
|
13
|
+
**Wrappers run INSIDE your handlers** and:
|
|
14
|
+
- ✅ Never conflict with middleware
|
|
15
|
+
- ✅ Never block requests
|
|
16
|
+
- ✅ Run after all routing is complete
|
|
17
|
+
- ✅ Optional per-route (only wrap what you need)
|
|
18
|
+
- ✅ Non-invasive and safe
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 🚀 Quick Start
|
|
23
|
+
|
|
24
|
+
### Step 1: Enable in Environment
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# .env.local
|
|
28
|
+
SECURENOW_CAPTURE_BODY=1
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Step 2: Wrap Your API Routes
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// app/api/login/route.ts
|
|
35
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
36
|
+
|
|
37
|
+
export const POST = withSecureNow(async (request: Request) => {
|
|
38
|
+
const body = await request.json();
|
|
39
|
+
// Your handler code...
|
|
40
|
+
return Response.json({ success: true });
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**That's it!** Body is captured with sensitive fields redacted.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 📊 How It Works
|
|
49
|
+
|
|
50
|
+
### Traditional Middleware (Problematic)
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
Request → Middleware (reads body) → Conflicts → Handler (may not receive)
|
|
54
|
+
❌ Can block/interfere
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Wrapper Approach (Safe)
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Request → All Middleware → Routing → Handler (your code)
|
|
61
|
+
↓
|
|
62
|
+
Wrapper captures body in background
|
|
63
|
+
↓
|
|
64
|
+
Response returned
|
|
65
|
+
✅ Never blocks or interferes
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Key difference:** The wrapper runs INSIDE your handler, not before it!
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 🎓 Usage Examples
|
|
73
|
+
|
|
74
|
+
### Basic Usage
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
78
|
+
|
|
79
|
+
export const POST = withSecureNow(async (request: Request) => {
|
|
80
|
+
const data = await request.json();
|
|
81
|
+
return Response.json({ received: data });
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### With NextAuth (No Conflicts!)
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// middleware.ts - Your auth middleware (no securenow here!)
|
|
89
|
+
import { getToken } from 'next-auth/jwt';
|
|
90
|
+
|
|
91
|
+
export async function middleware(request) {
|
|
92
|
+
// Just your auth logic - no securenow interference
|
|
93
|
+
const token = await getToken({ req: request });
|
|
94
|
+
if (!token) {
|
|
95
|
+
return NextResponse.redirect('/login');
|
|
96
|
+
}
|
|
97
|
+
return NextResponse.next();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// app/api/protected/route.ts - Wrap individual routes
|
|
101
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
102
|
+
|
|
103
|
+
export const POST = withSecureNow(async (request: Request) => {
|
|
104
|
+
// This runs AFTER middleware, so no conflicts!
|
|
105
|
+
const body = await request.json();
|
|
106
|
+
return Response.json({ success: true });
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Selective Wrapping
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
114
|
+
|
|
115
|
+
// Capture body for sensitive routes
|
|
116
|
+
export const POST = withSecureNow(async (request: Request) => {
|
|
117
|
+
const body = await request.json();
|
|
118
|
+
return Response.json({ success: true });
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Don't capture for other routes
|
|
122
|
+
export async function GET(request: Request) {
|
|
123
|
+
return Response.json({ data: 'public' });
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### With Context (Next.js 14+)
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
131
|
+
|
|
132
|
+
export const POST = withSecureNow(async (
|
|
133
|
+
request: Request,
|
|
134
|
+
context: { params: { id: string } }
|
|
135
|
+
) => {
|
|
136
|
+
const body = await request.json();
|
|
137
|
+
const { id } = context.params;
|
|
138
|
+
return Response.json({ id, body });
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Pages Router (API Routes)
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
146
|
+
|
|
147
|
+
async function handler(req, res) {
|
|
148
|
+
if (req.method === 'POST') {
|
|
149
|
+
// Your logic
|
|
150
|
+
res.json({ success: true });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export default withSecureNow(handler);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 🔒 Security Features
|
|
160
|
+
|
|
161
|
+
### Automatic Redaction
|
|
162
|
+
|
|
163
|
+
**20+ sensitive fields redacted automatically:**
|
|
164
|
+
```
|
|
165
|
+
password, passwd, pwd, secret, token, api_key, apikey,
|
|
166
|
+
access_token, auth, credentials, card, cvv, cvc, ssn, pin
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Example:**
|
|
170
|
+
```typescript
|
|
171
|
+
// Request body:
|
|
172
|
+
{ "username": "john", "password": "secret123" }
|
|
173
|
+
|
|
174
|
+
// Captured in trace:
|
|
175
|
+
{ "username": "john", "password": "[REDACTED]" }
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Custom Sensitive Fields
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# .env.local
|
|
182
|
+
SECURENOW_SENSITIVE_FIELDS=email,phone,address
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Size Limits
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# .env.local
|
|
189
|
+
SECURENOW_MAX_BODY_SIZE=20480 # 20KB (default: 10KB)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## ⚡ Performance
|
|
195
|
+
|
|
196
|
+
**Non-blocking design:**
|
|
197
|
+
- Body capture runs in background
|
|
198
|
+
- Handler returns immediately
|
|
199
|
+
- < 1ms overhead
|
|
200
|
+
- Fails silently (never breaks your app)
|
|
201
|
+
|
|
202
|
+
**Overhead comparison:**
|
|
203
|
+
```
|
|
204
|
+
Without wrapper: 0ms baseline
|
|
205
|
+
With wrapper: < 1ms (async capture)
|
|
206
|
+
Your handler logic: Unchanged
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## 🎯 When to Use
|
|
212
|
+
|
|
213
|
+
### ✅ Use Wrapper When:
|
|
214
|
+
- You want body capture on specific routes
|
|
215
|
+
- You have NextAuth or other middleware
|
|
216
|
+
- You want zero conflicts
|
|
217
|
+
- You want per-route control
|
|
218
|
+
|
|
219
|
+
### ❌ Don't Use When:
|
|
220
|
+
- You don't need body capture
|
|
221
|
+
- You only want basic tracing (already included!)
|
|
222
|
+
|
|
223
|
+
**Remember:** Body capture is OPTIONAL. You get full tracing without it!
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## 📝 Complete Setup
|
|
228
|
+
|
|
229
|
+
### 1. instrumentation.ts (Required for all tracing)
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
import { registerSecureNow } from 'securenow/nextjs';
|
|
233
|
+
|
|
234
|
+
export function register() {
|
|
235
|
+
registerSecureNow();
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### 2. .env.local
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# Required
|
|
243
|
+
SECURENOW_APPID=my-nextjs-app
|
|
244
|
+
SECURENOW_INSTANCE=http://signoz:4318
|
|
245
|
+
|
|
246
|
+
# Optional: Enable body capture
|
|
247
|
+
SECURENOW_CAPTURE_BODY=1
|
|
248
|
+
SECURENOW_MAX_BODY_SIZE=10240
|
|
249
|
+
SECURENOW_SENSITIVE_FIELDS=custom_field
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### 3. API Routes (Optional - only for body capture)
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
256
|
+
|
|
257
|
+
export const POST = withSecureNow(async (request: Request) => {
|
|
258
|
+
const body = await request.json();
|
|
259
|
+
return Response.json({ success: true });
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 4. middleware.ts (Your auth logic - no securenow!)
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// Just your regular middleware - no securenow imports needed!
|
|
267
|
+
import { getToken } from 'next-auth/jwt';
|
|
268
|
+
|
|
269
|
+
export async function middleware(request) {
|
|
270
|
+
// Your auth logic
|
|
271
|
+
const token = await getToken({ req: request });
|
|
272
|
+
if (!token) return NextResponse.redirect('/login');
|
|
273
|
+
return NextResponse.next();
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## 🎉 Benefits
|
|
280
|
+
|
|
281
|
+
### No Middleware Conflicts
|
|
282
|
+
- ✅ Works with NextAuth
|
|
283
|
+
- ✅ Works with any middleware
|
|
284
|
+
- ✅ Never interferes with routing
|
|
285
|
+
- ✅ Runs after all middleware completes
|
|
286
|
+
|
|
287
|
+
### Non-Blocking
|
|
288
|
+
- ✅ Captures in background
|
|
289
|
+
- ✅ Handler returns immediately
|
|
290
|
+
- ✅ Never delays responses
|
|
291
|
+
- ✅ Fails silently
|
|
292
|
+
|
|
293
|
+
### Flexible
|
|
294
|
+
- ✅ Per-route control
|
|
295
|
+
- ✅ Wrap only what you need
|
|
296
|
+
- ✅ Easy to add/remove
|
|
297
|
+
- ✅ Works with App Router & Pages Router
|
|
298
|
+
|
|
299
|
+
### Safe
|
|
300
|
+
- ✅ Uses request.clone() (doesn't consume original)
|
|
301
|
+
- ✅ Error handling (never crashes app)
|
|
302
|
+
- ✅ Size limits (prevents memory issues)
|
|
303
|
+
- ✅ Automatic redaction (protects sensitive data)
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## ❓ FAQ
|
|
308
|
+
|
|
309
|
+
### Q: Do I need to change my middleware?
|
|
310
|
+
|
|
311
|
+
**A:** No! Your middleware stays exactly as-is. The wrapper runs inside your handlers, not in middleware.
|
|
312
|
+
|
|
313
|
+
### Q: Will this conflict with NextAuth?
|
|
314
|
+
|
|
315
|
+
**A:** No! NextAuth runs in middleware, this runs in handlers. They never interact.
|
|
316
|
+
|
|
317
|
+
### Q: What if I don't want body capture on all routes?
|
|
318
|
+
|
|
319
|
+
**A:** Only wrap the routes you want! Other routes still get traced, just no body capture.
|
|
320
|
+
|
|
321
|
+
### Q: Does this block my requests?
|
|
322
|
+
|
|
323
|
+
**A:** No! The capture runs asynchronously in the background.
|
|
324
|
+
|
|
325
|
+
### Q: What happens if capture fails?
|
|
326
|
+
|
|
327
|
+
**A:** It fails silently. Your handler always executes normally.
|
|
328
|
+
|
|
329
|
+
### Q: Can I use both middleware and wrapper?
|
|
330
|
+
|
|
331
|
+
**A:** Use wrapper for Next.js (safe). Middleware is kept for backward compatibility but not recommended.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## 🎯 Summary
|
|
336
|
+
|
|
337
|
+
### Wrapper Approach (Recommended)
|
|
338
|
+
```typescript
|
|
339
|
+
// ✅ SAFE - Runs inside handler
|
|
340
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
341
|
+
export const POST = withSecureNow(handler);
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
**Benefits:**
|
|
345
|
+
- ✅ No middleware conflicts
|
|
346
|
+
- ✅ No blocking
|
|
347
|
+
- ✅ Per-route control
|
|
348
|
+
- ✅ Works with NextAuth
|
|
349
|
+
|
|
350
|
+
### Middleware Approach (Not Recommended for Next.js)
|
|
351
|
+
```typescript
|
|
352
|
+
// ❌ Can cause conflicts
|
|
353
|
+
export { middleware } from 'securenow/nextjs-middleware';
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Issues:**
|
|
357
|
+
- ❌ Conflicts with NextAuth
|
|
358
|
+
- ❌ Can block requests
|
|
359
|
+
- ❌ Runs before routing
|
|
360
|
+
- ❌ All-or-nothing
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## 🚀 Migration Guide
|
|
365
|
+
|
|
366
|
+
**If you're using middleware approach:**
|
|
367
|
+
|
|
368
|
+
### Before (Middleware - Problematic)
|
|
369
|
+
```typescript
|
|
370
|
+
// middleware.ts
|
|
371
|
+
import { middleware as securenowMiddleware } from 'securenow/nextjs-middleware';
|
|
372
|
+
export async function middleware(request) {
|
|
373
|
+
await securenowMiddleware(request); // ❌ Can conflict
|
|
374
|
+
// Your auth logic...
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### After (Wrapper - Safe)
|
|
379
|
+
```typescript
|
|
380
|
+
// middleware.ts - Remove securenow completely!
|
|
381
|
+
export async function middleware(request) {
|
|
382
|
+
// Just your auth logic - no securenow!
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// app/api/*/route.ts - Add wrapper to individual routes
|
|
386
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
387
|
+
export const POST = withSecureNow(async (request) => {
|
|
388
|
+
// Your handler
|
|
389
|
+
});
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**Result:** Zero conflicts, full control, no blocking!
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## ✅ Ready to Use!
|
|
397
|
+
|
|
398
|
+
**The wrapper approach is:**
|
|
399
|
+
- ✅ Production-ready
|
|
400
|
+
- ✅ Conflict-free
|
|
401
|
+
- ✅ Non-invasive
|
|
402
|
+
- ✅ Self-sufficient
|
|
403
|
+
|
|
404
|
+
**Your customers get:**
|
|
405
|
+
- ✅ Full tracing (always)
|
|
406
|
+
- ✅ Optional body capture (per route)
|
|
407
|
+
- ✅ No code changes needed (except wrapping routes)
|
|
408
|
+
- ✅ Works with any middleware
|
|
409
|
+
|
|
410
|
+
**Status: Recommended for all Next.js apps!** 🎊
|
|
411
|
+
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# 🚀 Quick Start: Body Capture in Next.js
|
|
2
|
+
|
|
3
|
+
## ✅ Recommended: Wrapper Approach (No Conflicts!)
|
|
4
|
+
|
|
5
|
+
This approach **never interferes** with your middleware or routing.
|
|
6
|
+
|
|
7
|
+
### Step 1: Enable in .env.local
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
SECURENOW_APPID=my-app
|
|
11
|
+
SECURENOW_INSTANCE=http://signoz:4318
|
|
12
|
+
SECURENOW_CAPTURE_BODY=1
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Step 2: Wrap Your API Routes
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// app/api/login/route.ts
|
|
19
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
20
|
+
|
|
21
|
+
export const POST = withSecureNow(async (request: Request) => {
|
|
22
|
+
const body = await request.json();
|
|
23
|
+
|
|
24
|
+
// Your logic here...
|
|
25
|
+
|
|
26
|
+
return Response.json({ success: true });
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Step 3: Keep Your Middleware Clean
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// middleware.ts - NO securenow imports!
|
|
34
|
+
import { getToken } from 'next-auth/jwt';
|
|
35
|
+
|
|
36
|
+
export async function middleware(request) {
|
|
37
|
+
// Just your auth logic - securenow doesn't interfere!
|
|
38
|
+
const token = await getToken({ req: request });
|
|
39
|
+
if (!token) {
|
|
40
|
+
return NextResponse.redirect('/login');
|
|
41
|
+
}
|
|
42
|
+
return NextResponse.next();
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**That's it!** 🎉
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## What Gets Captured
|
|
51
|
+
|
|
52
|
+
### ✅ Automatically Captured & Redacted
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Request:
|
|
56
|
+
{
|
|
57
|
+
"username": "john",
|
|
58
|
+
"password": "secret123",
|
|
59
|
+
"email": "john@example.com"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// In your traces (sensitive fields redacted):
|
|
63
|
+
{
|
|
64
|
+
"username": "john",
|
|
65
|
+
"password": "[REDACTED]",
|
|
66
|
+
"email": "john@example.com"
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 🔒 Auto-Redacted Fields (20+)
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
password, passwd, pwd, secret, token, api_key, access_token,
|
|
74
|
+
auth, credentials, card, cardnumber, cvv, cvc, ssn, pin, etc.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 📝 Supported Content Types
|
|
78
|
+
|
|
79
|
+
- ✅ JSON (`application/json`)
|
|
80
|
+
- ✅ GraphQL (`application/graphql`)
|
|
81
|
+
- ✅ Form data (`application/x-www-form-urlencoded`)
|
|
82
|
+
- ℹ️ Multipart (marked as `[MULTIPART - NOT CAPTURED]`)
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## ✨ Benefits
|
|
87
|
+
|
|
88
|
+
### Zero Conflicts
|
|
89
|
+
- ✅ Works perfectly with NextAuth
|
|
90
|
+
- ✅ Works with any middleware
|
|
91
|
+
- ✅ Never blocks requests
|
|
92
|
+
- ✅ Runs inside your handler (not before)
|
|
93
|
+
|
|
94
|
+
### Safe & Secure
|
|
95
|
+
- ✅ Automatic sensitive data redaction
|
|
96
|
+
- ✅ Size limits (configurable)
|
|
97
|
+
- ✅ Non-blocking (background capture)
|
|
98
|
+
- ✅ Fails silently (never breaks your app)
|
|
99
|
+
|
|
100
|
+
### Flexible
|
|
101
|
+
- ✅ Per-route control (wrap only what you need)
|
|
102
|
+
- ✅ Easy to add/remove
|
|
103
|
+
- ✅ Works with App Router & Pages Router
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 📊 Example: Full API Route
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
111
|
+
import { db } from '@/lib/db';
|
|
112
|
+
|
|
113
|
+
export const POST = withSecureNow(async (request: Request) => {
|
|
114
|
+
try {
|
|
115
|
+
// Parse body (securenow captures this automatically)
|
|
116
|
+
const { email, password } = await request.json();
|
|
117
|
+
|
|
118
|
+
// Your business logic
|
|
119
|
+
const user = await db.user.create({
|
|
120
|
+
data: { email, passwordHash: hash(password) }
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
return Response.json({
|
|
124
|
+
success: true,
|
|
125
|
+
userId: user.id
|
|
126
|
+
});
|
|
127
|
+
} catch (error) {
|
|
128
|
+
return Response.json({
|
|
129
|
+
success: false,
|
|
130
|
+
error: error.message
|
|
131
|
+
}, { status: 400 });
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Optional: Other methods without capture
|
|
136
|
+
export async function GET() {
|
|
137
|
+
const users = await db.user.findMany();
|
|
138
|
+
return Response.json({ users });
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Trace will show:**
|
|
143
|
+
- ✅ HTTP method, path, status
|
|
144
|
+
- ✅ Request body: `{"email":"john@example.com","password":"[REDACTED]"}`
|
|
145
|
+
- ✅ Response time
|
|
146
|
+
- ✅ IP address, user agent
|
|
147
|
+
- ✅ All without blocking or interfering!
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## ⚙️ Configuration
|
|
152
|
+
|
|
153
|
+
### Environment Variables
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Required
|
|
157
|
+
SECURENOW_APPID=my-nextjs-app
|
|
158
|
+
SECURENOW_INSTANCE=http://your-signoz:4318
|
|
159
|
+
|
|
160
|
+
# Body capture
|
|
161
|
+
SECURENOW_CAPTURE_BODY=1 # Enable body capture
|
|
162
|
+
SECURENOW_MAX_BODY_SIZE=10240 # Max size in bytes (10KB default)
|
|
163
|
+
SECURENOW_SENSITIVE_FIELDS=email,phone # Additional fields to redact
|
|
164
|
+
|
|
165
|
+
# Optional
|
|
166
|
+
OTEL_LOG_LEVEL=info # Logging level
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Custom Sensitive Fields
|
|
170
|
+
|
|
171
|
+
Add your own fields to redact:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
SECURENOW_SENSITIVE_FIELDS=credit_card_number,ssn,bank_account
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Now these will also show as `[REDACTED]` in traces!
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 🎓 More Examples
|
|
182
|
+
|
|
183
|
+
### Selective Wrapping
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// Capture body for login
|
|
187
|
+
export const POST = withSecureNow(async (request: Request) => {
|
|
188
|
+
const body = await request.json();
|
|
189
|
+
return Response.json({ success: true });
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// No capture for public endpoint
|
|
193
|
+
export async function GET() {
|
|
194
|
+
return Response.json({ status: 'ok' });
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### With Dynamic Routes
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// app/api/users/[id]/route.ts
|
|
202
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
203
|
+
|
|
204
|
+
export const PUT = withSecureNow(async (
|
|
205
|
+
request: Request,
|
|
206
|
+
{ params }: { params: { id: string } }
|
|
207
|
+
) => {
|
|
208
|
+
const body = await request.json();
|
|
209
|
+
const userId = params.id;
|
|
210
|
+
|
|
211
|
+
await updateUser(userId, body);
|
|
212
|
+
|
|
213
|
+
return Response.json({ updated: true });
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Pages Router
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
// pages/api/login.ts
|
|
221
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
222
|
+
|
|
223
|
+
async function handler(req, res) {
|
|
224
|
+
if (req.method === 'POST') {
|
|
225
|
+
const { email, password } = req.body;
|
|
226
|
+
// Your logic...
|
|
227
|
+
res.json({ success: true });
|
|
228
|
+
} else {
|
|
229
|
+
res.status(405).end();
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export default withSecureNow(handler);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 🐛 Troubleshooting
|
|
239
|
+
|
|
240
|
+
### Q: I'm getting "Response body disturbed or locked" errors
|
|
241
|
+
|
|
242
|
+
**A:** Don't use the middleware approach! Use the wrapper approach shown above. The wrapper runs inside your handler and never locks the request.
|
|
243
|
+
|
|
244
|
+
### Q: Bodies aren't being captured
|
|
245
|
+
|
|
246
|
+
**Check:**
|
|
247
|
+
1. Is `SECURENOW_CAPTURE_BODY=1` set in `.env.local`?
|
|
248
|
+
2. Did you wrap the route with `withSecureNow()`?
|
|
249
|
+
3. Is the request POST/PUT/PATCH?
|
|
250
|
+
4. Is content-type `application/json` or similar?
|
|
251
|
+
|
|
252
|
+
### Q: Can I use this with NextAuth?
|
|
253
|
+
|
|
254
|
+
**A:** Yes! That's exactly what it's designed for. Your middleware stays clean:
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
// middleware.ts - Just NextAuth, no securenow!
|
|
258
|
+
export async function middleware(request) {
|
|
259
|
+
const token = await getToken({ req: request });
|
|
260
|
+
// ...
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// API routes - Add securenow wrapper
|
|
264
|
+
export const POST = withSecureNow(handler);
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## ✅ Summary
|
|
270
|
+
|
|
271
|
+
**Setup (2 steps):**
|
|
272
|
+
1. Set `SECURENOW_CAPTURE_BODY=1` in `.env.local`
|
|
273
|
+
2. Wrap routes: `withSecureNow(handler)`
|
|
274
|
+
|
|
275
|
+
**Result:**
|
|
276
|
+
- ✅ Request bodies captured
|
|
277
|
+
- ✅ Sensitive fields redacted
|
|
278
|
+
- ✅ Zero middleware conflicts
|
|
279
|
+
- ✅ Non-blocking & safe
|
|
280
|
+
- ✅ Works with NextAuth
|
|
281
|
+
|
|
282
|
+
**That's it!** 🎊
|
|
283
|
+
|
|
284
|
+
📚 **More info:**
|
|
285
|
+
- `NEXTJS-WRAPPER-APPROACH.md` - Full guide
|
|
286
|
+
- `NEXTJS-BODY-CAPTURE-COMPARISON.md` - Comparison with middleware approach
|
|
287
|
+
|