When you’re building your first real-world web application, authentication feels magical until it suddenly doesn’t. You implement a login form, your backend returns a token, you store it somewhere, and everything works perfectly—until you open a second tab and your user is mysteriously logged out. Or you refresh the page and the shopping cart vanishes. Or worse, you deploy to production and discover your tokens are exposed to JavaScript, making your app vulnerable to attacks you didn’t even know existed.
- Authentication State That Disappears
- The Token Storage Dilemma
- The Token Storage Dilemma
- Multi-Tab Synchronization
- Token Expiration and Refresh
- CSRF and XSS Vulnerabilities
- How Cookies Solve These Problems
- 1. Automatic Inclusion in Requests
- Persistence Across Browser Restarts
- Security Through HttpOnly
- Cross-Tab Synchronization
- Protection Against CSRF with SameSite
- Real-World Example: Authentication and Shopping Cart
- Step-by-Step Implementation
These aren’t just theoretical problems. They’re the exact frustrations that junior developers face every single day, and they often stem from one fundamental misunderstanding about how web applications maintain state across requests.
Let me share a story that might sound familiar. A few years ago, I was mentoring a talented developer from Kathmandu who had built a beautiful e-commerce site. The UI was polished, the code was clean, but users kept complaining that their carts would empty randomly. After some investigation, we discovered the issue: he was storing the authentication token and cart data in component state. Every time a user opened a link in a new tab or refreshed the page, everything disappeared. The fix? Proper cookie implementation. Within a day, all those mysterious bugs vanished.
In this guide, I’ll walk you through everything you need to know about cookies in modern web development, using React, Next.js with TypeScript on the frontend and Spring Boot on the backend. We’ll build a real authentication system with automatic token refresh, and I’ll show you exactly how to avoid the pitfalls that trip up most developers.
The Pain Points: Why Cookie Management Matters
Before we dive into solutions, let’s talk about the real problems you’re trying to solve. Understanding these pain points will help you appreciate why cookies exist and how they solve these challenges elegantly.
Authentication State That Disappears
Imagine you’re building a blog site where users can write and publish articles. A user logs in successfully, starts writing a long article, then accidentally closes the tab or their browser crashes. When they come back and open your site again, they have to log in from scratch. Their draft? Gone. Their frustration? Maximum.
Imagine you’re building a simple login system for an online shop. A user logs in on the top frontend (your react app), and everything seems fine- they see their cart and profile. But then they refresh the page or click another section, and proof! They are logged out. Or worse, the backend (your Spring B0ot Server) doesn’t recognize them anymore so they have t log in again everytime.
This happens when developers store authentication tokens in memory using React state or even localStorage without proper persistence strategy. When the page reloads or a new tab opens, that state is lost. Your backend thinks the user is authenticated, but your frontend has no way to prove it.
The Token Storage Dilemma
Here’s a question that confuses many developers: where should you store your authentication token? You have several options, each with serious tradeoffs. Store it in localStorage and any malicious JavaScript code injected through XSS can steal it immediately. Store it in memory and it disappears on refresh. Store it in a regular cookie without proper flags and you’re vulnerable to CSRF attacks.
I’ve seen production applications where developers stored JWT tokens in localStorage, thinking it was the “modern” approach. Then a security audit revealed that a single XSS vulnerability in a third-party library could compromise every user’s account. The fix required a complete rewrite of the authentication flow.
The Token Storage Dilemma
Here’s a question that confuses many developers: where should you store your authentication token? You have several options, each with serious tradeoffs. Store it in localStorage and any malicious JavaScript code injected through XSS can steal it immediately. Store it in memory and it disappears on refresh. Store it in a regular cookie without proper flags and you’re vulnerable to CSRF attacks.
I’ve seen production applications where developers stored JWT tokens in localStorage, thinking it was the “modern” approach. Then a security audit revealed that a single XSS vulnerability in a third-party library could compromise every user’s account. The fix required a complete rewrite of the authentication flow.
Multi-Tab Synchronization
Modern users don’t browse with one tab anymore. They open your application in five different tabs simultaneously. When they log out in one tab, should the other four tabs know about it? When they add items to their shopping cart in tab one, should tab two show those items immediately? Without a proper synchronization mechanism, your application feels broken and inconsistent.
I once worked on an application where users would log out in one tab but remain “logged in” in others because each tab maintained its own authentication state in memory. Users would perform actions thinking they were authenticated, only to get cryptic error messages. The support tickets were endless.
Token Expiration and Refresh
JWT access tokens should expire quickly for security reasons—typically within fifteen minutes to an hour. But asking users to log in every hour destroys the user experience. You need a seamless token refresh mechanism that happens automatically in the background without interrupting the user’s workflow.
The naive approach is to refresh the token every time it expires. But what happens when your token refresh logic itself fails? Or when the refresh token expires? Or when you have multiple API calls happening simultaneously and they all try to refresh the token at once, creating a race condition? These edge cases turn what seems like a simple problem into a complex orchestration challenge.
CSRF and XSS Vulnerabilities
Security vulnerabilities aren’t abstract theoretical concerns—they’re real threats that can destroy your application and your reputation. Cross-Site Request Forgery means an attacker can trick a user’s browser into making authenticated requests to your application without the user’s knowledge. Cross-Site Scripting means an attacker can inject malicious JavaScript that steals user data or performs actions on their behalf.
When you don’t understand how to properly configure cookies with HttpOnly, Secure, and SameSite flags, you leave these vulnerabilities wide open. I’ve seen developers who thought they were building secure applications, only to discover during a penetration test that their entire authentication system could be compromised in minutes.
How Cookies Solve These Problems
Now that we understand the challenges, let’s talk about the solution. Cookies are small pieces of data that your browser stores and automatically sends with every HTTP request to a specific domain. Think of them as identification badges that your browser carries for you.
Think of cookies like a VIP pass at a concert:
- You show your ID once at the entrance (login)
- They give you a wristband (cookie)
- Now every time you move around, security sees your wristband and lets you through
- You don’t need to show your ID again!
Cookies work exactly the same way in web applications. When you log in successfully, the server gives your browser a cookie containing an authentication token. From that point forward, your browser automatically includes that cookie with every request to the server. You don’t have to manually attach it or remember to include it—the browser does this automatically.
1. Automatic Inclusion in Requests
This automatic behavior is incredibly powerful. When you use localStorage or SessionStgorage. Forget do do it once and that request fail. With cookies, the browser handles this for you automatically. Every fetch request, every form submission, every API call automatically includes the relevant cookies without any extra code.
This automatic inclusion also means your authentication works consistently across your entire application. Whether you’re making a request from a React component, form a server-side function in Next.js, or even from a plain HTML form, the authentication cookie goes along automatically.
Persistence Across Browser Restarts
When you set a cookie with an expiration date, the browser stores it persistently on disk. Close the browser, restart your computer, come back a week later—the cookie is still there until it expires. This solves the “lost state on refresh” problem completely. Your users can close their browser, come back later, and they’re still logged in because the authentication cookie persists.
Compare this to storing tokens in React state or even in memory. The moment the user refreshes the page, that state is gone. You’d have to implement complicated logic to restore it from somewhere, and you’d still lose it when the browser closes.
Security Through HttpOnly
Here’s where cookies become really interesting from a security perspective. When you set a cookie with the HttpOnly flag, JavaScript code running in the browser cannot read or access that cookie at all. This protects your authentication tokens from XSS attacks completely.
Think about that for a moment. Even if an attacker manages to inject malicious JavaScript into your application through a vulnerability in a third-party library, that JavaScript cannot steal the authentication token because the browser won’t let it access HttpOnly cookies. The token is there, it’s being sent with requests automatically, but malicious code can’t touch it.
This is fundamentally different from storing tokens in localStorage, where any JavaScript code can read them freely. An HttpOnly cookie is like keeping your ID badge in a special secure pocket that only security guards can check—pickpockets can’t get to it.
Cross-Tab Synchronization
Because cookies are stored at the browser level rather than the tab level, all tabs accessing the same domain share the same cookies automatically. When a user logs in in one tab, the cookie is immediately available to all other tabs. When they log out and the cookie gets deleted, it’s deleted for all tabs simultaneously.
This solves the multi-tab synchronization problem elegantly without requiring complex state management or broadcast channels or service workers. The browser handles it for you automatically because cookies are browser-level, not tab-level.
Protection Against CSRF with SameSite
The SameSite cookie attribute tells the browser when to send a cookie with requests. Setting it to “Lax” or “Strict” prevents the browser from sending your authentication cookies with requests that originate from other websites. This protects against CSRF attacks where a malicious site tries to make authenticated requests to your application using the user’s cookies.
Imagine someone emails you a malicious link. When you click it, it tries to make a request to your banking site to transfer money. Without SameSite protection, your browser would send your authentication cookies with that request, and the transfer would succeed. With SameSite=Lax, the browser refuses to send the authentication cookies with that cross-site request, and the attack fails.
Real-World Example: Authentication and Shopping Cart
Let me show you how this works in practice with a realistic example. We’ll build a blog site where users can log in, write articles, and the authentication state persists properly across tabs and browser restarts. We’ll also add a shopping cart feature where users can save articles to read later, and this cart will synchronize across all tabs automatically.
The User Flow (Brief Version)
Sarah visits our blog site and signs up. She submits her email and password, and the React frontend sends them to the Spring Boot backend at /api/auth/register.
The backend validates her details, creates the account, and generates two tokens:
-
Access Token (valid 15 minutes)
-
Refresh Token (valid 7 days)
Instead of sending these tokens in the JSON response, the backend stores them as HttpOnly cookies, so they’re safe from JavaScript attacks. Sarah’s browser automatically stores the cookies.
Now whenever Sarah browses the site—reading articles or adding items to her reading list—her browser automatically sends these cookies with every request. The backend reads the access token cookie, identifies her, and processes her actions.
After 15 minutes, her access token expires. When she tries to view her reading list, the backend returns 401 Unauthorized. The frontend catches this automatically and calls /api/auth/refresh. Since the refresh token cookie is still valid, the backend issues a new access token as a cookie, and the frontend retries the original request—Sarah never notices anything.
Sarah also opens several tabs. All tabs share the same cookies, so she’s logged in everywhere. Adding articles in one tab instantly reflects in others because the data is stored in the backend, not local state.
Finally, when she logs out, the frontend calls /api/auth/logout. The backend clears both cookies. Because cookies are browser-level, Sarah is logged out across all tabs at once.
Why This Architecture Works
This approach solves all the pain points we discussed earlier. The authentication state persists across browser restarts because cookies are stored on disk. Multiple tabs stay synchronized because they share the same cookies. Tokens are protected from XSS because they’re in HttpOnly cookies that JavaScript can’t access. CSRF is prevented because we use SameSite cookies and CSRF tokens. Token refresh happens automatically and seamlessly without the user noticing.
Most importantly, the user experience is smooth and predictable. Sarah doesn’t lose her state unexpectedly. She doesn’t get logged out randomly. Her reading list doesn’t disappear when she refreshes the page. The application just works the way she expects it to work.
Why This Architecture Works
This approach solves all the pain points we discussed earlier. The authentication state persists across browser restarts because cookies are stored on disk. Multiple tabs stay synchronized because they share the same cookies. Tokens are protected from XSS because they’re in HttpOnly cookies that JavaScript can’t access. CSRF is prevented because we use SameSite cookies and CSRF tokens. Token refresh happens automatically and seamlessly without the user noticing.
Most importantly, the user experience is smooth and predictable. Sarah doesn’t lose her state unexpectedly. She doesn’t get logged out randomly. Her reading list doesn’t disappear when she refreshes the page. The application just works the way she expects it to work.
Step-by-Step Implementation
Now let’s build this system step by step, starting with the Spring Boot backend and then moving to the React/Next.js frontend with TypeScript.
Step 1: Set Up Your Backend with Spring Boot
First, the server handles cookie creation. We’ll use Spring Security for auth and JWT for tokens.
-
Add Dependencies: In your pom.xml (for Maven), add:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency>
Create a configuration class to handle cookie creation with proper security settings:
package org.blogapp.dg_blogapp.utils;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.Arrays;
import java.util.Optional;
@Service
public class CookieUtil {
private static final String ACCESS_TOKEN_COOKIE = "accessToken";
private static final String REFRESH_TOKEN_COOKIE = "refreshToken";
@Value("${jwt.access-token-expiration}")
private int ACCESS_TOKEN_MAX_AGE;
@Value("${jwt.refresh-token-expiration}")
private int REFRESH_TOKEN_MAX_AGE;
@Value("${app.cookie.domain}")
private String domainName;
private Cookie createSecureCookie(String name, String value, int maxAge){
Cookie cookie = new Cookie(name, value);
cookie.setHttpOnly(true); //make the cookie inaccessible to javascript
cookie.setSecure(false); //true in prod //Ensures cookie is only sent over HTTPS, critical for prod to avoid middle-man attacks.
cookie.setPath("/");
cookie.setMaxAge(maxAge);
if(StringUtils.hasText(domainName)){
cookie.setDomain(domainName);
}
return cookie;
}
public void setAccessTokenCookie(HttpServletResponse response, String accessToken){
int maxAgeSeconds = (int) (ACCESS_TOKEN_MAX_AGE / 1000);
Cookie cookie = createSecureCookie(ACCESS_TOKEN_COOKIE, accessToken, maxAgeSeconds);
response.addCookie(cookie);
// Manual set-cookie header for better samesite support
// response.addHeader("Set-Cookie", String.format("%s=%s; path=/; HttpOnly; Secure; SameSite=Strict; Max-Age=%d", ACCESS_TOKEN_COOKIE, accessToken, maxAgeSeconds));
}
public void setRefreshTokenCookie(HttpServletResponse response, String refreshToken){
int maxAgeSeconds = (int) (REFRESH_TOKEN_MAX_AGE / 1000);
Cookie cookie = createSecureCookie(REFRESH_TOKEN_COOKIE, refreshToken, maxAgeSeconds);
response.addCookie(cookie);
}
public Optional<String> getCookieValue(HttpServletRequest request, String cookieName) {
if(request.getCookies() == null){
return Optional.empty();
}
return Arrays.stream(request.getCookies())
.filter(cookie -> cookieName.equals(cookie.getName()))
.map(Cookie::getValue)
.findFirst();
}
public Optional<String> getAccessToken(HttpServletRequest request) {
return getCookieValue(request, ACCESS_TOKEN_COOKIE);
}
public Optional<String> getRefreshToken(HttpServletRequest request) {
return getCookieValue(request, REFRESH_TOKEN_COOKIE);
}
/**
* Clear authentication cookies (logout)
*/
public void clearAuthCookie(HttpServletResponse response) {
Cookie accessCookie = new Cookie(ACCESS_TOKEN_COOKIE, null);
accessCookie.setPath("/");
accessCookie.setHttpOnly(false); //true in prod
accessCookie.setSecure(false); //true in prod
accessCookie.setMaxAge(0);
response.addCookie(accessCookie);
Cookie refreshCookie = new Cookie(REFRESH_TOKEN_COOKIE, null);
refreshCookie.setPath("/");
refreshCookie.setHttpOnly(true);
refreshCookie.setMaxAge(0);
response.addCookie(refreshCookie);
}
}
his class:
✔ Stores JWT tokens inside cookies
✔ Ensures cookies are secure
✔ Reads tokens when user makes requests
✔ Deletes tokens on logout
It’s a security helper for authentication.
Now in AutController:
package org.blogapp.dg_blogapp.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.blogapp.dg_blogapp.dto.JwtResponse;
import org.blogapp.dg_blogapp.dto.LoginResponse;
import org.blogapp.dg_blogapp.dto.LoginRequest;
import org.blogapp.dg_blogapp.dto.RegisterRequest;
import org.blogapp.dg_blogapp.dto.TokenRefreshResult;
import org.blogapp.dg_blogapp.dto.UserResponseDTO;
import org.blogapp.dg_blogapp.model.Role;
import org.blogapp.dg_blogapp.service.AuthenticationService;
import org.blogapp.dg_blogapp.service.JwtService;
import org.blogapp.dg_blogapp.utils.CookieUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;
import java.util.HashMap;
import java.util.Map;
/**
* REST controller for authentication endpoints.
*/
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
@Slf4j
//@Tag(name="Authentication", description="User authentication and registration endpoints")
public class AuthenticationController
{
private final AuthenticationService authService;
private JwtService jwtService;
private final CookieUtil cookieUtil;
@Operation(summary = "Register a new user", description = "Creates a new user with USER role")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "User registered successfully"),
@ApiResponse(responseCode = "409", description = "Username already exists")
})
@PostMapping("/register")
public ResponseEntity<Map<String, Object>> register(@Valid @RequestBody RegisterRequest request, HttpServletResponse response)
{
AuthResult result = authService.register(request, Role.USER);
// Handle HTTP concern: Set cookies
cookieUtil.setAccessTokenCookie(response, result.getAccessToken());
cookieUtil.setRefreshTokenCookie(response, result.getRefreshToken());
// Handle HTTP concern: Build response
Map<String, Object> responseBody = new HashMap<>();
responseBody.put("message", result.getMessage());
responseBody.put("user", result.getUser());
return ResponseEntity.status(HttpStatus.CREATED).body(responseBody);
}
@PostMapping("/login")
public ResponseEntity<Map<String, Object>> login(@Valid @RequestBody LoginRequest request, HttpServletResponse response)
{
// Call service for business logic
JwtResponse result = authService.login(request);
// Handle HTTP concern: Set cookies
cookieUtil.setAccessTokenCookie(response, result.getAccessToken());
cookieUtil.setRefreshTokenCookie(response, result.getRefreshToken());
// Handle HTTP concern: Build response
Map<String, Object> responseBody = new HashMap<>();
responseBody.put("accessToken", result.getAccessToken());
responseBody.put("refreshToken", result.getRefreshToken());
responseBody.put("message", "Login successful");
log.info("{}",responseBody);
return ResponseEntity.ok(responseBody);
}
@PostMapping("/refresh")
@Operation(summary = "Refresh access token", description = "Rotates access and refresh tokens")
public ResponseEntity<Map<String, String>> refreshToken(HttpServletRequest request, HttpServletResponse response)
{
String refreshToken = cookieUtil.getRefreshToken(request)
.orElseThrow(() -> new RuntimeException("Refresh token not found"));
TokenRefreshResult result = authService.refreshToken(refreshToken);
cookieUtil.setAccessTokenCookie(response, result.getAccessToken());
cookieUtil.setRefreshTokenCookie(response, result.getRefreshToken());
return ResponseEntity.ok(Map.of("message", result.getMessage()));
}
@Operation(summary = "Logout user")
@PostMapping("/logout")
public ResponseEntity<Map<String, String>> logout(HttpServletResponse response)
{
// Handle HTTP concern: Clear cookies
cookieUtil.clearAuthCookie(response);
// Handle HTTP concern: Build response
return ResponseEntity.ok(Map.of("message", "Logged out successfully"));
}
}
Now let’s set up a filter to extract the access token from cookies for authentication:
package org.blogapp.dg_blogapp.config;
import io.micrometer.common.lang.NonNull;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.blogapp.dg_blogapp.service.JwtService;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
@RequiredArgsConstructor
@Slf4j
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain)
throws ServletException, IOException {
//Allow options requests to pass through for CORS preflight
if(request.getMethod().equals("OPTIONS")) {
filterChain.doFilter(request, response);
return;
}
String jwt = extractTokenFromCookies(request);
if(jwt==null) {
filterChain.doFilter(request, response);
return;
}
try{
final String username = jwtService.extractUsername(jwt);
if(username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtService.isAccessTokenValid(jwt, userDetails)) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
}
catch(Exception e){
log.error(e.getMessage());
}
filterChain.doFilter(request, response);
}
private String extractTokenFromCookies(HttpServletRequest request) {
if(request.getCookies()==null) return null;
for(Cookie cookie : request.getCookies()) {
if("accessToken".equals(cookie.getName())) {
return cookie.getValue();
}
}
return null;
}
}
-
The filter checks every request and immediately allows CORS preflight OPTIONS requests to pass.
-
It extracts the accessToken from HttpOnly cookies in the incoming request.
-
If no token is found, the request continues without authentication.
-
If a token exists, it extracts the username and validates the JWT against the user’s details.
-
If the token is valid, it sets the authenticated user in SecurityContextHolder, letting Spring Security treat the request as logged-in.
Frontend: Next.js with TypeScript
Although this is a Next.js project same concept is applicable for react JS as well. Now let’s build the frontend. We’ll use Next.js with TypeScript and RTK Query for API calls because it handles caching, loading states, and error handling elegantly.
First, install the necessary dependencies:
npm install @reduxjs/toolkit react-redux # or yarn add @reduxjs/toolkit react-redux
Create your Redux store setup with RTK Query:
import { configureStore } from "@reduxjs/toolkit";
import blogSlice from "./features/blog/blogSlice";
import { authApi } from "./features/api/AuthApi";
import authSlice from "./features/authSlice";
export const makeStore = configureStore({
reducer: {
blog: blogSlice,
auth: authSlice,
[authApi.reducerPath]: authApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(authApi.middleware),
});
export type AppStoreType = typeof makeStore;
export type RootState = ReturnType<typeof makeStore.getState>;
export type AppDispatch = typeof makeStore.dispatch;
import { fetchBaseQuery } from "@reduxjs/toolkit/query/react";
const baseQuery = fetchBaseQuery({
baseUrl: process.env.NEXT_PUBLIC_API_BASE_URL,
credentials: "include", //This sends the cookie with every requeest
prepareHeaders: (headers) => {
headers.set("Content-Type", "application/json");
return headers;
},
});
export default baseQuery;
This is the complete overview of the implementation along with the detailed theoretical concepts.
You can check the cookies by pressing Ctrl + Shift + I (Inspect), then navigating to the Application tab and selecting the Cookies section.
For the complete guide on how the authentication works, visit this link. : (link will be provided within next 24 hours)