Skip to main content

Core Security Implementation

AnotherWrapper includes several security features out of the box. This guide explains the existing security measures and shows how to implement optional rate limiting:
  1. Database Security (RLS)
  2. API Route Protection
  3. Rate Limiting (not implemented but easy to add)
  4. AI Services Abuse Protection
  5. Email Security

Database Security with Supabase RLS

If you’ve followed the setup guides, Row Level Security (RLS) is already enabled and configured for all your tables, ensuring users can only access their own data.
Never disable RLS policies unless absolutely necessary.

RLS Guiding Principles

  1. User Ownership: Use auth.uid() to match the authenticated user with their data
  2. Default Deny: Start with all access denied, then explicitly grant permissions
  3. Minimal Access: Give users access only to what they absolutely need
  4. Separate Policies: Create distinct policies for different operations (SELECT, INSERT, etc.)
Here’s an example of common RLS policies:
-- Enable RLS
ALTER TABLE "documents" ENABLE ROW LEVEL SECURITY;

-- Users can only read their own documents
CREATE POLICY "Users can read own documents"
ON "documents"
FOR SELECT
USING (auth.uid() = user_id);

-- Users can only insert documents they own
CREATE POLICY "Users can insert own documents"
ON "documents"
FOR INSERT
WITH CHECK (auth.uid() = user_id);

-- Users can only update their own documents
CREATE POLICY "Users can update own documents"
ON "documents"
FOR UPDATE
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);

-- Users can only delete their own documents
CREATE POLICY "Users can delete own documents"
ON "documents"
FOR DELETE
USING (auth.uid() = user_id);
These policies ensure that users can only access, modify, or delete their own data, while administrators can manage all records through superuser access.

API Route Protection

All sensitive API routes in AnotherWrapper are protected using the centralized auth helpers in lib/auth/server.ts. Use requireApiUser() to protect API routes — it returns the authenticated user or throws a 401 response automatically:
app/api/protected/route.ts
import { requireApiUser } from "@/lib/auth/server";

export async function GET(req: Request) {
  // Throws 401 if not authenticated
  const user = await requireApiUser();

  // Your protected route logic here
  return Response.json({ message: "Protected data", userId: user.id });
}
For server components and pages, use requireUser() instead — it redirects to /auth if the user is not authenticated:
app/protected/page.tsx
import { requireUser } from "@/lib/auth/server";

export default async function ProtectedPage() {
  const user = await requireUser(); // Redirects to /auth if not logged in
  return <div>Welcome, {user.email}</div>;
}
Rate limiting is not implemented by default, but you can easily add it to protect your API routes from abuse. Here’s how:
  1. First, set up Upstash Redis:
npm install @upstash/redis @upstash/ratelimit
  1. Add to your .env:
UPSTASH_REDIS_REST_URL=your_url
UPSTASH_REDIS_REST_TOKEN=your_token
  1. Update the following files to implement rate limiting:
import { type NextRequest, NextResponse } from "next/server";
import { updateSession } from "@/lib/utils/supabase/middleware";
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";

// Initialize Redis client
const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});

// Configure rate limiter (example: 3 requests per minute)
const ratelimit = new Ratelimit({
  redis,
  limiter: Ratelimit.slidingWindow(3, "60 s"),
});

// Routes to rate limit
const urlsToRateLimit = [
  "/api/ai/generate",
  "/api/uploads",
  // Add your rate-limited routes
];

export async function middleware(request: NextRequest) {
  if (urlsToRateLimit.some((url) => request.url.includes(url))) {
    const ip = request.ip ?? "127.0.0.1";
    const { success } = await ratelimit.limit(ip);

    if (!success) {
      const url = new URL(request.url);
      return url.pathname.startsWith("/api/")
        ? NextResponse.json({ error: "Rate limit exceeded" }, { status: 429 })
        : NextResponse.redirect(new URL("/blocked", request.url));
    }
  }

  return await updateSession(request);
}

export const config = {
  matcher: [
    /*
     * Match all request paths except for the ones starting with:
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     * Feel free to modify this pattern to include more paths.
     */
    "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
  ],
};
The middleware handles the rate limiting logic, while the blocked page provides a user-friendly interface when limits are exceeded. Users will be redirected to this page when they hit the rate limit on non-API routes.

AI Services Abuse Protection

Protect against AI service abuse by setting hard limits in your AI service dashboards:
Always set up budget alerts and hard limits in your AI service dashboards to prevent unexpected costs.
All AI providers (OpenAI, Replicate, Anthropic, ElevenLabs, Groq, Google, xAI) have built-in tools to regulate usage and set maximum spending limits. Make sure to configure these limits in each provider’s dashboard to prevent abuse and unexpected costs. Additionally, AnotherWrapper’s credit system provides application-level metering. Users must have sufficient credits to use AI features, and credits are consumed atomically via consume_user_credits() to prevent race conditions.

Email Security

  • Default rate limit: 3 emails per hour without custom SMTP
  • With custom SMTP setup, you can configure your own rate limits

Email Contact Providers

Remember to regularly review your security implementations and update them as needed.