User & Admin Administration
This tutorial walks you through managing user accounts and administrative permissions using the UsersService and the built-in authentication hooks. You will learn how to fetch profile data, update user settings, and implement administrative access controls.
Prerequisites
Before starting, ensure you have:
- The frontend development server running.
- The generated API client available in
frontend/src/client. - TanStack Query (React Query) installed and configured.
Step 1: Accessing the Current User Profile
The foundation of user management is identifying the currently logged-in user. The project uses the UsersService.readUserMe() method within a custom hook to provide global access to the user's state.
In frontend/src/hooks/useAuth.ts, the useAuth hook fetches the current user:
import { useQuery } from "@tanstack/react-query"
import { UsersService, type UserPublic } from "@/client"
// Inside useAuth hook
const { data: user, isLoading } = useQuery<UserPublic | null, Error>({
queryKey: ["currentUser"],
queryFn: UsersService.readUserMe,
enabled: isLoggedIn(), // Only fetch if a token exists
})
This ensures that any component in your application can access the user's email, full name, and superuser status by calling const { user } = useAuth().
Step 2: Updating Personal Information
Users can manage their own profiles using the updateUserMe method. This is typically handled via a form that sends a PATCH request to the backend.
In frontend/src/components/UserSettings/UserInformation.tsx, a mutation is defined to handle updates:
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { UsersService, type UserUpdateMe } from "@/client"
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: (data: UserUpdateMe) =>
UsersService.updateUserMe({ requestBody: data }),
onSuccess: () => {
// Refresh the user data across the app
queryClient.invalidateQueries({ queryKey: ["currentUser"] })
},
})
const onSubmit = (data: UserUpdateMe) => {
mutation.mutate(data)
}
When mutation.mutate() is called, the UsersService sends the updated fields to /api/v1/users/me. On success, invalidateQueries triggers a re-fetch of the user profile to update the UI globally.
Step 3: Implementing Admin Access Control
Administrative features must be restricted to users where is_superuser is true. The project enforces this at the routing level using TanStack Router's beforeLoad hook.
In frontend/src/routes/_layout/admin.tsx, the route is protected as follows:
import { createFileRoute, redirect } from "@tanstack/react-router"
import { UsersService } from "@/client"
export const Route = createFileRoute("/_layout/admin")({
component: Admin,
beforeLoad: async () => {
try {
const user = await UsersService.readUserMe()
if (!user.is_superuser) {
// Redirect non-admins to the dashboard
throw redirect({
to: "/",
})
}
} catch (error) {
// Redirect to login if the user is not authenticated
throw redirect({
to: "/login",
})
}
},
})
This server-side check (via the API) ensures that even if a user manually navigates to /admin, they are redirected if they lack the necessary permissions.
Step 4: Performing Administrative Actions
Superusers can manage other accounts using methods like readUsers, createUser, and deleteUser.
In frontend/src/components/Admin/AddUser.tsx, the admin dashboard uses UsersService.createUser to register new accounts:
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { UsersService, type UserCreate } from "@/client"
const mutation = useMutation({
mutationFn: (data: UserCreate) =>
UsersService.createUser({ requestBody: data }),
onSuccess: () => {
// Refresh the list of users in the admin table
queryClient.invalidateQueries({ queryKey: ["users"] })
},
})
The UsersService.readUsers({ skip, limit }) method is similarly used in the Admin component to populate the user management table with paginated data.
Summary of Results
By following this pattern, you have implemented:
- Identity Management: Using
readUserMeto track the current session. - Self-Service: Allowing users to update their own data via
updateUserMe. - Authorization: Protecting routes by checking the
is_superuserflag. - Admin CRUD: Enabling superusers to manage the entire user base via the
UsersServiceadministrative methods.
Next, you can explore frontend/src/components/UserSettings/ChangePassword.tsx to see how UsersService.updatePasswordMe is used to handle secure credential updates.