Skip to main content

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:

  1. Identity Management: Using readUserMe to track the current session.
  2. Self-Service: Allowing users to update their own data via updateUserMe.
  3. Authorization: Protecting routes by checking the is_superuser flag.
  4. Admin CRUD: Enabling superusers to manage the entire user base via the UsersService administrative methods.

Next, you can explore frontend/src/components/UserSettings/ChangePassword.tsx to see how UsersService.updatePasswordMe is used to handle secure credential updates.