<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aswani Nayak</title>
    <description>The latest articles on DEV Community by Aswani Nayak (@aswani_nayak_cdcb2fe8ee38).</description>
    <link>https://dev.to/aswani_nayak_cdcb2fe8ee38</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3937023%2Fcf9892f5-ba86-45f8-8056-5a5f47d13ea7.jpg</url>
      <title>DEV Community: Aswani Nayak</title>
      <link>https://dev.to/aswani_nayak_cdcb2fe8ee38</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aswani_nayak_cdcb2fe8ee38"/>
    <language>en</language>
    <item>
      <title>Building a Full Enterprise-Ready React + Spring Boot Auth Flow: An End-to-End Guide</title>
      <dc:creator>Aswani Nayak</dc:creator>
      <pubDate>Fri, 21 Aug 2026 20:46:06 +0000</pubDate>
      <link>https://dev.to/aswani_nayak_cdcb2fe8ee38/building-a-full-enterprise-ready-react-spring-boot-auth-flow-an-end-to-end-guide-pip</link>
      <guid>https://dev.to/aswani_nayak_cdcb2fe8ee38/building-a-full-enterprise-ready-react-spring-boot-auth-flow-an-end-to-end-guide-pip</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Authentication is one of those things that looks simple in a tutorial and becomes surprisingly complex in production. Between token storage, CSRF protection, refresh flows, and protected routing, there are many places to get it wrong—and getting it wrong has real security consequences.&lt;/p&gt;

&lt;p&gt;In two earlier posts, I covered pieces of this puzzle: &lt;a href="https://dev.to/aswani_nayak_cdcb2fe8ee38/enabling-csrf-in-a-jwt-based-react-spring-boot-application-enterprise-ready-approach-8a0"&gt;Enabling CSRF in a JWT-Based React + Spring Boot Application&lt;/a&gt; and &lt;a href="https://dev.to/aswani_nayak_cdcb2fe8ee38/storing-personal-information-in-react-sessionstorage-vs-context-api-25pa"&gt;Storing Personal Information in React: sessionStorage vs Context API&lt;/a&gt;. This post ties those threads together into a complete, end-to-end authentication flow you can adapt for enterprise applications.&lt;/p&gt;

&lt;p&gt;We'll walk through the full journey: login → token issuance → secure storage → protected routes → token refresh → logout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;Before the code, here's the high-level flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┐         ┌──────────────────┐
│    React     │         │   Spring Boot    │
│   Frontend   │         │     Backend      │
└──────┬───────┘         └────────┬─────────┘
       │  1. POST /login          │
       │─────────────────────────&amp;gt;│
       │                          │  validate credentials
       │  2. JWT (httpOnly cookie)│  issue access + refresh
       │&amp;lt;─────────────────────────│
       │                          │
       │  3. GET /protected       │
       │  (+ CSRF token)          │
       │─────────────────────────&amp;gt;│  validate JWT + CSRF
       │  4. Protected data       │
       │&amp;lt;─────────────────────────│
       │                          │
       │  5. POST /refresh        │
       │─────────────────────────&amp;gt;│  rotate tokens
       │                          │
       │  6. POST /logout         │
       │─────────────────────────&amp;gt;│  invalidate session
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Design Decisions
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decision&lt;/th&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;th&gt;Rationale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Token storage&lt;/td&gt;
&lt;td&gt;httpOnly cookies&lt;/td&gt;
&lt;td&gt;Not accessible to JavaScript → mitigates XSS token theft&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSRF protection&lt;/td&gt;
&lt;td&gt;Double-submit / token pattern&lt;/td&gt;
&lt;td&gt;Required when using cookies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token type&lt;/td&gt;
&lt;td&gt;Short-lived access + refresh&lt;/td&gt;
&lt;td&gt;Limits exposure window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State management&lt;/td&gt;
&lt;td&gt;Context API for auth status&lt;/td&gt;
&lt;td&gt;Centralized, lightweight&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Why httpOnly cookies over localStorage? As I discussed in the storage blog, localStorage is readable by any script on the page—making it vulnerable to XSS. httpOnly cookies trade that risk for the need to handle CSRF, which we address below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Backend — Login and Token Issuance
&lt;/h2&gt;

&lt;p&gt;On successful authentication, the backend issues a JWT and sets it as an httpOnly, secure cookie rather than returning it in the response body.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/login"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;LoginRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                               &lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Authenticate credentials (delegated to AuthenticationManager)&lt;/span&gt;
    &lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;authenticationManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authenticate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UsernamePasswordAuthenticationToken&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUsername&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;

    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jwtService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generateAccessToken&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;refreshToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jwtService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generateRefreshToken&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Set access token as httpOnly cookie&lt;/span&gt;
    &lt;span class="nc"&gt;ResponseCookie&lt;/span&gt; &lt;span class="n"&gt;accessCookie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ResponseCookie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"access_token"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accessToken&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;httpOnly&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sameSite&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Strict"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofMinutes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addHeader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpHeaders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SET_COOKIE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accessCookie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="c1"&gt;// Refresh token typically set on a scoped path, e.g. /api/auth/refresh&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LoginResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Login successful"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;httpOnly(true) prevents JavaScript access.&lt;/li&gt;
