Documentation Index
Fetch the complete documentation index at: https://docs.builderbox.ai/llms.txt
Use this file to discover all available pages before exploring further.
When to Use Protected Routes
Use protected routes for:
- User-specific data
- Profile management
- User settings
- Personal data access
- User preferences
- Private content
Creating Protected Routes
import { router, protectedProcedure } from '../lib/trpc';
import { z } from 'zod';
export const yourRouter = router({
// Your protected route
yourProtectedRoute: protectedProcedure
.input(z.object({
yourInput: z.string(),
yourInput2: z.string(),
}))
.mutation(async ({ ctx, input }) => {
// Your logic here
return { success: true };
}),
});
Example Protected Routes
import { router, protectedProcedure } from '../lib/trpc';
import { z } from 'zod';
export const userRouter = router({
// Get user profile
getProfile: protectedProcedure.query(async ({ ctx }) => {
return ctx.session.user;
}),
// Update user settings
updateSettings: protectedProcedure
.input(z.object({
theme: z.enum(['light', 'dark']),
notifications: z.boolean(),
}))
.mutation(async ({ ctx, input }) => {
// Update user settings in database
return { success: true };
}),
});
Authentication Flow
Protected routes automatically check for a valid session:
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session) {
throw new TRPCError({
code: 'UNAUTHORIZED',
message: 'Authentication required',
});
}
return next();
});
Example: User Profile Management
// apps/server/src/routers/profile.ts
import { router, protectedProcedure } from '../lib/trpc';
import { z } from 'zod';
export const profileRouter = router({
// Get user profile
getProfile: protectedProcedure.query(async ({ ctx }) => {
const user = await prisma.user.findUnique({
where: { id: ctx.session.userId },
});
return user;
}),
// Update profile
updateProfile: protectedProcedure
.input(z.object({
name: z.string().optional(),
email: z.string().email().optional(),
bio: z.string().optional(),
}))
.mutation(async ({ ctx, input }) => {
const updated = await prisma.user.update({
where: { id: ctx.session.userId },
data: input,
});
return updated;
}),
});
Client Usage
// In your React component
function ProfileComponent() {
const { data: profile, isLoading } = trpc.getProfile.useQuery();
const updateProfile = trpc.profileRouter.updateProfile.useMutation();
const handleUpdate = async (data) => {
try {
await updateProfile.mutateAsync(data);
} catch (error) {
console.error('Error updating profile:', error);
}
};
return (
<div>
{isLoading ? 'Loading...' : (
<form onSubmit={handleUpdate}>
{/* Profile form fields */}
</form>
)}
</div>
);
}
Best Practices for Protected Routes
-
Session Management
- Always check session validity
- Handle session expiration
- Implement proper logout
-
Data Access
- Only return data the user has permission to access
- Implement proper data filtering
- Use database-level permissions
-
Error Handling
- Handle authentication errors gracefully
- Provide clear error messages
- Implement proper error logging
-
Security
- Validate all input data
- Implement CSRF protection
- Use secure session management
Security Considerations
-
Session Security
- Use secure session cookies
- Implement session timeout
- Handle session revocation
-
Data Protection
- Encrypt sensitive data
- Implement proper access controls
- Use database-level security
-
Input Validation
- Validate all user input
- Sanitize data before storage
- Implement proper error handling
Next Steps