Skip to content

feat: add UI authentication with cookie-based JWT support - #18

Merged
addee1 merged 10 commits into
mainfrom
feature/cookie-auth
Apr 14, 2026
Merged

feat: add UI authentication with cookie-based JWT support#18
addee1 merged 10 commits into
mainfrom
feature/cookie-auth

Conversation

@addee1

@addee1 addee1 commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

This PR introduces browser-based authentication using cookies alongside the existing API-based authentication.

✨ Features added

  • Login and signup pages using JTE templates
  • AuthViewController for handling UI-based authentication
  • JWT stored in HTTP-only cookies for browser sessions
  • JwtAuthenticationFilter updated to read token from both:
    • Authorization header (API/Postman)
    • Cookies (browser)
  • SecurityConfig updated to allow access to login and signup routes

🧠 Design decisions

  • Authentication logic is reused via AuthService and JwtService
  • Separation of concerns:
    • AuthController → API (JSON, Postman)
    • AuthViewController → UI (HTML, browser)
  • JWT is still only used for identifying the user
  • Roles and permissions are always resolved from the database

🧪 Testing

  • Verified login/signup flow via browser
  • JWT cookie is set correctly
  • Protected endpoints are accessible after login
  • Existing Postman flow remains functional

📌 Notes

This does not change existing authorization logic.
It only adds a UI layer for authentication.

Summary by CodeRabbit

  • New Features

    • Added browser-facing login and signup pages with form handling.
    • Added server-side flows to set an HttpOnly JWT cookie on successful browser login and to clear it on logout.
  • Security

    • Expanded public access to allow unauthenticated access to login and signup routes.

@coderabbitai

coderabbitai Bot commented Apr 13, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds browser-facing login/signup views and controller, permits those endpoints in security config, updates JWT filter to accept tokens from Authorization header or a JWT cookie, and adjusts API auth controller comments/imports (no signature changes).

Changes

Cohort / File(s) Summary
Security Configuration
src/main/java/org/example/alfs/config/SecurityConfig.java
Added permit rules for /login, /login-form, /signup, and /signup-form alongside existing allowlist entries.
Authentication API Controller (docs/imports)
src/main/java/org/example/alfs/controllers/AuthController.java
Added servlet cookie imports and clarified class/method Javadoc indicating this controller is JSON/API-focused; no signature or behavior changes in shown diff.
HTML Authentication Views (templates)
src/main/jte/login.jte, src/main/jte/signup.jte
New JTE templates rendering login and signup HTML forms that POST to /login-form and /signup-form.
HTML Authentication Endpoints (browser flow)
src/main/java/org/example/alfs/controllers/AuthViewController.java
New Spring MVC controller providing GET pages for /login and /signup, POST /signup-form (validation, signup, redirect), POST /login-form (login, JWT generation, set HttpOnly JWT cookie, redirect), and POST /logout (clear cookie, redirect).
JWT Authentication Filter
src/main/java/org/example/alfs/security/JwtAuthenticationFilter.java
doFilterInternal now extracts JWT from Authorization: Bearer ... header or from a JWT cookie when header token absent/blank; early-exits and proceeds without authentication if no token found.

Sequence Diagram(s)

sequenceDiagram
    participant Browser
    participant AuthViewController
    participant AuthService
    participant JwtService
    participant HttpResponse

    Browser->>AuthViewController: POST /login-form (username,password)
    AuthViewController->>AuthService: login(credentials)
    AuthService-->>AuthViewController: User
    AuthViewController->>JwtService: generateToken(user)
    JwtService-->>AuthViewController: JWT
    AuthViewController->>HttpResponse: addCookie(name="JWT", HttpOnly, maxAge=86400, path="/")
    AuthViewController-->>Browser: Redirect /api/hello
