<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ spring security - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ spring security - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 21 Sep 2026 13:07:19 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/spring-security/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ CSRF from Scratch: Browser Mechanics, Attacks, and Spring Security Implementation [Full Handbook] ]]>
                </title>
                <description>
                    <![CDATA[ If you've ever built a web application or configured Spring Security, you've almost certainly encountered Cross-Site Request Forgery (CSRF). In my previous guide, How OAuth 2.0 Works: A Practical Guid ]]>
                </description>
                <link>https://www.freecodecamp.org/news/csrf-from-scratch-browser-mechanics-attacks-and-spring-security-implementation-handbook/</link>
                <guid isPermaLink="false">6a74fe284ef5707f2879423d</guid>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ csrf ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cookies ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Thu, 06 Aug 2026 21:35:36 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/20e903c5-9011-4f14-b714-974e32d43f3c.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you've ever built a web application or configured Spring Security, you've almost certainly encountered Cross-Site Request Forgery (CSRF).</p>
<p>In my previous guide, <a href="https://medium.com/@ashutoshkrris/how-oauth-2-0-works-a-practical-guide-for-backend-developers-630977209476"><strong>How OAuth 2.0 Works: A Practical Guide for Backend Developers</strong></a>, I briefly touched on the mysterious <code>state</code> parameter and noted that its core purpose is protecting authorization flows against CSRF attacks.</p>
<p>At the time, we treated CSRF as a quick prerequisite concept. Today, we're taking a much deeper dive.</p>
<p>Perhaps you were building a REST API in Spring Boot, ran into unexpected HTTP 403 Forbidden errors on every <code>POST</code> request, and "fixed" it by adding <code>.csrf(csrf -&gt; csrf.disable())</code> to your Security Filter Chain.</p>
<p>Most tutorials treat CSRF as a checkbox item or a framework toggle. They immediately jump to code:</p>
<pre><code class="language-java">// What most tutorials show on line 1:
http.csrf(Customizer.withDefaults());
</code></pre>
<p>Starting with framework configuration hides how web security actually operates. Spring Security doesn't invent security rules out of thin air. It responds to the fundamental mechanics of web browsers, HTTP protocols, and cookies.</p>
<p>In this handbook, we'll take a bottom-up, first-principles approach. We won't talk about Spring Security until we've thoroughly explored browsers, HTTP headers, session management, and the underlying mechanics of Cross-Site Request Forgery.</p>
<p>By the end of this guide, you'll understand:</p>
<ul>
<li><p>Why browsers automatically attach credentials to outgoing requests.</p>
</li>
<li><p>Why that automatic behavior creates a fundamental vulnerability.</p>
</li>
<li><p>Why attackers never need to steal or read your cookies to exploit CSRF.</p>
</li>
<li><p>Why Same Origin Policy (SOP) and CORS don't prevent CSRF.</p>
</li>
<li><p>How modern defenses, from CSRF Tokens to <code>SameSite</code> cookies, work under the hood.</p>
</li>
<li><p>How Spring Security implements these defenses internally and how to configure them effectively.</p>
</li>
</ul>
<p>Let’s begin by stripping away frameworks and looking at how the web actually works.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-the-problem-before-csrf">The Problem Before CSRF</a></p>
</li>
<li><p><a href="#heading-why-browsers-automatically-send-cookies">Why Browsers Automatically Send Cookies</a></p>
</li>
<li><p><a href="#heading-when-automatic-cookies-become-dangerous">When Automatic Cookies Become Dangerous</a></p>
</li>
<li><p><a href="#heading-visualize-the-attack">Visualize the Attack</a></p>
</li>
<li><p><a href="#heading-why-the-browser-isnt-broken">Why the Browser Isn't Broken</a></p>
</li>
<li><p><a href="#heading-same-origin-policy-sop">Same Origin Policy (SOP)</a></p>
</li>
<li><p><a href="#heading-why-cors-does-not-prevent-csrf">Why CORS Does NOT Prevent CSRF</a></p>
</li>
<li><p><a href="#heading-safe-methods-and-state-mutation">Safe Methods and State Mutation</a></p>
</li>
<li><p><a href="#heading-csrf-tokens-synchronizer-token-pattern">CSRF Tokens (Synchronizer Token Pattern)</a></p>
</li>
<li><p><a href="#heading-double-submit-cookie-pattern">Double Submit Cookie Pattern</a></p>
</li>
<li><p><a href="#heading-samesite-cookies">SameSite Cookies</a></p>
</li>
<li><p><a href="#heading-origin-and-referer-headers">Origin and Referer Headers</a></p>
</li>
<li><p><a href="#heading-jwt-and-csrf-the-token-storage-dilemma">JWT and CSRF: The Token Storage Dilemma</a></p>
</li>
<li><p><a href="#heading-spring-security-csrf-internals">Spring Security CSRF Internals</a></p>
</li>
<li><p><a href="#heading-implement-csrf-protection-yourself">Implement CSRF Protection Yourself</a></p>
</li>
<li><p><a href="#heading-testing-csrf-protections">Testing CSRF Protections</a></p>
</li>
<li><p><a href="#heading-common-misconceptions">Common Misconceptions</a></p>
</li>
<li><p><a href="#heading-production-best-practices-checklist">Production Best Practices Checklist</a></p>
</li>
<li><p><a href="#heading-final-summary-amp-defense-matrix">Final Summary &amp; Defense Matrix</a></p>
</li>
</ul>
<h2 id="heading-the-problem-before-csrf">The Problem Before CSRF</h2>
<p>To understand security, we must first understand state.</p>
<p>The Hypertext Transfer Protocol (HTTP) is inherently <strong>stateless</strong>. This means that if Alice sends an HTTP request to <code>travelbuddy.com</code> (our example) at 10:00 AM, and sends another HTTP request to <code>travelbuddy.com</code> at 10:01 AM, the server treats those two requests as completely isolated, unrelated events.</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/c5c24ee5-450d-4252-8e79-3744f9814fbd.png" alt="Sequence diagram showing Alice’s browser making a successful GET request to the TravelBuddy Server, followed 1 minute later by a second GET request that returns a 401 Unauthorized error." style="display: block;" width="1071" height="860" loading="lazy">

