GuidesSecurity
Authentication
Secure your file uploads with proper authentication and authorization patterns
Authentication & Authorization
Secure your file upload endpoints with robust authentication and authorization middleware.
Important: Never expose upload endpoints without proper authentication in production. Unprotected endpoints can lead to storage abuse and security vulnerabilities.
Authentication Patterns
Better Auth (Recommended)
Modern, type-safe authentication with native TypeScript support:
import { s3 } from "@/lib/upload";
import { auth } from "@/lib/auth"; // Better Auth instance
const s3Router = s3.createRouter({
userFiles: s3.image()
.maxFileSize("5MB")
.maxFiles(10)
.middleware(async ({ req, metadata }) => {
const session = await auth.api.getSession({ headers: req.headers });
if (!session?.user?.id) {
throw new Error("Authentication required");
}
return {
...metadata,
userId: session.user.id,
userEmail: session.user.email,
};
}),
});
export const { GET, POST } = s3Router.handlers;NextAuth.js Integration
import { s3 } from "@/lib/upload";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
const s3Router = s3.createRouter({
userFiles: s3.image()
.maxFileSize("5MB")
.maxFiles(10)
.middleware(async ({ req, metadata }) => {
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
throw new Error("Authentication required");
}
return {
...metadata,
userId: session.user.id,
userEmail: session.user.email,
};
}),
});
export const { GET, POST } = s3Router.handlers;JWT Token Validation
import jwt from "jsonwebtoken";
const s3Router = s3.createRouter({
protectedUploads: s3.file()
.maxFileSize("10MB")
.maxFiles(5)
.middleware(async ({ req, metadata }) => {
const token = req.headers.get("authorization")?.replace("Bearer ", "");
if (!token) {
throw new Error("Authorization token required");
}
try {
const payload = jwt.verify(token, process.env.JWT_SECRET!) as any;
return {
...metadata,
userId: payload.sub,
roles: payload.roles || [],
};
} catch (error) {
throw new Error("Invalid or expired token");
}
}),
});Custom Authentication
const s3Router = s3.createRouter({
apiKeyUploads: s3.file()
.maxFileSize("25MB")
.maxFiles(1)
.types(['application/pdf', 'application/msword'])
.middleware(async ({ req, metadata }) => {
const apiKey = req.headers.get("x-api-key");
if (!apiKey) {
throw new Error("API key required");
}
// Validate API key against your database
const client = await validateApiKey(apiKey);
if (!client) {
throw new Error("Invalid API key");
}
return {
...metadata,
clientId: client.id,
plan: client.plan,
quotaUsed: client.quotaUsed,
};
}),
});Simple Role Checking
For apps with admins vs regular users:
const s3Router = s3.createRouter({
adminUploads: s3.file()
.maxFileSize("100MB")
.middleware(async ({ req, metadata }) => {
const { userId, role } = await authenticateUser(req);
if (role !== "admin") {
throw new Error("Admin access required");
}
return { ...metadata, userId, role };
}),
});That's it! For more complex permissions (multi-tenant, resource-based), see advanced patterns.