Loading
sequenceDiagram
    participant Browser
    participant JwtAuthenticationFilter
    participant AuthService
    participant SecurityContext

    Browser->>JwtAuthenticationFilter: Request (maybe Authorization header / maybe JWT cookie)
    JwtAuthenticationFilter->>JwtAuthenticationFilter: Try header "Bearer ..."
    alt header absent/blank
        JwtAuthenticationFilter->>JwtAuthenticationFilter: Try cookie "JWT"
    end
    JwtAuthenticationFilter->>AuthService: loadUserByUsername(subject)
    AuthService-->>JwtAuthenticationFilter: UserDetails
    JwtAuthenticationFilter->>JwtAuthenticationFilter: validate token
    JwtAuthenticationFilter->>SecurityContext: setAuthentication(authToken)
    JwtAuthenticationFilter-->>Browser: Proceed with request
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped from header to cookie with glee,
A tiny JWT tucked safe on my knee,
Forms and views now welcome browsers in,
HttpOnly whispers keep tokens from sin,
Hooray—secure hops and a crunchy cookie! 🍪

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature: adding browser-based UI authentication with HTTP-only cookie-based JWT support, which aligns with the primary changes across AuthViewController, JTE templates, and JwtAuthenticationFilter.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/cookie-auth

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
src/main/java/org/example/alfs/controllers/AuthController.java (1)

59-64: Remove unnecessary JWT cookie from REST API endpoint.

At lines 59–64, the JWT token is already returned in the JSON response body (LoginResponseDTO). Setting a cookie here is redundant for API clients like Postman. The /login endpoint's comment (line 47) confirms it is "mainly used for API testing", not browser-based login. Browser-based cookie handling already has a dedicated controller: AuthViewController.

Either remove the cookie-setting code, or if cookies must be set here for compatibility, add Secure and SameSite attributes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/alfs/controllers/AuthController.java` around lines
59 - 64, Remove the redundant JWT cookie being added in AuthController's login
handler: eliminate creation and adding of the Cookie object (jwtCookie and
response.addCookie(...)) since the token is already returned in LoginResponseDTO
and browser cookie handling is done by AuthViewController; if you need to
preserve cookie behavior for compatibility instead, ensure you set Secure and
SameSite attributes on the Cookie before adding it (and keep
HttpOnly/Path/MaxAge as appropriate) and document that choice.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/org/example/alfs/controllers/AuthViewController.java`:
- Line 70: Replace the ambiguous post-login redirect in AuthViewController (the
line returning "redirect:/api/hello") with a definitive target: either a UI
route like "redirect:/" or "redirect:/home" or a configurable property (e.g.,
app.ui.postLoginRedirect) accessed from the controller; remove the inline
comment. If you want to restore prior saved-request behavior instead, wire in a
SavedRequestAwareAuthenticationSuccessHandler or read the saved redirect URL and
return it from the same controller method. Update AuthViewController accordingly
so the redirect target is explicit and comment-free.
- Around line 39-48: The signup form handler currently builds SignupRequestDTO
manually from `@RequestParam` (method signupForm) which bypasses bean validation;
change the method signature to accept the form DTO directly as `@Valid`
`@ModelAttribute` org.example.alfs.dto.auth.SignupRequestDTO request (and add a
BindingResult bindingResult parameter) so Spring will validate `@NotBlank`
constraints, check bindingResult for errors and return the form view on
validation failure, otherwise call authService.signup(request) and continue
normal flow; ensure imports for javax/jakarta.validation.Valid and
org.springframework.web.bind.annotation.ModelAttribute and handle validation
errors consistently with your view logic.

In `@src/main/java/org/example/alfs/security/JwtAuthenticationFilter.java`:
- Around line 44-56: The Bearer branch in JwtAuthenticationFilter currently sets
jwt = authHeader.substring(7) even when the header is "Bearer " which yields an
empty string and prevents the cookie fallback; update the logic in the
authHeader handling (authHeader, jwt) to trim the extracted token and treat
empty strings as missing (set jwt back to null or skip assigning) so the
subsequent request.getCookies() loop (cookie name "JWT") will run when the token
is blank.