<p>Without a mechanism to remember Alice between requests, Alice would have to send her username and password inside <em>every single HTTP request</em> she makes. That would be horrific for both user experience and performance.</p>
<p>Before session mechanisms were standard, developers tried passing credentials via query parameters or basic authentication headers on every click. This led to credential exposure in server logs, browser histories, and URL shares.</p>
<h3 id="heading-how-do-sessions-and-cookies-solve-this">How Do Sessions and Cookies Solve This?</h3>
<p>To solve this, web engineers introduced the concept of <strong>Server-Side Sessions</strong> and <strong>HTTP Cookies</strong>.</p>
<p>When Alice logs into <code>TravelBuddy</code> by sending her username and password via a POST request to <code>https://travelbuddy.com/login</code>, the server verifies her credentials. Instead of asking Alice to log in again on the next page, the server creates a <strong>Session</strong> in its memory (or in a database/Redis cache) and assigns it a unique, unpredictable identifier: a <strong>Session ID</strong>.</p>
<p>The server then sends this Session ID back to Alice’s browser using a special HTTP response header: <code>Set-Cookie</code>.</p>
<pre><code class="language-plaintext">HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: JSESSIONID=abc123xyz789; Path=/; Secure; HttpOnly
</code></pre>
<p>When Alice’s browser receives this response, it sees the <code>Set-Cookie</code> header. It extracts <code>JSESSIONID=abc123xyz789</code> and stores it inside its internal storage unit: the <strong>Browser Cookie Jar</strong>.</p>
<p>Now, Alice is "logged in". The server remembers her via that session record, and the browser holds the key (<code>JSESSIONID</code>) to that session.</p>
<h2 id="heading-why-browsers-automatically-send-cookies">Why Browsers Automatically Send Cookies</h2>
<p>Now we arrive at the pivotal design choice made in the early days of the web.</p>
<p>Once the browser stores <code>JSESSIONID=abc123xyz789</code> in its cookie jar for the domain <code>travelbuddy.com</code>, how does that cookie get sent back to the server on subsequent requests?</p>
<p>Does the developer have to write custom JavaScript to attach the cookie? <strong>No.</strong></p>
<p>Browsers are explicitly designed to handle cookie management <strong>automatically</strong>.</p>
<h3 id="heading-the-request-lifecycle-and-automatic-cookie-attachment">The Request Lifecycle and Automatic Cookie Attachment</h3>
<p>Every time Alice's browser prepares an HTTP request to <code>https://travelbuddy.com</code> (whether caused by Alice clicking a link, submitting an HTML form, or JavaScript triggering a <code>fetch()</code> call), the browser follows this exact process:</p>
<ol>
<li><p><strong>URL Inspection:</strong> The browser examines the destination URL (for example, <code>https://travelbuddy.com/api/connections</code>).</p>
</li>
<li><p><strong>Cookie Jar Lookup:</strong> The browser scans its cookie jar for any stored cookies whose domain and path match <code>travelbuddy.com</code>.</p>
</li>
<li><p><strong>Validation Check:</strong> It verifies if the cookie has expired, and if flags like <code>Secure</code> (requires HTTPS) are respected.</p>
</li>
<li><p><strong>Header Injection:</strong> If valid cookies match, the browser automatically injects a <code>Cookie</code> header into the outgoing HTTP request payload.</p>
</li>
</ol>
<p>Here's what the outgoing request looks like as it leaves Alice's machine:</p>
<pre><code class="language-shell">POST /api/connections/add HTTP/1.1
Host: travelbuddy.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
Accept: text/html,application/xhtml+xml
Cookie: JSESSIONID=abc123xyz789
Content-Type: application/x-www-form-urlencoded

service=SkyScanner
</code></pre>
<p>Notice something critical: <strong>Neither Alice nor any custom frontend JavaScript explicitly attached</strong> <code>Cookie: JSESSIONID=abc123xyz789</code><strong>.</strong></p>
<p>The browser's internal engine attached it automatically before sending the byte stream across the network. From the server's perspective, receiving <code>Cookie: JSESSIONID=abc123xyz789</code> is proof that the request originated from an authenticated session belonging to Alice.</p>
<p>This automatic behavior is convenient. It makes web browsing seamless across page reloads and link navigation. But as we'll soon see, this convenience leaves a backdoor wide open.</p>
<h2 id="heading-when-automatic-cookies-become-dangerous">When Automatic Cookies Become Dangerous</h2>
<p>Is automatic cookie inclusion a vulnerability by itself?</p>
<p><strong>No.</strong> If Alice only visits <code>travelbuddy.com</code>, automatic cookie inclusion works exactly as intended.</p>
<p>The vulnerability emerges because of a simple web reality: <strong>Alice visits multiple websites in the same browser session.</strong></p>
<h3 id="heading-enter-evilcom">Enter <code>evil.com</code></h3>
<p>Suppose Alice is logged into <code>TravelBuddy</code> in Tab 1. Her session cookie (<code>JSESSIONID=abc123xyz789</code>) sits safely inside her browser's cookie jar for <code>travelbuddy.com</code>.</p>
<p>In Tab 2, Alice visits an unrelated website: <code>https://evil.com</code> (perhaps she clicked a link in a phishing email or a forum post).</p>
<p><code>evil.com</code> is controlled by an attacker. The attacker knows that <code>TravelBuddy</code> has a feature located at <code>POST</code> <code>[https://travelbuddy.com/api/connections/add</code> that connects third-party services. The attacker wants to trick Alice into connecting the attacker's malicious service to her account.</p>
<p>The attacker embeds the following hidden HTML form inside the HTML page served by <code>evil.com</code>:</p>
<pre><code class="language-html">&lt;!-- Hosted on https://evil.com/win-a-car.html --&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;body&gt;
  &lt;h1&gt;You won a free trip! Click below to claim.&lt;/h1&gt;
  
  &lt;!-- Hidden Form targeting TravelBuddy --&gt;
  &lt;form id="maliciousForm" action="https://travelbuddy.com/api/connections/add" method="POST"&gt;
    &lt;input type="hidden" name="service" value="MaliciousAttackerService" /&gt;
  &lt;/form&gt;

  &lt;script&gt;
    // Automatically submit the form as soon as the page loads
    document.getElementById('maliciousForm').submit();
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h3 id="heading-walkthrough-of-the-attack-execution">Walkthrough of the Attack Execution</h3>
<p>Let's trace step-by-step what happens when Alice opens <code>https://evil.com/win-a-car.html</code>:</p>
<ol>
<li><p>Alice's browser fetches and parses HTML from <code>evil.com</code>.</p>
</li>
<li><p>The browser encounters the <code>&lt;script&gt;</code> tag and executes <code>document.getElementById('maliciousForm').submit()</code>.</p>
</li>
<li><p>The browser prepares an outgoing <code>POST</code> request targeting <code>https://travelbuddy.com/api/connections/add</code>.</p>
</li>
<li><p>The browser looks at the target destination: <code>travelbuddy.com</code>.</p>
</li>
<li><p>The browser checks its Cookie Jar: <em>"Do I have any active cookies for</em> <code>travelbuddy.com</code><em>?"</em></p>
</li>
<li><p><strong>Yes!</strong> It finds <code>JSESSIONID=abc123xyz789</code> (Alice's active session cookie from Tab 1).</p>
</li>
<li><p>The browser automatically injects <code>Cookie: JSESSIONID=abc123xyz789</code> into the outgoing request payload heading to <code>travelbuddy.com</code>.</p>
</li>
<li><p>The request lands on the <code>TravelBuddy</code> Spring Boot backend server.</p>
</li>
</ol>
<h3 id="heading-the-servers-perspective">The Server's Perspective</h3>
<p>Here's what the <code>TravelBuddy</code> backend sees when processing the request:</p>
<pre><code class="language-shell">POST /api/connections/add HTTP/1.1
Host: travelbuddy.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
Content-Type: application/x-www-form-urlencoded
Cookie: JSESSIONID=abc123xyz789

service=MaliciousAttackerService
</code></pre>
<p>The <code>TravelBuddy</code> server checks the <code>Cookie</code> header. It validates <code>JSESSIONID=abc123xyz789</code> against its session store. The session is valid: it belongs to Alice!</p>
<p>The server assumes: <em>"Alice sent a POST request to add</em> <code>MaliciousAttackerService</code><em>. She is authenticated, so I will grant this request."</em></p>
<p>The server updates Alice's account state. <code>MaliciousAttackerService</code> is now connected to her profile.</p>
<h3 id="heading-the-core-realization-of-csrf">The Core Realization of CSRF</h3>
<p>Take a step back and examine what just happened:</p>
<ol>
<li><p><strong>The attacker NEVER saw or stole Alice’s session cookie.</strong> The attacker on <code>evil.com</code> can't read cookies belonging to <code>travelbuddy.com</code> due to browser isolation rules.</p>
</li>
<li><p><strong>The attacker did NOT break encryption.</strong> HTTPS was active the entire time.</p>
</li>
<li><p><strong>The attacker simply induced Alice's browser to make a request.</strong> The browser, faithfully executing its automatic cookie attachment rules, provided the credentials on behalf of the attacker. You could say the attacker got caught with their hand in Alice's cookie jar!</p>
</li>
</ol>
<p>This is <strong>Cross-Site Request Forgery in action</strong>: An attacker tricks a victim's browser into executing an unwanted, state-changing HTTP request to a trusted site where the victim is currently authenticated.</p>
<h2 id="heading-visualize-the-attack">Visualize the Attack</h2>
<p>Visualizing the interaction between Alice, the browser, <code>evil.com</code>, and <code>TravelBuddy</code> makes the underlying request flow clear.</p>
<h3 id="heading-1-the-complete-csrf-sequence">1. The Complete CSRF Sequence</h3>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/0431c42a-815b-482c-900e-7985c3f5ace1.png" alt="Sequence diagram illustrating a Cross-Site Request Forgery (CSRF) attack where an attacker site (evil.com) uses an auto-submitting form to trick a logged-in user’s browser into sending an authenticated request to travelbuddy.com." style="display: block;" width="2614" height="2116" loading="lazy">

<p>The attack unfolds across three distinct phases involving four main actors: Alice, her web browser, the TravelBuddy backend server, and the attacker site running on <code>evil.com</code>.</p>
<p>In the first phase, Alice authenticates with TravelBuddy. She submits her login credentials through her browser, which sends a POST request to the TravelBuddy backend. The backend verifies her credentials and responds with an HTTP 200 OK status alongside a <code>Set-Cookie</code> header containing <code>JSESSIONID=abc123xyz</code>.</p>
<p>Upon receiving this response, Alice's browser automatically saves this session identifier inside its cookie jar for the <code>travelbuddy.com</code> domain.</p>
<p>In the second phase, the attacker sets a trap. While keeping her TravelBuddy tab active, Alice opens a second browser tab and visits <code>evil.com</code>. Her browser requests the page <code>win-a-car.html</code> from <code>evil.com</code>. In response, <code>evil.com</code> serves an HTML document containing an invisible form targeting TravelBuddy, paired with an embedded JavaScript script designed to trigger immediately upon loading.</p>
<p>In the final phase, the attack executes automatically. The malicious JavaScript on <code>evil.com</code> calls <code>form.submit()</code>, commanding the browser to send a POST request to <code>https://travelbuddy.com/api/connections/add</code>.</p>
<p>Before sending the request across the network, the browser checks its cookie jar for any cookies matching <code>travelbuddy.com</code>. It finds Alice's active session cookie and automatically attaches <code>Cookie: JSESSIONID=abc123xyz</code> to the outgoing request payload. The TravelBuddy server receives the request, inspects the valid session cookie, assumes Alice intended to perform this action, and attaches the attacker's service to her account.</p>
<h3 id="heading-2-browser-decision-tree-during-outgoing-request">2. Browser Decision Tree during Outgoing Request</h3>
<p>When any request is fired, the browser follows a decision path regarding cookie attachment:</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/59876902-2a43-4082-81f8-83e2c198e0c6.png" alt="Flowchart showing how a web browser automatically checks its Cookie Jar and attaches valid cookies to an outgoing HTTP request targeting travelbuddy.com." style="display: block;" width="1168" height="2635" loading="lazy">

<p>This diagram outlines the automatic evaluation loop executed by a browser whenever an HTTP request is triggered from any tab or script.</p>
<p>The process begins as soon as an outgoing HTTP request is initiated. The browser first inspects the target URL to extract the destination domain, such as <code>travelbuddy.com</code>. Once the domain is identified, the browser queries its internal cookie storage to check whether any cookies are mapped to that target domain. If no matching cookies exist, the browser immediately skips credential attachment and dispatches the raw HTTP request across the network.</p>
<p>If matching cookies are found, the browser evaluates their validity. It checks whether the cookies have expired, whether the request path matches the path defined in the cookie, and whether security constraints like the <code>Secure</code> HTTPS flag are satisfied. If any validation check fails, the cookie is discarded, and the request proceeds without credentials. But if the cookies are valid and active, the browser constructs a <code>Cookie</code> header containing the stored session key and attaches it to the outgoing HTTP request payload before dispatching it across the network to the server.</p>
<h3 id="heading-3-session-and-cookie-lifecycle-state-diagram">3. Session and Cookie Lifecycle State Diagram</h3>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/b244543c-2ad6-455c-949d-eefe219eb4a0.png" alt="State diagram showing a user transitioning from an unauthenticated state to an authenticated state with automatic cookie management, and how maintaining an active session leaves the application vulnerable to CSRF when visiting a malicious site." style="display: block;" width="902" height="2096" loading="lazy">

<p>This state diagram tracks how a user moves between secure, authenticated, and vulnerable conditions during a web session.</p>
<p>When a user first opens their web browser, they begin in an unauthenticated state with no cookies stored for the target application. Submitting valid credentials via a login form transitions the user into an authenticated state. Inside this authenticated state, the server issues a <code>Set-Cookie</code> header, causing the browser to save the session ID in its cookie storage. For every subsequent request directed to that application, the browser automatically attaches the cookie while keeping the user logged in.</p>
<p>A vulnerability window opens when an authenticated user opens a second tab and navigates to an untrusted website while their application session remains active. This action shifts the browser context into a state vulnerable to Cross-Site Request Forgery. If the untrusted site fires a cross-site request back to the original application, the browser's automatic cookie attachment mechanism triggers, executing an unauthorized state change on the server. The cycle ends only when the user logs out or the server session expires, returning the client to the initial unauthenticated state.</p>
<h2 id="heading-why-the-browser-isnt-broken">Why the Browser Isn't Broken</h2>
<p>When developers first grasp CSRF, their immediate reaction is often: <em>"This is a terrible browser flaw! Why don't browser vendors fix this by disabling automatic cookie sending entirely?"</em></p>
<p>To understand why browsers behave this way, we must look at <strong>Web Compatibility</strong> and a concept known in security engineering as <strong>Ambient Authority</strong>.</p>
<h3 id="heading-the-principle-of-ambient-authority">The Principle of Ambient Authority</h3>
<p>When a system automatically applies a user's identity or credentials to every action without requiring explicit user intent for <em>that specific action</em>, the system is using <strong>ambient authority</strong>.</p>
<p>HTTP cookies are an ambient credential. If you're logged in, every request carrying a destination URL automatically includes your credential.</p>
<h3 id="heading-why-browser-vendors-dont-just-fix-it">Why Browser Vendors Don't Just "Fix" It</h3>
<p>The World Wide Web was created as a web of interconnected hypermedia documents. Cross-site interactions are a fundamental design feature of the web, not an accidental bug:</p>
<ul>
<li><p><strong>Images and assets:</strong> When <code>news.com</code> embeds an image hosted on <code>cdn.com</code>, your browser makes a cross-site request to <code>cdn.com</code>.</p>
</li>
<li><p><strong>Cross-site form submissions:</strong> In the early web (and still today), paying with PayPal meant an HTML form on <code>e-commerce.com</code> submitted data directly to <code>paypal.com</code>.</p>
</li>
<li><p><strong>Hyperlinks:</strong> Clicking a link on <code>google.com</code> takes you to <code>wikipedia.org</code> via a cross-site GET request.</p>
</li>
</ul>
<p>If browsers suddenly stopped attaching cookies to cross-site requests by default, <strong>millions of legacy websites built over three decades would break instantly.</strong> Users would be logged out whenever they clicked a link from an email, a search engine, or a social media site.</p>
<p>Browser vendors prioritize backward compatibility. Rather than removing cross-site capabilities, they introduced configurable security boundaries that developers can opt into.</p>
<p>To understand these boundaries, we must first look at the most fundamental browser security model: the <strong>Same Origin Policy</strong>.</p>
<h2 id="heading-same-origin-policy-sop">Same Origin Policy (SOP)</h2>
<p>Many developers assume: <em>"Doesn't the Same Origin Policy block cross-site requests?"</em></p>
<p>This is one of the most common misunderstandings in web development. Let's clarify what the Same Origin Policy actually is and what it does.</p>
<h3 id="heading-defining-an-origin">Defining an Origin</h3>
<p>An <strong>Origin</strong> in web security is defined by three components:</p>
<ol>
<li><p><strong>Scheme</strong> (Protocol, for example, <code>http</code> vs <code>https</code>)</p>
</li>
<li><p><strong>Host</strong> (Domain, for example, <code>travelbuddy.com</code>)</p>
</li>
<li><p><strong>Port</strong> (for example, <code>:80</code>, <code>:443</code>, <code>:8080</code>)</p>
</li>
</ol>
<p>Two URLs have the <strong>Same Origin</strong> if and only if all three components match exactly.</p>
<table>
<thead>
<tr>
<th>URL 1</th>
<th>URL 2</th>
<th>Same Origin?</th>
<th>Reason</th>
</tr>
</thead>
<tbody><tr>
<td><code>https://travelbuddy.com/page1</code></td>
<td><code>https://travelbuddy.com/page2</code></td>
<td><strong>YES</strong></td>
<td>Scheme, host, and port match.</td>
</tr>
<tr>
<td><code>http://travelbuddy.com/page1</code></td>
<td><code>https://travelbuddy.com/page1</code></td>
<td><strong>NO</strong></td>
<td>Scheme differs (<code>http</code> vs <code>https</code>).</td>
</tr>
<tr>
<td><code>https://travelbuddy.com/page1</code></td>
<td><code>https://api.travelbuddy.com/page1</code></td>
<td><strong>NO</strong></td>
<td>Host differs (<code>travelbuddy.com</code> vs <code>api.travelbuddy.com</code>).</td>
</tr>
<tr>
<td><code>https://travelbuddy.com:8080</code></td>
<td><code>https://travelbuddy.com:9090</code></td>
<td><strong>NO</strong></td>
<td>Port differs (<code>8080</code> vs <code>9090</code>).</td>
</tr>
</tbody></table>
<h3 id="heading-what-sop-protects-vs-what-sop-allows">What SOP Protects vs. What SOP Allows</h3>
<p>The Same Origin Policy governs how scripts running on one origin can interact with resources on another origin.</p>
<p><strong>The SOP Golden Rule:</strong> Same Origin Policy restricts scripts from <strong>READING</strong> responses from another origin. Same Origin Policy generally <strong>DOES NOT PREVENT</strong> scripts or HTML from <strong>SENDING</strong> requests to another origin.</p>
<p>Let's emphasize this distinction:</p>
<p>Sending a request: <code>evil.com</code> can create an HTML form like this: <code>&lt;form action="https://travelbuddy.com/api/delete" method="POST"&gt;</code>. When the form is submitted, the browser will send the request to <code>travelbuddy.com</code>. The backend will process the request and mutate the database state.</p>
<p>Reading the response: JavaScript running on <code>evil.com</code> attempts to inspect the HTTP response body returned by <code>travelbuddy.com</code>. The browser <strong>blocks</strong> JavaScript from reading that data because <code>evil.com</code> and <code>travelbuddy.com</code> are different origins.</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/dd549ea3-7d83-494a-90b0-9a7a3c0a91b8.png" alt="Sequence diagram showing how the Browser’s Same-Origin Policy (SOP) blocks malicious JavaScript on evil.com from reading a cross-origin HTTP response from travelbuddy.com, even though the server executed the request." style="display: block;" width="1508" height="816" loading="lazy">

<p>Notice the flaw relative to CSRF: <strong>CSRF is an attack on state mutation, not data retrieval.</strong></p>
<p>The attacker on <code>evil.com</code> doesn't care to read the response payload returning from <code>travelbuddy.com</code>. Their goal was simply to trigger the action on the server. Because SOP permits request execution and only blocks response reading, <strong>Same Origin Policy alone offers zero protection against CSRF.</strong></p>
<h2 id="heading-why-cors-does-not-prevent-csrf">Why CORS Does NOT Prevent CSRF</h2>
<p>This brings us to another major source of confusion: <strong>Cross-Origin Resource Sharing (CORS)</strong>.</p>
<p>In developer forums, when someone experiences a CSRF issue or a cross-site issue, a common suggestion is: <em>"Just configure CORS properly on your backend!"</em></p>
<p>Let's state this as clearly as possible: CORS does <strong>NOT</strong> prevent CSRF attacks. In fact, CORS is designed to <em>relax</em> Same Origin Policy restrictions, not add new security restrictions.</p>
<h3 id="heading-reading-vs-sending-revisited">Reading vs. Sending Revisited</h3>
<p>Remember: SOP blocks cross-origin reading by default.</p>
<p>CORS (Cross-Origin Resource Sharing) is a mechanism that allows a server (for example, <code>travelbuddy.com</code>) to explicitly tell the browser: <em>"I trust JavaScript running on</em> <code>trusted-partner.com</code><em>. You may allow</em> <code>trusted-partner.com</code> <em>to read my responses."</em></p>
<p>CORS is an opt-in mechanism to <strong>allow cross-origin reading</strong>. Disabling or improperly configuring CORS doesn't stop a browser from sending a forged request.</p>
<h3 id="heading-simple-requests-vs-preflighted-requests">Simple Requests vs. Preflighted Requests</h3>
<p>To understand why CORS fails to stop CSRF, we must examine how browsers handle cross-origin HTTP requests under CORS rules. Browsers divide cross-origin requests into two categories:</p>
<ol>
<li><p>Simple Requests</p>
</li>
<li><p>Preflighted Requests</p>
</li>
</ol>
<h4 id="heading-1-simple-requests">1. Simple Requests</h4>
<p>A request is considered a <strong>Simple Request</strong> if it satisfies all of the following:</p>
<ul>
<li><p>Uses HTTP methods: <code>GET</code>, <code>HEAD</code>, or <code>POST</code>.</p>
</li>
<li><p>Uses standard browser Content-Types: <code>application/x-www-form-urlencoded</code>, <code>multipart/form-data</code>, or <code>text/plain</code>.</p>
</li>
<li><p>Doesn't set custom HTTP headers (like <code>X-Requested-With</code> or <code>Authorization</code>).</p>
</li>
</ul>
<p>When a browser encounters a <strong>Simple Request</strong> (such as a standard HTML form POST), it sends the request immediately to the target server.</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/a0f9324c-2d7b-4495-a519-c95f5c959be4.png" alt="Sequence diagram illustrating why CORS does not prevent CSRF attacks on simple requests, showing that travelbuddy.com executes a state-changing POST request before the browser blocks evil.com from reading the response." style="display: block;" width="1877" height="1184" loading="lazy">

<p>As the diagram shows, the server executes the SQL <code>UPDATE</code> or <code>INSERT</code> statement the moment the request arrives. By the time the browser evaluates CORS headers on the returning response, the state mutation on the server has already happened.</p>
<h4 id="heading-2-preflighted-requests">2. Preflighted Requests</h4>
<p>If a request uses non-standard methods (<code>PUT</code>, <code>DELETE</code>) or non-standard content types (<code>application/json</code>), or custom headers, the browser first sends an <code>OPTIONS</code> request called a <strong>Preflight Request</strong>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/9ec33169-fa8b-48e6-b59f-7365f435ca33.png" alt="Sequence diagram demonstrating how CORS preflight requests (OPTIONS) prevent CSRF attacks by stopping non-simple requests (like JSON payloads) before the actual POST request is sent to travelbuddy.com." style="display: block;" width="1509" height="918" loading="lazy">

<p>Because <code>OPTIONS</code> preflight requests don't carry side-effects and are checked before sending the actual request, CORS <em>incidentally</em> stops cross-origin JSON requests from unapproved domains.</p>
<p>But relying on CORS for security is dangerous: an attacker can easily fall back to a Simple Request (<code>application/x-www-form-urlencoded</code>) using a standard HTML form submission, completely bypassing the CORS preflight check.</p>
<h2 id="heading-safe-methods-and-state-mutation">Safe Methods and State Mutation</h2>
<p>Before we dive into effective defenses, we must address an architectural concept defined in HTTP specifications (RFC 9110): <strong>Safe Methods</strong> and <strong>Idempotency</strong>.</p>
<p>HTTP methods are categorized based on their intended impact on server state:</p>
<ul>
<li><p><strong>Safe Methods (</strong><code>GET</code><strong>,</strong> <code>HEAD</code><strong>,</strong> <code>OPTIONS</code><strong>,</strong> <code>TRACE</code><strong>):</strong> These methods are defined as read-only operations. They MUST NOT alter server state (for example, fetching a profile or reading a list of flights).</p>
</li>
<li><p><strong>Unsafe / State-Modifying Methods (</strong><code>POST</code><strong>,</strong> <code>PUT</code><strong>,</strong> <code>DELETE</code><strong>,</strong> <code>PATCH</code><strong>):</strong> These methods are intended to perform actions, modify databases, create resources, or trigger transactions.</p>
</li>
</ul>
<h3 id="heading-the-developer-crime-state-changing-get-requests">The Developer Crime: State-Changing GET Requests</h3>
<p>Consider what happens if a junior developer on the <code>TravelBuddy</code> team writes code like this:</p>
<pre><code class="language-java">// ❌ DANGEROUS CODE: State mutation via GET request
@GetMapping("/api/connections/delete")
public String deleteConnection(@RequestParam String serviceId, HttpSession session) {
    User user = (User) session.getAttribute("user");
    connectionService.deleteForUser(user, serviceId);
    return "redirect:/dashboard";
}
</code></pre>
<p>Why is this an architectural error and a massive security vulnerability?</p>
<p>Because an attacker on <code>evil.com</code> doesn't even need an HTML form or JavaScript to trigger a <code>GET</code> request. They can trigger a <code>GET</code> request using simple HTML element tags:</p>
<pre><code class="language-html">&lt;!-- Hosted on evil.com --&gt;
&lt;img src="https://travelbuddy.com/api/connections/delete?serviceId=SkyScanner" width="0" height="0" /&gt;
</code></pre>
<p>When Alice's browser parses the HTML from <code>evil.com</code>, it encounters the <code>&lt;img&gt;</code> tag. To render the page, the browser automatically sends a <code>GET</code> request to <code>https://travelbuddy.com/api/connections/delete?serviceId=SkyScanner</code>, automatically attaching Alice's session cookie.</p>
<p>The backend receives the <code>GET</code> request, executes <code>connectionService.deleteForUser(...)</code>, and wipes Alice's integration!</p>
<h3 id="heading-rule-1-of-web-security">Rule #1 of Web Security</h3>
<p><code>GET</code> <strong>requests MUST ALWAYS be safe and read-only.</strong> Never perform state mutations (creates, updates, deletes) inside a <code>GET</code> handler.</p>
<p>Enforcing safe <code>GET</code> requests is the foundation of web security. But keeping <code>GET</code> requests read-only only protects against image-tag vectors: it doesn't protect your <code>POST</code>, <code>PUT</code>, or <code>DELETE</code> endpoints from CSRF.</p>
<p>For state-modifying requests, we need specialized defenses.</p>
<h2 id="heading-csrf-tokens-synchronizer-token-pattern">CSRF Tokens (Synchronizer Token Pattern)</h2>
<p>Now that you understand the core vulnerability (that browsers automatically attach ambient credentials/cookies to outgoing cross-site requests) you can bake standard security right into your app.</p>
<h3 id="heading-what-problem-existed-before-csrf-tokens">What Problem Existed Before CSRF Tokens?</h3>
<p>Servers couldn't differentiate between an HTTP request triggered intentionally by the user from inside <code>travelbuddy.com</code>'s real user interface and one forged by <code>evil.com</code> that caused the browser to automatically attach the user's cookies.</p>
<p>From the server's perspective, both requests looked identical: same session cookie, target URL, and payload structure.</p>
<h3 id="heading-how-do-csrf-tokens-solve-this">How Do CSRF Tokens Solve This?</h3>
<p>To distinguish genuine requests from forged requests, we must require a piece of evidence that <strong>only the real application knows</strong>, and that an external attacker site can't forge or read.</p>
<p>This defense is known as the <strong>Synchronizer Token Pattern</strong> (or <strong>CSRF Token</strong>).</p>
<h3 id="heading-how-the-synchronizer-token-pattern-works">How the Synchronizer Token Pattern Works</h3>
<ol>
<li><p><strong>Token generation:</strong> When Alice logs in or requests a page containing a form from <code>travelbuddy.com</code>, the server generates a cryptographically strong, random, unpredictable string (for example, a 128-bit SecureRandom UUID).</p>
</li>
<li><p><strong>Session storage:</strong> The server binds this generated string to Alice's server-side session state.</p>
</li>
<li><p><strong>Token injection into the UI:</strong> The server includes this token inside the HTML response rendered to Alice, typically as a hidden input field inside forms, or as a meta tag for JavaScript to read.</p>
</li>
<li><p><strong>Token submission:</strong> When Alice submits the form, her browser sends the hidden token back in the request body (or as a custom HTTP header).</p>
</li>
<li><p><strong>Server validation:</strong> The server compares the token received in the request against the token saved in Alice's server-side session.</p>
<ul>
<li><p>If the tokens match: Request is <strong>Genuine</strong>. Process it.</p>
</li>
<li><p>If the tokens don't match (or the token is missing): Request is <strong>Forged</strong>. Reject with HTTP 403 Forbidden!</p>
</li>
</ul>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/5e748f3c-c543-4d70-b772-40af5597af08.png" alt="Sequence diagram demonstrating the Synchronizer Token Pattern (CSRF token), where TravelBuddy Server generates a secret token stored in Alice's session and embeds it in an HTML form to validate subsequent POST requests." style="display: block;" width="2622" height="1890" loading="lazy">

<h3 id="heading-html-form-example">HTML Form Example</h3>
<p>Here is how <code>TravelBuddy</code> renders a protected form:</p>
<pre><code class="language-html">&lt;!-- Rendered by TravelBuddy at https://travelbuddy.com/connect-service --&gt;
&lt;form action="/api/connections/add" method="POST"&gt;
  &lt;!-- Standard form fields --&gt;
  &lt;label for="service"&gt;Service Name:&lt;/label&gt;
  &lt;input type="text" id="service" name="service" value="SkyScanner" /&gt;

  &lt;!-- Secret CSRF Token injected by Server Template Engine (Thymeleaf/JSP) --&gt;
  &lt;input type="hidden" name="_csrf" value="CSRF-KEY-998877" /&gt;

  &lt;button type="submit"&gt;Submit&lt;/button&gt;
&lt;/form&gt;
</code></pre>
<p>When submitted, the raw HTTP request looks like this:</p>
<pre><code class="language-shell">POST /api/connections/add HTTP/1.1
Host: travelbuddy.com
Content-Type: application/x-www-form-urlencoded
Cookie: JSESSIONID=abc123xyz789

service=SkyScanner&amp;_csrf=CSRF-KEY-998877
</code></pre>
<h3 id="heading-why-attackers-cant-forge-the-csrf-token">Why Attackers Can't Forge the CSRF Token</h3>
<p>Now let's trace what happens when <code>evil.com</code> tries to forge this request:</p>
<ol>
<li><p><code>evil.com</code> builds an auto-submitting form targeting <code>https://travelbuddy.com/api/connections/add</code>.</p>
</li>
<li><p>To succeed, <code>evil.com</code> must include <code>_csrf=CSRF-KEY-998877</code> in its form payload.</p>
</li>
<li><p><strong>How can</strong> <code>evil.com</code> <strong>get</strong> <code>CSRF-KEY-998877</code><strong>?</strong></p>
<ul>
<li><p>Can <code>evil.com</code> guess it? <strong>No.</strong> The token is a cryptographically secure random value (for example, 128 bits of entropy).</p>
</li>
<li><p>Can <code>evil.com</code> make an AJAX <code>GET</code> request to <code>travelbuddy.com</code> to read the HTML form and extract the token? <strong>No!</strong> Because Same Origin Policy (SOP) blocks <code>evil.com</code> JavaScript from reading the response contents of <code>travelbuddy.com</code>.</p>
</li>
</ul>
</li>
</ol>
<p>Because the attacker can't read the page from <code>travelbuddy.com</code>, they can't extract the valid token. When <code>evil.com</code> submits its forged form without a valid <code>_csrf</code> token, the <code>TravelBuddy</code> backend rejects the request immediately:</p>
<pre><code class="language-shell">HTTP/1.1 403 Forbidden
Content-Type: application/json

{
  "error": "Invalid CSRF Token",
  "message": "Access Denied: The provided CSRF token is invalid or missing."
}
</code></pre>
<h2 id="heading-double-submit-cookie-pattern">Double Submit Cookie Pattern</h2>
<p>While the Synchronizer Token Pattern is robust, it requires the server to maintain server-side session state to store the token.</p>
<p>What if your backend application is stateless (for example, microservices scaled horizontally across multiple servers without shared session storage)?</p>
<p>Enter the <strong>Double Submit Cookie Pattern</strong>.</p>
<h3 id="heading-how-double-submit-cookie-works">How Double Submit Cookie Works</h3>
<p>In a stateless architecture, the server can't look up a token in a session store. Instead, it relies on cryptographic and domain-isolation properties:</p>
<ol>
<li><p><strong>Cookie generation:</strong> When a user logs in, the server generates a random, cryptographically secure CSRF token.</p>
</li>
<li><p><strong>Setting the cookie:</strong> The server sends this token to the browser as a cookie (for example, <code>XSRF-TOKEN</code>). Crucially, this cookie is <strong>NOT</strong> marked <code>HttpOnly</code>, so client-side JavaScript running on <code>travelbuddy.com</code> can read it.</p>
</li>
<li><p><strong>Frontend header injection:</strong> When the Single Page Application (SPA, such as React, Angular, or Vue) running on <code>travelbuddy.com</code> makes an HTTP request, its custom API client (for example, Axios or <code>fetch</code>) reads the <code>XSRF-TOKEN</code> cookie value and copies that exact value into a custom HTTP request header (for example, <code>X-XSRF-TOKEN</code>).</p>
</li>
<li><p><strong>Server verification:</strong> When the request arrives, the server compares the value in the cookie against the value in the custom header.</p>
</li>
</ol>
<p>If <code>Cookie Value == Header Value</code>, the request is valid.</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/09c2f58e-ca6c-4af7-a141-be69c449f58a.png" alt="Sequence diagram illustrating the Double Submit Cookie pattern, where JavaScript reads a non-HttpOnly CSRF token cookie and echoes its value in a custom HTTP header for server validation." style="display: block;" width="2828" height="1520" loading="lazy">

<h3 id="heading-why-double-submit-cookie-works-against-cross-site-attackers">Why Double Submit Cookie Works against Cross-Site Attackers</h3>
<p>Suppose Alice visits <code>evil.com</code>:</p>
<ol>
<li><p><code>evil.com</code> triggers a cross-site request to <code>travelbuddy.com</code>.</p>
</li>
<li><p>The browser automatically attaches the stored <code>XSRF-TOKEN</code> cookie to the outgoing request.</p>
</li>
<li><p><strong>But</strong> <code>evil.com</code> <strong>must also set the custom header</strong> <code>X-XSRF-TOKEN</code> <strong>with a matching value.</strong></p>
</li>
<li><p>Can <code>evil.com</code> read the <code>XSRF-TOKEN</code> cookie to copy its value into the header? <strong>No!</strong> Browsers strictly prevent <code>evil.com</code> from reading cookies set by <code>travelbuddy.com</code>.</p>
</li>
<li><p>Can <code>evil.com</code> write custom headers on a cross-site request? <strong>No!</strong> Adding custom HTTP headers triggers a CORS preflight (<code>OPTIONS</code>) request, which <code>travelbuddy.com</code> will reject for <code>evil.com</code>.</p>
</li>
</ol>
<p>Since <code>evil.com</code> can't read the cookie value, it can't provide a matching value in the HTTP header. The server compares <code>Header (null)</code> vs <code>Cookie (secret-value-123)</code>, sees a mismatch, and rejects the request.</p>
<h2 id="heading-samesite-cookies">SameSite Cookies</h2>
<p>For over two decades, developers relied entirely on CSRF tokens. Then, in 2016, browser engineers introduced an elegant, browser-native defense mechanism directly into the HTTP cookie specification: the <code>SameSite</code> <strong>attribute</strong>. This defense really takes the biscuit when it comes to simplicity.</p>
<h3 id="heading-what-problem-existed-before-samesite">What Problem Existed Before <code>SameSite</code>?</h3>
<p>Cookies were strictly cross-site by default. If a site set a cookie, the browser attached it to <em>every</em> HTTP request targeting that domain, regardless of where the request originated.</p>
<h3 id="heading-how-samesite-solves-this">How <code>SameSite</code> Solves This</h3>
<p>The <code>SameSite</code> cookie attribute allows developers to instruct the browser whether to attach a cookie during cross-site requests.</p>
<p>Syntax in HTTP response:</p>
<pre><code class="language-shell">Set-Cookie: JSESSIONID=abc123xyz789; Path=/; Secure; HttpOnly; SameSite=Lax
</code></pre>
<p><code>SameSite</code> accepts three values: <code>Strict</code>, <code>Lax</code>, and <code>None</code>.</p>
<table style="min-width:100px"><colgroup><col style="min-width:25px"><col style="min-width:25px"><col style="min-width:25px"><col style="min-width:25px"></colgroup><tbody><tr><td><p><strong>SameSite Mode</strong></p></td><td><p><strong>Same-Site Requests</strong></p></td><td><p><strong>Cross-Site Top-Level Navigation (for example, clicking a link)</strong></p></td><td><p><strong>Cross-Site Subrequests (for example, HTML forms, AJAX, &lt;img&gt;, &lt;iframe&gt;)</strong></p></td></tr><tr><td><p><code>Strict</code></p></td><td><p>Sent</p></td><td><p><strong>Blocked</strong></p></td><td><p><strong>Blocked</strong></p></td></tr><tr><td><p><code>Lax</code> (Modern Default)</p></td><td><p>Sent</p></td><td><p><strong>Sent</strong> (Safe <code>GET</code> methods only)</p></td><td><p><strong>Blocked</strong></p></td></tr><tr><td><p><code>None</code></p></td><td><p>Sent</p></td><td><p>Sent</p></td><td><p>Sent (Requires <code>Secure</code> flag)</p></td></tr></tbody></table>

<h3 id="heading-deep-dive-into-samesite-modes">Deep Dive into SameSite Modes</h3>
<h4 id="heading-1-samesitestrict">1. <code>SameSite=Strict</code></h4>
<p>This is the most secure setting. The browser <strong>never</strong> attaches the cookie on any cross-site request.</p>
<p>Let's say that Alice is logged into <code>TravelBuddy</code> (<code>SameSite=Strict</code>). She clicks a link on <code>twitter.com</code> pointing to <code>https://travelbuddy.com/dashboard</code>.</p>
<p>Because the navigation originated from a cross-site source (<code>twitter.com</code>), the browser <strong>omits</strong> the <code>JSESSIONID</code> cookie. Alice lands on <code>TravelBuddy</code> appearing logged out.</p>
<p>This gives her maximum security, but introduces user friction for standard link navigation.</p>
<h4 id="heading-2-samesitelax-modern-browser-default">2. <code>SameSite=Lax</code> (Modern Browser Default)</h4>
<p><code>Lax</code> provides a pragmatic balance between security and user experience.</p>
<ul>
<li><p><strong>Top-level navigations (</strong><code>GET</code><strong>):</strong> If Alice clicks a link on <code>twitter.com</code> to open <code>https://travelbuddy.com/dashboard</code>, the browser <strong>includes</strong> the cookie. Alice stays logged in!</p>
</li>
<li><p><strong>State-modifying / cross-site requests (</strong><code>POST</code><strong>,</strong> <code>PUT</code><strong>,</strong> <code>DELETE</code> <strong>or</strong> <code>&lt;img&gt;</code> <strong>tags):</strong> If <code>evil.com</code> submits a cross-site <code>POST</code> form to <code>travelbuddy.com</code>, the browser <strong>blocks and strips</strong> the cookie.</p>
</li>
</ul>
<pre><code class="language-shell">/* Cross-site POST request from evil.com targeting travelbuddy.com */
POST /api/connections/add HTTP/1.1
Host: travelbuddy.com
User-Agent: Mozilla/5.0
/* Cookie header is STRIPPED by browser because SameSite=Lax! */

service=MaliciousService
</code></pre>
<p>Because the cookie is missing, <code>TravelBuddy</code> treats the request as unauthenticated and drops it with HTTP 401 Unauthorized.</p>
<h4 id="heading-3-samesitenone">3. <code>SameSite=None</code></h4>
<p>Disables <code>SameSite</code> restrictions entirely. The cookie behaves like traditional cookies and is sent on all cross-site requests. Modern browsers require <code>SameSite=None</code> to be accompanied by the <code>Secure</code> attribute (HTTPS only).</p>
<h3 id="heading-is-samesitelax-a-complete-replacement-for-csrf-tokens">Is <code>SameSite=Lax</code> a Complete Replacement for CSRF Tokens?</h3>
<p>Modern browsers (Chrome, Firefox, Edge, Safari) now set <code>SameSite=Lax</code> as the implicit default if no <code>SameSite</code> attribute is specified.</p>
<p>This doesn't mean CSRF tokens are dead. <code>SameSite=Lax</code> should be viewed as <strong>defense-in-depth</strong>, not a total replacement for CSRF tokens, for several reasons:</p>
<ol>
<li><p><strong>Older browsers:</strong> Legacy browsers or specialized embedded web views don't enforce modern <code>SameSite</code> defaults.</p>
</li>
<li><p><strong>Top-level GET vulnerabilities:</strong> If your application incorrectly mutates state on a <code>GET</code> request, <code>SameSite=Lax</code> will <strong>not</strong> protect you, because <code>Lax</code> permits cookies on top-level cross-site <code>GET</code> navigations.</p>
</li>
<li><p><strong>Client-side refresh windows:</strong> Some browsers apply a 2-minute "Lax-by-default" window exception for top-level POSTs on newly set cookies to handle legacy authentication flows.</p>
</li>
</ol>
<h2 id="heading-origin-and-referer-headers">Origin and Referer Headers</h2>
<p>In addition to CSRF tokens and <code>SameSite</code> cookies, servers can inspect incoming HTTP headers to verify the geographical source of a request: the <code>Origin</code> and <code>Referer</code> headers.</p>
<h3 id="heading-understanding-the-headers">Understanding the Headers</h3>
<p>When a browser makes an HTTP request, it automatically attaches contextual metadata headers:</p>
<ul>
<li><p><code>Origin</code> <strong>Header:</strong> Indicates the origin (scheme + domain + port) of the page that initiated the request. For example: <code>Origin: https://evil.com</code></p>
</li>
<li><p><code>Referer</code> <strong>Header:</strong> Contains the full URL of the exact web page that initiated the request. For example: <code>Referer: https://evil.com/win-a-car.html</code></p>
</li>
</ul>
<h3 id="heading-server-side-validation-logic">Server-Side Validation Logic</h3>
<p>When a state-modifying request (<code>POST</code>, <code>PUT</code>, <code>DELETE</code>) arrives at <code>TravelBuddy</code>, a security filter can inspect these headers:</p>
<pre><code class="language-java">// Conceptual Origin/Referer Checking Logic
public boolean isValidRequest(HttpServletRequest request) {
    String origin = request.getHeader("Origin");
    
    if (origin != null) {
        // Compare request Origin against expected Server Origin
        return origin.equals("https://travelbuddy.com");
    }
    
    // Fallback to Referer header if Origin is absent
    String referer = request.getHeader("Referer");
    if (referer != null) {
        return referer.startsWith("https://travelbuddy.com/");
    }
    
    // If both headers are missing, drop or handle cautiously
    return false;
}
</code></pre>
<h3 id="heading-limitations-of-originreferer-verification">Limitations of Origin/Referer Verification</h3>
<p>While checking <code>Origin</code> and <code>Referer</code> is lightweight and stateless, it has operational limitations:</p>
<ol>
<li><p><strong>Privacy stripping:</strong> Corporate proxies, privacy extensions, VPNs, and browser settings often strip <code>Referer</code> headers to protect user privacy.</p>
</li>
<li><p><strong>Missing</strong> <code>Origin</code> <strong>on certain requests:</strong> The <code>Origin</code> header is generally included on <code>POST</code>/<code>PUT</code>/<code>DELETE</code> requests, but may be omitted on cross-site <code>GET</code> navigations.</p>
</li>
<li><p><strong>Subdomain vulnerabilities:</strong> If an attacker compromises a separate application hosted on <code>blog.travelbuddy.com</code>, an origin check verifying <code>*.travelbuddy.com</code> might accept the forged request.</p>
</li>
</ol>
<h2 id="heading-jwt-and-csrf-the-token-storage-dilemma">JWT and CSRF: The Token Storage Dilemma</h2>
<p>One of the most heavily debated topics in modern architecture is: "Does using JSON Web Tokens (JWT) make my application immune to CSRF?"</p>
<p>The answer depends entirely on where and how the frontend application stores and sends the JWT.</p>
<p>Let's evaluate the two primary JWT storage strategies.</p>
<h3 id="heading-strategy-a-storing-jwt-in-localstorage-or-sessionstorage">Strategy A: Storing JWT in <code>localStorage</code> or <code>sessionStorage</code></h3>
<p>In this architecture, when Alice logs in, the backend returns a JWT in the JSON response body. The frontend JavaScript saves the JWT in Web Storage (<code>localStorage</code> or <code>sessionStorage</code>).</p>
<p>For every API request, JavaScript explicitly attaches the token as a Bearer token inside the <code>Authorization</code> HTTP header:</p>
<pre><code class="language-shell">POST /api/connections/add HTTP/1.1
Host: travelbuddy.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

{"service": "SkyScanner"}
</code></pre>
<h4 id="heading-is-strategy-a-vulnerable-to-csrf">Is Strategy A Vulnerable to CSRF?</h4>
<p>No: strategy A is completely immune to CSRF.</p>
<p>Why? Because the browser <strong>never automatically attaches</strong> <code>localStorage</code> <strong>items or</strong> <code>Authorization: Bearer</code> <strong>headers</strong> to outgoing requests.</p>
<p>If Alice visits <code>evil.com</code>, <code>evil.com</code> can send a request to <code>travelbuddy.com</code>. But because <code>evil.com</code> can't read Alice's <code>localStorage</code> (due to Same Origin Policy), it can't extract the JWT. And because the browser doesn't attach the <code>Authorization</code> header automatically, the forged request arrives at <code>TravelBuddy</code> without credentials and fails.</p>
<h4 id="heading-the-catch-xss-vulnerability">The Catch: XSS Vulnerability</h4>
<p>While Strategy A eliminates CSRF, it introduces a severe risk: <strong>Cross-Site Scripting (XSS)</strong>. Any third-party JavaScript library or injected XSS script running on <code>travelbuddy.com</code> can execute <code>localStorage.getItem('jwt')</code>, steal Alice's token, and send it to an attacker's command-and-control server. Once stolen, the token can be used from anywhere in the world.</p>
<h3 id="heading-strategy-b-storing-jwt-in-an-httponly-cookie">Strategy B: Storing JWT in an <code>HttpOnly</code> Cookie</h3>
<p>To protect JWTs from XSS theft, security engineers often store the JWT inside a <code>Set-Cookie</code> header marked with the <code>HttpOnly</code> flag:</p>
<pre><code class="language-shell">Set-Cookie: jwt_token=eyJhbGciOi...; Path=/; HttpOnly; Secure; SameSite=Lax
</code></pre>
<p>When marked <code>HttpOnly</code>, client-side JavaScript <strong>can't read or steal</strong> the cookie.</p>
<h4 id="heading-is-strategy-b-vulnerable-to-csrf">Is Strategy B Vulnerable to CSRF?</h4>
<p>Yes: strategy B is vulnerable to CSRF unless explicitly defended.</p>
<p>Why? Because the moment you put an authentication credential inside a Cookie, <strong>you re-introduce automatic cookie attachment.</strong> The browser treats a JWT cookie exactly like a session cookie.</p>
<p>If <code>evil.com</code> triggers a cross-site request to <code>travelbuddy.com</code>, the browser automatically attaches <code>Cookie: jwt_token=eyJhbGciOi...</code>.</p>
<h3 id="heading-summary-matrix-jwt-storage-trade-offs">Summary Matrix: JWT Storage Trade-offs</h3>
<table style="min-width:150px"><colgroup><col style="min-width:25px"><col style="min-width:25px"><col style="min-width:25px"><col style="min-width:25px"><col style="min-width:25px"><col style="min-width:25px"></colgroup><tbody><tr><td><p><strong>Storage Location</strong></p></td><td><p><strong>Transmitted Via</strong></p></td><td><p><strong>Automatic Browser Attachment?</strong></p></td><td><p><strong>CSRF Vulnerable?</strong></p></td><td><p><strong>XSS Vulnerable to Token Theft?</strong></p></td><td><p><strong>Primary Defenses Needed</strong></p></td></tr><tr><td><p><code>localStorage</code></p></td><td><p><code>Authorization: Bearer &lt;jwt&gt;</code> Header</p></td><td><p><strong>No</strong></p></td><td><p><strong>No</strong></p></td><td><p><strong>YES</strong></p></td><td><p>Strict Content Security Policy (CSP), Input Sanitization</p></td></tr><tr><td><p><code>HttpOnly</code><strong> Cookie</strong></p></td><td><p><code>Cookie: jwt=&lt;jwt&gt;</code> Header</p></td><td><p><strong>YES</strong></p></td><td><p><strong>YES</strong></p></td><td><p><strong>No</strong></p></td><td><p>CSRF Tokens OR <code>SameSite=Lax/Strict</code></p></td></tr></tbody></table>

<h2 id="heading-oauth-state-parameter-amp-login-csrf">OAuth State Parameter &amp; Login CSRF</h2>
<p>In the introduction, I mentioned that OAuth 2.0 uses a <code>state</code> parameter to protect against CSRF. Let's connect our understanding back to OAuth authentication flows and explore a specialized variant of CSRF called <strong>Login CSRF</strong>.</p>
<h3 id="heading-what-is-login-csrf">What is Login CSRF?</h3>
<p>In standard CSRF, the attacker tries to force a victim to perform an action inside the <em>victim's</em> account (for example, adding an integration to Alice's account).</p>
<p>In <strong>Login CSRF</strong>, the attacker tries to force the victim's browser to log into the <em>attacker's</em> account.</p>
<h4 id="heading-how-login-csrf-works">How Login CSRF Works</h4>
<p>First, the attacker logs into <code>TravelBuddy</code> and initiates an OAuth login flow (for example, "Sign in with Google").</p>
<p>Then Google redirects the attacker's browser back to <code>https://travelbuddy.com/login/oauth2/code/google?code=ATTACKER_AUTHORIZATION_CODE</code>.</p>
<p>The attacker <strong>intercepts and pauses</strong> this request before the code is exchanged, copying the redirect URL containing <code>code=ATTACKER_AUTHORIZATION_CODE</code>.</p>
<p>Next, the attacker crafts a link or malicious page on <code>evil.com</code> that forces Alice's browser to open that exact URL: <code>https://travelbuddy.com/login/oauth2/code/google?code=ATTACKER_AUTHORIZATION_CODE</code>.</p>
<p>Alice's browser executes the request. <code>TravelBuddy</code> takes <code>ATTACKER_AUTHORIZATION_CODE</code>, exchanges it with Google, and logs Alice's browser session into the <strong>Attacker's TravelBuddy account</strong>.</p>
<p>Then Alice, believing she's in her own account, enters sensitive travel data or attaches her credit card. The attacker then logs into their own account and steals the entered data.</p>
<h3 id="heading-how-the-oauth-state-parameter-prevents-login-csrf">How the OAuth <code>state</code> Parameter Prevents Login CSRF</h3>
<p>To prevent Login CSRF, OAuth 2.0 uses the <code>state</code> parameter, which acts as a CSRF token for authorization flows.</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/16cc15d1-4ee6-4608-9395-0c7ca5235d81.png" alt="Sequence diagram illustrating OAuth 2.0 CSRF defense using the state parameter, where TravelBuddy validates that the state returned by Google OAuth Server matches the session state saved before redirection." style="display: block;" width="2657" height="1376" loading="lazy">

<p>If an attacker tries to inject their authorization code into Alice's browser, the attacker's <code>state</code> parameter won't match the random <code>state</code> stored in Alice's session. <code>TravelBuddy</code> rejects the callback, stopping Login CSRF.</p>
<h3 id="heading-comparison-table-csrf-token-vs-oauth-state-vs-pkce">Comparison Table: CSRF Token vs OAuth State vs PKCE</h3>
<table style="min-width:100px"><colgroup><col style="min-width:25px"><col style="min-width:25px"><col style="min-width:25px"><col style="min-width:25px"></colgroup><tbody><tr><td><p><strong>Defense Mechanism</strong></p></td><td><p><strong>Primary Purpose</strong></p></td><td><p><strong>How It Works</strong></p></td><td><p><strong>Target Vulnerability</strong></p></td></tr><tr><td><p><strong>CSRF Token</strong></p></td><td><p>Protects standard web application state mutations.</p></td><td><p>Server issues random token to UI and verifies token on incoming POST requests.</p></td><td><p>CSRF on forms/APIs inside established sessions.</p></td></tr><tr><td><p><strong>OAuth </strong><code>state</code></p></td><td><p>Binds an OAuth authorization request to the user session that initiated it.</p></td><td><p>Client passes random state to Identity Provider (IdP); IdP returns state on callback redirect.</p></td><td><p>Login CSRF/Authorization Code Injection.</p></td></tr><tr><td><p><strong>PKCE</strong> (Proof Key for Code Exchange)</p></td><td><p>Prevents authorization code interception on public clients (mobile/SPA).</p></td><td><p>Client generates <code>code_verifier</code> and sends hashed <code>code_challenge</code> to IdP. Proves ownership during token exchange.</p></td><td><p>Authorization Code Interception on mobile/native apps.</p></td></tr></tbody></table>

<h2 id="heading-spring-security-csrf-internals">Spring Security CSRF Internals</h2>
<p>Now that you've learned these first principles (browser cookies, SOP, CORS, CSRF tokens, <code>SameSite</code>, and OAuth state) you're ready to look at how modern frameworks handle CSRF.</p>
<p>We'll analyze <strong>Spring Security</strong> (Spring Boot 3.x / 4 architecture, using Java 21).</p>
<h3 id="heading-the-mechanics-csrffilter">The Mechanics: <code>CsrfFilter</code></h3>
<p>Spring Security implements CSRF protection through an HTTP Filter inserted into its filter chain: <code>CsrfFilter</code>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/dc479386-e392-40f9-a234-869f153596e3.svg" alt="Flowchart showing the internal execution flow of Spring Security's CsrfFilter, validating safe HTTP methods and comparing request tokens against session tokens to either allow request passage or return HTTP 403 Forbidden." style="display: block;" width="654.984375" height="1179.5625" loading="lazy">

<h3 id="heading-spring-security-csrf-key-architecture-components">Spring Security CSRF Key Architecture Components</h3>
<p>Spring Security decomposes CSRF responsibilities into clear interfaces:</p>
<ol>
<li><p><code>CsrfToken</code><strong>:</strong> An interface representing the token payload (contains <code>getHeaderName()</code>, <code>getParameterName()</code>, and <code>getToken()</code>).</p>
</li>
<li><p><code>CsrfTokenRepository</code><strong>:</strong> Responsible for generating, saving, and loading tokens.</p>
<ul>
<li><p><code>HttpSessionCsrfTokenRepository</code> (Default): Stores the CSRF token in the HTTP Session under a key.</p>
</li>
<li><p><code>CookieCsrfTokenRepository</code>: Stores the CSRF token in a cookie (for stateless/SPA applications).</p>
</li>
</ul>
</li>
<li><p><code>CsrfTokenRequestHandler</code><strong>:</strong> Handles making the token available to the UI template or parsing incoming headers/parameters.</p>
<ul>
<li>In modern Spring Security, <code>XorCsrfTokenRequestAttributeHandler</code> is used by default to protect against side-channel attacks like BREACH by masking tokens with a random XOR mask per request.</li>
</ul>
</li>
<li><p><strong>Deferred CSRF Tokens:</strong> Introduced in Spring Security 6, tokens are loaded <strong>deferred/lazily</strong>. Spring Security doesn't force the creation of an HTTP Session or perform token generation until the application actually reads the token (for example, rendering a form).</p>
</li>
</ol>
<h3 id="heading-modern-spring-security-configuration-spring-boot-3x-4">Modern Spring Security Configuration (Spring Boot 3.x / 4)</h3>
<p>Here's an enterprise-ready Spring Security configuration written in modern Java 21 DSL style:</p>
<pre><code class="language-java">package com.travelbuddy.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -&gt; auth
                .requestMatchers("/public/**", "/login", "/register").permitAll()
                .anyRequest().authenticated()
            )
            .formLogin(form -&gt; form
                .loginPage("/login")
                .defaultSuccessUrl("/dashboard", true)
            )
            // Configure CSRF explicitly using modern Lambda DSL
            .csrf(csrf -&gt; csrf
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .csrfTokenRequestHandler(new XorCsrfTokenRequestAttributeHandler())
                .ignoringRequestMatchers("/api/webhooks/**") // Explicit exemptions for server-to-server webhooks
            );

        return http.build();
    }
}
</code></pre>
<p>This configuration uses Spring Security's modern <strong>SecurityFilterChain</strong> instead of the deprecated <code>WebSecurityConfigurerAdapter</code>. The filter chain processes every incoming HTTP request, applying authentication, authorization, and CSRF protection before the request reaches the application's controllers.</p>
<p>The <code>authorizeHttpRequests()</code> method defines the authorization rules. Public endpoints such as <code>/public/**</code>, <code>/login</code>, and <code>/register</code> are accessible without authentication, while all other requests require a logged-in user.</p>
<p>CSRF protection is enabled using <code>CookieCsrfTokenRepository.withHttpOnlyFalse()</code>, which stores the CSRF token in a cookie named <code>XSRF-TOKEN</code>. Because the cookie is readable by JavaScript, frontend frameworks such as React, Angular, or Vue can include the token in the <code>X-XSRF-TOKEN</code> request header. Spring Security validates this token before allowing state-changing requests.</p>
<p>The <code>XorCsrfTokenRequestAttributeHandler</code> further improves security by masking the CSRF token with a random XOR value on each response, helping protect against compression-based attacks such as BREACH. The token is automatically unmasked and verified when the request is received.</p>
<p>Finally, <code>ignoringRequestMatchers("/api/webhooks/**")</code> excludes webhook endpoints from CSRF validation because they receive requests from trusted external services rather than browser sessions. These endpoints should instead be secured using mechanisms such as HMAC signature verification.</p>
<h2 id="heading-implement-csrf-protection-yourself">Implement CSRF Protection Yourself</h2>
<p>To demystify Spring Security entirely, let's build our own lightweight, custom CSRF protection mechanism in raw Java 21 and Spring Boot without using Spring Security's <code>CsrfFilter</code>.</p>
<p>This hands-on exercise proves that security frameworks aren't magical: they're structured applications of web fundamentals.</p>
<h3 id="heading-step-1-create-a-custom-csrf-filter">Step 1: Create a Custom CSRF Filter</h3>
<pre><code class="language-java">package com.travelbuddy.security;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Set;

@Component
public class CustomCsrfFilter extends OncePerRequestFilter {

    private static final String CSRF_SESSION_ATTRIBUTE = "CUSTOM_CSRF_TOKEN";
    private static final String CSRF_PARAM_NAME = "_csrf";
    private static final String CSRF_HEADER_NAME = "X-CSRF-TOKEN";
    
    // Define safe HTTP methods that do not modify state
    private static final Set&lt;String&gt; SAFE_METHODS = Set.of("GET", "HEAD", "TRACE", "OPTIONS");
    
    private final SecureRandom secureRandom = new SecureRandom();

    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                    HttpServletResponse response, 
                                    FilterChain filterChain) throws ServletException, IOException {

        HttpSession session = request.getSession(true);

        // 1. Ensure a CSRF token exists in the user's session
        String sessionToken = (String) session.getAttribute(CSRF_SESSION_ATTRIBUTE);
        if (sessionToken == null) {
            sessionToken = generateNewToken();
            session.setAttribute(CSRF_SESSION_ATTRIBUTE, sessionToken);
        }

        // Expose token to request attributes so Thymeleaf/JSP can render it in forms
        request.setAttribute("csrfToken", sessionToken);

        // 2. Check if the incoming request method is SAFE
        if (SAFE_METHODS.contains(request.getMethod())) {
            // Safe request: Allow execution to proceed
            filterChain.doFilter(request, response);
            return;
        }

        // 3. Unsafe request (POST, PUT, DELETE): Extract actual token from Header or Parameter
        String actualToken = request.getHeader(CSRF_HEADER_NAME);
        if (actualToken == null || actualToken.isBlank()) {
            actualToken = request.getParameter(CSRF_PARAM_NAME);
        }

        // 4. Validate Token
        if (actualToken != null &amp;&amp; actualToken.equals(sessionToken)) {
            // Token matches! Proceed to controller handler
            filterChain.doFilter(request, response);
        } else {
            // Token missing or mismatched! Reject forged request
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            response.setContentType("application/json");
            response.getWriter().write("""
                {
                    "error": "Forbidden",
                    "message": "Custom CSRF Filter: Invalid or missing CSRF token."
                }
                """);
        }
    }

    private String generateNewToken() {
        byte[] randomBytes = new byte[32];
        secureRandom.nextBytes(randomBytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes);
    }
}
</code></pre>
<p>The <code>CustomCsrfFilter</code> extends Spring's <code>OncePerRequestFilter</code>, ensuring the filter executes only once for each HTTP request. When a request arrives, it checks the user's session for a CSRF token. If no token exists, a new 256-bit cryptographically secure random token is generated using <code>SecureRandom</code> and stored in the session.</p>
<p>The filter then exposes the token as a request attribute using <code>request.setAttribute("csrfToken", sessionToken)</code>, allowing server-side template engines such as Thymeleaf to include it in hidden form fields. For safe HTTP methods (<code>GET</code>, <code>HEAD</code>, <code>OPTIONS</code>, and <code>TRACE</code>), the filter skips CSRF validation and immediately passes the request to the next filter since these methods shouldn't modify server state.</p>
<p>For state-changing requests such as <code>POST</code>, <code>PUT</code>, and <code>DELETE</code>, the filter retrieves the submitted CSRF token from either the <code>X-CSRF-TOKEN</code> request header (used by JavaScript clients) or the <code>_csrf</code> form parameter (used by HTML forms). It then compares this value with the token stored in the user's session. If the tokens match, the request proceeds normally. If the token is missing or invalid, the filter blocks the request by returning an <strong>HTTP 403 Forbidden</strong> response with a JSON error message.</p>
<h3 id="heading-step-2-register-the-custom-filter">Step 2: Register the Custom Filter</h3>
<pre><code class="language-java">package com.travelbuddy.config;

import com.travelbuddy.security.CustomCsrfFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class WebFilterConfig {

    @Bean
    public FilterRegistrationBean&lt;CustomCsrfFilter&gt; loggingFilter(CustomCsrfFilter filter) {
        FilterRegistrationBean&lt;CustomCsrfFilter&gt; registrationBean = new FilterRegistrationBean&lt;&gt;();
        registrationBean.setFilter(filter);
        registrationBean.addUrlPatterns("/api/*"); // Protect API endpoints
        return registrationBean;
    }
}
</code></pre>
<p>The <code>WebFilterConfig</code> class registers the custom <code>CustomCsrfFilter</code> using Spring Boot's <code>FilterRegistrationBean</code>, allowing the filter to be added to the underlying Servlet container without relying on Spring Security's filter chain. The <code>setFilter(filter)</code> method attaches the <code>CustomCsrfFilter</code> instance to the registration, while <code>addUrlPatterns("/api/*")</code> limits its execution to requests targeting <code>/api/*</code> endpoints. As a result, only API requests pass through the custom CSRF validation before reaching the application's <code>@RestController</code> methods.</p>
<h3 id="heading-compare-custom-filter-vs-spring-securitys-csrffilter">Compare Custom Filter vs. Spring Security's <code>CsrfFilter</code></h3>
<table style="min-width:75px"><colgroup><col style="min-width:25px"><col style="min-width:25px"><col style="min-width:25px"></colgroup><tbody><tr><td><p><strong>Feature</strong></p></td><td><p><strong>Our Custom Filter</strong></p></td><td><p><strong>Spring Security CsrfFilter</strong></p></td></tr><tr><td><p><strong>Token Generation</strong></p></td><td><p>Basic <code>SecureRandom</code> Base64 string</p></td><td><p>Cryptographically secure UUID / Custom generators</p></td></tr><tr><td><p><strong>BREACH Defense</strong></p></td><td><p>None (Raw token matching)</p></td><td><p>Masked Tokens (<code>XorCsrfTokenRequestAttributeHandler</code>)</p></td></tr><tr><td><p><strong>Storage Strategy</strong></p></td><td><p>Fixed <code>HttpSession</code></p></td><td><p>Pluggable (<code>HttpSession</code>, Cookie, Custom Repositories)</p></td></tr><tr><td><p><strong>Performance</strong></p></td><td><p>Immediate session creation</p></td><td><p>Lazy / Deferred token generation (Spring Security 6+)</p></td></tr><tr><td><p><strong>SPA Integration</strong></p></td><td><p>Manual header handling</p></td><td><p>Built-in <code>CookieCsrfTokenRepository</code></p></td></tr></tbody></table>

<p>Building this filter manually shows that Spring Security isn't magic. It performs the exact steps we built: checking HTTP methods, extracting tokens, and comparing request attributes against stored session state.</p>
<h2 id="heading-testing-csrf-protections">Testing CSRF Protections</h2>
<p>To verify that CSRF defenses are working correctly, you should know how to inspect, attack, and test your applications using various tools.</p>
<h3 id="heading-1-browser-devtools-inspection">1. Browser DevTools Inspection</h3>
<p>Open Chrome or Firefox DevTools (<code>F12</code>), navigate to the <strong>Application</strong> tab, and select <strong>Cookies</strong>:</p>
<ul>
<li><p>Inspect <code>JSESSIONID</code>: Verify that <code>HttpOnly</code> and <code>Secure</code> flags are set.</p>
</li>
<li><p>Inspect <code>SameSite</code> column: Verify whether <code>Lax</code> or <code>Strict</code> is active.</p>
</li>
</ul>
<p>In the <strong>Network</strong> tab, inspect a submitted <code>POST</code> request payload:</p>
<ul>
<li>Look for <code>_csrf</code> under Form Data, or <code>X-XSRF-TOKEN</code> under Request Headers.</li>
</ul>
<h3 id="heading-2-testing-via-curl">2. Testing via <code>curl</code></h3>
<p>Let's attempt a forged request using command-line <code>curl</code>.</p>
<h4 id="heading-test-attempt-a-submit-post-without-csrf-token-simulating-attacker">Test Attempt A: Submit POST without CSRF Token (Simulating Attacker)</h4>
<pre><code class="language-shell">curl -i -X POST https://travelbuddy.com/api/connections/add \
     -H "Cookie: JSESSIONID=abc123xyz789" \
     -d "service=SkyScanner"
</code></pre>
<p>Expected Response:</p>
<pre><code class="language-shell">HTTP/1.1 403 Forbidden
Content-Type: application/json

{"error":"Forbidden","message":"Invalid CSRF Token"}
</code></pre>
<h4 id="heading-test-attempt-b-fetch-token-and-submit-valid-request-legitimate-client-flow">Test Attempt B: Fetch Token and Submit Valid Request (Legitimate Client Flow)</h4>
<pre><code class="language-shell"># Step 1: Fetch session cookie and CSRF token from page
curl -i -c cookies.txt https://travelbuddy.com/connect-service

# Step 2: Extract token value from HTML, then submit POST request with Cookie + Token
curl -i -b cookies.txt -X POST https://travelbuddy.com/api/connections/add \
     -H "X-CSRF-TOKEN: CSRF-KEY-998877" \
     -d "service=SkyScanner"
</code></pre>
<p>Expected Response:</p>
<pre><code class="language-shell">HTTP/1.1 200 OK
Content-Type: application/json

{"status":"success","message":"Service connected successfully"}
</code></pre>
<h3 id="heading-3-why-postman-can-mislead-developers">3. Why Postman Can Mislead Developers</h3>
<p>Developers frequently report: <em>"I enabled CSRF protection in Spring Boot, but when I test my POST request in Postman, it succeeds without sending a CSRF token! Why?"</em></p>
<p>Postman is an API client, <strong>not a web browser</strong>. When you run a request in Postman, Postman doesn't maintain a cross-site sandbox, nor does it enforce Same Origin Policy or automatic ambient cookie injection unless explicitly configured.</p>
<p>If you don't manually attach a session cookie in Postman, the backend treats the Postman request as unauthenticated. If you use Postman's Interceptor cookie sync, Postman acts like a client explicitly sending parameters. Postman tests API contracts, but it doesn't simulate the browser's ambient authorization rules.</p>
<h3 id="heading-4-automated-integration-testing-with-spring-security-test">4. Automated Integration Testing with Spring Security Test</h3>
<p>In Java unit/integration tests, Spring Security provides test mock builders to simulate CSRF tokens effortlessly:</p>
<pre><code class="language-java">package com.travelbuddy.controller;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
class ConnectionControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithMockUser(username = "alice")
    void addConnection_WithoutCsrf_ShouldReturn403Forbidden() throws Exception {
        mockMvc.perform(post("/api/connections/add")
                .param("service", "SkyScanner"))
                .andExpect(status().isForbidden());
    }

    @Test
    @WithMockUser(username = "alice")
    void addConnection_WithCsrf_ShouldSucceed() throws Exception {
        mockMvc.perform(post("/api/connections/add")
                .param("service", "SkyScanner")
                .with(csrf())) // Injects a valid mock CSRF token into request
                .andExpect(status().isOk());
    }
}
</code></pre>
<h2 id="heading-common-misconceptions">Common Misconceptions</h2>
<p>Let's dispel the seven most persistent myths surrounding CSRF.</p>
<h3 id="heading-myth-1-csrf-and-xss-are-the-same-thing">Myth 1: "CSRF and XSS are the same thing."</h3>
<p><strong>Fact:</strong> CSRF and XSS are completely different vulnerability vectors with opposite mechanisms:</p>
<ul>
<li><p><strong>XSS (Cross-Site Scripting):</strong> Attacker injects malicious JavaScript <em>into</em> your site to execute scripts inside your origin (stealing data, reading DOM, extracting local storage).</p>
</li>
<li><p><strong>CSRF (Cross-Site Request Forgery):</strong> Attacker tricks a victim's browser <em>on a different origin</em> into sending an HTTP request to your site. The attacker cannot read your site's DOM or steal cookies.</p>
</li>
</ul>
<h3 id="heading-myth-2-https-prevents-csrf-attacks">Myth 2: "HTTPS prevents CSRF attacks."</h3>
<p><strong>Fact:</strong> HTTPS encrypts the transport channel between the browser and server. It prevents wiretapping and man-in-the-middle attacks. But in a CSRF attack, the browser itself sends encrypted, valid HTTPS requests. Encrypting the pipe doesn't stop the browser from sending a forged request down that pipe.</p>
<h3 id="heading-myth-3-our-app-requires-authentication-so-were-safe-from-csrf">Myth 3: "Our app requires authentication, so we're safe from CSRF."</h3>
<p><strong>Fact:</strong> Authentication is what <strong>enables</strong> CSRF. CSRF specifically targets authenticated users because the browser automatically attaches their authenticated session cookies.</p>
<h3 id="heading-myth-4-our-api-uses-jwts-so-we-dont-have-to-worry-about-csrf">Myth 4: "Our API uses JWTs, so we don't have to worry about CSRF."</h3>
<p><strong>Fact:</strong> If your JWT is stored in an <code>HttpOnly</code> Cookie, you're fully vulnerable to CSRF because cookies are attached automatically. CSRF is a function of credential transmission mechanism (cookies), not credential payload structure (JWT vs Session ID).</p>
<h3 id="heading-myth-5-cors-blocks-cross-site-attacks">Myth 5: "CORS blocks cross-site attacks."</h3>
<p><strong>Fact:</strong> CORS controls response reading, not request execution. Simple requests (<code>application/x-www-form-urlencoded</code> HTML forms) execute state modifications on the backend long before CORS checks evaluate response headers.</p>
<h3 id="heading-myth-6-samesitelax-makes-csrf-tokens-obsolete">Myth 6: "SameSite=Lax makes CSRF tokens obsolete."</h3>
<p><strong>Fact:</strong> <code>SameSite=Lax</code> is an excellent defense, but top-level GET navigations still carry cookies, legacy browsers don't support it properly, and edge-case refresh windows exist. CSRF tokens remain necessary as defense-in-depth.</p>
<h3 id="heading-myth-7-attackers-can-read-our-csrf-token-from-the-html-form">Myth 7: "Attackers can read our CSRF token from the HTML form."</h3>
<p><strong>Fact:</strong> Same Origin Policy (SOP) strictly prevents JavaScript running on <code>evil.com</code> from fetching and reading HTML DOM nodes rendered from <code>travelbuddy.com</code>.</p>
<h2 id="heading-production-best-practices-checklist">Production Best Practices Checklist</h2>
<p>When deploying Spring Boot applications to production, follow this architectural security checklist:</p>
<h3 id="heading-1-identify-your-architecture-type">1. Identify Your Architecture Type</h3>
<ul>
<li><p><strong>Monolithic HTML Rendering (Thymeleaf, JSP):</strong> Use Synchronizer Token Pattern stored in <code>HttpSession</code>. Ensure all HTML forms include <code>_csrf</code> hidden fields.</p>
</li>
<li><p><strong>Single Page Application (React/Angular + Spring Boot API):</strong> Use Double Submit Cookie pattern (<code>CookieCsrfTokenRepository.withHttpOnlyFalse()</code>) combined with custom frontend request interceptors.</p>
</li>
<li><p><strong>Stateless Pure REST API (Machine-to-Machine / Native Mobile Apps using</strong> <code>Authorization: Bearer</code> <strong>headers):</strong> Disable CSRF (<code>.csrf(csrf -&gt; csrf.disable())</code>), because clients explicitly manage non-cookie tokens.</p>
</li>
</ul>
<h3 id="heading-2-cookie-security-flags">2. Cookie Security Flags</h3>
<p>Ensure every authentication cookie sets these attributes:</p>
<ul>
<li><p><code>Secure</code> = <code>true</code> (HTTPS only)</p>
</li>
<li><p><code>HttpOnly</code> = <code>true</code> (Prevents XSS token theft)</p>
</li>
<li><p><code>SameSite</code> = <code>Lax</code> or <code>Strict</code> (Browser-native cross-site blocking)</p>
</li>
</ul>
<h3 id="heading-3-keep-get-requests-read-only">3. Keep GET Requests Read-Only</h3>
<p>Audit your codebase to ensure no <code>@GetMapping</code> or <code>HttpServletRequest.getMethod().equals("GET")</code> handles database updates, account deletions, or password resets.</p>
<h3 id="heading-4-cross-origin-defense-layers">4. Cross-Origin Defense Layers</h3>
<p>Implement strict <code>Origin</code> and <code>Referer</code> header validation filters on state-modifying endpoints.</p>
<p>Also, deploy a robust Content Security Policy (CSP) header to reduce XSS risk (since XSS can be used to bypass CSRF defenses).</p>
<h3 id="heading-5-webhooks-and-external-callbacks">5. Webhooks and External Callbacks</h3>
<p>For server-to-server endpoints (such as Stripe or GitHub webhooks):</p>
<ul>
<li><p>Explicitly exempt webhook endpoints from standard CSRF filters in Spring Security (<code>ignoringRequestMatchers("/api/webhooks/**")</code>).</p>
</li>
<li><p>Secure webhooks using <strong>HMAC Signature Verification</strong> (<code>X-Hub-Signature-256</code>) instead of session cookies.</p>
</li>
</ul>
<h2 id="heading-final-summary-amp-defense-matrix">Final Summary &amp; Defense Matrix</h2>
<p>Cross-Site Request Forgery (CSRF) isn't a bug in browser design. It's an unintended consequence of web convenience: <strong>browsers automatically attach stored domain cookies to every outgoing request.</strong></p>
<p>When an attacker tricks a user into visiting a malicious origin (<code>evil.com</code>), the attacker relies on the browser's ambient authority to attach authenticated session credentials to a forged, state-changing request targeting your application (<code>travelbuddy.com</code>).</p>
<p>To prevent CSRF, modern web applications employ multi-layered security defenses working in tandem:</p>
<h3 id="heading-comprehensive-defense-matrix">Comprehensive Defense Matrix</h3>
<table style="min-width:125px"><colgroup><col style="min-width:25px"><col style="min-width:25px"><col style="min-width:25px"><col style="min-width:25px"><col style="min-width:25px"></colgroup><tbody><tr><td><p><strong>Defense Mechanism</strong></p></td><td><p><strong>Mechanism Layer</strong></p></td><td><p><strong>Primary Target / Action</strong></p></td><td><p><strong>Advantages</strong></p></td><td><p><strong>Limitations</strong></p></td></tr><tr><td><p><strong>Synchronizer Token Pattern</strong></p></td><td><p>Application Server</p></td><td><p>Binds unpredictable random token to server session. Verifies hidden form parameter.</p></td><td><p>Cryptographically bulletproof. Complete protection against cross-site forged requests.</p></td><td><p>Requires server-side session state (or state management).</p></td></tr><tr><td><p><strong>Double Submit Cookie Pattern</strong></p></td><td><p>Client + Server</p></td><td><p>Cookie value copied into custom HTTP header by JS. Verified server-side.</p></td><td><p>Fully stateless; ideal for SPAs (React/Angular) and microservices.</p></td><td><p>Requires non-HttpOnly cookie readable by JS. Vulnerable if subdomains are compromised.</p></td></tr><tr><td><p><code>SameSite=Lax / Strict</code><strong> Cookies</strong></p></td><td><p>Browser Engine</p></td><td><p>Instructs browser to strip cookies from cross-site requests.</p></td><td><p>Native browser enforcement. Zero server token storage required.</p></td><td><p>Legacy browser gaps. Doesn't protect state-modifying <code>GET</code> operations.</p></td></tr><tr><td><p><code>Origin</code><strong> / </strong><code>Referer</code><strong> Validation</strong></p></td><td><p>Application / Gateway</p></td><td><p>Checks incoming source headers against known server origins.</p></td><td><p>Stateless and extremely fast execution.</p></td><td><p>Headers can be stripped by privacy software/proxies.</p></td></tr><tr><td><p><strong>Bearer Tokens (</strong><code>Authorization</code><strong> Header)</strong></p></td><td><p>API Client</p></td><td><p>Token stored in <code>localStorage</code>. Attached explicitly via JS headers.</p></td><td><p>Completely immune to CSRF (no automatic browser attachment).</p></td><td><p>High risk of XSS token theft if <code>localStorage</code> is accessed by malicious scripts.</p></td></tr></tbody></table>

<p>By mastering these fundamental concepts (how browsers handle cookies, how origins operate, and how frameworks implement token validation) you can build backend architectures that are secure by design.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Spring Boot Tutorial – How to Build Fast and Modern Java Apps ]]>
                </title>
                <description>
                    <![CDATA[ By Yiğit Kemal Erinç In this article I am going to walk you through building a prototype with Spring Boot. Think of it like building a project for a hackathon or a prototype for your startup in limited time.  In other words, we are not trying to buil... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/spring-boot-tutorial-build-fast-modern-java-app/</link>
                <guid isPermaLink="false">66d45e4b182810487e0ce161</guid>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 20 Sep 2021 19:43:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/09/pexels-ramdas-ware-102896.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Yiğit Kemal Erinç</p>
<p>In this article I am going to walk you through building a prototype with Spring Boot. Think of it like building a project for a hackathon or a prototype for your startup in limited time. </p>
<p>In other words, we are not trying to build something perfect – but rather something that works.</p>
<p>If you get stuck in any part of this tutorial or if I have forgotten to mention something, you can check out the GitHub repository I have included in the <strong>Conclusion</strong>.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>Foundations of Java and OOP</li>
<li>Basic knowledge of relational databases (one-to-many, many-to-many, and so on)</li>
<li>Fundamentals of Spring would be helpful</li>
<li>Basic level HTML</li>
</ul>
<p>Also make sure you have the following:</p>
<ul>
<li><a target="_blank" href="https://www.oracle.com/java/technologies/javase-downloads.html">JDK (Java Development Kit)</a> latest</li>
<li><a target="_blank" href="https://www.jetbrains.com/idea/">IntelliJ IDEA</a> or some other Java IDE</li>
</ul>
<h2 id="heading-what-are-we-building">What are we building?</h2>
<p>We will build an amenity reservation system where users will log in and reserve a time to use a service such as fitness center, pool, or sauna. </p>
<p>Each amenity will have a certain capacity (number of people that can use the service at the same time) so that people can make use of the amenities safely during the Covid-19 pandemic.</p>
<h3 id="heading-list-of-features-for-the-app">List of Features for the App</h3>
<p>We can think of our app as the reservation system for an apartment complex. </p>
<ul>
<li>Users should be able to log in.</li>
<li>We will assume that the accounts of residents are pre-created and there will be no sign-up feature.</li>
<li>Users should be able to view their reservations. </li>
<li>Users should be able to create new reservations by selecting the amenity type, date, and time.</li>
<li><strong>Only logged-in</strong> <strong>users</strong> should be able to see the reservations page and create reservations.</li>
<li>We should check the capacity and only create new reservations if the current number of reservations does not exceed the capacity.</li>
</ul>
<h3 id="heading-technologies-well-use">Technologies We'll Use</h3>
<p>We will learn about a lot of useful technologies that will make you more efficient as a Spring Boot developer. I will briefly mention what they are and what they are good for and then we will see them in action.</p>
<ul>
<li>Bootify</li>
<li>Hibernate</li>
<li>Spring Boot</li>
<li>Maven</li>
<li>JPA</li>
<li>Swagger</li>
<li>H2 In-Memory Database</li>
<li>Thymeleaf</li>
<li>Bootstrap</li>
<li>Spring Security</li>
</ul>
<h2 id="heading-why-spring-boot">Why Spring Boot?</h2>
<p>The Spring framework is generally used for enterprise level/large scale jobs. It is not usually the first option that comes to mind for smaller projects – but I will argue that it can be quite fast for prototyping. </p>
<p>It has the following advantages:</p>
<ul>
<li>Annotation-based development generates a lot of code for you behind the scenes. And especially with the availability of libraries like Lombok, it has became a lot easier to focus on the business logic.</li>
<li>It has nice in-memory database support, so that we don't need to create a real database and connect to it. (H2)</li>
<li>It has a mature ecosystem so you can readily find answers to most questions.</li>
<li>Almost "no configuration" is required. With the help of Spring Boot, we get rid of ugly XML configurations on the Spring side of things and configuring your application is really easy.</li>
<li>There's a lot happening behind the scenes. Spring provides so much magic and does so many things to get things going. So you don't usually need to care about that stuff and can just let the framework handle things.</li>
<li>We have <a target="_blank" href="https://github.com/spring-projects/spring-security">Spring Security.</a> Having one of the most comprehensive, battle-tested security frameworks on your side gives you more confidence in the security of your application. It also takes care of a good share of the hard work for you.</li>
</ul>
<h2 id="heading-how-to-create-the-project-with-bootify">How to Create the Project with Bootify</h2>
<p>To create the project, you will use <a target="_blank" href="https://bootify.io/"><strong>Bootify</strong></a>. It's a freemium service that makes Spring Boot development faster by generating a lot of boilerplate code for you and letting you focus on business logic instead.</p>
<p><strong>Bootify</strong> allows us to specify our preferences and automatically imports the dependencies similar to <strong>Spring Initializr</strong>. </p>
<p>But there is more than that. You can also specify your entities and it will generate the corresponding model and DTO classes. It can even generate the service and controller level code for common <strong>CRUD</strong> operations.</p>
<p>I believe it is a more convenient tool for API development than it is for MVC apps since it generates REST API code by default. But it will still make our lives easier even with a Spring Boot MVC application that contains views. We will just need to make some adjustments to the generated code.</p>
<p>Let's open the <strong>Bootify</strong> website and click the "Start Project" button at the top right corner.</p>
<p>You should select:</p>
<ul>
<li><strong>Maven</strong> as the build type</li>
<li>Java version: 14</li>
<li>Tick enable <strong>Lombok</strong></li>
<li>DBMS: <strong>H2</strong> database</li>
<li>Tick <strong>add</strong> <strong>dateCreated/lastUpdated</strong> to entities</li>
<li>Packages: Technical</li>
<li>Enable <strong>OpenAPI/Swagger UI</strong></li>
<li>Add <strong>org.springframework.boot:spring-boot-devtools</strong> to further dependencies</li>
</ul>
<p>After you are done, you should see this:</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/screencapture-bootify-io-app-8U9U2BBTLEAX-2021-04-09-16_06_29-1024x754.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now let's specify our entities. Start by clicking the <strong>Entities</strong> tab on the left menu.</p>
<p>We will have the following entities and relations:</p>
<ol>
<li><strong>Reservation</strong> that contains the data related to each reservation such as reservation date, reservation starting time, ending time, and the user who owns this reservation.</li>
<li>The <strong>User</strong> entity that contains our user model and will have relations with <strong>Reservation</strong>.</li>
<li>The <strong>Amenity</strong> entity to hold the type of Amenity and its capacity (maximum number of reservations for a certain time, for example 2 people can use and reserve the Sauna for the same time).</li>
</ol>
<p>Let's define our <strong>Reservation</strong> entity as follows and keep "Add REST endpoints" checked (even though we will modify the output). Then click the Save button.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-1-1024x577.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We will specify the relations later, so the only field that our user entity has is the id field.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-1024x445.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We could create an entity for Amenities to store the data of the amenity name and its capacity and then we could reference it from the <strong>Reservation</strong>. But the relationship between Amenity and Reservation would be one-to-one. </p>
<p>So instead, for the sake of simplicity, we will create an enum called <strong>AmenityType</strong> and store the <strong>AmenityType</strong> inside <strong>Reservation</strong>.</p>
<p>Now let's create a relationship between the <strong>User</strong> and <strong>Reservation</strong> entities by clicking the + button next to the <strong>Relations</strong> menu.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Menu to create relations</em></p>
<p>It will be a <strong>Many-to-one</strong> relationship since a user can have many reservations but a reservation must have one and only one user. We will make sure this is the case by checking the required box.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-3-1024x507.png" alt="Image" width="600" height="400" loading="lazy">
<em>User-Reservation Relation</em></p>
<p>We click "Save Changes" and we are done. Your final model should look like this:</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-4-1024x481.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now click the download button on the left menu to download the generated project code so we can start working on it. You can see the first commit on the project repository to compare with yours if you have any problems.</p>
<p>After you download the project, open it in an IDE – I'll use <strong>IntelliJ IDEA</strong>. Your file structure should look like this:</p>
<pre><code>├── amenity-reservation-system.iml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── amenity_reservation_system
│       │           ├── AmenityReservationSystemApplication.java
│       │           ├── HomeController.java
│       │           ├── config
│       │           │   ├── DomainConfig.java
│       │           │   ├── JacksonConfig.java
│       │           │   └── RestExceptionHandler.java
│       │           ├── domain
│       │           │   ├── Reservation.java
│       │           │   └── User.java
│       │           ├── model
│       │           │   ├── ErrorResponse.java
│       │           │   ├── FieldError.java
│       │           │   ├── ReservationDTO.java
│       │           │   └── UserDTO.java
│       │           ├── repos
│       │           │   ├── ReservationRepository.java
│       │           │   └── UserRepository.java
│       │           ├── rest
│       │           │   ├── ReservationController.java
│       │           │   └── UserController.java
│       │           └── service
│       │               ├── ReservationService.java
│       │               └── UserService.java
│       └── resources
│           └── application.yml
└── target
    ├── classes
    │   ├── application.yml
    │   └── com
    │       └── amenity_reservation_system
    │           ├── AmenityReservationSystemApplication.class
    │           ├── HomeController.class
    │           ├── config
    │           │   ├── DomainConfig.class
    │           │   ├── JacksonConfig.class
    │           │   └── RestExceptionHandler.class
    │           ├── domain
    │           │   ├── Reservation.class
    │           │   └── User.class
    │           ├── model
    │           │   ├── ErrorResponse.class
    │           │   ├── FieldError.class
    │           │   ├── ReservationDTO.class
    │           │   └── UserDTO.class
    │           ├── repos
    │           │   ├── ReservationRepository.class
    │           │   └── UserRepository.class
    │           ├── rest
    │           │   ├── ReservationController.class
    │           │   └── UserController.class
    │           └── service
    │               ├── ReservationService.class
    │               └── UserService.class
    └── generated-sources
        └── annotations
</code></pre><h2 id="heading-how-to-test-and-explore-the-generated-code">How to Test and Explore the Generated Code</h2>
<p>Let's take our time to experiment with the generated code and understand it layer by layer.</p>
<p>The <strong>Repos</strong> folder contains the code for the data access layer, namely our repositories. We will use <strong>JPA</strong> methods to retrieve our data, which are pre-made query methods you can use by defining them inside the repository interface. </p>
<p>Notice that our repository classes extend the <strong>JpaRepository</strong> interface. This is the interface that allows us to use the mentioned methods. </p>
<p>JPA queries follow a certain convention, and when we create the method that obeys the conventions, it will automatically know what data you want to retrieve, behind the scenes. If you don't yet get it, do not worry, we will see examples.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-5-1024x719.png" alt="Image" width="600" height="400" loading="lazy">
<em>Example keywords, sample phrases and their corresponding JPQL snippets (queries)</em></p>
<p>The <strong>Model</strong> classes present our data model, and which classes will have which fields. </p>
<p>Each model class corresponds to a database table with the same name and the fields in the model class will be columns in the corresponding table. </p>
<p>Notice the annotation <strong>@Entity</strong> on top of our model classes. This annotation is handled by <a target="_blank" href="https://hibernate.org/"><strong>Hibernate</strong></a> and whenever Hibernate sees <strong>@Entity</strong>, it will create a table using the name of our class as table name. </p>
<p>If you are wondering, "What is Hibernate anyways?", it is an <strong>object-relational-mapping</strong> (ORM) tool for Java that allows us to map the <strong>POJOs</strong> (Plain Old Java Object) to database tables. It can also provide features such as data validation constraints, but we will not go deep into Hibernate in this post since it is a vast topic on its own. </p>
<p>An awesome feature of Hibernate is that it handles all table creation and deletion operations so you don't have to use additional <strong>SQL</strong> scripts.</p>
<p>We also represent the relationships between objects in model classes. To see an example, take a look at our <strong>User</strong> class:</p>
<pre><code class="lang-java">    <span class="hljs-meta">@OneToMany(mappedBy = "user")</span>
    <span class="hljs-keyword">private</span> Set&lt;Reservation&gt; userReservations;
</code></pre>
<p>It has a <strong>userReservations</strong> object that holds a set of references that resembles the reservations of this particular user. In the <strong>Reservation</strong> class we have the reverse-relation as:</p>
<pre><code class="lang-java"><span class="hljs-meta">@ManyToOne(fetch = FetchType.LAZY)</span>
<span class="hljs-meta">@JoinColumn(name = "user_id", nullable = false)</span>
<span class="hljs-keyword">private</span> User user;
</code></pre>
<p>Having references on both sides makes it possible to access the other side of the relationship (user object to reservation and vice versa).</p>
<p><strong>Controllers</strong> will handle the requests that are passed to this controller by the request handler and return the corresponding views, in this case. </p>
<p>The controllers that were generated by Bootify are configured to return JSON responses, and we will modify them in the next section to return our views.</p>
<p><strong>Services</strong> will hold the logic of our application. The best practice is to keep controllers thin by keeping the business logic in a separate place, the service classes. </p>
<p>Controllers should not interact with the repositories directly, but instead call the service which will interact with the repository, perform any additional operation, and return the result to the controller.</p>
<h3 id="heading-lets-try-out-the-api">Let's Try Out the API</h3>
<p>Now, let's get to the fun part and try our API to see it on action. Run the Spring application on your favorite IDE. Open your browser and go to this address:</p>
<pre><code>http:<span class="hljs-comment">//localhost:8080/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/</span>
</code></pre><p>Swagger automatically documents our code and allows you to send requests easily. You should be seeing this:</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/screencapture-localhost-8080-swagger-ui-index-html-2021-04-17-21_27_48-1024x914.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let's first create a user by sending a <strong>POST</strong> request to <strong>UserController</strong>. We will do that by clicking the last box (the green one) under user-controller list.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/Screen-Shot-2021-04-17-at-21.30.41-1024x565.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><strong>Swagger</strong> shows us the parameters that this endpoint expects – only the id for now – and also the responses that the API returns. </p>
<p>Click the "Try it out" button at the top right corner. It asks you to enter an id. I know it is nonsense and the code will not even use this id you enter, but we will fix that in the next section (it is just a problem with the generated code). </p>
<p>For the sake of experimenting, enter any number, like 1 for the id, and click the execute button.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/screencapture-localhost-8080-swagger-ui-index-html-2021-04-17-21_39_32-547x1024.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The response body contains the id of the created object. We can confirm that it is created on the database by checking the H2 console. </p>
<p>But before doing that, we need to make a minor adjustment to the <strong>application.yml</strong> file which contains the application settings and configuration. Open your <strong>application.yml</strong> file and paste in the following code:</p>
<pre><code>spring:
  datasource:
    url: ${<span class="hljs-attr">JDBC_DATABASE_URL</span>:jdbc:h2:mem:amenity-reservation-system}
    <span class="hljs-attr">username</span>: ${<span class="hljs-attr">JDBC_DATABASE_USERNAME</span>:sa}
    <span class="hljs-attr">password</span>: ${<span class="hljs-attr">JDBC_DATABASE_PASSWORD</span>:}
  <span class="hljs-attr">dbcp2</span>:
    max-wait-millis: <span class="hljs-number">30000</span>
    validation-query: <span class="hljs-string">"SELECT 1"</span>
    validation-query-timeout: <span class="hljs-number">30</span>
  <span class="hljs-attr">jpa</span>:
    hibernate:
      ddl-auto: update
    open-<span class="hljs-keyword">in</span>-view: <span class="hljs-literal">false</span>
    <span class="hljs-attr">properties</span>:
      hibernate:
        jdbc:
          lob:
            non_contextual_creation: <span class="hljs-literal">true</span>
        <span class="hljs-attr">id</span>:
          new_generator_mappings: <span class="hljs-literal">true</span>
<span class="hljs-attr">springdoc</span>:
  pathsToMatch: <span class="hljs-regexp">/api/</span>**
</code></pre><p>Then we should be able to access the H2 console by going to this address:</p>
<pre><code>http:<span class="hljs-comment">//localhost:8080/h2-console/</span>
</code></pre><p><img src="https://erinc.io/wp-content/uploads/2021/04/image-6-1024x724.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here you need to check that the username is "sa" and click the Connect button.</p>
<p>Click the USER table on the left menu and the console will write the select all query for you.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-7-1024x573.png" alt="Image" width="600" height="400" loading="lazy">
<em>H2 Admin Panel</em></p>
<p>Let's click the <strong>Run</strong> button that is above the query.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-8-1024x466.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We can see that the <strong>User</strong> object is indeed created – great!</p>
<p>We already have a working API at this point and we have not written a single line of code.</p>
<h3 id="heading-how-to-adjust-the-code-for-our-use-case">How to Adjust the Code for our Use Case</h3>
<p>As I mentioned earlier, the generated code does not fully suit our use case and we need to make some adjustments to it. </p>
<p>Let's remove the model folder which contains DTOs and stuff that we will not use. We will show the data inside views instead.</p>
<pre><code>cd src/main/java/com/amenity_reservation_system/ 
rm -rf model
</code></pre><p>We will have a lot of errors now since the code uses the DTO classes, but we will get rid of most of it after removing the controller classes. </p>
<p>We will delete the controllers because we do not want to expose the functionality of modifying our data anymore. Our users should be able to do that by interacting with our UI, and we will create new controllers to return the view components in the next section.</p>
<pre><code>rm -rf rest
</code></pre><p>Finally, we need to do some refactoring to our service classes since the DTO classes are not present anymore:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.service;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.domain.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.UserRepository;
<span class="hljs-keyword">import</span> java.util.List;
<span class="hljs-keyword">import</span> java.util.stream.Collectors;
<span class="hljs-keyword">import</span> org.springframework.http.HttpStatus;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;
<span class="hljs-keyword">import</span> org.springframework.web.server.ResponseStatusException;


<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserRepository userRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserService</span><span class="hljs-params">(<span class="hljs-keyword">final</span> UserRepository userRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.userRepository = userRepository;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;User&gt; <span class="hljs-title">findAll</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.findAll();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">get</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Long id)</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.findById(id)
                .orElseThrow(() -&gt; <span class="hljs-keyword">new</span> ResponseStatusException(HttpStatus.NOT_FOUND));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Long <span class="hljs-title">create</span><span class="hljs-params">(<span class="hljs-keyword">final</span> User user)</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.save(user).getId();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">update</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Long id, <span class="hljs-keyword">final</span> User user)</span> </span>{
        <span class="hljs-keyword">final</span> User existingUser = userRepository.findById(id)
                .orElseThrow(() -&gt; <span class="hljs-keyword">new</span> ResponseStatusException(HttpStatus.NOT_FOUND));

        userRepository.save(user);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">delete</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Long id)</span> </span>{
        userRepository.deleteById(id);
    }
}
</code></pre>
<p>We basically removed the DTO-related code from the <strong>UserService</strong> class and replaced the return types with <strong>User</strong>. Let's do the same for <strong>ReservationService</strong>.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.service;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.domain.Reservation;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.domain.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.ReservationRepository;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.UserRepository;
<span class="hljs-keyword">import</span> java.util.List;
<span class="hljs-keyword">import</span> java.util.stream.Collectors;
<span class="hljs-keyword">import</span> org.springframework.http.HttpStatus;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;
<span class="hljs-keyword">import</span> org.springframework.web.server.ResponseStatusException;


<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ReservationService</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> ReservationRepository reservationRepository;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserRepository userRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ReservationService</span><span class="hljs-params">(<span class="hljs-keyword">final</span> ReservationRepository reservationRepository,
            <span class="hljs-keyword">final</span> UserRepository userRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.reservationRepository = reservationRepository;
        <span class="hljs-keyword">this</span>.userRepository = userRepository;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Reservation&gt; <span class="hljs-title">findAll</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> reservationRepository.findAll();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Reservation <span class="hljs-title">get</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Long id)</span> </span>{
        <span class="hljs-keyword">return</span> reservationRepository.findById(id)
                .orElseThrow(() -&gt; <span class="hljs-keyword">new</span> ResponseStatusException(HttpStatus.NOT_FOUND));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Long <span class="hljs-title">create</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Reservation reservation)</span> </span>{
        <span class="hljs-keyword">return</span> reservationRepository.save(reservation).getId();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">update</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Long id, <span class="hljs-keyword">final</span> Reservation reservation)</span> </span>{
        <span class="hljs-keyword">final</span> Reservation existingReservation = reservationRepository.findById(id)
                .orElseThrow(() -&gt; <span class="hljs-keyword">new</span> ResponseStatusException(HttpStatus.NOT_FOUND));
        reservationRepository.save(reservation);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">delete</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Long id)</span> </span>{
        reservationRepository.deleteById(id);
    }

}
</code></pre>
<p>Let's also remove the config classes:</p>
<pre><code>rm -rf config
</code></pre><p>And rename the domain folder to model. If you are using an IDE, I strongly advise that you use your IDE's rename functionality to rename this folder since it will automatically rename the imports to match the new package name.</p>
<pre><code>mv domain model
</code></pre><p>Also, make sure that your model classes (<strong>User</strong> and <strong>Reservation</strong>) have the right package name after this operation. The first line of these two files should be:</p>
<pre><code>package com.amenity_reservation_system.model;
</code></pre><p>If it stays as domain package, you may have errors.</p>
<p>At this point, you should be able to compile and run the project without any problems.</p>
<h2 id="heading-how-to-create-the-controllers-and-view-files-to-show-data">How to Create the Controllers and View Files to Show Data</h2>
<p><strong>Thymeleaf</strong> is a template engine for Spring that allows us to create UIs and display our model data to the users. </p>
<p>We can access the Java objects inside the Thymeleaf template, and we can also use plain old HTML, CSS and JavaScript. If you know about JSPs, this is JSP on steroids.</p>
<p>Let's create some Thymeleaf templates that will not do anything but show the data for now. We will style them in the next section. We will also create the controllers that will return these views.</p>
<p>Before getting started with the Thymeleaf templates, we need to add a Maven dependency for Spring Boot Thymeleaf. Your dependencies should look like this in your <strong>pom.xml</strong> file:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">project</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://maven.apache.org/POM/4.0.0"</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema-instance"</span>
        <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">modelVersion</span>&gt;</span>4.0.0<span class="hljs-tag">&lt;/<span class="hljs-name">modelVersion</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">parent</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.4.4<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">relativePath</span> /&gt;</span><span class="hljs-comment">&lt;!-- lookup parent from repository --&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">parent</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>amenity-reservation-system<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>amenity-reservation-system<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">java.version</span>&gt;</span>14<span class="hljs-tag">&lt;/<span class="hljs-name">java.version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-validation<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-data-jpa<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.h2database<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>h2<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>runtime<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springdoc<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>springdoc-openapi-ui<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.5.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-devtools<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.projectlombok<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>lombok<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.18.20<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>provided<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>test<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-thymeleaf<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">build</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">build</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">project</span>&gt;</span>
</code></pre>
<p>You can just copy and paste the inner content of the dependencies tag. Now let's tell Maven to install the dependencies:</p>
<pre><code>mvn clean install
</code></pre><p>We are now ready to create our views. Let's create a directory under resources to hold our view template files like this:</p>
<pre><code>cd ../../../resources
mkdir templates
</code></pre><p>And create a view file:</p>
<pre><code>cd templates
touch index.html
</code></pre><p>Copy and paste the following snippet into it. This file will be our home page in the future.</p>
<pre><code>&lt;!DOCTYPE HTML&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Amenities Reservation App<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">th:rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">th:href</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
hello world!
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/jquery/3.0.0/jquery.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/popper.js/1.12.9-1/umd/popper.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/js/bootstrap.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></span>
</code></pre><p>We also need to create a controller that will return us this view so we can see it in the browser.</p>
<pre><code>cd ../java/com/amenity_reservation_system
mkdir controller &amp;&amp; cd controller
touch HomeController
</code></pre><p>Paste this code into the HomeController:</p>
<pre><code>package com.amenity_reservation_system.controller;

<span class="hljs-keyword">import</span> org.springframework.stereotype.Controller;
<span class="hljs-keyword">import</span> org.springframework.ui.Model;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.GetMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;


@Controller
public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomeController</span> </span>{

    @GetMapping(<span class="hljs-string">"/"</span>)
    public <span class="hljs-built_in">String</span> index(Model model) {

        <span class="hljs-keyword">return</span> <span class="hljs-string">"index"</span>;
    }
}
</code></pre><p>Notice how we annotate our method with <strong>@Controller</strong> instead of <strong>@RestController</strong> this time. The @RestController annotation implies that the controller will return a REST response whereas a <strong>@Controller</strong> can return pre-rendered (SSR) views/HTML.</p>
<p>When a request arrives in our application, Spring will automatically run this controller method. Then it will find the <strong>index.html</strong> file we previously created under the resources and send that file to the client.</p>
<p>Let's confirm that it is working by sending a request to our application. Do not forget to restart first, then send this request:</p>
<pre><code>GET localhost:<span class="hljs-number">8080</span>
</code></pre><p>You should be able to see the Hello World message on the browser.</p>
<h2 id="heading-how-to-define-different-types-of-amenities">How to Define Different Types of Amenities</h2>
<p>We have the <strong>Reservation</strong> class but we have not created a way to specify which type of amenity is getting reserved (the pool, sauna, or gym).</p>
<p>There are multiple ways to do this. One of them would be to create an entity called Amenity to store shared data among entities. Then we'd create <strong>PoolAmenity</strong>, <strong>SaunaAmenity</strong>, and <strong>GymAmenity</strong> classes which would then extend the Amenity class. </p>
<p>This is a nice and extendable solution but it feels a bit like overkill for our simple application, since we do not have much data specific to the amenity type. We are only going to have a capacity for each amenity type.</p>
<p>To keep things simple and not to bother ourselves with table inheritance and other complicated stuff, let's just create an enum to indicate the amenity type as a String and let each reservation have one of these.</p>
<p>Let's switch to the model directory from the controller directory and create the enum for <strong>AmenityType</strong>:</p>
<pre><code>cd ../model
touch AmenityType.java
</code></pre><pre><code>public enum AmenityType {
    POOL(<span class="hljs-string">"POOL"</span>), SAUNA(<span class="hljs-string">"SAUNA"</span>), GYM(<span class="hljs-string">"GYM"</span>);

    private final <span class="hljs-built_in">String</span> name;

    private AmenityType(<span class="hljs-built_in">String</span> value) {
        name = value;
    }

    @Override
    public <span class="hljs-built_in">String</span> toString() {
        <span class="hljs-keyword">return</span> name;
    }
}
</code></pre><p>In this enum, we define a name variable to hold the name of the enum and create a private constructor to only allow a limited set of types. Notice that the type declarations call the constructor from within the class with their name values.</p>
<p>Now we need to modify the Reservation class to hold a reference to <strong>AmenityType</strong>:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Enumerated(EnumType.STRING)</span>
<span class="hljs-meta">@Column(nullable = false)</span>
<span class="hljs-keyword">private</span> AmenityType amenityType;
</code></pre>
<p>We use the <strong>@Enumerated</strong> annotation to describe how we want to store the enum in our database. We'll also make it not nullable because every <strong>Reservation</strong> must have an <strong>AmenityType</strong>.</p>
<h2 id="heading-how-to-show-a-users-reservations">How to Show a User's Reservations</h2>
<p>What is the most crucial feature for our app? Creating reservations and showing a user's reservations. </p>
<p>We do not have a way to authenticate users yet, so we can't really ask the user to login and then show their reservations. But we still want to implement and test the functionality to reserve an amenity and show reservations.</p>
<p>For that purpose, we can ask Spring to put some initial data into our database whenever the application runs. Then we can query that data to test if our queries actually work. We can then proceed to call these services from our <strong>Views</strong> and add authentication to our application in the next sections.</p>
<p>We will use a <strong>CommandLineRunner</strong> bean to run the initial code. Whenever Spring Container finds a bean of type CommandLineRunner it will run the code inside it. Before that step, let's add a few methods to our model classes to make object creation easier and less verbose.</p>
<p>Take a look at the model classes' annotations and you should see annotations like <strong>@Getter</strong> and <strong>@Setter</strong>. These are <strong>Lombok</strong> annotations.</p>
<p>Lombok is an annotation processor we can use to make our coding experience better by letting it generate code for us. When we annotate a class with <strong>@Getter</strong> and <strong>@Setter</strong>, it generates the getters and setters for each field of this class. </p>
<p>Spring uses getter and setter methods for many trivial operations behind the scenes so these are almost always required. And creating them for every entity easily becomes a hassle without the help of Lombok. </p>
<p>Lombok can do more than that though. We will also add the following annotations to our <strong>Reservation</strong> and <strong>User</strong> classes:</p>
<pre><code>@Builder
@NoArgsConstructor
@AllArgsConstructor
</code></pre><p>With these annotations, Lombok implements the builder creational pattern for this class and also creates 2 constructors: One with no arguments (default constructor) and another one with all arguments. I think it is awesome that we can do so much by adding just a few annotations. </p>
<p>We are now ready to add some initial data. Go to your main class (<strong>AmenityReservationSystemApplication.java</strong>) and add this method:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.AmenityType;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.Reservation;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.ReservationRepository;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.UserRepository;
<span class="hljs-keyword">import</span> org.springframework.boot.CommandLineRunner;
<span class="hljs-keyword">import</span> org.springframework.boot.SpringApplication;
<span class="hljs-keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;

<span class="hljs-keyword">import</span> java.text.DateFormat;
<span class="hljs-keyword">import</span> java.text.SimpleDateFormat;
<span class="hljs-keyword">import</span> java.time.LocalDate;
<span class="hljs-keyword">import</span> java.time.LocalTime;
<span class="hljs-keyword">import</span> java.time.ZoneId;
<span class="hljs-keyword">import</span> java.util.Date;


<span class="hljs-meta">@SpringBootApplication</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AmenityReservationSystemApplication</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        SpringApplication.run(AmenityReservationSystemApplication.class, args);
    }

    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> CommandLineRunner <span class="hljs-title">loadData</span><span class="hljs-params">(UserRepository userRepository,
                                      ReservationRepository reservationRepository)</span> </span>{
        <span class="hljs-keyword">return</span> (args) -&gt; {
            User user = userRepository.save(<span class="hljs-keyword">new</span> User());
            DateFormat dateFormat = <span class="hljs-keyword">new</span> SimpleDateFormat(<span class="hljs-string">"dd/MM/yyyy HH:mm:ss"</span>);
            Date date = <span class="hljs-keyword">new</span> Date();
            LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            Reservation reservation = Reservation.builder()
                    .reservationDate(localDate)
                    .startTime(LocalTime.of(<span class="hljs-number">12</span>, <span class="hljs-number">00</span>))
                    .endTime(LocalTime.of(<span class="hljs-number">13</span>, <span class="hljs-number">00</span>))
                    .user(user)
                    .amenityType(AmenityType.POOL)
                    .build();

            reservationRepository.save(reservation);
        };
    }
}
</code></pre>
<p>If you get an error about saving operations such as "Inferred type 'S' for parameter ... does not match", it's because we renamed the domain directory to model. Go to the repository classes and fix the paths of imports to <strong>model.User</strong> and <strong>model.Reservation</strong>.</p>
<p>Notice how we used the <strong>builder pattern</strong> to create the reservation object easily. When the object creation gets complex and a constructor requires so many parameters, it's easy to forget the order of parameters or just mess up the order. </p>
<p>Without the builder pattern, we would either need to call a constructor with so many parameters or call the default constructor and write #properties code to call the setters.</p>
<p>After you are done, run your application again to insert the initial data and connect to <strong>H2 console</strong> as we learned before to confirm that our date is indeed inserted. If you do not have any errors, you should be able to see that the user and the reservation are inserted successfully.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-9-1024x325.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We have inserted a reservation to be able to test the functionality to list the reservations but our views currently do not have a way to show the reservations and add reservations. We need to create the UI for that. </p>
<p>We do not have an authentication or sign-up mechanism yet, so act like the user with ID 10001 is logged in. Later we will improve on that by dynamically checking who is logged in and showing a different page if the user is not logged in.</p>
<h3 id="heading-how-to-create-views-with-thymeleaf">How to Create Views with Thymeleaf</h3>
<p>Let's get started by creating a simple home page and a navbar for ourselves. We will use Thymeleaf fragments for the navbar code. </p>
<p>Thymeleaf fragments allow us to create reusable component-like structures similar to React/Vue components if you are familiar with them. Let's create a folder for our fragments under templates and call it fragments.</p>
<pre><code>mkdir fragments
touch nav.html
</code></pre><p>We will put our navbar inside <strong>nav.html</strong> file. Copy and paste the following code:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">th:fragment</span>=<span class="hljs-string">"nav"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar navbar-expand navbar-dark bg-primary"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-nav w-100"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand text-color"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>Amenities Reservation System<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>It is not doing much in its current state, but we may add a login button or some links in the future. </p>
<p>Now let's create a simple home page that will serve the users that are not logged in. We will have our navbar fragment on top and have a login button to ask the user to log in before using the app.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">HTML</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Amenities Reservation App<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">th:rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">th:href</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">th:insert</span>=<span class="hljs-string">"fragments/nav :: nav"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-light"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"background-image: url('https://source.unsplash.com/1920x1080/?nature');
                                   position: absolute;
                                   left: 0;
                                   top: 0;
                                   opacity: 0.6;
                                   z-index: -1;
                                   min-height: 100vh;
                                   min-width: 100vw;"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"padding-top: 20vh; display: flex; flex-direction: column; align-items: center;"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"display-3"</span>&gt;</span>Reservation management made easy.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"lead"</span>&gt;</span>Lorem, ipsum dolor sit amet consectetur adipisicing elit.
            Numquam in quia natus magnam ducimus quas molestias velit vero maiores.
            Eaque sunt laudantium voluptas. Fugiat molestiae ipsa delectus iusto vel quod.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/reservations"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-success btn-lg my-2"</span>&gt;</span>Reserve an Amenity<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/jquery/3.0.0/jquery.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/popper.js/1.12.9-1/umd/popper.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/js/bootstrap.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>It should look like this:</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/05/image-1024x533.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We will create another page to show if the user is already logged in. To keep it simple we will also treat it as a home page, and if the user is logged in, they will be able to see their reservations on the home page. </p>
<p>It is also good in terms of practicality for the user since it decreases the steps they need to take to view their reservations. </p>
<p>We will now create this page as another endpoint. But after adding the login to our application we will show this previous page if the user is not logged in and the next page if they are logged in, dynamically.</p>
<p>Before we start working on our new page, let's add another mapping to <strong>HomeController</strong> that will return our new page. We will later merge these two controllers:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.domain.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.service.UserService;
<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Controller;
<span class="hljs-keyword">import</span> org.springframework.ui.Model;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.GetMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;


<span class="hljs-meta">@Controller</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomeController</span> </span>{

    <span class="hljs-keyword">final</span> UserService userService;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">HomeController</span><span class="hljs-params">(UserService userService)</span> </span>{
        <span class="hljs-keyword">this</span>.userService = userService;
    }

    <span class="hljs-meta">@GetMapping("/")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">index</span><span class="hljs-params">(Model model)</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"index"</span>;
    }

    <span class="hljs-meta">@GetMapping("/reservations")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">reservations</span><span class="hljs-params">(Model model)</span> </span>{
        User user = userService.get(<span class="hljs-number">10000L</span>);
        model.addAttribute(<span class="hljs-string">"user"</span>, user);

        <span class="hljs-keyword">return</span> <span class="hljs-string">"reservations"</span>;
    }
}
</code></pre>
<p>If a request is received at "/reservations", this code will call our userService and ask for the user with id 10000L. Then it will add this user to the <strong>Model</strong>. </p>
<p>View will access this model and present the information about this user's reservations. We have also autowired the user service to use it.</p>
<p>Navigate to the templates folder if you are not already there and create another file called "reservations.html":</p>
<pre><code>touch reservations.html
</code></pre><p>Copy and paste the following code:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">HTML</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Reservations<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">th:rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">th:href</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">th:insert</span>=<span class="hljs-string">"fragments/nav :: nav"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"padding-top: 10vh; display: flex; flex-direction: column; align-items: center;"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Welcome <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">" ${user.getFullName()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Amenity<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Date<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Start Time<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>End Time<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">th:each</span>=<span class="hljs-string">"reservation : ${user.getReservations()}"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getAmenityType()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getReservationDate()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getStartTime()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getEndTime()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/jquery/3.0.0/jquery.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/popper.js/1.12.9-1/umd/popper.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/js/bootstrap.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>In this <strong>Thymeleaf</strong> template, we import <strong>Bootstrap</strong> and <strong>Thymeleaf</strong> as before and we access the user variable that was added to the model in our controller by using the ${} syntax. </p>
<p>To access data, Thymeleaf uses the getter methods of the object and we can print that information by using the <code>th:text</code> attribute. Thymeleaf also supports loops. In the <code>tbody</code> we have a <code>th:each</code> loop, which we can think of as a foreach loop over a user's reservations. So we loop over the reservations and display them in a table.</p>
<p>You may have an error that says something like "Could not initialize proxy, ... lazy loading". This is caused by the view trying to access the reservations object while it does not yet exist. To get rid of that we can modify the following lines in <strong>User.java</strong>:</p>
<pre><code class="lang-java">    <span class="hljs-meta">@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)</span>
    <span class="hljs-keyword">private</span> Set&lt;Reservation&gt; reservations = <span class="hljs-keyword">new</span> HashSet&lt;&gt;();
</code></pre>
<p>We add a statement to tell Java to fetch this object eagerly.</p>
<p>Now you should be able to view the reservations page:</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/05/image-1-1024x488.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-create-a-reservation">How to Create a Reservation</h3>
<p>We also need a way to create new reservations, so let's build that mechanism for our pre-created user like we did with showing the reservations. Then we can alter it to show the reservations of the currently logged-in user.</p>
<p>Before going forward, we need to update the date formats in our <strong>Reservation.java</strong> file to avoid any format mismatch problems. Make sure your formats for these variables are the same:</p>
<pre><code class="lang-java">    <span class="hljs-meta">@DateTimeFormat(pattern = "yyyy-MM-dd")</span>
    <span class="hljs-meta">@Column(nullable = false)</span>
    <span class="hljs-keyword">private</span> LocalDate reservationDate;

    <span class="hljs-meta">@DateTimeFormat(pattern = "HH:mm")</span>
    <span class="hljs-meta">@Column</span>
    <span class="hljs-keyword">private</span> LocalTime startTime;

    <span class="hljs-meta">@DateTimeFormat(pattern = "HH:mm")</span>
    <span class="hljs-meta">@Column</span>
    <span class="hljs-keyword">private</span> LocalTime endTime;
</code></pre>
<p>In the previous section, we created our <strong>reservations</strong> controller. Now we need to modify it a little bit to add another attribute to the model. </p>
<p>We learned how we can access the objects that are added to the model by using the ${} syntax. Now we are going to do something similar:</p>
<pre><code class="lang-java"><span class="hljs-meta">@GetMapping("/reservations")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">reservations</span><span class="hljs-params">(Model model, HttpSession session)</span> </span>{
        User user = userService.get(<span class="hljs-number">10000L</span>);
        session.setAttribute(<span class="hljs-string">"user"</span>, user);
        Reservation reservation = <span class="hljs-keyword">new</span> Reservation();
        model.addAttribute(<span class="hljs-string">"reservation"</span>, reservation);

        <span class="hljs-keyword">return</span> <span class="hljs-string">"reservations"</span>;
    }
</code></pre>
<p>We are updating our reservations controller to move the user object to the session because we want that to be accessible from another controller method and not only from a template. </p>
<p>Think of it like this: once a user is logged in, this user's account will be responsible for every action that's taken after that point. You can think of Session as a global variable that is accessible from everywhere. </p>
<p>We also create a <strong>Reservation</strong> object and add it to the model. <strong>Thymeleaf</strong> will access this newly created object in our view template using this model and it will call the setters to set its fields.</p>
<p>Now let's create the view for creating the reservation. We are going to use <a target="_blank" href="https://getbootstrap.com/docs/4.0/components/modal/">Bootstrap Modal</a> to display a form modal after a button is clicked.</p>
<p>We can first handle the code to call the modal we are going to create in the next step, move to the reservations.html file, and add this snippet after the table tag we added before:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
  <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
  <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>
  <span class="hljs-attr">data-toggle</span>=<span class="hljs-string">"modal"</span>
  <span class="hljs-attr">data-target</span>=<span class="hljs-string">"#createReservationModal"</span>
&gt;</span>
  Create Reservation
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Modal --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>
  <span class="hljs-attr">th:insert</span>=<span class="hljs-string">"fragments/modal :: modal"</span>
  <span class="hljs-attr">th:with</span>=<span class="hljs-string">"reservation=${reservation}"</span>
&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>This button will trigger our modal. In the div, we insert this modal that we are going to create and we use the <code>th:with</code> tag to pass the reservation object that was put in the model in our controller. If we do not do this, the fragment will not know about the reservation object.</p>
<p>We also need to change how we access the user to print their name because we no longer store it in the modal but in session:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Welcome <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">" ${session.user.getFullName()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
</code></pre>
<p>So your final <strong>reservations.html</strong> file should be looking like this:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Reservations<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
      <span class="hljs-attr">th:rel</span>=<span class="hljs-string">"stylesheet"</span>
      <span class="hljs-attr">th:href</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "</span>
    /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">th:insert</span>=<span class="hljs-string">"fragments/nav :: nav"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>
        <span class="hljs-attr">style</span>=<span class="hljs-string">"padding-top: 10vh; display: flex; flex-direction: column; align-items: center;"</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Welcome <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">" ${session.user.getFullName()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Amenity<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Date<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Start Time<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>End Time<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">th:each</span>=<span class="hljs-string">"reservation : ${session.user.getReservations()}"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getAmenityType()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getReservationDate()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getStartTime()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getEndTime()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>
          <span class="hljs-attr">data-toggle</span>=<span class="hljs-string">"modal"</span>
          <span class="hljs-attr">data-target</span>=<span class="hljs-string">"#createReservationModal"</span>
        &gt;</span>
          Create Reservation
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

        <span class="hljs-comment">&lt;!-- Modal --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">th:insert</span>=<span class="hljs-string">"fragments/modal :: modal"</span>
          <span class="hljs-attr">th:with</span>=<span class="hljs-string">"reservation=${reservation}"</span>
        &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/jquery/3.0.0/jquery.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/popper.js/1.12.9-1/umd/popper.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/js/bootstrap.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>We are now ready to create the modal fragment. We can create a fragment for the modal just like we did with the nav:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">pwd</span>
/src/main/resources
<span class="hljs-built_in">cd</span> templates/fragments
touch modal.html
</code></pre>
<p>And paste in the following template code:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
      <span class="hljs-attr">class</span>=<span class="hljs-string">"modal fade"</span>
      <span class="hljs-attr">th:fragment</span>=<span class="hljs-string">"modal"</span>
      <span class="hljs-attr">id</span>=<span class="hljs-string">"createReservationModal"</span>
      <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"-1"</span>
      <span class="hljs-attr">role</span>=<span class="hljs-string">"dialog"</span>
      <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"createReservationModalTitle"</span>
      <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-dialog"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"document"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-content"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-header"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-title"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"createReservationModalTitle"</span>&gt;</span>
              Create Reservation
            <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
              <span class="hljs-attr">class</span>=<span class="hljs-string">"close"</span>
              <span class="hljs-attr">data-dismiss</span>=<span class="hljs-string">"modal"</span>
              <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Close"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span><span class="hljs-symbol">&amp;times;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-body"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">form</span>
              <span class="hljs-attr">action</span>=<span class="hljs-string">"#"</span>
              <span class="hljs-attr">th:action</span>=<span class="hljs-string">"@{/reservations-submit}"</span>
              <span class="hljs-attr">th:object</span>=<span class="hljs-string">"${reservation}"</span>
              <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group row"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"type-select"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-2 col-form-label"</span>
                  &gt;</span>Amenity<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>
                &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-10"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">select</span>
                    <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"type-select"</span>
                    <span class="hljs-attr">th:field</span>=<span class="hljs-string">"*{amenityType}"</span>
                  &gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"POOL"</span>&gt;</span>POOL<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"SAUNA"</span>&gt;</span>SAUNA<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"GYM"</span>&gt;</span>GYM<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group row"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"start-date"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-2 col-form-label"</span>
                  &gt;</span>Date<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>
                &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-10"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"start-date"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"trip-start"</span>
                    <span class="hljs-attr">th:field</span>=<span class="hljs-string">"*{reservationDate}"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">"2018-07-22"</span>
                    <span class="hljs-attr">min</span>=<span class="hljs-string">"2021-05-01"</span>
                    <span class="hljs-attr">max</span>=<span class="hljs-string">"2021-12-31"</span>
                  /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group row"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"start-time"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-2 col-form-label"</span>
                  &gt;</span>From<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>
                &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-10"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"time"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"start-time"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"time"</span>
                    <span class="hljs-attr">th:field</span>=<span class="hljs-string">"*{startTime}"</span>
                    <span class="hljs-attr">min</span>=<span class="hljs-string">"08:00"</span>
                    <span class="hljs-attr">max</span>=<span class="hljs-string">"19:30"</span>
                    <span class="hljs-attr">required</span>
                  /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group row"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"end-time"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-2 col-form-label"</span>&gt;</span>To<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-10"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"time"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"end-time"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"time"</span>
                    <span class="hljs-attr">th:field</span>=<span class="hljs-string">"*{endTime}"</span>
                    <span class="hljs-attr">min</span>=<span class="hljs-string">"08:30"</span>
                    <span class="hljs-attr">max</span>=<span class="hljs-string">"20:00"</span>
                    <span class="hljs-attr">required</span>
                  /&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">small</span>&gt;</span>Amenities are available from 8 am to 8 pm<span class="hljs-tag">&lt;/<span class="hljs-name">small</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-footer"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
                  <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-secondary"</span>
                  <span class="hljs-attr">data-dismiss</span>=<span class="hljs-string">"modal"</span>
                &gt;</span>
                  Close
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Submit"</span>&gt;</span>
                  Save changes
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>There are a few important points that you need to take note of here.</p>
<p>Notice how we access the reservation object in the form tag:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>
  <span class="hljs-attr">action</span>=<span class="hljs-string">"#"</span>
  <span class="hljs-attr">th:action</span>=<span class="hljs-string">"@{/reservations-submit}"</span>
  <span class="hljs-attr">th:object</span>=<span class="hljs-string">"${reservation}"</span>
  <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span>
&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>The <strong><code>th:object</code></strong> tag associates this form with the reservation object that we have created before. <strong><code>th:action</code></strong> determines where this object will be sent when the form is submitted, and our submission method will be <strong>POST</strong>. We will create this controller with the mapping to <strong>/reservations-submit</strong> after this step.</p>
<p>We use the <strong><code>th:field</code></strong> tag to bind the inputs to our reservation object's fields. Thymeleaf calls the setters of the reservation object whenever that input field's value changes.</p>
<p>Now let's create the controller that will receive this form. Go to <strong>HomeController</strong> and add the following method:</p>
<pre><code class="lang-java"><span class="hljs-meta">@PostMapping("/reservations-submit")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">reservationsSubmit</span><span class="hljs-params">(<span class="hljs-meta">@ModelAttribute</span> Reservation reservation,
                                     <span class="hljs-meta">@SessionAttribute("user")</span> User user)</span> </span>{

        <span class="hljs-comment">// Save to DB after updating</span>
        <span class="hljs-keyword">assert</span> user != <span class="hljs-keyword">null</span>;
        reservation.setUser(user);
        reservationService.create(reservation);
        Set&lt;Reservation&gt; userReservations = user.getReservations();
        userReservations.add(reservation);
        user.setReservations(userReservations);
        userService.update(user.getId(), user);
        <span class="hljs-keyword">return</span> <span class="hljs-string">"redirect:/reservations"</span>;
    }
</code></pre>
<p>And also add the <strong>ReservationService</strong> to our dependencies:</p>
<pre><code class="lang-java">    <span class="hljs-keyword">final</span> UserService userService;
    <span class="hljs-keyword">final</span> ReservationService reservationService;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">HomeController</span><span class="hljs-params">(UserService userService, ReservationService reservationService)</span> </span>{
        <span class="hljs-keyword">this</span>.userService = userService;
        <span class="hljs-keyword">this</span>.reservationService = reservationService;
    }
</code></pre>
<p>After our modal fragment posts the reservation object to this controller, that object will be bound with the <strong>@ModelAttribute</strong> annotation. We also need the user so we use <strong>@SessionAttribute</strong> to get a reference to it.</p>
<p>The fields of the reservation object should be all set by the form. Now we just need to save it to the database. </p>
<p>We do that by calling the <strong>create</strong> method. Then we add the new Reservation to the user's list of reservations and update the user to reflect these changes. We then redirect the user to the reservations page to show the updated reservations list.</p>
<p>Your reservations page should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/LFJE0Ad---Imgur.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And when you click the button, the create reservation modal should pop up.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/image-42.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-add-authentication-and-authorization-to-the-app">How to Add Authentication and Authorization to the App</h2>
<p>We will use <strong>Spring Security</strong> to add authentication and authorization to our application. We want to make sure that nobody can see each other's reservations and that the users must be logged in to create reservations. </p>
<p>If you want to learn more about it, I wrote an article that provides an overview of <a target="_blank" href="https://auth0.com/blog/spring-security-overview/">Spring Security</a>. </p>
<p>We will keep it simple and mostly use the defaults because this is a difficult topic on its own. If you want to learn how to properly set up Spring Security Auth, you can check out my <a target="_blank" href="https://www.freecodecamp.org/news/how-to-setup-jwt-authorization-and-authentication-in-spring/">article</a> on that. </p>
<p>We need to add "Spring Security" and "Thymeleaf Spring Security" to our dependencies, so open your pom.xml and add the following to your list of dependencies:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-security<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.thymeleaf.extras<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>thymeleaf-extras-springsecurity5<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.0.4.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<p>Now, by default, Spring Security makes all the endpoints protected, so we need to configure it to allow viewing the home page. </p>
<p>Let's create a config folder to contain our <strong>WebSecurityConfig</strong> file. Assuming you are on the root folder:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /src/main/java/com/amenity_reservation_system
mkdir config &amp;&amp; <span class="hljs-built_in">cd</span> config
touch WebSecurityConfig.java
</code></pre>
<p>This should be the content of your config file:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.config;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.service.UserDetailsServiceImpl;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;
<span class="hljs-keyword">import</span> org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
<span class="hljs-keyword">import</span> org.springframework.security.config.annotation.web.builders.HttpSecurity;
<span class="hljs-keyword">import</span> org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
<span class="hljs-keyword">import</span> org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
<span class="hljs-keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

<span class="hljs-meta">@Configuration</span>
<span class="hljs-meta">@EnableWebSecurity</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebSecurityConfig</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">WebSecurityConfigurerAdapter</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserDetailsServiceImpl userDetailsService;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> BCryptPasswordEncoder bCryptPasswordEncoder;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">WebSecurityConfig</span><span class="hljs-params">(UserDetailsServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder)</span> </span>{
        <span class="hljs-keyword">this</span>.userDetailsService = userDetailsService;
        <span class="hljs-keyword">this</span>.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception </span>{
        http
                .authorizeRequests()
                .antMatchers(<span class="hljs-string">"/"</span>, <span class="hljs-string">"/webjars/**"</span>).permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .permitAll()
                .and()
                .logout()
                .permitAll()
                .logoutSuccessUrl(<span class="hljs-string">"/"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(AuthenticationManagerBuilder auth)</span> <span class="hljs-keyword">throws</span> Exception </span>{
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

}
</code></pre>
<p>I will not go into the details, but here's a summary of what happened here: </p>
<ul>
<li>we configured Spring Security to permit all requests made to the home page ("/")</li>
<li>we configured our styles ("/webjars/**")</li>
<li>we asked it to provide us with login and logout forms </li>
<li>and we asked it to permit the requests to them as well and redirect to the home page after logout is successful</li>
</ul>
<p>Isn't it amazing what you can achieve with just a few statements?</p>
<p>We also configured our <strong>AuthenticationManagerBuilder</strong> to use bCryptPasswordEncoder and userDetailsService. But wait, we don't have neither of them yet, and your IDE may already be complaining about that. So let's create them.</p>
<p>Before we go on, it may be a good idea to add <strong>username</strong> and passwordHash fields to our <strong>User</strong> class. We'll use them to authenticate the user instead of using their full name. Then we'll add it to the constructor.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.model;

<span class="hljs-keyword">import</span> java.time.OffsetDateTime;
<span class="hljs-keyword">import</span> java.util.HashSet;
<span class="hljs-keyword">import</span> java.util.Set;
<span class="hljs-keyword">import</span> javax.persistence.*;

<span class="hljs-keyword">import</span> lombok.AllArgsConstructor;
<span class="hljs-keyword">import</span> lombok.Getter;
<span class="hljs-keyword">import</span> lombok.NoArgsConstructor;
<span class="hljs-keyword">import</span> lombok.Setter;


<span class="hljs-meta">@Entity</span>
<span class="hljs-meta">@Getter</span>
<span class="hljs-meta">@Setter</span>
<span class="hljs-meta">@AllArgsConstructor</span>
<span class="hljs-meta">@NoArgsConstructor</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{

    <span class="hljs-meta">@Id</span>
    <span class="hljs-meta">@Column(nullable = false, updatable = false)</span>
    <span class="hljs-meta">@SequenceGenerator(
            name = "primary_sequence",
            sequenceName = "primary_sequence",
            allocationSize = 1,
            initialValue = 10000
    )</span>
    <span class="hljs-meta">@GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "primary_sequence"
    )</span>
    <span class="hljs-keyword">private</span> Long id;

    <span class="hljs-meta">@Column(nullable = false, unique = true)</span>
    <span class="hljs-keyword">private</span> String fullName;

    <span class="hljs-meta">@Column(nullable = false, unique = true)</span>
    <span class="hljs-keyword">private</span> String username;

    <span class="hljs-meta">@Column</span>
    <span class="hljs-keyword">private</span> String passwordHash;

    <span class="hljs-meta">@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)</span>
    <span class="hljs-keyword">private</span> Set&lt;Reservation&gt; reservations = <span class="hljs-keyword">new</span> HashSet&lt;&gt;();

    <span class="hljs-meta">@Column(nullable = false, updatable = false)</span>
    <span class="hljs-keyword">private</span> OffsetDateTime dateCreated;

    <span class="hljs-meta">@Column(nullable = false)</span>
    <span class="hljs-keyword">private</span> OffsetDateTime lastUpdated;

    <span class="hljs-meta">@PrePersist</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">prePersist</span><span class="hljs-params">()</span> </span>{
        dateCreated = OffsetDateTime.now();
        lastUpdated = dateCreated;
    }

    <span class="hljs-meta">@PreUpdate</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preUpdate</span><span class="hljs-params">()</span> </span>{
        lastUpdated = OffsetDateTime.now();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">User</span><span class="hljs-params">(String fullName, String username, String passwordHash)</span> </span>{
        <span class="hljs-keyword">this</span>.fullName = fullName;
        <span class="hljs-keyword">this</span>.username = username;
        <span class="hljs-keyword">this</span>.passwordHash = passwordHash;
    }
}
</code></pre>
<p>Create a file called <strong>UserDetailsServiceImpl</strong> under the services folder:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> service
touch UserDetailsServiceImpl.java
</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.service;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.UserRepository;
<span class="hljs-keyword">import</span> org.springframework.security.core.userdetails.UserDetails;
<span class="hljs-keyword">import</span> org.springframework.security.core.userdetails.UserDetailsService;
<span class="hljs-keyword">import</span> org.springframework.security.core.userdetails.UsernameNotFoundException;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;

<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserDetailsServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">UserDetailsService</span> </span>{

    <span class="hljs-keyword">private</span> UserRepository userRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserDetailsServiceImpl</span><span class="hljs-params">(UserRepository userRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.userRepository = userRepository;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> UserDetails <span class="hljs-title">loadUserByUsername</span><span class="hljs-params">(String username)</span> <span class="hljs-keyword">throws</span> UsernameNotFoundException </span>{
        <span class="hljs-keyword">final</span> User user = userRepository.findUserByUsername(username);

        <span class="hljs-keyword">if</span> (user == <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UsernameNotFoundException(username);
        }

        UserDetails userDetails = org.springframework.security.core.userdetails.User.withUsername(
                user.getUsername()).password(user.getPwHash()).roles(<span class="hljs-string">"USER"</span>).build();

        <span class="hljs-keyword">return</span> userDetails;
    }
}
</code></pre>
<p>This basically tells Spring Security that we want to use the <strong>User</strong> entity we created earlier by getting the <strong>User</strong> object from our database and using the JPA method on our repository. But again, we do not have the <strong>findUserByUsername</strong> method on our <strong>UserRepository</strong>. You can try fixing this on your own as a challenge, it is really simple.</p>
<p>Remember, we do not need to write queries. It is sufficient to provide the signature and let JPA do the work.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.repos;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.User;
<span class="hljs-keyword">import</span> org.springframework.data.jpa.repository.JpaRepository;


<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserRepository</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JpaRepository</span>&lt;<span class="hljs-title">User</span>, <span class="hljs-title">Long</span>&gt; </span>{

    <span class="hljs-function">User <span class="hljs-title">findUserByUsername</span><span class="hljs-params">(String username)</span></span>;
}
</code></pre>
<p>We also need a <strong>BCryptPasswordEncoder</strong> bean to satisfy that dependency in <strong>WebSecurityConfig</strong> and to make it work. Let's modify our main class to add a bean and change the constructor parameters to give our predefined <strong>User</strong> a username.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.AmenityType;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.Reservation;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.ReservationRepository;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.UserRepository;
<span class="hljs-keyword">import</span> org.springframework.boot.CommandLineRunner;
<span class="hljs-keyword">import</span> org.springframework.boot.SpringApplication;
<span class="hljs-keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
<span class="hljs-keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

<span class="hljs-keyword">import</span> java.text.DateFormat;
<span class="hljs-keyword">import</span> java.text.SimpleDateFormat;
<span class="hljs-keyword">import</span> java.time.LocalDate;
<span class="hljs-keyword">import</span> java.time.LocalTime;
<span class="hljs-keyword">import</span> java.time.ZoneId;
<span class="hljs-keyword">import</span> java.util.Date;


<span class="hljs-meta">@SpringBootApplication</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AmenityReservationSystemApplication</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        SpringApplication.run(AmenityReservationSystemApplication.class, args);
    }


    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> CommandLineRunner <span class="hljs-title">loadData</span><span class="hljs-params">(UserRepository userRepository,
                                      ReservationRepository reservationRepository)</span> </span>{
    <span class="hljs-keyword">return</span> (args) -&gt; {
      User user =
          userRepository.save(
              <span class="hljs-keyword">new</span> User(<span class="hljs-string">"Yigit Kemal Erinc"</span>,
                      <span class="hljs-string">"yigiterinc"</span>,
                      bCryptPasswordEncoder().encode(<span class="hljs-string">"12345"</span>)));
      DateFormat dateFormat = <span class="hljs-keyword">new</span> SimpleDateFormat(<span class="hljs-string">"dd/MM/yyyy HH:mm:ss"</span>);
      Date date = <span class="hljs-keyword">new</span> Date();
      LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
      Reservation reservation =
          Reservation.builder()
              .reservationDate(localDate)
              .startTime(LocalTime.of(<span class="hljs-number">12</span>, <span class="hljs-number">00</span>))
              .endTime(LocalTime.of(<span class="hljs-number">13</span>, <span class="hljs-number">00</span>))
              .user(user)
              .amenityType(AmenityType.POOL)
              .build();

      reservationRepository.save(reservation);
    };
    }

    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> BCryptPasswordEncoder <span class="hljs-title">bCryptPasswordEncoder</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BCryptPasswordEncoder();
    }
}
</code></pre>
<p>Your application should be ready to compile now and it should already be redirecting you to the login page if you send a request to "/reservations". </p>
<p>It would be nice to have buttons for log-in and log-out on the navbar, and we want to show login if user is not authenticated and logout otherwise. We can do it this way in <strong>nav.html</strong>:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span> <span class="hljs-attr">xmlns:sec</span>=<span class="hljs-string">"http://www.w3.org/1999/xhtml"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">th:fragment</span>=<span class="hljs-string">"nav"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar navbar-expand navbar-dark bg-primary"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-nav w-100"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand text-color"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>Amenities Reservation System<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">sec:authorize</span>=<span class="hljs-string">"isAnonymous()"</span>
           <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand text-color"</span> <span class="hljs-attr">th:href</span>=<span class="hljs-string">"@{/login}"</span>&gt;</span>Log in<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">sec:authorize</span>=<span class="hljs-string">"isAuthenticated()"</span>
               <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand text-color"</span> <span class="hljs-attr">th:href</span>=<span class="hljs-string">"@{/logout}"</span>&gt;</span>Log out<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The log in link should now be visible on the navbar.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screen-Shot-2021-09-10-at-02.19.09.png" alt="Image" width="600" height="400" loading="lazy">
<em>Home page when you are not logged in</em></p>
<h2 id="heading-how-to-show-a-logged-in-users-reservations">How to Show a Logged-in User's Reservations</h2>
<p>Our Reservations page is currently displaying the reservations of one hard-coded user and not the reservations of the logged-in user. </p>
<pre><code class="lang-java">    <span class="hljs-meta">@GetMapping("/reservations")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">reservations</span><span class="hljs-params">(Model model, HttpSession session)</span> </span>{
        User user = userService.get(<span class="hljs-number">10000L</span>);
        session.setAttribute(<span class="hljs-string">"user"</span>, user);
        Reservation reservation = <span class="hljs-keyword">new</span> Reservation();
        model.addAttribute(<span class="hljs-string">"reservation"</span>, reservation);

        <span class="hljs-keyword">return</span> <span class="hljs-string">"reservations"</span>;
    }
</code></pre>
<p>We need to show the reservations of the currently logged-in user. To achieve that, we should use some Spring Security.</p>
<p>Go to the <strong>HomeController</strong> (I know, that name is a bit problematic right now) class and change it with the following code:</p>
<pre><code class="lang-java"><span class="hljs-meta">@GetMapping("/reservations")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">reservations</span><span class="hljs-params">(Model model, HttpSession session)</span> </span>{
        UserDetails principal = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String name = principal.getUsername();
        User user = userService.getUserByUsername(name);

        <span class="hljs-comment">// This should always be the case </span>
        <span class="hljs-keyword">if</span> (user != <span class="hljs-keyword">null</span>) {
            session.setAttribute(<span class="hljs-string">"user"</span>, user);

            <span class="hljs-comment">// Empty reservation object in case the user creates a new reservation</span>
            Reservation reservation = <span class="hljs-keyword">new</span> Reservation();
            model.addAttribute(<span class="hljs-string">"reservation"</span>, reservation);

            <span class="hljs-keyword">return</span> <span class="hljs-string">"reservations"</span>;
        }

        <span class="hljs-keyword">return</span> <span class="hljs-string">"index"</span>;    
        }
</code></pre>
<p>Since we have added Spring Security to the project, it automatically creates the <strong>Authentication</strong> object behind the scenes – we are getting that from <strong>SecurityContextHolder</strong>. </p>
<p>We are grabbing the <strong><a target="_blank" href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/core/userdetails/UserDetails.html#:~:text=Interface%20UserDetails&amp;text=Provides%20core%20user%20information.,later%20encapsulated%20into%20Authentication%20objects.">UserDetails</a></strong> object which stores the info related to user. Then we check if the user object is null. This should always be the case since <em>reservations</em> is a protected endpoint and the user must be logged in to see that page – but it is always good to make sure everything is as expected.</p>
<p>Then we call the <strong>UserService</strong> class to get the <strong>User</strong> object which has this username – but we have not added the <strong>getUserByUsername</strong> method yet. So let's move to the <strong>UserService</strong> and add this simple method.</p>
<pre><code class="lang-java">    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">getUserByUsername</span><span class="hljs-params">(String username)</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.findUserByUsername(username);
    }
</code></pre>
<p>Now you should be able to see the logged-in user's reservations. You can try that by adding another user and creating reservations for that user as well. </p>
<h3 id="heading-how-to-check-the-capacity">How to Check the Capacity</h3>
<p>We currently don't have a mechanism to store the Capacity of each amenity type. We need to store those somehow and also check that there is enough capacity before we approve a reservation. </p>
<p>For that purpose, let's create a class called <strong>Capacity</strong> under our model folder.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.model;

<span class="hljs-keyword">import</span> lombok.AllArgsConstructor;
<span class="hljs-keyword">import</span> lombok.Getter;
<span class="hljs-keyword">import</span> lombok.NoArgsConstructor;
<span class="hljs-keyword">import</span> lombok.Setter;

<span class="hljs-keyword">import</span> javax.persistence.*;

<span class="hljs-meta">@Entity</span>
<span class="hljs-meta">@Getter</span>
<span class="hljs-meta">@Setter</span>
<span class="hljs-meta">@AllArgsConstructor</span>
<span class="hljs-meta">@NoArgsConstructor</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Capacity</span> </span>{

    <span class="hljs-meta">@Id</span>
    <span class="hljs-meta">@Column(nullable = false, updatable = false)</span>
    <span class="hljs-meta">@SequenceGenerator(
            name = "primary_sequence",
            sequenceName = "primary_sequence",
            allocationSize = 1,
            initialValue = 10000
    )</span>
    <span class="hljs-meta">@GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "primary_sequence"
    )</span>
    <span class="hljs-keyword">private</span> Long id;

    <span class="hljs-meta">@Column(nullable = false, unique = true)</span>
    <span class="hljs-meta">@Enumerated(EnumType.STRING)</span>
    <span class="hljs-keyword">private</span> AmenityType amenityType;

    <span class="hljs-meta">@Column(nullable = false)</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> capacity;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Capacity</span><span class="hljs-params">(AmenityType amenityType, <span class="hljs-keyword">int</span> capacity)</span> </span>{
        <span class="hljs-keyword">this</span>.amenityType = amenityType;
        <span class="hljs-keyword">this</span>.capacity = capacity;
    }
}
</code></pre>
<p>This is the entity that will represent our logical construct to be stored in our database. It is basically a map entry with an AmenityType and its corresponding capacity.</p>
<p>We also need a repository to store the <strong>Capacity</strong> entries, so let's create the CapacityRepository under the <strong>repos</strong> folder.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.repos;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.Capacity;
<span class="hljs-keyword">import</span> org.springframework.data.jpa.repository.JpaRepository;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">CapacityRepository</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JpaRepository</span>&lt;<span class="hljs-title">Capacity</span>, <span class="hljs-title">Long</span>&gt; </span>{
}
</code></pre>
<p>We need to populate this new table with the initial capacities. We could read the initial capacities from a config file or something, but let's keep it simple and hardcode it using loadData in our main method.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.AmenityType;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.Capacity;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.Reservation;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.CapacityRepository;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.ReservationRepository;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.UserRepository;
<span class="hljs-keyword">import</span> org.springframework.boot.CommandLineRunner;
<span class="hljs-keyword">import</span> org.springframework.boot.SpringApplication;
<span class="hljs-keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
<span class="hljs-keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

<span class="hljs-keyword">import</span> java.text.DateFormat;
<span class="hljs-keyword">import</span> java.text.SimpleDateFormat;
<span class="hljs-keyword">import</span> java.time.LocalDate;
<span class="hljs-keyword">import</span> java.time.LocalTime;
<span class="hljs-keyword">import</span> java.time.ZoneId;
<span class="hljs-keyword">import</span> java.util.Date;
<span class="hljs-keyword">import</span> java.util.HashMap;
<span class="hljs-keyword">import</span> java.util.Map;

<span class="hljs-meta">@SpringBootApplication</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AmenityReservationSystemApplication</span> </span>{

  <span class="hljs-keyword">private</span> Map&lt;AmenityType, Integer&gt; initialCapacities =
      <span class="hljs-keyword">new</span> HashMap&lt;&gt;() {
        {
          put(AmenityType.GYM, <span class="hljs-number">20</span>);
          put(AmenityType.POOL, <span class="hljs-number">4</span>);
          put(AmenityType.SAUNA, <span class="hljs-number">1</span>);
        }
      };

  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
    SpringApplication.run(AmenityReservationSystemApplication.class, args);
  }

  <span class="hljs-meta">@Bean</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> CommandLineRunner <span class="hljs-title">loadData</span><span class="hljs-params">(
      UserRepository userRepository,
      CapacityRepository capacityRepository)</span> </span>{
    <span class="hljs-keyword">return</span> (args) -&gt; {
      userRepository.save(
          <span class="hljs-keyword">new</span> User(<span class="hljs-string">"Yigit Kemal Erinc"</span>, <span class="hljs-string">"yigiterinc"</span>, bCryptPasswordEncoder().encode(<span class="hljs-string">"12345"</span>)));

      <span class="hljs-keyword">for</span> (AmenityType amenityType : initialCapacities.keySet()) {
        capacityRepository.save(<span class="hljs-keyword">new</span> Capacity(amenityType, initialCapacities.get(amenityType)));
      }
    };
  }

  <span class="hljs-meta">@Bean</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> BCryptPasswordEncoder <span class="hljs-title">bCryptPasswordEncoder</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BCryptPasswordEncoder();
  }
}
</code></pre>
<p>I just added the capacities inside the <strong>initialCapacities</strong> map then saved those to the <strong>CapacityRepository</strong> inside the <strong>loadData</strong> method.</p>
<p>We can now check if the number of reservations in the requested time exceeds the capacity and reject the reservation request if it does.</p>
<p>So here is the logic: We need to fetch the number of reservations that are on the same day and overlap with this current request. Then we need to fetch the capacity for this amenity type, and if the capacity is exceeded we can throw an exception. </p>
<p>Therefore we need a query to get the number of potentially overlapping reservations. It is not the easiest query to write, but JPA is very convenient and we can access that query inside our <strong>ReservationRepository</strong> without needing to write any SQL or HQL (Hibernate Query Language). </p>
<p>I encourage you to try it yourself before moving forward, because this is like the sole reason why I have included this concept of capacity in this tutorial (to show an example of a more advanced JPA query).</p>
<p>So this is how the <strong>ReservationService</strong>'s create method looks. You need to replace the 0 with a call to reservationRepository to get the number of overlapping reservations. </p>
<p>If the current number of overlapping reservations is equal to the capacity, it means that the next one will exceed it so we throw the exception.</p>
<pre><code class="lang-java"><span class="hljs-function"><span class="hljs-keyword">public</span> Long <span class="hljs-title">create</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Reservation reservation)</span> </span>{
        <span class="hljs-keyword">int</span> capacity = capacityRepository.findByAmenityType(reservation.getAmenityType()).getCapacity();
        <span class="hljs-keyword">int</span> overlappingReservations = <span class="hljs-number">0</span>; <span class="hljs-comment">// TODO</span>

        <span class="hljs-keyword">if</span> (overlappingReservations &gt;= capacity) {
            <span class="hljs-comment">// Throw a custom exception</span>
        }

        <span class="hljs-keyword">return</span> reservationRepository.save(reservation).getId();
    }
</code></pre>
<p>To find the overlapping reservations there are a few conditions we need to check:</p>
<p>First of all, the reservation date should be the same as the date in the request.</p>
<ol>
<li>Start time can be before the startTime of a new request. In that case, the end time should be later than our request, in order to overlap. (startTimeBeforeAndEndTimeAfter)</li>
<li>Or, endTime can be after but the startTime can actually be between the startTime and endTime of the request. (endTimeAfterOrStartTimeBetween)</li>
</ol>
<p>So our final query should return all reservations which match any of these 2 possibilities.</p>
<p>We can express it like this: </p>
<pre><code class="lang-java"><span class="hljs-function">List&lt;Reservation&gt; <span class="hljs-title">findReservationsByReservationDateAndStartTimeBeforeAndEndTimeAfterOrStartTimeBetween</span>
            <span class="hljs-params">(LocalDate reservationDate, LocalTime startTime, LocalTime endTime, LocalTime betweenStart, LocalTime betweenEnd)</span></span>;
</code></pre>
<p>And the final create method looks like this:</p>
<pre><code class="lang-java"> <span class="hljs-function"><span class="hljs-keyword">public</span> Long <span class="hljs-title">create</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Reservation reservation)</span> </span>{
        <span class="hljs-keyword">int</span> capacity = capacityRepository.findByAmenityType(reservation.getAmenityType()).getCapacity();
        <span class="hljs-keyword">int</span> overlappingReservations = reservationRepository
                .findReservationsByReservationDateAndStartTimeBeforeAndEndTimeAfterOrStartTimeBetween(
                        reservation.getReservationDate(),
                        reservation.getStartTime(), reservation.getEndTime(),
                        reservation.getStartTime(), reservation.getEndTime()).size();

        <span class="hljs-keyword">if</span> (overlappingReservations &gt;= capacity) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> CapacityFullException(<span class="hljs-string">"This amenity's capacity is full at desired time"</span>);
        }

        <span class="hljs-keyword">return</span> reservationRepository.save(reservation).getId();
    }
</code></pre>
<p>You don't need to worry about the custom exception, but if you are interested in that, here is the code:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.exception;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CapacityFullException</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">RuntimeException</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CapacityFullException</span><span class="hljs-params">(String message)</span> </span>{
        <span class="hljs-keyword">super</span>(message);
    }
}
</code></pre>
<p>We should normally show an error modal if the capacity is exceeded but I will skip that to avoid repetitive UI stuff. You can try that as a challenge if you wish.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, we have learned about so many technologies that make development with Spring Boot easier and faster. </p>
<p>I believe many people underestimate the framework in terms of development speed and the quality of the resulting work. </p>
<p>Assuming you are fluent with the technology, I would argue that Spring Boot is not any slower (in development) than any other backend framework if you do everything in the modern fashion. </p>
<p>You can find the whole code in this repository:</p>
<p><a target="_blank" href="https://github.com/yigiterinc/amenity-reservation-system.git">https://github.com/yigiterinc/amenity-reservation-system.git</a></p>
<p>If you are interested in reading more content like this, feel free to subscribe to my blog at <a target="_blank" href="https://erinc.io/">https://erinc.io</a> to get notified about my new posts.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Java Spring Boot JWT Authorization and Authentication ]]>
                </title>
                <description>
                    <![CDATA[ By Yiğit Kemal Erinç In the past month, I had a chance to implement JWT auth for a side project. I have previously worked with JWT in Ruby on Rails, but this was my first time in Spring.  In this post, I will try to explain what I have ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-setup-jwt-authorization-and-authentication-in-spring/</link>
                <guid isPermaLink="false">66d45e44182810487e0ce155</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JSON Web Tokens ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JWT ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 12 Aug 2020 20:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/08/jwt.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Yiğit Kemal Erinç</p>
<p>In the past month, I had a chance to implement JWT auth for a side project. I have previously worked with JWT in Ruby on Rails, but this was my first time in Spring. </p>
<p>In this post, I will try to explain what I have learned and applied in my project to share my experience and hopefully help some people. </p>
<p>We will start by taking a quick look at the theory behind JWT and how it works. Then we will look at how to implement it in a Spring Boot application.</p>
<h2 id="heading-jwt-basics">JWT Basics</h2>
<p>JWT, or JSON Web Tokens (<a target="_blank" href="https://tools.ietf.org/html/rfc7519">RFC 7519</a>), is a standard that is mostly used for securing REST APIs. Despite being a relatively new technology, it is gaining rapid popularity.</p>
<p>In the JWT auth process, the front end (client) firstly sends some credentials to authenticate itself (username and password in our case, since we're working on a web application). </p>
<p>The server (the Spring app in our case) then checks those credentials, and if they are valid, it generates a JWT and returns it. </p>
<p>After this step client has to provide this token in the request’s <strong>Authorization</strong> header in the “Bearer TOKEN” form. The back end will check the validity of this token and authorize or reject requests. The token may also store user roles and authorize the requests based on the given authorities.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/1.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-implementation">Implementation</h2>
<p>Now let’s see how we can implement the JWT login and save mechanism in a real Spring application.</p>
<h3 id="heading-dependencies">Dependencies</h3>
<p>You can see the list of Maven dependencies that our example code uses below. Note that the core dependencies like Spring Boot and Hibernate are not included in this screenshot.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/2-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-saving-users">Saving Users</h3>
<p>We will start by creating controllers to save users securely and authenticate them based on username and password.</p>
<p>We have a model entity called User. It is a simple entity class that maps to the <strong>USER</strong> table. You can use whatever properties you need depending on your application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/3-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We also have a simple <strong>UserRepository</strong> class to save users. We need to override the <strong>findByUsername</strong> method since we will use it in authentication.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserRepository</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JpaRepository</span>&lt;<span class="hljs-title">User</span>, <span class="hljs-title">String</span>&gt;</span>{ 
    <span class="hljs-function">User <span class="hljs-title">findByUsername</span><span class="hljs-params">(String username)</span></span>; 
}
</code></pre>
<p>We should never store plaintext passwords in the database because many users tend to use the same password for multiple sites. </p>
<p>There are many different hashing algorithms, but the most commonly used one is <strong>BCrypt</strong> and it is a recommended method of secure hashing. You can check out <a target="_blank" href="https://security.blogoverflow.com/2013/09/about-secure-password-hashing/#:~:text=Passwords%20should%20be%20hashed%20with,providing%20most%20security%20is%20bcrypt.">this</a> article for more information on the topic.</p>
<p>To hash the password, we will define a <strong>BCrypt</strong> bean in <strong>@SpringBootApplication</strong> and annotate the main class as follows:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Bean</span> <span class="hljs-function"><span class="hljs-keyword">public</span> BCryptPasswordEncoder <span class="hljs-title">bCryptPasswordEncoder</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BCryptPasswordEncoder(); 
}
</code></pre>
<p>We will call the methods on this bean when we need to hash a password.</p>
<p>We also need a UserController to save users. We create the controller, annotate it with <strong>@RestController,</strong> and define the corresponding mapping. </p>
<p>In our application, we save the user based on a DTO object that is passed from the front end. You can also pass a User object in <strong>@RequestBody</strong>.</p>
<p>After we pass the DTO object, we encrypt the password field using the <strong>BCrypt</strong> bean we created earlier. You could also do this in the controller, but it is a better practice to put this logic in the service class.</p>
<pre><code class="lang-java"><span class="hljs-meta">@Transactional(rollbackFor = Exception.class)</span> 
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">saveDto</span><span class="hljs-params">(UserDto userDto)</span> </span>{ 
    userDto.setPassword(bCryptPasswordEncoder
           .encode(userDto.getPassword())); 
    <span class="hljs-keyword">return</span> save(<span class="hljs-keyword">new</span> User(userDto)).getId(); 
}
</code></pre>
<h3 id="heading-authentication-filter">Authentication Filter</h3>
<p>We need authentication to make sure that the user is really who they claim to be. We will be using the classic username/password pair to accomplish this.</p>
<p>Here are the steps to implement authentication:</p>
<ol>
<li>Create our Authentication Filter that extends <strong>UsernamePasswordAuthenticationFilter</strong></li>
<li>Create a security configuration class that extends <strong>WebSecurityConfigurerAdapter</strong> and apply the filter</li>
</ol>
<p>Here is the code for our Authentication Filter – as you might know, filters are the backbone of Spring Security.</p>


<p>Let’s go over this code step by step.</p>
<p>This class extends <strong>UsernamePasswordAuthenticationFilter</strong> which is the default class for password authentication in Spring Security. We extend it to define our custom authentication logic.</p>
<p>We make a call to the <strong>setFilterProcessesUrl</strong> method in our constructor. This method sets the default login URL to the provided parameter. </p>
<p>If you remove this line, Spring Security creates the <strong>“/login”</strong> endpoint by default. It defines the login endpoint for us, which is why we will not define a login endpoint in our controller explicitly. </p>
<p>After this line our login endpoint will be <strong>/api/services/controller/user/login</strong>. You can use this function to stay consistent with your endpoints.</p>
<p>We override the <strong>attemptAuthentication</strong> and <strong>successfulAuthentication</strong> methods of the <strong>UsernameAuthenticationFilter</strong> class.</p>
<p>The <strong>attemptAuthentication</strong> function runs when the user tries to log in to our application. It reads the credentials, creates a user POJO from them, and then checks the credentials to authenticate. </p>
<p>We pass the username, password, and an empty list. The empty list represents the authorities (roles), and we leave it as is since we do not have any roles in our application yet.</p>
<p>If the authentication is successful, the <strong>successfulAuthentication</strong> method runs. The parameters of this method are passed by Spring Security behind the scenes. </p>
<p>The <strong>attemptAuthentication</strong> method returns an <strong>Authentication</strong> object that contains the authorities we passed while attempting. </p>
<p>We want to return a token to user after authentication is successful, so we create the token using username, secret, and expiration date. We need to define the <strong>SECRET</strong> and <strong>EXPIRATION_DATE</strong> now.</p>


<p>We create a class to be a container for our constants. You can set the secret to whatever you want, but the best practice is making the secret key as long as your hash. We use the <strong>HS256</strong> algorithm in this example, so our secret key is 256 bits/32 chars.</p>
<p>The expiration time is set to 15 minutes, because it is the best practice against secret key brute-forcing attacks. The time is in milliseconds.</p>
<p>We have prepared our Authentication filter, but it is not active yet. We also need an Authorization filter, and then we will apply them both through a configuration class. </p>
<p>This filter will check the existence and validity of the access token on the Authorization header. We will specify which endpoints will be subject to this filter in our configuration class.</p>
<h3 id="heading-authorization-filter">Authorization Filter</h3>


<p>The <strong>doFilterInternal</strong> method intercepts the requests then checks the Authorization header. If the header is not present or doesn’t start with “BEARER”, it proceeds to the filter chain. </p>
<p>If the header is present, the <strong>getAuthentication</strong> method is invoked. <strong>getAuthentication</strong> verifies the JWT, and if the token is valid, it returns an access token which Spring will use internally. </p>
<p>This new token is then saved to SecurityContext. You can also pass in Authorities to this token if you need for role-based authorization.</p>
<p>Our filters are ready, and now we need to put them into action with the help of a configuration class.</p>
<h3 id="heading-configuration">Configuration</h3>


<p>We annotate this class with <strong>@EnableWebSecurity</strong> and extend <strong>WebSecurityConfigureAdapter</strong> to implement our custom security logic. </p>
<p>We autowire the BCrypt bean that we defined earlier. We also autowire the <strong>UserDetailsService</strong> to find the user’s account. </p>
<p>The most important method is the one which accepts an <strong>HttpSecurity</strong> object. Here we specify the secure endpoints and filters that we want to apply. We configure CORS, and then we permit all post requests to our sign up URL that we defined in the constants class. </p>
<p>You can add other ant matchers to filter based on URL patterns and roles, and you can <a target="_blank" href="https://stackoverflow.com/questions/44067650/spring-security-role-based-access">check</a> this StackOverflow question for examples regarding that. The other method configures the <strong>AuthenticationManager</strong> to use our encoder object as its password encoder while checking the credentials.</p>
<h3 id="heading-testing">Testing</h3>
<p>Let’s send a few requests to test if it works properly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here we send a GET request to access a protected resource. Our server responds with a 403 code. This is the expected behavior because we haven’t provided a token in the header. Now let’s create a user:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/5.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>To create a user, we send a post request with our User DTO data. We will use this user to login and get an access token.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/6.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Great! We got the token. After this point, we will use this token to access protected resources.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/7.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We provide the token in the Authorization header and we are now allowed access to our protected endpoint.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial I have walked you through the steps I took when implementing JWT authorization and password authentication in Spring. We also learned how to save a user securely. </p>
<p>Thank you for reading – I hope it was helpful to you. If you are interested in reading more content like this, feel free to subscribe to my blog at <a target="_blank" href="https://erinc.io">https://erinc.io</a>. :)</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
