securenow 4.0.3 → 4.0.6
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/CUSTOMER-GUIDE.md +5 -1
- 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-WRAPPER-APPROACH.md +411 -0
- package/QUICKSTART-BODY-CAPTURE.md +287 -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 +24 -61
- package/package.json +17 -2
- package/postinstall.js +117 -22
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# Next.js Body Capture - Choosing the Right Approach
|
|
2
|
+
|
|
3
|
+
## 🎯 Two Approaches Available
|
|
4
|
+
|
|
5
|
+
SecureNow offers two ways to capture request bodies in Next.js:
|
|
6
|
+
|
|
7
|
+
1. **Wrapper Approach** (Recommended ✅)
|
|
8
|
+
2. **Middleware Approach** (Use with caution ⚠️)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## ✅ Wrapper Approach (RECOMMENDED)
|
|
13
|
+
|
|
14
|
+
### How It Works
|
|
15
|
+
|
|
16
|
+
Wrap individual API route handlers to capture bodies **inside the handler**:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
20
|
+
|
|
21
|
+
export const POST = withSecureNow(async (request: Request) => {
|
|
22
|
+
const body = await request.json();
|
|
23
|
+
return Response.json({ success: true });
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### ✅ Pros
|
|
28
|
+
|
|
29
|
+
- **Zero middleware conflicts** - Doesn't interfere with NextAuth or other middleware
|
|
30
|
+
- **Never blocks requests** - Runs after routing is complete
|
|
31
|
+
- **Per-route control** - Wrap only the routes you need
|
|
32
|
+
- **Non-invasive** - Your middleware stays unchanged
|
|
33
|
+
- **Safe** - Runs inside your handler, can't prevent handler execution
|
|
34
|
+
- **Background capture** - Doesn't delay responses
|
|
35
|
+
|
|
36
|
+
### ❌ Cons
|
|
37
|
+
|
|
38
|
+
- Requires wrapping each route individually (but only the ones you want!)
|
|
39
|
+
- Slightly more verbose (one extra line per route)
|
|
40
|
+
|
|
41
|
+
### When to Use
|
|
42
|
+
|
|
43
|
+
- ✅ You have NextAuth or other middleware
|
|
44
|
+
- ✅ You want zero conflicts
|
|
45
|
+
- ✅ You want fine-grained control
|
|
46
|
+
- ✅ You prioritize reliability
|
|
47
|
+
- ✅ **This is the recommended approach for most users**
|
|
48
|
+
|
|
49
|
+
### Setup
|
|
50
|
+
|
|
51
|
+
**Step 1:** Enable in .env.local
|
|
52
|
+
```bash
|
|
53
|
+
SECURENOW_CAPTURE_BODY=1
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Step 2:** Wrap your API routes
|
|
57
|
+
```typescript
|
|
58
|
+
// app/api/login/route.ts
|
|
59
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
60
|
+
|
|
61
|
+
export const POST = withSecureNow(async (request: Request) => {
|
|
62
|
+
const body = await request.json();
|
|
63
|
+
// Your logic...
|
|
64
|
+
return Response.json({ success: true });
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**That's it!** No middleware.ts needed.
|
|
69
|
+
|
|
70
|
+
📚 **Full guide:** See `NEXTJS-WRAPPER-APPROACH.md`
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## ⚠️ Middleware Approach (Use with Caution)
|
|
75
|
+
|
|
76
|
+
### How It Works
|
|
77
|
+
|
|
78
|
+
Export SecureNow's middleware to capture bodies **before your handlers**:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
// middleware.ts
|
|
82
|
+
export { middleware } from 'securenow/nextjs-middleware';
|
|
83
|
+
|
|
84
|
+
export const config = {
|
|
85
|
+
matcher: '/api/:path*',
|
|
86
|
+
};
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### ✅ Pros
|
|
90
|
+
|
|
91
|
+
- One-time setup (no per-route wrapping)
|
|
92
|
+
- Applies to all routes automatically
|
|
93
|
+
|
|
94
|
+
### ❌ Cons
|
|
95
|
+
|
|
96
|
+
- **Can conflict with NextAuth** and other middleware
|
|
97
|
+
- **May block requests** from reaching handlers
|
|
98
|
+
- **All-or-nothing** - applies to all matched routes
|
|
99
|
+
- **Runs before routing** - can interfere with request flow
|
|
100
|
+
- **May cause "Response body disturbed or locked" errors**
|
|
101
|
+
|
|
102
|
+
### When to Use
|
|
103
|
+
|
|
104
|
+
- You have no other middleware
|
|
105
|
+
- You want to capture ALL routes
|
|
106
|
+
- You're okay with potential conflicts
|
|
107
|
+
- **Not recommended if you use NextAuth or have complex middleware**
|
|
108
|
+
|
|
109
|
+
### Known Issues
|
|
110
|
+
|
|
111
|
+
**Conflicts with NextAuth:**
|
|
112
|
+
```typescript
|
|
113
|
+
// ❌ This can cause conflicts
|
|
114
|
+
export { middleware } from 'securenow/nextjs-middleware';
|
|
115
|
+
|
|
116
|
+
// If you also use NextAuth, you'll need complex middleware composition
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Solution:** Use the wrapper approach instead!
|
|
120
|
+
|
|
121
|
+
📚 **Full guide:** See `NEXTJS-BODY-CAPTURE.md` (but consider wrapper approach first)
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 🔄 Comparison Table
|
|
126
|
+
|
|
127
|
+
| Feature | Wrapper Approach | Middleware Approach |
|
|
128
|
+
|---------|-----------------|---------------------|
|
|
129
|
+
| **Setup complexity** | Per-route wrapping | One-time setup |
|
|
130
|
+
| **Middleware conflicts** | ✅ None | ⚠️ Possible |
|
|
131
|
+
| **NextAuth compatibility** | ✅ Perfect | ❌ Can conflict |
|
|
132
|
+
| **Request blocking** | ✅ Never | ⚠️ Possible |
|
|
133
|
+
| **Control granularity** | ✅ Per-route | ❌ All-or-nothing |
|
|
134
|
+
| **Error impact** | ✅ Isolated | ⚠️ Can block all routes |
|
|
135
|
+
| **Recommended for** | ✅ Most users | ⚠️ Simple apps only |
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 🎯 Our Recommendation
|
|
140
|
+
|
|
141
|
+
### For Most Users (Especially with NextAuth)
|
|
142
|
+
|
|
143
|
+
**Use the Wrapper Approach:**
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
// middleware.ts - Your auth logic (no securenow!)
|
|
147
|
+
export async function middleware(request) {
|
|
148
|
+
// Just your middleware - no securenow imports
|
|
149
|
+
const token = await getToken({ req: request });
|
|
150
|
+
if (!token) return NextResponse.redirect('/login');
|
|
151
|
+
return NextResponse.next();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// app/api/protected/route.ts - Wrap individual routes
|
|
155
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
156
|
+
|
|
157
|
+
export const POST = withSecureNow(async (request: Request) => {
|
|
158
|
+
// Your handler - no conflicts!
|
|
159
|
+
const body = await request.json();
|
|
160
|
+
return Response.json({ success: true });
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Why?**
|
|
165
|
+
- ✅ Zero conflicts
|
|
166
|
+
- ✅ Your middleware stays clean
|
|
167
|
+
- ✅ Per-route control
|
|
168
|
+
- ✅ Never blocks requests
|
|
169
|
+
|
|
170
|
+
### For Simple Apps (No Other Middleware)
|
|
171
|
+
|
|
172
|
+
**You can use Middleware Approach:**
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// middleware.ts
|
|
176
|
+
export { middleware } from 'securenow/nextjs-middleware';
|
|
177
|
+
|
|
178
|
+
export const config = {
|
|
179
|
+
matcher: '/api/:path*',
|
|
180
|
+
};
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Why?**
|
|
184
|
+
- ✅ One-time setup
|
|
185
|
+
- ✅ Auto-applies to all routes
|
|
186
|
+
- ⚠️ But be aware of potential conflicts if you add other middleware later
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 📊 Real-World Scenarios
|
|
191
|
+
|
|
192
|
+
### Scenario 1: NextAuth + SecureNow
|
|
193
|
+
|
|
194
|
+
**❌ Middleware Approach - Can Cause Issues:**
|
|
195
|
+
```typescript
|
|
196
|
+
// middleware.ts
|
|
197
|
+
import { getToken } from 'next-auth/jwt';
|
|
198
|
+
import { middleware as securenowMiddleware } from 'securenow/nextjs-middleware';
|
|
199
|
+
|
|
200
|
+
export async function middleware(request) {
|
|
201
|
+
// Complex composition needed - prone to conflicts
|
|
202
|
+
await securenowMiddleware(request);
|
|
203
|
+
const token = await getToken({ req: request });
|
|
204
|
+
// ...
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**✅ Wrapper Approach - Clean & Safe:**
|
|
209
|
+
```typescript
|
|
210
|
+
// middleware.ts - Just NextAuth
|
|
211
|
+
export async function middleware(request) {
|
|
212
|
+
const token = await getToken({ req: request });
|
|
213
|
+
if (!token) return NextResponse.redirect('/login');
|
|
214
|
+
return NextResponse.next();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// app/api/*/route.ts - Add SecureNow per route
|
|
218
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
219
|
+
export const POST = withSecureNow(handler);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Scenario 2: Rate Limiting + SecureNow
|
|
223
|
+
|
|
224
|
+
**❌ Middleware Approach:**
|
|
225
|
+
```typescript
|
|
226
|
+
// Multiple middleware = conflicts
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
**✅ Wrapper Approach:**
|
|
230
|
+
```typescript
|
|
231
|
+
// middleware.ts - Just rate limiting
|
|
232
|
+
export async function middleware(request) {
|
|
233
|
+
await checkRateLimit(request);
|
|
234
|
+
return NextResponse.next();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// routes - Add SecureNow
|
|
238
|
+
export const POST = withSecureNow(handler);
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Scenario 3: Simple API (No Other Middleware)
|
|
242
|
+
|
|
243
|
+
**✅ Either Approach Works:**
|
|
244
|
+
|
|
245
|
+
**Option A - Wrapper:**
|
|
246
|
+
```typescript
|
|
247
|
+
export const POST = withSecureNow(handler);
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Option B - Middleware:**
|
|
251
|
+
```typescript
|
|
252
|
+
export { middleware } from 'securenow/nextjs-middleware';
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Both work fine when you have no other middleware!
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 🚀 Migration Guide
|
|
260
|
+
|
|
261
|
+
### From Middleware to Wrapper
|
|
262
|
+
|
|
263
|
+
**Before:**
|
|
264
|
+
```typescript
|
|
265
|
+
// middleware.ts
|
|
266
|
+
export { middleware } from 'securenow/nextjs-middleware';
|
|
267
|
+
export const config = { matcher: '/api/:path*' };
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**After:**
|
|
271
|
+
```typescript
|
|
272
|
+
// middleware.ts - Delete securenow import!
|
|
273
|
+
// (Keep your other middleware like NextAuth)
|
|
274
|
+
|
|
275
|
+
// app/api/login/route.ts
|
|
276
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
277
|
+
export const POST = withSecureNow(async (request) => {
|
|
278
|
+
// Your handler
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// app/api/register/route.ts
|
|
282
|
+
import { withSecureNow } from 'securenow/nextjs-wrapper';
|
|
283
|
+
export const POST = withSecureNow(async (request) => {
|
|
284
|
+
// Your handler
|
|
285
|
+
});
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Result:** No more conflicts! 🎉
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## ✅ Summary
|
|
293
|
+
|
|
294
|
+
### Quick Decision Guide
|
|
295
|
+
|
|
296
|
+
**Do you have NextAuth or other middleware?**
|
|
297
|
+
- Yes → Use **Wrapper Approach** ✅
|
|
298
|
+
- No → Either works, but wrapper is safer
|
|
299
|
+
|
|
300
|
+
**Do you want per-route control?**
|
|
301
|
+
- Yes → Use **Wrapper Approach** ✅
|
|
302
|
+
- No → Middleware works
|
|
303
|
+
|
|
304
|
+
**Do you prioritize zero conflicts?**
|
|
305
|
+
- Yes → Use **Wrapper Approach** ✅
|
|
306
|
+
- Not critical → Middleware works
|
|
307
|
+
|
|
308
|
+
**Do you experience "Response body disturbed" errors?**
|
|
309
|
+
- Yes → Switch to **Wrapper Approach** ✅
|
|
310
|
+
|
|
311
|
+
### Bottom Line
|
|
312
|
+
|
|
313
|
+
**For 90% of users:** Use the **Wrapper Approach**
|
|
314
|
+
|
|
315
|
+
It's safer, more flexible, and conflict-free!
|
|
316
|
+
|
|
317
|
+
📚 **Full documentation:**
|
|
318
|
+
- Wrapper: `NEXTJS-WRAPPER-APPROACH.md`
|
|
319
|
+
- Middleware: `NEXTJS-BODY-CAPTURE.md`
|
|
320
|
+
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
# Next.js Body Capture - Self-Sufficient Solution
|
|
2
|
+
|
|
3
|
+
## 🚀 Enable Body Capture in Next.js (2 Steps)
|
|
4
|
+
|
|
5
|
+
### Step 1: Enable in Environment
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# .env.local
|
|
9
|
+
SECURENOW_CAPTURE_BODY=1
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
### Step 2: Create middleware.ts
|
|
13
|
+
|
|
14
|
+
**Just ONE line!** Create `middleware.ts` in your project root:
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
export { middleware } from 'securenow/nextjs-middleware';
|
|
18
|
+
|
|
19
|
+
export const config = {
|
|
20
|
+
matcher: '/api/:path*', // Apply to API routes
|
|
21
|
+
};
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**That's it!** 🎉 Bodies are now captured with sensitive data automatically redacted.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## ✨ Why This Works
|
|
29
|
+
|
|
30
|
+
**Self-sufficient design:**
|
|
31
|
+
- ✅ **One-line import** - No code to write
|
|
32
|
+
- ✅ **All logic in package** - Redaction, parsing, size limits
|
|
33
|
+
- ✅ **Zero configuration** - Works with defaults
|
|
34
|
+
- ✅ **Doesn't lock request stream** - Uses `request.clone()`
|
|
35
|
+
- ✅ **Safe by default** - 20+ sensitive fields redacted
|
|
36
|
+
|
|
37
|
+
**No customer code changes needed!** Just import and configure where to apply.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 📊 What Gets Captured
|
|
42
|
+
|
|
43
|
+
### ✅ JSON Requests
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
POST /api/users
|
|
47
|
+
Content-Type: application/json
|
|
48
|
+
|
|
49
|
+
{
|
|
50
|
+
"username": "john",
|
|
51
|
+
"password": "secret123" ← Automatically redacted
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Captured:**
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"username": "john",
|
|
59
|
+
"password": "[REDACTED]"
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### ✅ GraphQL Requests
|
|
64
|
+
|
|
65
|
+
```graphql
|
|
66
|
+
POST /api/graphql
|
|
67
|
+
Content-Type: application/graphql
|
|
68
|
+
|
|
69
|
+
mutation Login {
|
|
70
|
+
login(email: "john@example.com", password: "secret") ← Redacted
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**Captured:**
|
|
75
|
+
```graphql
|
|
76
|
+
mutation Login {
|
|
77
|
+
login(email: "john@example.com", password: "[REDACTED]")
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### ✅ Form Data
|
|
82
|
+
|
|
83
|
+
```http
|
|
84
|
+
POST /api/contact
|
|
85
|
+
Content-Type: application/x-www-form-urlencoded
|
|
86
|
+
|
|
87
|
+
name=John&email=john@example.com&message=Hello
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Captured:**
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"name": "John",
|
|
94
|
+
"email": "john@example.com",
|
|
95
|
+
"message": "Hello"
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## ⚙️ Configuration
|
|
102
|
+
|
|
103
|
+
### Matcher Patterns
|
|
104
|
+
|
|
105
|
+
**Apply to all API routes:**
|
|
106
|
+
```typescript
|
|
107
|
+
export const config = {
|
|
108
|
+
matcher: '/api/:path*',
|
|
109
|
+
};
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Apply to specific routes:**
|
|
113
|
+
```typescript
|
|
114
|
+
export const config = {
|
|
115
|
+
matcher: ['/api/login', '/api/register', '/api/graphql'],
|
|
116
|
+
};
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Apply to everything except static files:**
|
|
120
|
+
```typescript
|
|
121
|
+
export const config = {
|
|
122
|
+
matcher: '/((?!_next/static|_next/image|favicon.ico).*)',
|
|
123
|
+
};
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Apply to multiple patterns:**
|
|
127
|
+
```typescript
|
|
128
|
+
export const config = {
|
|
129
|
+
matcher: ['/api/:path*', '/graphql'],
|
|
130
|
+
};
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Environment Variables
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Max body size (default: 10KB)
|
|
137
|
+
SECURENOW_MAX_BODY_SIZE=20480
|
|
138
|
+
|
|
139
|
+
# Custom sensitive fields to redact
|
|
140
|
+
SECURENOW_SENSITIVE_FIELDS=email,phone,address
|
|
141
|
+
|
|
142
|
+
# Enable debug logging
|
|
143
|
+
OTEL_LOG_LEVEL=debug
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 🔒 Security Features
|
|
149
|
+
|
|
150
|
+
### Automatic Redaction (20+ Fields)
|
|
151
|
+
|
|
152
|
+
These are **always redacted**:
|
|
153
|
+
```
|
|
154
|
+
password, passwd, pwd, secret, token, api_key, apikey,
|
|
155
|
+
access_token, auth, credentials, mysql_pwd, stripeToken,
|
|
156
|
+
card, cardnumber, cvv, cvc, ccv, ssn, pin
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Custom Sensitive Fields
|
|
160
|
+
|
|
161
|
+
Add your own:
|
|
162
|
+
```bash
|
|
163
|
+
SECURENOW_SENSITIVE_FIELDS=credit_card,phone_number,dob
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Now these are also redacted automatically!
|
|
167
|
+
|
|
168
|
+
### Size Protection
|
|
169
|
+
|
|
170
|
+
Bodies larger than `SECURENOW_MAX_BODY_SIZE` show:
|
|
171
|
+
```
|
|
172
|
+
[TOO LARGE: 50000 bytes]
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 🎯 File Structure
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
your-nextjs-app/
|
|
181
|
+
├── middleware.ts ← Create this (1 line import!)
|
|
182
|
+
├── instrumentation.ts ← Already created by installer
|
|
183
|
+
├── .env.local ← Set SECURENOW_CAPTURE_BODY=1
|
|
184
|
+
├── app/
|
|
185
|
+
│ └── api/
|
|
186
|
+
│ ├── login/route.ts ← Bodies auto-captured
|
|
187
|
+
│ ├── users/route.ts ← Bodies auto-captured
|
|
188
|
+
│ └── graphql/route.ts ← Bodies auto-captured
|
|
189
|
+
└── ...
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 🧪 Testing
|
|
195
|
+
|
|
196
|
+
### Test Body Capture
|
|
197
|
+
|
|
198
|
+
1. **Create middleware.ts:**
|
|
199
|
+
```typescript
|
|
200
|
+
export { middleware } from 'securenow/nextjs-middleware';
|
|
201
|
+
export const config = { matcher: '/api/:path*' };
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
2. **Enable in .env.local:**
|
|
205
|
+
```bash
|
|
206
|
+
SECURENOW_CAPTURE_BODY=1
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
3. **Make a test request:**
|
|
210
|
+
```bash
|
|
211
|
+
curl -X POST http://localhost:3000/api/test \
|
|
212
|
+
-H "Content-Type: application/json" \
|
|
213
|
+
-d '{"username":"test","password":"secret123"}'
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
4. **Check SigNoz:**
|
|
217
|
+
- Find the `/api/test` trace
|
|
218
|
+
- Look for `http.request.body` attribute
|
|
219
|
+
- Verify password shows `[REDACTED]`
|
|
220
|
+
|
|
221
|
+
### Debug Mode
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
OTEL_LOG_LEVEL=debug npm run dev
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
You'll see:
|
|
228
|
+
```
|
|
229
|
+
[securenow] 📝 Body capture enabled
|
|
230
|
+
[securenow] 📚 Import middleware from securenow/nextjs-middleware
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 🎓 Complete Setup Example
|
|
236
|
+
|
|
237
|
+
### 1. instrumentation.ts (auto-created by installer)
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
import { registerSecureNow } from 'securenow/nextjs';
|
|
241
|
+
|
|
242
|
+
export function register() {
|
|
243
|
+
registerSecureNow();
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### 2. middleware.ts (create this for body capture)
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
export { middleware } from 'securenow/nextjs-middleware';
|
|
251
|
+
|
|
252
|
+
export const config = {
|
|
253
|
+
matcher: '/api/:path*',
|
|
254
|
+
};
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### 3. .env.local
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# Required
|
|
261
|
+
SECURENOW_APPID=my-nextjs-app
|
|
262
|
+
SECURENOW_INSTANCE=http://your-signoz:4318
|
|
263
|
+
|
|
264
|
+
# Optional: Enable body capture
|
|
265
|
+
SECURENOW_CAPTURE_BODY=1
|
|
266
|
+
SECURENOW_MAX_BODY_SIZE=20480
|
|
267
|
+
SECURENOW_SENSITIVE_FIELDS=email,phone
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### 4. Done! ✅
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
npm run dev
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## 💡 Why Two Files?
|
|
279
|
+
|
|
280
|
+
**instrumentation.ts** - OpenTelemetry setup (required)
|
|
281
|
+
- Sets up tracing infrastructure
|
|
282
|
+
- Auto-captures IP, headers, geo data
|
|
283
|
+
- Runs for all requests
|
|
284
|
+
|
|
285
|
+
**middleware.ts** - Body capture (optional)
|
|
286
|
+
- Intercepts requests to clone and read body
|
|
287
|
+
- Only needed if you want body capture
|
|
288
|
+
- Can be applied selectively to routes
|
|
289
|
+
|
|
290
|
+
**Separation = flexibility!** You can have tracing without body capture.
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## ⚡ Performance
|
|
295
|
+
|
|
296
|
+
**Overhead per request:**
|
|
297
|
+
- **Without middleware:** 0ms (just tracing)
|
|
298
|
+
- **With middleware:** < 1ms (clone + parse + redact)
|
|
299
|
+
|
|
300
|
+
**The middleware:**
|
|
301
|
+
- Uses `request.clone()` - doesn't lock original
|
|
302
|
+
- Runs async - doesn't block request
|
|
303
|
+
- Fails gracefully - errors don't break app
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## ❓ FAQ
|
|
308
|
+
|
|
309
|
+
### Q: Is this truly self-sufficient?
|
|
310
|
+
|
|
311
|
+
**A:** Yes! Just export the middleware:
|
|
312
|
+
```typescript
|
|
313
|
+
export { middleware } from 'securenow/nextjs-middleware';
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
All logic (parsing, redaction, size limits) is in the package.
|
|
317
|
+
|
|
318
|
+
### Q: Do I need to write any redaction code?
|
|
319
|
+
|
|
320
|
+
**A:** No! 20+ sensitive fields are redacted automatically. Just add custom ones if needed via env vars.
|
|
321
|
+
|
|
322
|
+
### Q: Can I customize the redaction?
|
|
323
|
+
|
|
324
|
+
**A:** Yes, via environment variables:
|
|
325
|
+
```bash
|
|
326
|
+
SECURENOW_SENSITIVE_FIELDS=my_custom_field,another_field
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Q: Will this slow down my app?
|
|
330
|
+
|
|
331
|
+
**A:** No! < 1ms overhead. Uses `request.clone()` so original is unaffected.
|
|
332
|
+
|
|
333
|
+
### Q: Can I apply to specific routes only?
|
|
334
|
+
|
|
335
|
+
**A:** Yes! Use the matcher config:
|
|
336
|
+
```typescript
|
|
337
|
+
export const config = {
|
|
338
|
+
matcher: ['/api/login', '/api/graphql'],
|
|
339
|
+
};
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Q: What if I don't want body capture?
|
|
343
|
+
|
|
344
|
+
**A:** Don't create `middleware.ts`! Just use `instrumentation.ts` for tracing without bodies.
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## 🎉 Summary
|
|
349
|
+
|
|
350
|
+
**Enable body capture:**
|
|
351
|
+
|
|
352
|
+
1. ```bash
|
|
353
|
+
SECURENOW_CAPTURE_BODY=1 # in .env.local
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
2. ```typescript
|
|
357
|
+
export { middleware } from 'securenow/nextjs-middleware'; # in middleware.ts
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
**Result:**
|
|
361
|
+
- ✅ All request bodies captured
|
|
362
|
+
- ✅ Sensitive data redacted
|
|
363
|
+
- ✅ JSON, GraphQL, Form supported
|
|
364
|
+
- ✅ No customer code changes
|
|
365
|
+
- ✅ Package handles everything
|
|
366
|
+
|
|
367
|
+
**Self-sufficient design** - customers just import and configure! 🚀
|
|
368
|
+
|