In `@src/main/jte/login.jte`:
- Around line 5-11: The labels for the username and password fields are not
associated with their inputs; update the Username label and its corresponding
<input name="username"> to include a matching id (e.g., id="username") and add
for="username" on the <label>, and do the same for the Password label/input pair
(e.g., id="password" and for="password") so assistive technologies can correctly
bind the labels to the inputs.

In `@src/main/jte/signup.jte`:
- Around line 5-11: The labels in signup.jte are not bound to their inputs; add
id attributes to the username and password inputs (e.g., id="username" and
id="password") and set the corresponding label for attributes (for="username"
and for="password") so the <label> elements are associated with the <input
name="username"> and <input name="password"> respectively to improve
accessibility.

---

Nitpick comments:
In `@src/main/java/org/example/alfs/controllers/AuthController.java`:
- Around line 59-64: Remove the redundant JWT cookie being added in
AuthController's login handler: eliminate creation and adding of the Cookie
object (jwtCookie and response.addCookie(...)) since the token is already
returned in LoginResponseDTO and browser cookie handling is done by
AuthViewController; if you need to preserve cookie behavior for compatibility
instead, ensure you set Secure and SameSite attributes on the Cookie before
adding it (and keep HttpOnly/Path/MaxAge as appropriate) and document that
choice.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2ca1a260-c1de-430f-bb1b-9f6ac8d1a5fe

📥 Commits

Reviewing files that changed from the base of the PR and between 7fd42ef and a12f870.

📒 Files selected for processing (6)
  • src/main/java/org/example/alfs/config/SecurityConfig.java
  • src/main/java/org/example/alfs/controllers/AuthController.java
  • src/main/java/org/example/alfs/controllers/AuthViewController.java
  • src/main/java/org/example/alfs/security/JwtAuthenticationFilter.java
  • src/main/jte/login.jte
  • src/main/jte/signup.jte

Comment thread src/main/java/org/example/alfs/controllers/AuthViewController.java

response.addCookie(cookie);

return "redirect:/api/hello"; // should redirect to home?

@coderabbitai coderabbitai Bot Apr 13, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Resolve the post-login redirect target before merge.

Line 70 contains an unresolved “should redirect to home?” note in behavior code. Please decide a final target (UI landing page vs API endpoint) and remove ambiguity.

