
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
@brassproof/nextjs
Advanced tools
BRASS integration helpers for Next.js - React hooks and API route middleware
BRASS integration for Next.js with React hooks and API route helpers. Add privacy-preserving rate limiting to your Next.js app in minutes.
npm install @brassproof/nextjs
'use client'
import { useBrass } from '@brassproof/nextjs'
export function CommentForm() {
const { mintAndSubmit, isLoading, error, remaining } = useBrass({
scope: 'comment-submission',
onSuccess: (result) => {
console.log(`${result.remaining} comments remaining`)
},
})
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
await mintAndSubmit('/api/submit-comment', {
comment: 'Hello world!'
})
}
return (
<form onSubmit={handleSubmit}>
<textarea name="comment" />
<button disabled={isLoading}>
{isLoading ? 'Posting...' : 'Post Comment'}
</button>
{error && <p>Error: {error.message}</p>}
{remaining !== null && <p>{remaining} comments remaining today</p>}
</form>
)
}
// app/api/submit-comment/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { withBrassVerifier } from '@brassproof/nextjs'
async function handler(request: NextRequest) {
const { comment } = await request.json()
// Process the comment - BRASS has already verified rate limits
console.log('Comment:', comment)
return NextResponse.json({ success: true })
}
export const POST = withBrassVerifier(handler, {
scope: 'comment-submission',
onVerified: (result) => {
console.log(`Verified! ${result.remaining} remaining`)
},
})
useBrass(options?)React hook for client-side BRASS integration.
Options:
| Property | Type | Default | Description |
|---|---|---|---|
issuerUrl | string | Hosted issuer | BRASS issuer endpoint URL |
scope | string | 'generic' | Rate limit scope identifier |
onError | (error: Error) => void | - | Error callback |
onSuccess | (result) => void | - | Success callback |
Returns:
{
mintAndSubmit: <T>(endpoint: string, data: object, options?: RequestInit) => Promise<T>
isLoading: boolean
error: Error | null
remaining: number | null
}
Example:
const { mintAndSubmit, isLoading, error } = useBrass({
scope: 'signup',
onSuccess: () => alert('Account created!'),
onError: (err) => console.error(err),
})
await mintAndSubmit('/api/signup', {
email: 'user@example.com',
password: 'secure123'
})
withBrassVerifier(handler, options?)Higher-order function to protect Next.js API routes.
Options:
| Property | Type | Default | Description |
|---|---|---|---|
scope | string | 'generic' | Rate limit scope |
rateLimits | Record<string, RateLimit> | Defaults | Custom rate limits |
kvNamespace | KVNamespace | - | Storage backend for rate limiting |
onVerified | (result) => void | Promise<void> | - | Called after successful verification |
onRateLimited | (result) => NextResponse | - | Custom rate limit response |
Example:
import { withBrassVerifier } from '@brassproof/nextjs'
const handler = async (request: NextRequest) => {
// Your protected logic here
return NextResponse.json({ success: true })
}
export const POST = withBrassVerifier(handler, {
scope: 'api-call',
rateLimits: {
'api-call': { maxRequests: 100, windowSeconds: 3600 }
},
onRateLimited: ({ remaining, resetAt }) => {
return NextResponse.json(
{
error: 'Too many requests',
remaining,
resetAt: new Date(resetAt).toISOString()
},
{ status: 429 }
)
}
})
# Required
BRASS_SECRET_KEY=your_secret_key_here
BRASS_ISSUER_PUBKEY=issuer_public_key_hex
# Optional (for self-hosted or managed service)
BRASS_ISSUER_URL=https://your-issuer-endpoint.com
Get these values:
'use client'
import { useState } from 'react'
import { useBrass } from '@brassproof/nextjs'
export function SignupForm() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const { mintAndSubmit, isLoading, error, remaining } = useBrass({
scope: 'signup',
onSuccess: () => {
alert('Account created successfully!')
},
})
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
try {
await mintAndSubmit('/api/signup', { email, password })
} catch (err) {
console.error('Signup failed:', err)
}
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
required
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
required
/>
<button type="submit" disabled={isLoading}>
{isLoading ? 'Creating account...' : 'Sign Up'}
</button>
{error && <p className="error">{error.message}</p>}
{remaining !== null && (
<p>{remaining} signups remaining today</p>
)}
</form>
)
}
// app/api/signup/route.ts
import { NextRequest, NextResponse } from 'next/server'
import { withBrassVerifier } from '@brassproof/nextjs'
import { hashPassword, createUser } from '@/lib/auth'
async function signupHandler(request: NextRequest) {
const { email, password } = await request.json()
// Validate input
if (!email || !password) {
return NextResponse.json(
{ error: 'Email and password required' },
{ status: 400 }
)
}
// Create user in database
const hashedPassword = await hashPassword(password)
const user = await createUser(email, hashedPassword)
return NextResponse.json({
success: true,
userId: user.id,
})
}
export const POST = withBrassVerifier(signupHandler, {
scope: 'signup',
rateLimits: {
'signup': { maxRequests: 5, windowSeconds: 86400 } // 5 per day
},
})
export const POST = withBrassVerifier(handler, {
rateLimits: {
'comment': { maxRequests: 3, windowSeconds: 86400 },
'signup': { maxRequests: 5, windowSeconds: 86400 },
'api-call': { maxRequests: 100, windowSeconds: 3600 },
},
})
const { mintAndSubmit } = useBrass({
scope: 'comment',
onError: (error) => {
if (error.message.includes('Rate limit')) {
toast.error('Too many comments. Try again tomorrow!')
} else {
toast.error('Something went wrong')
}
},
onSuccess: (result) => {
toast.success(`Comment posted! ${result.remaining} remaining`)
},
})
import type {
UseBrassOptions,
UseBrassReturn,
WithBrassVerifierOptions,
BrassProtectedHandler,
} from '@brassproof/nextjs'
const options: UseBrassOptions = {
scope: 'comment',
}
const handler: BrassProtectedHandler = async (request) => {
// Your logic
return NextResponse.json({ success: true })
}
Ensure the client is sending the token. Check that useBrass().mintAndSubmit() is being used correctly.
Set BRASS_SECRET_KEY and BRASS_ISSUER_PUBKEY environment variables.
User has hit the rate limit. This is expected behavior. Wait for the rate limit window to reset.
MIT - see LICENSE for details.
FAQs
BRASS integration helpers for Next.js - React hooks and API route middleware
We found that @brassproof/nextjs demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.