&lt;li&gt;secure(true) ensures the cookie is only sent over HTTPS.&lt;/li&gt;
&lt;li&gt;sameSite("Strict") adds a layer of CSRF defense (though we won't rely on it alone).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: Backend — CSRF Protection
&lt;/h2&gt;

&lt;p&gt;Because we're using cookies, we need CSRF protection. Spring Security supports the double-submit cookie pattern via CookieCsrfTokenRepository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SecurityFilterChain&lt;/span&gt; &lt;span class="nf"&gt;filterChain&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpSecurity&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;csrf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csrf&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;csrf&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;csrfTokenRepository&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CookieCsrfTokenRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withHttpOnlyFalse&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;csrfTokenRequestHandler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SpaCsrfTokenRequestHandler&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizeHttpRequests&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;requestMatchers&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/auth/login"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/api/auth/refresh"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;permitAll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;anyRequest&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;authenticated&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addFilterBefore&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jwtAuthFilter&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;UsernamePasswordAuthenticationFilter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CSRF token cookie is intentionally not httpOnly, because the frontend must read it and echo it back in a request header. The attacker's site can't read your cookies cross-origin, so this remains safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Frontend — Configuring the HTTP Client
&lt;/h2&gt;

&lt;p&gt;Configure your HTTP client to send cookies and include the CSRF token on state-changing requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;axios&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;withCredentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// send cookies with every request&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Attach CSRF token from cookie to outgoing requests&lt;/span&gt;
&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;csrfToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;XSRF-TOKEN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;csrfToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-XSRF-TOKEN&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;csrfToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`(^| )&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;=([^;]+)`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;decodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Frontend — Auth State with Context API
&lt;/h2&gt;

&lt;p&gt;Since the JWT lives in an httpOnly cookie (invisible to JS), we track authentication status—not the token itself—in React Context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AuthContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;AuthProvider&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// On mount, check if an existing session is valid&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/auth/me&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/auth/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/auth/me&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/auth/logout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AuthContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Provider&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;logout&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/AuthContext.Provider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useAuth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Design note: We don't store the token in Context or state—only the user's authenticated status. The browser handles the cookie automatically. This is the safest pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Frontend — Protecting Routes
&lt;/h2&gt;

&lt;p&gt;Wrap protected routes so unauthenticated users are redirected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Navigate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useAuth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./AuthContext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProtectedRoute&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useAuth&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Navigate&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;replace&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt;
  &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProtectedRoute&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Dashboard&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ProtectedRoute&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Handling Token Refresh
&lt;/h2&gt;

&lt;p&gt;Short-lived access tokens improve security but require a refresh mechanism. A response interceptor can transparently retry after refreshing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interceptors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;original&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_retry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_retry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/auth/refresh&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// rotates cookies server-side&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;original&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;            &lt;span class="c1"&gt;// retry original request&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refreshError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Refresh failed → force logout&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refreshError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Security tip: Implement refresh token rotation on the backend—issue a new refresh token on each use and invalidate the old one. This limits damage if a refresh token is ever compromised.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Logout
&lt;/h2&gt;

&lt;p&gt;Logout must clear cookies server-side, since the frontend can't touch httpOnly cookies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/logout"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;logout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpServletResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ResponseCookie&lt;/span&gt; &lt;span class="n"&gt;clearedCookie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ResponseCookie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"access_token"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;httpOnly&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// expire immediately&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addHeader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpHeaders&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SET_COOKIE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clearedCookie&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="c1"&gt;// Also invalidate the refresh token in your store&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LogoutResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Logged out"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Pitfalls to Avoid
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pitfall&lt;/th&gt;
&lt;th&gt;Consequence&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CORS misconfiguration&lt;/td&gt;
&lt;td&gt;Requests blocked or insecure&lt;/td&gt;
&lt;td&gt;Configure allowed origins explicitly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forgetting withCredentials&lt;/td&gt;
&lt;td&gt;Cookies not sent&lt;/td&gt;
&lt;td&gt;Set on HTTP client&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long-lived access tokens&lt;/td&gt;
&lt;td&gt;Large exposure window&lt;/td&gt;
&lt;td&gt;Short access + refresh tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Not rotating refresh tokens&lt;/td&gt;
&lt;td&gt;Replay attacks&lt;/td&gt;
&lt;td&gt;Rotate on every refresh&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skipping CSRF with cookie auth&lt;/td&gt;
&lt;td&gt;CSRF vulnerability&lt;/td&gt;
&lt;td&gt;Enable CSRF protection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storing JWT in localStorage&lt;/td&gt;
&lt;td&gt;XSS token theft&lt;/td&gt;
&lt;td&gt;Use httpOnly cookies&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Bringing It Together
&lt;/h2&gt;

&lt;p&gt;A production-grade auth flow isn't a single feature—it's a coordinated system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login issues tokens as secure, httpOnly cookies.&lt;/li&gt;
&lt;li&gt;CSRF protection guards cookie-based requests.&lt;/li&gt;
&lt;li&gt;Context API tracks authentication status (never the token).&lt;/li&gt;
&lt;li&gt;Protected routes gate access on the frontend.&lt;/li&gt;
&lt;li&gt;Token refresh keeps sessions alive without long-lived tokens.&lt;/li&gt;
&lt;li&gt;Logout clears state on both ends.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each piece reinforces the others. Skip one, and you introduce a gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Note on Verification
&lt;/h2&gt;

&lt;p&gt;The code samples here are illustrative and follow common, widely-recommended patterns. Spring Security and React library APIs evolve, so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verify the exact API for your versions (e.g., Spring Security's CSRF configuration has changed across major releases).&lt;/li&gt;
&lt;li&gt;Adapt cookie attributes (SameSite, domain, path) to your deployment topology.&lt;/li&gt;
&lt;li&gt;Always test the full flow against your own security requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post completes the authentication series that began with the &lt;a href="https://dev.to/aswani_nayak_cdcb2fe8ee38/enabling-csrf-in-a-jwt-based-react-spring-boot-application-enterprise-ready-approach-8a0"&gt;CSRF&lt;/a&gt; and &lt;a href="https://dev.to/aswani_nayak_cdcb2fe8ee38/storing-personal-information-in-react-sessionstorage-vs-context-api-25pa"&gt;storage&lt;/a&gt; articles. If there's a specific piece you'd like me to expand—refresh token rotation, CORS configuration, or role-based access—let me know.&lt;/p&gt;

</description>
      <category>react</category>
      <category>springboot</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Securing AI-Assisted Development Workflows: Best Practices for Enterprise Teams</title>
      <dc:creator>Aswani Nayak</dc:creator>
      <pubDate>Fri, 21 Aug 2026 18:54:12 +0000</pubDate>
      <link>https://dev.to/aswani_nayak_cdcb2fe8ee38/securing-ai-assisted-development-workflows-best-practices-for-enterprise-teams-5d3</link>
      <guid>https://dev.to/aswani_nayak_cdcb2fe8ee38/securing-ai-assisted-development-workflows-best-practices-for-enterprise-teams-5d3</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;br&gt;
AI coding assistants have moved from novelty to necessity. Tools that suggest, complete, and even generate entire functions are now embedded in the daily workflow of many development teams. In my earlier post, &lt;a href="https://dev.to/aswani_nayak_cdcb2fe8ee38/from-prompting-to-production-a-practical-framework-for-ai-assisted-software-development-37pp"&gt;From Prompting to Production&lt;/a&gt;, I explored how to systematically integrate these tools into software delivery. But adoption without governance creates a new attack surface.&lt;/p&gt;

&lt;p&gt;The uncomfortable truth is this: &lt;strong&gt;the same tools that accelerate your team can quietly leak your secrets, introduce vulnerabilities, and expand your compliance risk&lt;/strong&gt;. For enterprise teams—where security, privacy, and auditability are non-negotiable—AI assistance demands the same rigor we apply to any other part of the SDLC.&lt;/p&gt;

&lt;p&gt;This post lays out a practical framework for securing AI-assisted development, organized around four pillars: &lt;strong&gt;data protection, code validation, secret management, and team governance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why This Matters&lt;/strong&gt;&lt;br&gt;
Before diving into practices, it's worth being explicit about the risks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fomamds7jf6msz9a9varv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fomamds7jf6msz9a9varv.png" alt=" " width="746" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each of these is manageable—but only with intentional guardrails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pillar 1: Protect Sensitive Data and Source Code&lt;/strong&gt;&lt;br&gt;
The most immediate concern is what leaves your environment when developers use AI tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommended Practices&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Understand the data flow.&lt;/strong&gt; Know whether your AI tool sends code to external servers, and whether that data is used for training. Review the vendor's data retention and privacy terms carefully.&lt;br&gt;
&lt;strong&gt;Prefer enterprise or self-hosted deployments&lt;/strong&gt;. Where available, enterprise tiers often offer contractual guarantees that your data won't be used for model training and may support private deployments.&lt;br&gt;
&lt;strong&gt;Classify your codebase.&lt;/strong&gt; Not all repositories carry the same sensitivity. Establish clear rules about which projects may use AI assistance and which must not.&lt;br&gt;
&lt;strong&gt;Use IDE-level controls.&lt;/strong&gt; Many tools allow you to exclude specific files, directories, or file patterns (e.g., .env, config files) from being sent as context.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Vendor capabilities vary and change frequently. Always verify current data-handling policies directly with your tool provider before relying on them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Pillar 2: Validate AI-Generated Code&lt;/strong&gt;&lt;br&gt;
AI suggestions are plausible—not guaranteed correct or secure. Treat all generated code as untrusted until reviewed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Practical Review Checklist&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Does it do what you intended?&lt;/strong&gt; Read and understand every line before accepting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does it introduce known vulnerability patterns?&lt;/strong&gt; Watch for injection risks, weak cryptography, improper input validation, and insecure defaults.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Does it follow your standards?&lt;/strong&gt; Naming, error handling, logging, and architectural conventions still apply.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is it tested?&lt;/strong&gt; AI-generated code deserves the same test coverage as human-written code.
&lt;strong&gt;Automate What You Can&lt;/strong&gt;
Integrate security scanning into your pipeline so that AI-generated code is subject to the same gates as everything else:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example CI stage (illustrative)&lt;/span&gt;
&lt;span class="na"&gt;security-checks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;verify&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;run-static-analysis&lt;/span&gt;     &lt;span class="c1"&gt;# SAST tooling&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;run-dependency-scan&lt;/span&gt;     &lt;span class="c1"&gt;# detect vulnerable dependencies&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;run-secret-scan&lt;/span&gt;         &lt;span class="c1"&gt;# catch committed secrets&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Static analysis (SAST), dependency scanning, and secret detection are your safety net when a risky suggestion slips through review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pillar 3: Keep Secrets Out of Prompts and Suggestions&lt;/strong&gt;&lt;br&gt;
Secrets are especially dangerous in an AI context because they can be both &lt;strong&gt;leaked outward&lt;/strong&gt; (pasted into a prompt) and &lt;strong&gt;suggested inward&lt;/strong&gt; (autocompleted from patterns).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommended Practices&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Never paste real credentials into prompts.&lt;/strong&gt; Use placeholders when asking for help with authentication or configuration code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use secret managers.&lt;/strong&gt; Keep credentials in a dedicated vault or secrets manager rather than in code that AI tools can read as context.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enable pre-commit secret scanning.&lt;/strong&gt; Catch accidental commits before they reach your repository.&lt;br&gt;
Here's an example of writing auth code the right way—with no hardcoded secrets:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Good: secrets loaded from environment / secret manager&lt;/span&gt;
&lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${jwt.secret}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;jwtSecret&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Avoid: hardcoded secrets that AI tools may learn or expose&lt;/span&gt;
&lt;span class="c1"&gt;// private String jwtSecret = "super-secret-value";&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ties directly to enterprise auth patterns—like the JWT and CSRF approach I covered previously. Secure code and secure workflows reinforce each other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pillar 4: Establish Team Governance&lt;/strong&gt;&lt;br&gt;
Individual discipline isn't enough at enterprise scale. You need shared, documented rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building an AI Usage Policy&lt;/strong&gt;&lt;br&gt;
Consider addressing these areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Approved tools.&lt;/strong&gt; Maintain a list of vetted AI assistants and their permitted use contexts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prohibited data.&lt;/strong&gt; Explicitly define what must never be shared with AI tools (customer data, secrets, regulated information).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Review requirements.&lt;/strong&gt; Mandate human review and sign-off for AI-generated code, especially in security-sensitive areas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Training&lt;/strong&gt;. Ensure developers understand both the capabilities and the risks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Auditability&lt;/strong&gt;. Where possible, keep a record of how and where AI assistance is used in your codebase.&lt;br&gt;
&lt;strong&gt;A Simple Adoption Maturity Model&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffb9sy3asote59hkwah5x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffb9sy3asote59hkwah5x.png" alt=" " width="529" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most enterprise teams should aim for at least &lt;strong&gt;Level 3&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bringing It Together&lt;/strong&gt;&lt;br&gt;
Securing AI-assisted development isn't about slowing your team down—it's about making acceleration sustainable. The framework in short:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Protect data&lt;/strong&gt; — control what leaves your environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate code&lt;/strong&gt; — trust nothing until reviewed and scanned.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guard secrets&lt;/strong&gt; — keep credentials out of prompts and suggestions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Govern usage&lt;/strong&gt; — codify shared rules and enforce them.
AI assistance is here to stay. The teams that win won't be the ones who adopt fastest—they'll be the ones who adopt safely.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What's Next?&lt;/strong&gt;&lt;br&gt;
In a future post, I'll dive deeper into &lt;strong&gt;integrating security scanning into CI/CD pipelines&lt;/strong&gt;, expanding on Pillar 2 with concrete tooling patterns. If you found this useful, that's the natural next step in the series.&lt;/p&gt;

&lt;p&gt;Have thoughts or experiences with securing AI workflows on your team? I'd love to hear them.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>governance</category>
      <category>security</category>
      <category>websecurity</category>
    </item>
    <item>
      <title>From Prompting to Production: A Practical Framework for AI-Assisted Software Development</title>
      <dc:creator>Aswani Nayak</dc:creator>
      <pubDate>Wed, 22 Jul 2026 16:06:22 +0000</pubDate>
      <link>https://dev.to/aswani_nayak_cdcb2fe8ee38/from-prompting-to-production-a-practical-framework-for-ai-assisted-software-development-37pp</link>
      <guid>https://dev.to/aswani_nayak_cdcb2fe8ee38/from-prompting-to-production-a-practical-framework-for-ai-assisted-software-development-37pp</guid>
      <description>&lt;p&gt;&lt;em&gt;How structured workflows, context engineering, and human oversight can transform AI from a coding assistant into a true engineering partner.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Generative AI is rapidly changing how software is built. While many development teams have experimented with AI-powered coding tools, the real challenge is not generating code—it's creating a repeatable process that produces reliable, high-quality outcomes.&lt;br&gt;
Recently, we conducted a hands-on workshop to explore how AI can support the complete software development lifecycle. Rather than using toy examples, the session focused on solving a real business problem while applying a structured AI-assisted development workflow.&lt;br&gt;
The result was more than just working software. We uncovered a practical framework that helps engineers collaborate effectively with AI agents, improve productivity, and maintain engineering quality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Importance of Preparation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the key messages before the workshop was simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't start with code. Start with understanding.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Developers were encouraged to review business requirements in advance and become familiar with the problem domain before engaging coding agents.&lt;br&gt;
The goal was not simply to generate code faster, but to:&lt;br&gt;
    • Understand the business problem&lt;br&gt;
    • Validate AI-generated outputs&lt;br&gt;
    • Review implementation plans critically&lt;br&gt;
    • Verify test cases before implementation&lt;br&gt;
The workshop reinforced a crucial principle:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI can accelerate development, but humans remain responsible for understanding the business intent.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Shift from Prompt Engineering to Context Engineering&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Many discussions about AI focus on writing the perfect prompt.&lt;br&gt;
The workshop highlighted something more important:&lt;br&gt;
Context engineering.&lt;br&gt;
The best outcomes occurred when engineers supplied:&lt;br&gt;
    • Business objectives&lt;br&gt;
    • Functional requirements&lt;br&gt;
    • Acceptance criteria&lt;br&gt;
    • System context&lt;br&gt;
    • Integration dependencies&lt;br&gt;
    • Architectural constraints&lt;br&gt;
    • Source-of-truth considerations&lt;br&gt;
Instead of immediately asking an AI agent to generate code, the team first provided comprehensive context and required the agent to fully understand the problem.&lt;br&gt;
For example:&lt;/p&gt;

&lt;p&gt;"I want to create a new Spring Boot application for a sales platform. Review the requirements, understand the acceptance criteria, and grill me on the requirements before creating an implementation plan."&lt;/p&gt;

&lt;p&gt;The business requirement explained that sellers needed a streamlined way to serve customers while relying on existing systems as the source of truth and avoiding unnecessary data duplication across platforms.&lt;br&gt;
Providing this level of context dramatically improved the quality of AI-generated plans, test cases, and implementation recommendations.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;"Grill Me"&lt;/strong&gt; Approach&lt;/p&gt;

&lt;p&gt;One of the most valuable concepts introduced during the workshop was the Grill Me technique.&lt;br&gt;
Rather than immediately proposing a solution, the AI agent is instructed to challenge assumptions and ask follow-up questions until it understands the requirements thoroughly.&lt;br&gt;
This transforms the agent from a code generator into a business analyst.&lt;br&gt;
Instead of guessing, the AI asks questions such as:&lt;br&gt;
    • What business outcome are we trying to achieve?&lt;br&gt;
    • What systems currently own the data?&lt;br&gt;
    • What are the integration constraints?&lt;br&gt;
    • What are the edge cases?&lt;br&gt;
    • What constitutes success?&lt;br&gt;
The objective is to eliminate ambiguity before planning or implementation begins.&lt;br&gt;
This often uncovers gaps in requirements long before development starts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Structured AI Development Workflow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The workshop followed a repeatable workflow designed to maximize AI effectiveness while preserving engineering discipline.&lt;/p&gt;

&lt;p&gt;Step 1: Requirement Discovery&lt;/p&gt;

&lt;p&gt;Provide the business requirements to the AI agent and ask it to fully understand the request before proposing a solution.&lt;br&gt;
The agent should review the available context and ask clarifying questions until requirements are well understood.&lt;br&gt;
Outcome: Clear understanding of the problem.&lt;/p&gt;

&lt;p&gt;Step 2: Implementation Planning&lt;/p&gt;

&lt;p&gt;Once requirements are understood, the AI generates:&lt;br&gt;
    • Solution architecture&lt;br&gt;
    • Technical approach&lt;br&gt;
    • Task breakdown&lt;br&gt;
    • Risks and assumptions&lt;br&gt;
Outcome: An actionable implementation plan.&lt;/p&gt;

&lt;p&gt;Step 3: Human Review&lt;/p&gt;

&lt;p&gt;Developers review the proposed plan and challenge assumptions.&lt;br&gt;
This is one of the most important phases in the process.&lt;br&gt;
The objective is not to approve the plan blindly but to verify:&lt;br&gt;
    • Architectural decisions&lt;br&gt;
    • Business alignment&lt;br&gt;
    • Missing requirements&lt;br&gt;
    • Technical feasibility&lt;br&gt;
Outcome: A validated implementation strategy.&lt;/p&gt;

&lt;p&gt;Step 4: Test-Driven Development&lt;/p&gt;

&lt;p&gt;Before writing code, the AI generates test cases.&lt;br&gt;
A structured TDD approach encourages engineers to define expected system behavior before implementation begins.&lt;br&gt;
Benefits include:&lt;br&gt;
    • Better requirement validation&lt;br&gt;
    • Improved quality&lt;br&gt;
    • Higher confidence in outcomes&lt;br&gt;
    • Earlier detection of requirement gaps&lt;br&gt;
Outcome: Comprehensive test coverage aligned to business needs.&lt;/p&gt;

&lt;p&gt;Step 5: Review Test Cases&lt;/p&gt;

&lt;p&gt;Developers review generated tests to ensure:&lt;br&gt;
    • Requirements are fully represented&lt;br&gt;
    • Edge cases are covered&lt;br&gt;
    • Acceptance criteria are addressed&lt;br&gt;
Strong test cases frequently reveal requirement gaps before implementation starts.&lt;br&gt;
Outcome: Reliable validation criteria.&lt;/p&gt;

&lt;p&gt;Step 6: Code Implementation&lt;/p&gt;

&lt;p&gt;After requirements, plans, and tests have been validated, the AI generates implementation code.&lt;br&gt;
Because the earlier phases established strong guardrails, implementation quality improves significantly.&lt;br&gt;
Outcome: Faster and more accurate development.&lt;/p&gt;

&lt;p&gt;Step 7: Validation and Refinement&lt;/p&gt;

&lt;p&gt;AI-generated code should never be considered production-ready by default.&lt;br&gt;
Engineers still perform:&lt;br&gt;
    • Code reviews&lt;br&gt;
    • Functional validation&lt;br&gt;
    • Performance verification&lt;br&gt;
    • Security checks&lt;br&gt;
    • Refinement and optimization&lt;br&gt;
Outcome: Production-quality software.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why This Approach Works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Several important lessons emerged from the workshop.&lt;br&gt;
Requirements Quality Drives AI Quality&lt;br&gt;
The quality of the output is directly related to the quality of the requirements provided.&lt;br&gt;
Clear business requirements consistently produce:&lt;br&gt;
    • Better implementation plans&lt;br&gt;
    • Better test coverage&lt;br&gt;
    • Better code quality&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Human Oversight Remains Critical&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI can accelerate analysis, planning, testing, and coding.&lt;br&gt;
It cannot replace engineering judgment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developers remain responsible for:&lt;/strong&gt;&lt;br&gt;
    • Understanding business intent&lt;br&gt;
    • Challenging assumptions&lt;br&gt;
    • Evaluating architecture&lt;br&gt;
    • Ensuring quality&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TDD Complements AI Extremely Well&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Generating tests before implementation creates a powerful partnership between developers and AI agents.&lt;br&gt;
Tests provide structure, define expectations, and reduce ambiguity.&lt;br&gt;
The combination of AI-generated tests and human review proved particularly effective.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Process Matters More Than the Model&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the most surprising lessons was that success depended less on the specific AI model being used and more on the workflow surrounding it.&lt;br&gt;
Teams often focus on finding the "best" model.&lt;br&gt;
In reality, a disciplined process consistently delivered better results than relying on model capabilities alone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Evolving Role of Developers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Perhaps the most significant takeaway is that software engineering is evolving.&lt;br&gt;
Developers are spending less time writing repetitive code and more time:&lt;br&gt;
    • Understanding business problems&lt;br&gt;
    • Evaluating solutions&lt;br&gt;
    • Reviewing AI-generated outputs&lt;br&gt;
    • Designing systems&lt;br&gt;
    • Defining quality standards&lt;br&gt;
    • Making architectural decisions&lt;br&gt;
The most valuable engineering skill is no longer typing code quickly.&lt;br&gt;
It is providing the right context, asking the right questions, and validating the right outcomes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The future of software development is not about replacing engineers with AI.&lt;br&gt;
It is about creating an effective partnership between human expertise and AI capabilities.&lt;br&gt;
The workshop demonstrated that successful AI adoption begins long before code generation. It starts with understanding requirements, providing rich context, challenging assumptions, reviewing plans, validating tests, and maintaining ownership of quality throughout the development lifecycle.&lt;br&gt;
When combined with a disciplined workflow, AI becomes more than a productivity tool—it becomes a force multiplier for engineering teams.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>software</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Enabling CSRF in a JWT-Based React + Spring Boot Application (Enterprise-Ready Approach)</title>
      <dc:creator>Aswani Nayak</dc:creator>
      <pubDate>Wed, 27 May 2026 13:52:27 +0000</pubDate>
      <link>https://dev.to/aswani_nayak_cdcb2fe8ee38/enabling-csrf-in-a-jwt-based-react-spring-boot-application-enterprise-ready-approach-8a0</link>
      <guid>https://dev.to/aswani_nayak_cdcb2fe8ee38/enabling-csrf-in-a-jwt-based-react-spring-boot-application-enterprise-ready-approach-8a0</guid>
      <description>&lt;p&gt;Modern applications often use:&lt;br&gt;
&lt;strong&gt;•   React SPA (Single Page Application)&lt;br&gt;
• Spring Boot backend&lt;br&gt;
• JWT-based authentication&lt;br&gt;
• Stateless REST APIs&lt;/strong&gt;&lt;br&gt;
In this architecture, it’s common to disable CSRF:&lt;br&gt;
&lt;strong&gt;Code&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;.csrf(AbstractHttpConfigurer::disable)&lt;/code&gt;&lt;br&gt;
However, many enterprise security teams and tools (e.g., GitHub CodeQL) flag this as a &lt;strong&gt;high-severity issue&lt;/strong&gt;.&lt;br&gt;
This blog explains:&lt;br&gt;
• ✅ Why CSRF is flagged&lt;br&gt;
• ✅ Whether JWT APIs need CSRF&lt;br&gt;
• ✅ How to enable CSRF without breaking your SPA&lt;br&gt;
• ✅ A production-ready implementation&lt;/p&gt;

&lt;p&gt;1️⃣ &lt;strong&gt;Understanding the Problem&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;What is CSRF?&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;CSRF (Cross-Site Request Forgery)&lt;/strong&gt; is an attack where a malicious website tricks a browser into making an authenticated request to another site.&lt;br&gt;
CSRF attacks rely on:&lt;br&gt;
• Automatic cookie sending by the browser&lt;br&gt;
• Session-based authentication&lt;br&gt;
Spring Security enables CSRF by default for this reason.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why JWT APIs Typically Disable CSRF&lt;/strong&gt;&lt;br&gt;
In a JWT-based system:&lt;br&gt;
• Authentication is done via:&lt;br&gt;
• Authorization: Bearer &lt;br&gt;
• Browsers do NOT automatically attach Authorization headers.&lt;br&gt;
• No session cookies are involved.&lt;br&gt;
• The API is stateless.&lt;br&gt;
Therefore, CSRF protection is &lt;strong&gt;not strictly required&lt;/strong&gt;.&lt;br&gt;
However...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Security Teams Still Want It Enabled&lt;/strong&gt;&lt;br&gt;
Enterprise AppSec teams often require:&lt;br&gt;
• Defense-in-depth&lt;br&gt;
• Uniform policy enforcement&lt;br&gt;
• Future-proof protection (in case cookies are introduced later)&lt;br&gt;
• Clean security scans without exceptions&lt;br&gt;
Instead of disabling CSRF, we can implement it correctly for SPA.&lt;/p&gt;

&lt;p&gt;2️⃣ &lt;strong&gt;Enterprise-Ready Solution&lt;/strong&gt;&lt;br&gt;
We will:&lt;br&gt;
• ✅ Keep JWT authentication&lt;br&gt;
• ✅ Keep backend stateless&lt;br&gt;
• ✅ Enable CSRF&lt;br&gt;
• ✅ Make it work with React SPA&lt;br&gt;
• ✅ Pass security review&lt;br&gt;
The key is:&lt;br&gt;
&lt;strong&gt;Code&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;CookieCsrfTokenRepository&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;3️⃣ &lt;strong&gt;Spring Boot Implementation&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;Step 1: Security Configuration&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Code&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final JwtAuthenticationFilter jwtAuthenticationFilter;

    public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) {
        this.jwtAuthenticationFilter = jwtAuthenticationFilter;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http
            // ✅ Enable CSRF with Cookie repository (SPA-friendly)
            .csrf(csrf -&amp;gt; csrf
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            )

            // ✅ Keep application stateless
            .sessionManagement(session -&amp;gt;
                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            )

            .authorizeHttpRequests(auth -&amp;gt; auth
                .requestMatchers("/auth/**").permitAll()
                .anyRequest().authenticated()
            )

            // ✅ Add JWT filter
            .addFilterBefore(jwtAuthenticationFilter,
                    UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;strong&gt;What This Does&lt;/strong&gt;&lt;br&gt;
Spring Security will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Generate a CSRF token&lt;/li&gt;
&lt;li&gt; Send it in a cookie named:
XSRF-TOKEN&lt;/li&gt;
&lt;li&gt; Expect the frontend to send it back in header:
X-XSRF-TOKEN
This pattern is SPA-friendly and secure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;4️⃣ &lt;strong&gt;React Implementation&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;Step 1: Enable Credentials&lt;/strong&gt;&lt;br&gt;
When using cookies, you must enable credentials:&lt;br&gt;
&lt;strong&gt;Code&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const api = axios.create({
  baseURL: "http://localhost:8080",
  withCredentials: true
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;strong&gt;Step 2: Read CSRF Cookie&lt;/strong&gt;&lt;br&gt;
Helper function:&lt;br&gt;
&lt;strong&gt;Code&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getCookie(name) {
  const value = `; ${document.cookie}`;
  const parts = value.split(`; ${name}=`);
  if (parts.length === 2) return parts.pop().split(';').shift();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ &lt;strong&gt;Step 3: Axios Interceptor&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Code&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;api.interceptors.request.use((config) =&amp;gt; {

  const jwt = localStorage.getItem("jwt");
  const csrfToken = getCookie("XSRF-TOKEN");

  if (jwt) {
    config.headers.Authorization = `Bearer ${jwt}`;
  }

  if (csrfToken) {
    config.headers["X-XSRF-TOKEN"] = csrfToken;
  }

  return config;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every request sends:&lt;br&gt;
• ✅ JWT token&lt;br&gt;
• ✅ CSRF token&lt;/p&gt;

&lt;p&gt;5️⃣ &lt;strong&gt;CORS Configuration (Critical)&lt;/strong&gt;&lt;br&gt;
When using cookies, you must allow credentials.&lt;br&gt;
&lt;strong&gt;Code&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(List.of("http://localhost:3000"));
    configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
    configuration.setAllowedHeaders(
        List.of("Authorization", "Content-Type", "X-XSRF-TOKEN")
    );
    configuration.setAllowCredentials(true);

    UrlBasedCorsConfigurationSource source =
            new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And enable CORS:&lt;br&gt;
&lt;strong&gt;Code&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;http.cors(Customizer.withDefaults());&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;6️⃣ &lt;strong&gt;Request Flow Explained&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;Initial Request&lt;/strong&gt;&lt;br&gt;
• Backend generates CSRF token&lt;br&gt;
• Sends XSRF-TOKEN cookie&lt;br&gt;
✅ &lt;strong&gt;API Call&lt;/strong&gt;&lt;br&gt;
React sends:&lt;br&gt;
Authorization: Bearer &lt;br&gt;
X-XSRF-TOKEN: &lt;br&gt;
✅ &lt;strong&gt;Spring Validates&lt;/strong&gt;&lt;br&gt;
• JWT signature&lt;br&gt;
• CSRF token match&lt;br&gt;
If both valid → request succeeds.&lt;/p&gt;

&lt;p&gt;7️⃣ Architecture Summary&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faw0q0k8cjgg3ax95aapo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faw0q0k8cjgg3ax95aapo.png" alt=" " width="168" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;8️⃣ &lt;strong&gt;Why This Is a Strong Design&lt;/strong&gt;&lt;br&gt;
Even though JWT Authorization header authentication does not require CSRF, enabling it provides:&lt;br&gt;
• Defense-in-depth&lt;br&gt;
• Protection against future cookie-based changes&lt;br&gt;
• Compliance with security standards&lt;br&gt;
• Cleaner audit results&lt;br&gt;
This approach balances:&lt;br&gt;
✅ Security&lt;br&gt;
✅ Architecture purity&lt;br&gt;
✅ Enterprise compliance&lt;/p&gt;

&lt;p&gt;9️⃣ &lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;br&gt;
If you are building:&lt;br&gt;
• React SPA&lt;br&gt;
• Spring Boot backend&lt;br&gt;
• JWT authentication&lt;br&gt;
And your security team requires CSRF to be enabled:&lt;br&gt;
✅ Use CookieCsrfTokenRepository&lt;br&gt;
✅ Send CSRF token via header&lt;br&gt;
✅ Keep the application stateless&lt;br&gt;
This gives you:&lt;br&gt;
• Modern architecture&lt;br&gt;
• Strong security posture&lt;br&gt;
• Enterprise-ready implementation&lt;/p&gt;

</description>
      <category>react</category>
      <category>security</category>
      <category>springboot</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Storing Personal Information in React: sessionStorage vs Context API</title>
      <dc:creator>Aswani Nayak</dc:creator>
      <pubDate>Mon, 18 May 2026 02:25:35 +0000</pubDate>
      <link>https://dev.to/aswani_nayak_cdcb2fe8ee38/storing-personal-information-in-react-sessionstorage-vs-context-api-25pa</link>
      <guid>https://dev.to/aswani_nayak_cdcb2fe8ee38/storing-personal-information-in-react-sessionstorage-vs-context-api-25pa</guid>
      <description>&lt;p&gt;When building React applications, developers often need to handle personal information such as names, emails, profile data, or authentication details.&lt;br&gt;
A common question arises:&lt;br&gt;
Should I store personal information in sessionStorage or use React’s Context API?&lt;br&gt;
The answer depends heavily on security, persistence needs, and application design. In this post, we’ll break down the differences, risks, and best practices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding the Two Options&lt;br&gt;
1️⃣ What Is sessionStorage?&lt;/strong&gt;&lt;br&gt;
sessionStorage is a browser-based storage mechanism that:&lt;br&gt;
• Stores data per tab&lt;br&gt;
• Persists across page refreshes&lt;br&gt;
• Clears when the tab is closed&lt;br&gt;
• Is accessible via JavaScript&lt;br&gt;
Example:&lt;br&gt;
Code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Store data&lt;/span&gt;
&lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userEmail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user@example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Retrieve data&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sessionStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userEmail&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2️⃣ What Is React Context API?&lt;/strong&gt;&lt;br&gt;
The Context API is a React feature that allows you to:&lt;br&gt;
• Share state across components&lt;br&gt;
• Store data in memory&lt;br&gt;
• Avoid prop drilling&lt;br&gt;
• Reset data on page refresh&lt;br&gt;
Example:&lt;br&gt;
Code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Key Differences&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fov25hwjnk9uawpwwsmhe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fov25hwjnk9uawpwwsmhe.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Security Considerations (Critical for Personal Info)&lt;/strong&gt;&lt;br&gt;
When storing personal information (PII), security should be your top priority.&lt;br&gt;
🔴 &lt;strong&gt;Risks of Using sessionStorage&lt;/strong&gt;&lt;br&gt;
• Accessible via browser DevTools&lt;br&gt;
• Accessible to any script running on the page&lt;br&gt;
• Vulnerable to Cross-Site Scripting (XSS)&lt;br&gt;
• Persists after refresh (increasing exposure window)&lt;br&gt;
If your app suffers from an XSS vulnerability, malicious code could easily run:&lt;br&gt;
&lt;strong&gt;Code&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;sessionStorage.getItem("userSSN");&lt;/code&gt;&lt;br&gt;
That’s a serious risk.&lt;/p&gt;




&lt;p&gt;🟢 &lt;strong&gt;Why Context API Is Safer&lt;/strong&gt;&lt;br&gt;
Context data:&lt;br&gt;
• Lives only in memory&lt;br&gt;
• Disappears on refresh&lt;br&gt;
• Is scoped within your React app&lt;br&gt;
• Is not automatically accessible globally&lt;br&gt;
However, note:&lt;br&gt;
Context is still vulnerable to XSS if your app is compromised.&lt;br&gt;
No client-side storage is 100% secure.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;When Should You Use Each?&lt;/strong&gt;&lt;br&gt;
✅ &lt;strong&gt;Use Context API When:&lt;/strong&gt;&lt;br&gt;
• Handling sensitive personal information&lt;br&gt;
• Data does not need to survive page refresh&lt;br&gt;
• You want better encapsulation&lt;br&gt;
• Managing user session state&lt;br&gt;
Examples:&lt;br&gt;
• User profile details&lt;br&gt;
• Temporary form data&lt;br&gt;
• Authenticated user state&lt;/p&gt;




&lt;p&gt;✅ Use sessionStorage When:&lt;br&gt;
• You need data to persist across refresh&lt;br&gt;
• The data is low sensitivity&lt;br&gt;
• UX depends on temporary persistence&lt;br&gt;
Examples:&lt;br&gt;
• Wizard step progress&lt;br&gt;
• Non-sensitive UI preferences&lt;br&gt;
• Temporary search filters&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What You Should NEVER Store in sessionStorage&lt;/strong&gt;&lt;br&gt;
Avoid storing:&lt;br&gt;
• Passwords&lt;br&gt;
• Social Security Numbers&lt;br&gt;
• Credit card numbers&lt;br&gt;
• Medical data&lt;br&gt;
• Raw authentication tokens&lt;br&gt;
• Sensitive PII&lt;br&gt;
If the data would be catastrophic if exposed — don’t store it client-side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Best Practice Architecture&lt;/strong&gt;&lt;br&gt;
For handling personal information securely in modern React apps:&lt;br&gt;
✅ &lt;strong&gt;Recommended Approach&lt;/strong&gt;&lt;br&gt;
• Store authentication tokens in &lt;strong&gt;HTTP-only secure cookies&lt;/strong&gt;&lt;br&gt;
• Store user profile data in &lt;strong&gt;React Context (memory)&lt;/strong&gt;&lt;br&gt;
• Keep highly sensitive data on the &lt;strong&gt;backend only&lt;/strong&gt;&lt;br&gt;
Architecture flow:&lt;br&gt;
Backend&lt;br&gt;
   ↓&lt;br&gt;
HTTP-only cookie (auth token)&lt;br&gt;
   ↓&lt;br&gt;
React Context (user state in memory)&lt;br&gt;
Why this works:&lt;br&gt;
• HTTP-only cookies cannot be accessed via JavaScript&lt;br&gt;
• Context keeps sensitive UI data ephemeral&lt;br&gt;
• Exposure window is minimized&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Recommendation&lt;/strong&gt;&lt;br&gt;
If you're choosing between sessionStorage and Context API for personal information:&lt;br&gt;
✅ Use &lt;strong&gt;React Context&lt;/strong&gt; for sensitive data&lt;br&gt;
⚠️ Use sessionStorage only for low-risk persistence needs&lt;br&gt;
And remember:&lt;br&gt;
The most secure data is the data you never store on the client.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>security</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