I can draft a small follow-up patch that redirects to a configurable UI route (or to a saved-request URL) if you want.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/alfs/controllers/AuthViewController.java` at line
70, Replace the ambiguous post-login redirect in AuthViewController (the line
returning "redirect:/api/hello") with a definitive target: either a UI route
like "redirect:/" or "redirect:/home" or a configurable property (e.g.,
app.ui.postLoginRedirect) accessed from the controller; remove the inline
comment. If you want to restore prior saved-request behavior instead, wire in a
SavedRequestAwareAuthenticationSuccessHandler or read the saved redirect URL and
return it from the same controller method. Update AuthViewController accordingly
so the redirect target is explicit and comment-free.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we keep this for development. Will change this later when UI is done.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@addee1, understood — keeping it as-is during development is reasonable. Would you like me to open a follow-up GitHub issue to track the redirect target cleanup once the UI is finalized, so it doesn't get lost?


🧠 Learnings used
Learnt from: addee1
Repo: ithsjava25/project-backend-alfs PR: 9
File: src/main/java/org/example/alfs/config/SecurityConfig.java:27-29
Timestamp: 2026-04-09T09:49:11.596Z
Learning: In the project `ithsjava25/project-backend-alfs`, the Spring Security configuration (`src/main/java/org/example/alfs/config/SecurityConfig.java`) intentionally disables CSRF and frame options, and permits the H2 console without authentication. This is by design for development-only use — the project is a stateless JWT-based REST API not targeting production deployment. Do not flag these settings as security issues.

Learnt from: FionaSprinkles
Repo: ithsjava25/project-backend-alfs PR: 11
File: src/main/java/org/example/alfs/services/TicketService.java:50-54
Timestamp: 2026-04-09T13:26:48.849Z
Learning: In `ithsjava25/project-backend-alfs`, the IDOR vulnerability in `TicketService.getTicketById()` (and the `GET /view/id/{id}` endpoint in `TicketController`) is a known, intentionally deferred issue. Authorization/ownership checks will be added in a future PR when authentication and authorization are implemented. Do not re-flag this as a new issue.

Comment thread src/main/jte/login.jte Outdated
Comment thread src/main/jte/signup.jte Outdated
Comment on lines +64 to +75
User user = authService.login(username, password);

String token = jwtService.generateToken(user);

Cookie cookie = new Cookie("JWT", token);
cookie.setHttpOnly(true);
cookie.setPath("/");
cookie.setMaxAge(60 * 60 * 24);

response.addCookie(cookie);

return "redirect:/api/hello"; // should redirect to home?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add error handling if the login fails? Or is that maybe a later concern?

@addee1 addee1 Apr 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably align with @FionaSprinkles on how we want to handle this in the UI.
For example, if we want an error page, or just show an error message directly in the login form.
But we should definately have error handling for the UI also.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's discuss this on discord :)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/org/example/alfs/controllers/AuthViewController.java`:
- Around line 71-76: The JWT cookie creation in AuthViewController currently
uses java.servlet.Cookie (see the code that constructs Cookie cookie = new
Cookie("JWT", token) and the matching clear path) and must be hardened: replace
these with org.springframework.http.ResponseCookie builders so you can set
secure=true and sameSite (e.g., "Lax" or "Strict"), keep httpOnly(true),
path("/"), and maxAge as before; do the same for the cookie-clear branch (build
a ResponseCookie with maxAge(0) or maxAge(0) and the same
secure/httpOnly/sameSite/path attributes) and add the cookie to the response via
ResponseCookie.toString() in the Set-Cookie header or
response.addHeader("Set-Cookie", responseCookie.toString()) so attributes are
applied consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d3007a31-90e1-4345-b127-04410a75a233

📥 Commits

Reviewing files that changed from the base of the PR and between a12f870 and 76de487.

📒 Files selected for processing (5)
  • src/main/java/org/example/alfs/controllers/AuthController.java
  • src/main/java/org/example/alfs/controllers/AuthViewController.java
  • src/main/java/org/example/alfs/security/JwtAuthenticationFilter.java
  • src/main/jte/login.jte
  • src/main/jte/signup.jte
✅ Files skipped from review due to trivial changes (4)
  • src/main/jte/login.jte
  • src/main/java/org/example/alfs/controllers/AuthController.java
  • src/main/jte/signup.jte
  • src/main/java/org/example/alfs/security/JwtAuthenticationFilter.java

Comment on lines +71 to +76
Cookie cookie = new Cookie("JWT", token);
cookie.setHttpOnly(true);
cookie.setPath("/");
cookie.setMaxAge(60 * 60 * 24);

response.addCookie(cookie);

@coderabbitai coderabbitai Bot Apr 14, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "AuthViewController.java"

Repository: ithsjava25/project-backend-alfs

Length of output: 143


🏁 Script executed:

cat -n ./src/main/java/org/example/alfs/controllers/AuthViewController.java | sed -n '60,110p'

Repository: ithsjava25/project-backend-alfs

Length of output: 1622


🏁 Script executed:

head -20 ./src/main/java/org/example/alfs/controllers/AuthViewController.java

Repository: ithsjava25/project-backend-alfs

Length of output: 801


🏁 Script executed:

ls -la | grep -E "pom.xml|build.gradle"

Repository: ithsjava25/project-backend-alfs

