Part 3: Protecting Routes and Security

If you haven't already, I would recommend having a quick look at the Introduction & Sequence Diagram
Welcome to the 3-part series that helps you create a scalable production-ready authentication system using pure JWT & a middleware for your SvelteKit project
Part 3 → Protecting Routes & Security
You are reading Part 3
Goal: Secure the app with middleware and discuss best practices for a production-ready system.
Topics we'll cover
Server Hooks (Middleware): Use SvelteKit hooks to verify JWT and secure routes.
Security Considerations: Token storage (HTTP-only cookies), CSRF protection, token expiration, HTTPS, etc.
Conclusion & Next Steps: Recap and suggestions like refresh tokens or role-based access.
SvelteKit Server Hooks (Middleware)
Now we'll implement the authentication middleware in SvelteKit's server hooks:
// src/hooks.server.ts
import { authenticateRequest } from "$lib/auth/jwt";
import { clearAuthCookies } from "$lib/auth/cookies";
import type { Handle } from "@sveltejs/kit";
import type { JwtPayload } from "$lib/auth/jwt";
// Extend the Locals interface to include our user property
declare global {
namespace App {
interface Locals {
user?: Omit<JwtPayload, "iat" | "exp">;
}
}
}
export const handle: Handle = async ({ event, resolve }) => {
const { cookies, url } = event;
// Public routes that don't require authentication
const publicRoutes = [
"/auth/sign-in",
"/auth/sign-up",
"/auth/forgot-password",
"/auth/reset-password",
"/auth/logout",
];
// Check if the current route is public
const isPublicRoute = publicRoutes.some(
(route) =>
url.pathname === route ||
url.pathname.startsWith("/api/public/")
);
// First, verify the authentication status for all routes
const authResult = authenticateRequest(cookies);
if (authResult.success && authResult.user) {
// User is authenticated
event.locals.user = authResult.user;
// Maintain backward compatibility with existing code
if (!cookies.get("user")) {
cookies.set("user", JSON.stringify(authResult.user), {
path: "/",
httpOnly: true,
});
}
// If user is authenticated and trying to access public routes like sign-in
// redirect them to the dashboard instead
if (isPublicRoute && url.pathname !== "/auth/logout") {
return Response.redirect(new URL("/dashboard", url));
}
} else {
// User is not authenticated
if (!isPublicRoute) {
// Non-public route requires authentication, redirect to login
clearAuthCookies(cookies);
return Response.redirect(new URL("/auth/sign-in", url));
}
}
return resolve(event);
};
Security Considerations
When implementing JWT authentication, consider the following security aspects:
Token Storage: Store tokens in HTTP-only cookies to prevent XSS attacks
CSRF Protection: Implement CSRF tokens for form submissions
Token Expiration: Use short-lived tokens to minimize damage from token theft
Secure Connection: Always use HTTPS in production
Environment Variables: Store your JWT secret in environment variables, not in code
Conclusion
We've built a complete authentication system using SvelteKit, TypeScript, and "pure JWT" authentication. This approach gives us the benefits of stateless authentication while still maintaining proper user management and security audit capabilities.
The key advantage of this implementation is that we don't need to query the database for each authenticated request, making our application more scalable. Instead, we rely on the cryptographic integrity of the JWT itself to validate the user's identity.
Next Steps
To further enhance this system, you might consider:
Implementing refresh tokens for longer sessions
Adding email verification for signup
Supporting password reset functionality
Implementing role-based access control
Adding two-factor authentication
I hope this tutorial helps you build secure and scalable authentication systems with SvelteKit!
Previous → Part 2: Authentication Flows
Subscribe to my newsletter
Read articles from Mukesh Jaiswal directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Mukesh Jaiswal
Mukesh Jaiswal
Driving business growth with AI Automation (as Business Automation Partner) | Helping startups build (as Software Developer)