Route Protection
Securing your application involves protecting both the server-side API endpoints and the client-side user interface routes. Archibald provides a unified way to handle this using the RouteConfig on the server and standard React patterns on the client.
Server-Side Protection
In Archibald, server-side route protection is defined in the RouteConfig for each module. The auth object within the route options determines how the AuthModule handles the request.
Authentication Modes
There are three primary authentication modes:
required: The request must have a valid session. If not, the server returns a401 Unauthorizederror.optional: If a valid session exists, it is loaded into the request context. If not, the request proceeds as an anonymous request.try: Similar to optional, but often used when you want to attempt authentication without failing if the token is invalid or expired.
Example Configuration
// src/server/routes/account.ts
import { type DefaultRouteConfig, RouteMethod } from '@archibald/core';
const AccountServerRouteConfig: DefaultRouteConfig[] = [
{
method: RouteMethod.GET,
path: 'account',
handler: 'AccountController.getAccountInfo',
options: {
auth: {
strategy: 'jwt',
mode: 'required'
},
description: 'Gets account data for user',
tags: ['api', 'Account']
}
}
];
Client-Side Protection
On the client-side, protection is typically handled by checking the authentication state and redirecting the user if they lack access.
Web (React) Restricted Routes
In web applications, it is idiomatic to use a RestrictedRoute component to wrap protected content.
import { useIsLoggedIn } from '@archibald/auth';
import { useMatchPattern, Navigate } from '@archibald/core';
import { type PropsWithChildren, Suspense } from 'react';
function RestrictedRoute({ children }: PropsWithChildren) {
const isLoggedIn = useIsLoggedIn();
const alreadyOnLoginPath = useMatchPattern('login');
if (!isLoggedIn && !alreadyOnLoginPath) {
// Redirect to login page if not authenticated
return <Navigate to="/login" />;
}
return <Suspense>{children}</Suspense>;
}
Native (Expo Router)
In native applications using expo-router, you can use Stack.Protected to guard specific screens.
import { useIsLoggedIn } from '@archibald/auth';
import { Stack } from 'expo-router';
export default function ProfileLayout() {
const isLoggedIn = useIsLoggedIn();
return (
<Stack>
<Stack.Protected guard={isLoggedIn}>
<Stack.Screen name="index" options={{ title: 'Your Account' }} />
<Stack.Screen name="change-password" options={{ title: 'Change Password' }} />
</Stack.Protected>
<Stack.Protected guard={!isLoggedIn}>
<Stack.Screen name="login" options={{ title: 'Login' }} />
</Stack.Protected>
</Stack>
);
}