Length of output: 132


🏁 Script executed:

cat pom.xml | grep -A 5 -B 5 "spring-boot"

Repository: ithsjava25/project-backend-alfs

Length of output: 3101


Add Secure and SameSite attributes to JWT cookies on set/clear paths.

Lines 71–76 and 95–100 create JWT cookies without Secure and SameSite attributes. While this project is development-focused, proper cookie hardening remains a best practice. Use ResponseCookie with explicit security flags:

Suggested implementation
+import java.time.Duration;
+import org.springframework.http.ResponseCookie;
@@
-            Cookie cookie = new Cookie("JWT", token);
-            cookie.setHttpOnly(true);
-            cookie.setPath("/");
-            cookie.setMaxAge(60 * 60 * 24);
-
-            response.addCookie(cookie);
+            ResponseCookie cookie = ResponseCookie.from("JWT", token)
+                    .httpOnly(true)
+                    .secure(true)      // if local HTTP is required, gate by profile/env
+                    .sameSite("Lax")
+                    .path("/")
+                    .maxAge(Duration.ofHours(24))
+                    .build();
+            response.addHeader("Set-Cookie", cookie.toString());
@@
-        Cookie cookie = new Cookie("JWT", null);
-        cookie.setHttpOnly(true);
-        cookie.setPath("/");
-        cookie.setMaxAge(0);
-
-        response.addCookie(cookie);
+        ResponseCookie cookie = ResponseCookie.from("JWT", "")
+                .httpOnly(true)
+                .secure(true)
+                .sameSite("Lax")
+                .path("/")
+                .maxAge(Duration.ZERO)
+                .build();
+        response.addHeader("Set-Cookie", cookie.toString());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Cookie cookie = new Cookie("JWT", token);
cookie.setHttpOnly(true);
cookie.setPath("/");
cookie.setMaxAge(60 * 60 * 24);
response.addCookie(cookie);
import java.time.Duration;
import org.springframework.http.ResponseCookie;
// ... other code ...
ResponseCookie cookie = ResponseCookie.from("JWT", token)
.httpOnly(true)
.secure(true) // if local HTTP is required, gate by profile/env
.sameSite("Lax")
.path("/")
.maxAge(Duration.ofHours(24))
.build();
response.addHeader("Set-Cookie", cookie.toString());
// ... in logout/clear section (around line 95-100) ...
ResponseCookie cookie = ResponseCookie.from("JWT", "")
.httpOnly(true)
.secure(true)
.sameSite("Lax")
.path("/")
.maxAge(Duration.ZERO)
.build();
response.addHeader("Set-Cookie", cookie.toString());
🧰 Tools
🪛 ast-grep (0.42.1)

[warning] 75-75: The application does not appear to verify inbound requests which can lead to a Cross-site request forgery (CSRF) vulnerability. If the application uses cookie-based authentication, an attacker can trick users into sending authenticated HTTP requests without their knowledge from any arbitrary domain they visit. To prevent this vulnerability start by identifying if the framework or library leveraged has built-in features or offers plugins for CSRF protection. CSRF tokens should be unique and securely random. The Synchronizer Token or Double Submit Cookie patterns with defense-in-depth mechanisms such as the sameSite cookie flag can help prevent CSRF. For more information, see: [Cross-site request forgery prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Req\ uest_Forgery_Prevention_Cheat_Sheet.html).
Context: response.addCookie(cookie);
Note: [CWE-352] Cross-Site Request Forgery (CSRF). [REFERENCES]
- https://stackoverflow.com/questions/42717210/samesite-cookie-in-java-application

(cookie-missing-samesite-java)


[warning] 75-75: A cookie was detected without setting the 'secure' flag. The 'secure' flag for cookies prevents the client from transmitting the cookie over insecure channels such as HTTP. Set the 'secure' flag by calling '.setSecure(true);'.
Context: response.addCookie(cookie);
Note: [CWE-614] Sensitive Cookie in HTTPS Session Without 'Secure' Attribute. [REFERENCES]
- https://owasp.org/www-community/controls/SecureCookieAttribute

