Capgemini Senior Software Engineer – Java Full Stack Interview Preparation
This document consolidates the interview discussion around Authentication & Authorization, React state management, controlled vs uncontrolled components, and custom hooks, tailored for a Senior Software Engineer / Java Full Stack role.
1. Authentication and Authorization in a Full Stack Project
Section titled “1. Authentication and Authorization in a Full Stack Project”Interview Question
Section titled “Interview Question”Explain how you’re doing authentication and authorization in your current project.
Senior-Level Answer
Section titled “Senior-Level Answer”In our React + Spring Boot application, authentication and authorization are handled separately.
- Authentication verifies who the user is.
- Authorization verifies what the authenticated user is allowed to do.
The React frontend interacts with an authentication mechanism, typically an enterprise Identity Provider (IdP) or authentication service. After successful authentication, the application receives a token such as a JWT.
The token can contain or represent:
- User ID
- Username
- Roles
- Authorities / permissions
- Expiration time
Example conceptual token payload:
{ "sub": "john", "roles": ["ADMIN"], "permissions": [ "CREATE_USER", "UPDATE_USER", "DELETE_USER" ], "exp": 1780000000}The frontend uses the authenticated session/token for subsequent API calls. The Spring Boot backend validates the token and performs the actual authorization checks.
End-to-End Flow
Section titled “End-to-End Flow”flowchart LR
A[React Login Page] --> B[Authentication Service / IdP]
B --> C[Authentication Successful]
C --> D[JWT / Access Token]
D --> E[React Application]
E --> F[Axios Interceptor]
F --> G[API Gateway / Spring Boot]
G --> H[Spring Security Filter Chain]
H --> I[Validate Token]
I --> J[Extract Authorities]
J --> K[SecurityContext]
K --> L[Controller]
L --> M[Service]
M --> N[Database]
Important Interview Point
Section titled “Important Interview Point”The frontend is not the security boundary.
React can hide buttons, menus, and routes based on permissions, but a user can bypass frontend code by calling the API directly through Postman, curl, or another client.
Therefore:
Authorization must always be enforced on the backend.
2. Authorized User Trying to Access an API Without Permission
Section titled “2. Authorized User Trying to Access an API Without Permission”Interview Question
Section titled “Interview Question”Suppose I am an authenticated user, but I try to access an API for which I don’t have permission. How do you handle this in React and Spring Boot?
React Side
Section titled “React Side”After login, the application can maintain user information such as:
{ "id": 101, "name": "John", "roles": ["USER"], "permissions": [ "VIEW_REPORT" ]}This information can be maintained in:
- Context API
- Redux Toolkit
- Another application-level state mechanism
React can then conditionally render UI elements.
For example:
{user?.permissions.includes("CREATE_USER") && ( <button>Create User</button>)}If the user doesn’t have CREATE_USER, the button can be hidden.
Similarly, protected routes can be implemented:
/admin | +-- Check authentication | +-- Check role | +-- Allow / redirectHowever, this is only a UX-level protection.
What Happens If the User Calls the API Directly?
Section titled “What Happens If the User Calls the API Directly?”Suppose the user doesn’t have:
DELETE_USERbut tries:
DELETE /api/users/101The request still reaches the backend.
Spring Security validates the access token and establishes the authenticated user.
Then authorization is checked.
Example:
@PreAuthorize("hasAuthority('DELETE_USER')")@DeleteMapping("/users/{id}")public void deleteUser(@PathVariable Long id) { userService.deleteUser(id);}If the user has the required authority:
Request | vJWT Validation | vAuthority Check | vControllerIf the user does not have the required authority:
Request | vJWT Validation | vAuthority Check | X403 ForbiddenThe controller should not execute.
Authentication vs Authorization
Section titled “Authentication vs Authorization”| Concept | Question | Example |
|---|---|---|
| Authentication | Who are you? | User successfully logged in |
| Authorization | What can you do? | User can view reports but cannot delete users |
401 vs 403
Section titled “401 vs 403”A useful senior-level distinction:
| HTTP Status | Meaning |
|---|---|
401 Unauthorized |
Authentication is missing or invalid |
403 Forbidden |
User is authenticated but doesn’t have sufficient permission |
3. How React Manages Application State
Section titled “3. How React Manages Application State”Interview Question
Section titled “Interview Question”In React, how do you manage application state?
React applications usually have different categories of state.
Local Component State
Section titled “Local Component State”Use useState when state belongs to a single component.
const [name, setName] = useState("");const [isOpen, setIsOpen] = useState(false);Typical use cases:
- Form fields
- Modal visibility
- Dropdown state
- Local UI state
Shared State
Section titled “Shared State”When multiple components need the same state, we can use:
- Context API
- Redux Toolkit
Examples:
- Logged-in user
- Roles
- Permissions
- Theme
- Language
- Application configuration
Server State
Section titled “Server State”Data retrieved from backend APIs is often better treated as server state.
A solution such as TanStack Query can handle:
- API fetching
- Caching
- Refetching
- Retry
- Loading state
- Error state
- Cache invalidation
Typical State Architecture
Section titled “Typical State Architecture”flowchart TD
A[React Application] --> B[Local State]
A --> C[Global Client State]
A --> D[Server State]
B --> B1[useState]
B --> B2[useReducer]
C --> C1[Context API]
C --> C2[Redux Toolkit]
D --> D1[TanStack Query]
D --> D2[API Cache]
Senior-Level Answer
Section titled “Senior-Level Answer”I don’t put everything into Redux. I classify state first. Component-specific UI state stays local with useState or useReducer. Cross-cutting state such as authentication, user permissions, theme, or application configuration can use Context API or Redux Toolkit. API data is server state, so for a larger application I prefer a dedicated server-state solution such as TanStack Query. This keeps the architecture maintainable and avoids unnecessary global state.
4. How Context API Stores User Details, Roles, and Permissions
Section titled “4. How Context API Stores User Details, Roles, and Permissions”Context API is useful when authentication information needs to be consumed by many components.
Auth Context
Section titled “Auth Context”import { createContext, useContext, useState } from "react";
const AuthContext = createContext(null);
export function AuthProvider({ children }) { const [user, setUser] = useState(null);
return ( <AuthContext.Provider value={{ user, setUser }}> {children} </AuthContext.Provider> );}
export function useAuth() { return useContext(AuthContext);}The provider can wrap the application:
<AuthProvider> <App /></AuthProvider>After login:
const { setUser } = useAuth();
login(credentials).then((response) => { setUser(response.user);});The user can then be accessed from any component:
const { user } = useAuth();
const isAdmin = user?.roles.includes("ADMIN");
const canCreate = user?.permissions.includes("CREATE_USER");Conditional UI:
{canCreate && ( <button>Create User</button>)}5. How Redux Toolkit Stores User Details, Roles, and Permissions
Section titled “5. How Redux Toolkit Stores User Details, Roles, and Permissions”For a larger application, Redux Toolkit provides a centralized and structured state store.
Auth Slice
Section titled “Auth Slice”import { createSlice } from "@reduxjs/toolkit";
const authSlice = createSlice({ name: "auth",
initialState: { token: null, user: null },
reducers: { loginSuccess(state, action) { state.token = action.payload.token; state.user = action.payload.user; },
logout(state) { state.token = null; state.user = null; } }});
export const { loginSuccess, logout} = authSlice.actions;
export default authSlice.reducer;After successful login:
dispatch(loginSuccess(response));The store conceptually looks like:
Redux Store | +-- auth | +-- token | +-- user | +-- id +-- name +-- roles +-- permissionsRead the user:
const user = useSelector( state => state.auth.user);Check a role:
const isAdmin = user?.roles.includes("ADMIN");Check a permission:
const canDelete = user?.permissions.includes("DELETE_USER");6. Axios Interceptor and Authentication
Section titled “6. Axios Interceptor and Authentication”An Axios request interceptor can attach the access token automatically to API requests.
Conceptually:
axios.interceptors.request.use(config => { const token = getAccessToken();
if (token) { config.headers.Authorization = `Bearer ${token}`; }
return config;});Request:
GET /api/usersAuthorization: Bearer <access-token>The backend then validates the token.
Important Security Note
Section titled “Important Security Note”Avoid treating browser-accessible storage as a completely secure location for sensitive tokens. The exact strategy depends on the application’s security architecture. For browser applications, secure HttpOnly, Secure, appropriately configured cookies are often preferred for session/token handling where the architecture supports them.
7. Context API vs Redux Toolkit
Section titled “7. Context API vs Redux Toolkit”| Feature | Context API | Redux Toolkit |
|---|---|---|
| Setup | Simple | More structured |
| Best suited for | Cross-cutting/simple shared state | Complex global state |
| Authentication | Good | Good |
| Theme / language | Excellent | Usually unnecessary |
| Complex workflows | Limited | Strong |
| DevTools | Limited | Redux DevTools |
| Middleware | Limited/manual | Strong ecosystem |
| Large application | Can become difficult if overused | Better suited |
| State organization | Provider-based | Central store + slices |
Senior-Level Recommendation
Section titled “Senior-Level Recommendation”Don’t say:
Redux is always better.
Instead say:
I choose based on application complexity. Context API is sufficient for relatively simple cross-cutting concerns such as authentication, theme, or locale. Redux Toolkit becomes more useful when the application has complex shared state, multiple update paths, asynchronous workflows, debugging requirements, or many independent features.
8. Controlled and Uncontrolled Components
Section titled “8. Controlled and Uncontrolled Components”Interview Question
Section titled “Interview Question”What is the difference between controlled and uncontrolled components in React?
Controlled Component
Section titled “Controlled Component”React state controls the input value.
const [name, setName] = useState("");
<input value={name} onChange={e => setName(e.target.value)}/>Flow:
flowchart LR
A[User Types] --> B[onChange]
B --> C[setState]
C --> D[React State]
D --> E[Input Value]
Advantages
Section titled “Advantages”- Easy validation
- Easy conditional rendering
- Centralized form state
- Predictable behavior
Typical use cases:
- Login form
- Registration form
- Search box
- Complex business forms
Uncontrolled Component
Section titled “Uncontrolled Component”The DOM maintains the input value.
const inputRef = useRef();
<input ref={inputRef} />Read the value:
const value = inputRef.current.value;Flow:
flowchart LR
A[User Types] --> B[DOM Input]
B --> C[useRef]
C --> D[Read Value]
Typical Use Cases
Section titled “Typical Use Cases”- Simple forms
- File inputs
- Integrating with some third-party libraries
- Situations where you don’t need React state for every keystroke
Comparison
Section titled “Comparison”| Controlled | Uncontrolled |
|---|---|
| React owns value | DOM owns value |
Usually uses useState |
Usually uses useRef |
| Easier validation | Simpler for basic cases |
| More React state updates | Fewer React state updates |
| Excellent for complex forms | Useful for simple/DOM-oriented scenarios |
9. When Should We Create a Custom Hook?
Section titled “9. When Should We Create a Custom Hook?”Interview Question
Section titled “Interview Question”When should we create a custom hook in React?
A custom hook is useful when we need to reuse stateful React logic across multiple components.
The key point is:
Custom hooks share logic, not the same state instance.
If three components call the same custom hook, each call normally has its own hook state unless the hook internally connects to shared state.
10. Requirements / Scenarios for Custom Hooks
Section titled “10. Requirements / Scenarios for Custom Hooks”Create a custom hook when you identify repeated behavior such as:
Authentication
Section titled “Authentication”useAuth()Could expose:
userlogin()logout()isAuthenticatedhasRole()hasPermission()API Handling
Section titled “API Handling”useFetch()Could manage:
dataloadingerrorrefetch()Debouncing
Section titled “Debouncing”useDebounce()Useful for:
- Search
- Auto-complete
- API calls triggered by typing
Window Size
Section titled “Window Size”useWindowSize()Useful when components need responsive JavaScript behavior.
Pagination
Section titled “Pagination”usePagination()Can encapsulate:
- Current page
- Page size
- Next page
- Previous page
- Total pages
Local Storage
Section titled “Local Storage”useLocalStorage()Can encapsulate reading/writing browser storage.
11. Custom Hook Example
Section titled “11. Custom Hook Example”import { useEffect, useState} from "react";
function useFetch(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null);
useEffect(() => { setLoading(true);
fetch(url) .then(response => { if (!response.ok) { throw new Error( "Request failed" ); }
return response.json(); }) .then(result => { setData(result); setError(null); }) .catch(err => { setError(err); }) .finally(() => { setLoading(false); });
}, [url]);
return { data, loading, error };}Use it in a component:
function EmployeeList() { const { data, loading, error } = useFetch("/api/employees");
if (loading) { return <p>Loading...</p>; }
if (error) { return <p>Unable to load employees.</p>; }
return ( <ul> {data?.map(employee => ( <li key={employee.id}> {employee.name} </li> ))} </ul> );}12. Custom Hook for Authorization
Section titled “12. Custom Hook for Authorization”A particularly useful example for this interview is useAuthorization.
import { useAuth } from "./AuthContext";
export function useAuthorization() { const { user } = useAuth();
const hasRole = (role) => user?.roles?.includes(role) ?? false;
const hasPermission = (permission) => user?.permissions?.includes(permission) ?? false;
return { hasRole, hasPermission };}Component:
function UserManagement() { const { hasPermission } = useAuthorization();
return ( <> {hasPermission("CREATE_USER") && ( <button> Create User </button> )}
{hasPermission("DELETE_USER") && ( <button> Delete User </button> )} </> );}This avoids duplicating permission-checking logic throughout the application.
Important
Section titled “Important”This only controls the frontend experience.
The backend still needs:
@PreAuthorize( "hasAuthority('DELETE_USER')")13. Complete React + Spring Boot Security Architecture
Section titled “13. Complete React + Spring Boot Security Architecture”A senior-level explanation can combine all of the above:
flowchart TB
U[User] --> R[React Application]
R --> L[Login]
L --> IDP[Identity Provider / Auth Service]
IDP --> T[Access Token / JWT]
T --> R
R --> S[Auth Context / Redux Toolkit]
S --> UI[Menus / Buttons / Protected Routes]
R --> AX[Axios Interceptor]
AX --> G[API Gateway / Spring Boot]
G --> SF[Spring Security Filter Chain]
SF --> JV[JWT Validation]
JV --> AC[Authorities / Roles]
AC --> SC[SecurityContext]
SC --> AZ{Authorization Check}
AZ -->|Allowed| C[Controller]
AZ -->|Denied| F[403 Forbidden]
C --> SV[Service Layer]
SV --> DB[(Database)]
14. Complete Interview Answer
Section titled “14. Complete Interview Answer”If the Capgemini interviewer asks all these questions together, a strong answer would be:
In our React and Spring Boot application, authentication is handled through an authentication service or enterprise Identity Provider. After successful authentication, the client receives an access token, typically a JWT, containing or representing the user’s identity and authorities.
On the React side, we maintain user information such as user ID, roles, and permissions using Context API or Redux Toolkit. This allows components to conditionally render menus, buttons, and protected routes. Axios interceptors can attach the access token to API requests.
However, the React application is not our security boundary. If an authenticated user manually calls an API for which they don’t have permission, the request still reaches Spring Boot. Spring Security validates the token, creates the authenticated security context, and checks the required authority using mechanisms such as
@PreAuthorizeandhasAuthority(). If the user doesn’t have the required permission, the backend returns403 Forbiddenand the controller is not executed.For React state management, I classify state into local state, shared client state, and server state. I use
useStateoruseReducerfor local state, Context API or Redux Toolkit for shared state, and a server-state solution such as TanStack Query where appropriate for API data.I create custom hooks when I have reusable stateful logic. For example, authentication logic can be encapsulated in
useAuth, permission checks inuseAuthorization, and common API behavior in a data-fetching hook. This improves separation of concerns, reduces duplication, and makes components easier to maintain.For forms, I generally use controlled components when business validation and dynamic behavior are required, while uncontrolled components can be useful for simpler DOM-driven scenarios or specific inputs such as file uploads.
15. Senior-Level Points to Remember
Section titled “15. Senior-Level Points to Remember”For a Capgemini Senior Software Engineer interview, emphasize these points:
- Authentication != Authorization
- React authorization is primarily UX-level protection
- Spring Boot is the real security enforcement point
401generally means authentication failure403means authenticated but insufficient permission- Use roles for coarse-grained access
- Use permissions/authorities for fine-grained access
- Don’t put every piece of state into Redux
- Custom hooks are for reusing stateful logic
- Context API and Redux Toolkit solve different levels of application-state complexity
- API/server state is different from client state
- Never trust permissions supplied only by the frontend
- Token expiration and refresh need to be handled
- Authorization should also be considered at the service/API boundary
- Keep authentication, authorization, state management, and UI concerns separated
Quick Revision
Section titled “Quick Revision”Authentication ↓Who is the user?
Authorization ↓What can the user do?
React ↓UX-level permission handling
Axios ↓Attach access token
Spring Security ↓Validate token
Authorities / Roles ↓Authorization
@PreAuthorize ↓Allow / Deny
403 ↓Insufficient permission