(cookie-missing-secure-flag-java)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/alfs/controllers/AuthViewController.java` around
lines 71 - 76, The JWT cookie creation in AuthViewController currently uses
java.servlet.Cookie (see the code that constructs Cookie cookie = new
Cookie("JWT", token) and the matching clear path) and must be hardened: replace
these with org.springframework.http.ResponseCookie builders so you can set
secure=true and sameSite (e.g., "Lax" or "Strict"), keep httpOnly(true),
path("/"), and maxAge as before; do the same for the cookie-clear branch (build
a ResponseCookie with maxAge(0) or maxAge(0) and the same
secure/httpOnly/sameSite/path attributes) and add the cookie to the response via
ResponseCookie.toString() in the Set-Cookie header or
response.addHeader("Set-Cookie", responseCookie.toString()) so attributes are
applied consistently.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix this later! Thanks for input

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@addee1, sounds good! Would you like me to open a GitHub issue to track this cookie hardening improvement (adding Secure and SameSite attributes via ResponseCookie) so it doesn't get lost?


🧠 Learnings used
Learnt from: addee1
Repo: ithsjava25/project-backend-alfs PR: 9
File: src/main/java/org/example/alfs/config/SecurityConfig.java:27-29
Timestamp: 2026-04-09T09:49:11.596Z
Learning: In the project `ithsjava25/project-backend-alfs`, the Spring Security configuration (`src/main/java/org/example/alfs/config/SecurityConfig.java`) intentionally disables CSRF and frame options, and permits the H2 console without authentication. This is by design for development-only use — the project is a stateless JWT-based REST API not targeting production deployment. Do not flag these settings as security issues.

Learnt from: addee1
Repo: ithsjava25/project-backend-alfs PR: 9
File: src/main/resources/application.properties:19-20
Timestamp: 2026-04-09T10:02:51.794Z
Learning: In the project `ithsjava25/project-backend-alfs`, the JWT secret is intentionally hardcoded in `src/main/resources/application.properties` (`jwt.secret=bXlTdXBlclNlY3JldEtleU15U3VwZXJTZWNyZXRLZXk=`). This is by design for development/demo purposes only — the team is aware it should be externalized via environment variables or a secrets manager in a production setup. Do not flag this as a security issue.

Learnt from: FionaSprinkles
Repo: ithsjava25/project-backend-alfs PR: 11
File: src/main/java/org/example/alfs/services/TicketService.java:50-54
Timestamp: 2026-04-09T13:26:48.849Z
Learning: In `ithsjava25/project-backend-alfs`, the IDOR vulnerability in `TicketService.getTicketById()` (and the `GET /view/id/{id}` endpoint in `TicketController`) is a known, intentionally deferred issue. Authorization/ownership checks will be added in a future PR when authentication and authorization are implemented. Do not re-flag this as a new issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes please!

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

gh issue create \
  --repo ithsjava25/project-backend-alfs \
  --title "Harden JWT cookies: add Secure and SameSite attributes via ResponseCookie" \
  --body "## Summary

The JWT cookie set in \`AuthViewController\` (and its logout/clear path) currently uses \`jakarta.servlet.http.Cookie\` without \`Secure\` or \`SameSite\` attributes. This should be hardened by replacing both cookie creation and cookie-clear paths with \`org.springframework.http.ResponseCookie\` builders.

## Changes needed

Replace the \`jakarta.servlet.http.Cookie\` usage in \`src/main/java/org/example/alfs/controllers/AuthViewController.java\` with \`ResponseCookie\`:

\`\`\`java
import java.time.Duration;
import org.springframework.http.ResponseCookie;

// Set cookie on login:
ResponseCookie cookie = ResponseCookie.from(\"JWT\", token)
        .httpOnly(true)
        .secure(true)
        .sameSite(\"Lax\")
        .path(\"/\")
        .maxAge(Duration.ofHours(24))
        .build();
response.addHeader(\"Set-Cookie\", cookie.toString());

// Clear cookie on logout:
ResponseCookie cookie = ResponseCookie.from(\"JWT\", \"\")
        .httpOnly(true)
        .secure(true)
        .sameSite(\"Lax\")
        .path(\"/\")
        .maxAge(Duration.ZERO)
        .build();
response.addHeader(\"Set-Cookie\", cookie.toString());
\`\`\`

> Note: If local HTTP development (non-HTTPS) is needed, consider gating the \`secure(true)\` flag by Spring profile or environment variable.

## References

- Flagged in PR `#18`: https://github.com/ithsjava25/project-backend-alfs/pull/18#discussion_r3080199509
- Requested by `@addee1`

## Why this matters

- Missing \`Secure\` flag: cookie can be transmitted over HTTP, exposing the JWT (CWE-614).
- Missing \`SameSite\` flag: leaves the app open to CSRF via cookie-based auth (CWE-352).
" \
  --assignee addee1

Length of output: 60


@addee1, done! I've opened issue #20"Harden JWT cookies: add Secure and SameSite attributes via ResponseCookie" — assigned to you, with full details and the suggested ResponseCookie implementation for both the login (set) and logout (clear) paths. 🐇


🧠 Learnings used
Learnt from: addee1
Repo: ithsjava25/project-backend-alfs PR: 9
File: src/main/java/org/example/alfs/config/SecurityConfig.java:27-29
Timestamp: 2026-04-09T09:49:11.596Z
Learning: In the project `ithsjava25/project-backend-alfs`, the Spring Security configuration (`src/main/java/org/example/alfs/config/SecurityConfig.java`) intentionally disables CSRF and frame options, and permits the H2 console without authentication. This is by design for development-only use — the project is a stateless JWT-based REST API not targeting production deployment. Do not flag these settings as security issues.

Learnt from: FionaSprinkles
Repo: ithsjava25/project-backend-alfs PR: 11
File: src/main/java/org/example/alfs/services/TicketService.java:50-54
Timestamp: 2026-04-09T13:26:48.849Z
Learning: In `ithsjava25/project-backend-alfs`, the IDOR vulnerability in `TicketService.getTicketById()` (and the `GET /view/id/{id}` endpoint in `TicketController`) is a known, intentionally deferred issue. Authorization/ownership checks will be added in a future PR when authentication and authorization are implemented. Do not re-flag this as a new issue.

Learnt from: addee1
Repo: ithsjava25/project-backend-alfs PR: 9
File: src/main/resources/application.properties:19-20
Timestamp: 2026-04-09T10:02:51.794Z
Learning: In the project `ithsjava25/project-backend-alfs`, the JWT secret is intentionally hardcoded in `src/main/resources/application.properties` (`jwt.secret=bXlTdXBlclNlY3JldEtleU15U3VwZXJTZWNyZXRLZXk=`). This is by design for development/demo purposes only — the team is aware it should be externalized via environment variables or a secrets manager in a production setup. Do not flag this as a security issue.

Learnt from: addee1
Repo: ithsjava25/project-backend-alfs PR: 8
File: src/main/resources/application.properties:5-7
Timestamp: 2026-04-11T16:56:55.483Z
Learning: In the project `ithsjava25/project-backend-alfs`, the MinIO credentials (`storage.s3.accessKey=minioadmin` and `storage.s3.secretKey=minioadmin`) are intentionally hardcoded in `src/main/resources/application.properties`. This is by design for development/demo purposes only — the team is aware these should be externalized via environment variables or a secrets manager in a production setup. Do not flag these as security issues.

@addee1
addee1 merged commit 005d232 into main Apr 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants