Skip to content

Add JWT authentication, RBAC and signup functionality - #9

Merged
addee1 merged 15 commits into
mainfrom
feature/jwt-service
Apr 9, 2026
Merged

Add JWT authentication, RBAC and signup functionality#9
addee1 merged 15 commits into
mainfrom
feature/jwt-service

Conversation

@addee1

@addee1 addee1 commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

🔐 Summary

This PR introduces authentication and security to the application using JWT.

✨ Features

  • Implemented login endpoint that generates JWT tokens
  • Added signup endpoint for user registration (default role: REPORTER)
  • Passwords are securely hashed using BCrypt
  • Implemented JwtAuthenticationFilter to authenticate requests
  • Configured stateless session management with Spring Security
  • Disabled default login mechanisms (formLogin, httpBasic)

🔒 Authorization

  • Added role-based access control using @PreAuthorize
  • Verified access rules for ADMIN, INVESTIGATOR and REPORTER roles

🛠 Utilities

  • Added SecurityUtils to retrieve the currently authenticated user from SecurityContext

🧪 Testing

  • Verified login returns valid JWT
  • Tested protected endpoints with different roles
  • Confirmed 401 for missing token and 403 for insufficient permissions

🧠 Design decisions

  • Role is included in JWT but not used for authorization
  • Roles are instead fetched from the database on each request to ensure up-to-date permissions

🚀 Next steps

  • Apply access control in service layer
  • Secure actual business endpoints (tickets, comments, etc.)

Summary by CodeRabbit

  • New Features

    • JWT token-based authentication; login now returns a token
    • User signup endpoint with input validation
    • Role-based API access control (ADMIN, INVESTIGATOR, REPORTER)
    • New test API endpoints demonstrating role-restricted and public routes
  • Configuration

    • JWT configuration properties (secret and expiration)
    • H2 in-memory database setup with web console access
  • Bug Fixes / Behavior

    • Authentication failures now return a consistent "Bad credentials" response

addee1 added 5 commits April 9, 2026 11:25
- Added JwtService for token generation and validation
- Implemented JwtAuthenticationFilter
- Configured stateless Spring Security
- Disabled default login mechanisms
- Implemented login endpoint with JWT token generation
- Added signup endpoint for user registration
- Passwords are hashed using BCrypt
- Default role set to REPORTER for new users
- Added protected endpoints for ADMIN, INVESTIGATOR and REPORTER
- Verified role-based authorization
- Provides helper method to retrieve current user from SecurityContext
@coderabbitai

coderabbitai Bot commented Apr 9, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@addee1 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 11 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 10 minutes and 11 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 288fbbf3-8483-4c4d-bfa2-028fa52ec9dd

📥 Commits

Reviewing files that changed from the base of the PR and between d7e3c25 and 78ceb89.

📒 Files selected for processing (1)
  • src/main/java/org/example/alfs/controllers/AuthController.java
📝 Walkthrough

Walkthrough

Adds JWT-based auth: JJWT dependencies, JwtService for token generation/validation, a JwtAuthenticationFilter, SecurityConfig with stateless chain and route allowances, signup/login endpoints returning JWTs, role-protected test endpoints, DTO/service updates, and H2 + JWT properties.

Changes

Cohort / File(s) Summary
Maven Dependencies
pom.xml
Added JJWT libs: io.jsonwebtoken:jjwt-api:0.12.5, io.jsonwebtoken:jjwt-impl:0.12.5 (runtime), io.jsonwebtoken:jjwt-jackson:0.12.5 (runtime).
Security config & filter
src/main/java/org/example/alfs/config/SecurityConfig.java, src/main/java/org/example/alfs/security/JwtAuthenticationFilter.java
New SecurityConfig defines stateless filter chain (exposes /auth/**, /h2-console/**), disables CSRF/frame options, and inserts JwtAuthenticationFilter before UsernamePasswordAuthenticationFilter. JwtAuthenticationFilter parses Bearer tokens, loads user, validates token, and sets SecurityContext.
JWT service & utils
src/main/java/org/example/alfs/security/JwtService.java, src/main/java/org/example/alfs/security/SecurityUtils.java
Added JwtService (generate/parse/validate tokens; reads jwt.secret and jwt.expiration) and SecurityUtils helper to obtain the authenticated User from SecurityContext via UserRepository.
Controllers
src/main/java/org/example/alfs/controllers/AuthController.java, src/main/java/org/example/alfs/controllers/TestController.java
AuthController now depends on JwtService; /auth/login returns LoginResponseDTO(token) and new POST /auth/signup added. New TestController provides multiple role-restricted endpoints using @PreAuthorize.
DTOs & service logic
src/main/java/org/example/alfs/dto/auth/LoginResponseDTO.java, src/main/java/org/example/alfs/dto/auth/SignupRequestDTO.java, src/main/java/org/example/alfs/services/AuthService.java
LoginResponseDTO now carries a single token field. Added SignupRequestDTO with validation. AuthService.login() unified unauthorized messages to "Bad credentials"; added signup() to create REPORTER users with encoded passwords.
Configuration
src/main/resources/application.properties
Added H2 datasource and console settings, JPA dialect/ddl-auto, and new jwt.secret and jwt.expiration properties.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Filter as JwtAuthenticationFilter
    participant JwtSvc as JwtService
    participant Repo as UserRepository
    participant SecCtx as SecurityContext
    participant Endpoint as ProtectedEndpoint

    Client->>Filter: HTTP request (Authorization: Bearer <token>)
    Filter->>Filter: skip if URI startsWith /auth or /h2-console
    Filter->>JwtSvc: extractUsername(<token>)
    JwtSvc->>JwtSvc: parse & verify signature
    JwtSvc-->>Filter: username / fail
    alt username extracted
      Filter->>Repo: findByUsername(username)
      Repo-->>Filter: User entity / not found
      alt user found
        Filter->>JwtSvc: isTokenValid(<token>, user)
        JwtSvc-->>Filter: valid / invalid
        alt valid
          Filter->>SecCtx: set Authentication (UsernamePasswordAuthenticationToken)
        end
      end
    end
    Filter->>Endpoint: continue filter chain
    Endpoint-->>Client: response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 I nibble secrets, stitch a key,
Tokens snug beneath the tree,
Filters guard each burrowed gate,
Roles keep pathways neat and straight,
Hop—securely, we authenticate.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.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 clearly and accurately summarizes the main changes: JWT authentication, RBAC, and signup functionality are all central to the changeset.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/jwt-service

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: 8

🧹 Nitpick comments (5)
src/main/java/org/example/alfs/config/SecurityConfig.java (1)

6-7: Unused imports.

HttpMethod and Customizer are imported but not used in this configuration.

🧹 Remove unused imports
 import org.example.alfs.security.JwtAuthenticationFilter;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpMethod;
-import org.springframework.security.config.Customizer;
 import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/alfs/config/SecurityConfig.java` around lines 6 -
7, The SecurityConfig file contains unused imports HttpMethod and Customizer;
remove the imports for HttpMethod and
org.springframework.security.config.Customizer from SecurityConfig (so only
actually used imports remain) to clean up the class and eliminate unused-import
warnings.
src/main/java/org/example/alfs/dto/auth/SignupRequestDTO.java (1)

12-16: Consider adding password strength and username format validation.

The @NotBlank constraints ensure non-empty values, but consider adding:

  • @Size(min = 8) on password for minimum length enforcement
  • @Pattern or @Size on username for format/length constraints

This would prevent weak passwords and invalid usernames at the API boundary rather than relying solely on downstream logic.

💡 Example enhancement
     `@NotBlank`(message = "Username is required")
+    `@Size`(min = 3, max = 50, message = "Username must be between 3 and 50 characters")
     private String username;

     `@NotBlank`(message = "Password is required")
+    `@Size`(min = 8, message = "Password must be at least 8 characters")
     private String password;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/alfs/dto/auth/SignupRequestDTO.java` around lines
12 - 16, Update the SignupRequestDTO validation to enforce stronger constraints:
add `@Size`(min = 8) (and optionally max) to the password field on class
SignupRequestDTO to require a minimum length, and add `@Size`(min = X, max = Y)
and/or `@Pattern`(regexp = "...") to the username field to enforce allowed length
and format. Ensure you import the corresponding javax.validation.constraints
annotations (Size, Pattern) and adjust error messages to reflect the new rules
for the username and password fields.
src/main/resources/application.properties (1)

10-12: H2 console should be disabled in production.

The H2 console provides direct database access and should only be enabled in development environments. Consider making this conditional on the active profile.

💡 Profile-based configuration

Move H2 console settings to application-dev.properties:

# application-dev.properties
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

And in the main application.properties:

-# H2 CONSOLE
-spring.h2.console.enabled=true
-spring.h2.console.path=/h2-console
+# H2 CONSOLE - enabled only in dev profile
+spring.h2.console.enabled=false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/resources/application.properties` around lines 10 - 12, Move the H2
console settings out of the global application.properties and into a dev-only
profile file: create application-dev.properties containing
spring.h2.console.enabled=true and spring.h2.console.path=/h2-console, then in
the main application.properties set spring.h2.console.enabled=false (or remove
the keys) so the H2 console (spring.h2.console.enabled and
spring.h2.console.path) is only active when the "dev" profile is used.
src/main/java/org/example/alfs/security/JwtService.java (1)

57-59: Remove the extractRole method or add documentation explaining its purpose.

The extractRole method is unused dead code. It's defined but never called anywhere in the codebase, yet per your design (lines 29-37), role from the token is intentionally not used for authorization. This unused method can confuse future maintainers into misusing it.

Either remove it to align with the security design, or retain it with a clear comment explaining why it exists despite not being used (e.g., for future extensibility).

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

In `@src/main/java/org/example/alfs/security/JwtService.java` around lines 57 -
59, The method extractRole in JwtService is dead/unnecessary given the design
that token roles aren't used for authorization; either delete the
extractRole(String token) method to avoid confusion, or keep it but add a clear
Javadoc comment above extractRole explaining it is intentionally unused (kept
only for future extensibility or diagnostics) and referencing that authorization
intentionally uses another mechanism (see extractAllClaims usage/design). Ensure
the chosen change is applied only within JwtService and that no external callers
rely on extractRole before removal.
src/main/java/org/example/alfs/controllers/TestController.java (1)

9-64: Move the RBAC demo controller out of the production API surface.

These routes are scaffolding for security checks, not business endpoints. Leaving them enabled in main permanently expands the externally reachable API and makes authorization behavior discoverable through test-only paths.

🤖 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/TestController.java` around lines
9 - 64, TestController and its demo endpoints (class TestController with methods
allRoles, createTicket, assignTicket, updateStatus, hello, adminOnly,
investigatorOnly, reporterOnly) must not be exposed in production; either move
the entire TestController source out of the main API surface into the test
source set (e.g., src/test/java) or restrict its bean registration with a
non-production profile/property. Concretely: remove TestController from the main
runtime classpath and relocate it to test sources OR annotate the class with a
conditional such as `@Profile`({"dev","test"}) or
`@ConditionalOnProperty`(name="app.enable-rbac-demo", havingValue="true",
matchIfMissing=false) so it is not created in production; update imports and
package as needed and verify endpoints no longer appear when running with the
production profile.
🤖 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/config/SecurityConfig.java`:
- Around line 27-29: Security is currently relaxed for all environments; update
configuration so H2 console and disabled security headers apply only in dev:
create application-dev.properties (set spring.profiles.active=dev for local
testing or document how to activate) with spring.h2.console.enabled=true and
application-prod.properties with spring.h2.console.enabled=false, then change
SecurityConfig to apply .csrf(csrf -> csrf.disable()), .headers(...frame ->
frame.disable()) and the permit rule for "/h2-console/**" only when the "dev"
profile is active (use `@Profile`("dev") on a dedicated
WebSecurityConfigurerAdapter/Bean or conditionally build the HttpSecurity in a
method guarded by Environment/Profiles), leaving the stricter defaults for prod;
also remove the unused imports HttpMethod and Customizer from SecurityConfig.

In `@src/main/java/org/example/alfs/controllers/AuthController.java`:
- Around line 48-52: Remove the development BCrypt helper endpoint from
AuthController: delete the public hash() method annotated with
`@GetMapping`("/hash") (and its use of new
BCryptPasswordEncoder().encode("test123")), or if you need similar functionality
only for local testing move it behind a non-production guard (e.g., profile
check) or into test utilities so it is not exposed on the unauthenticated
/auth/** surface; make sure to remove the `@GetMapping` and method declaration for
hash in AuthController.

In `@src/main/java/org/example/alfs/security/JwtAuthenticationFilter.java`:
- Around line 43-60: The JwtAuthenticationFilter currently prints sensitive data
(raw JWT and extracted username) via System.out.println; remove any
System.out.println calls that log the JWT or user identity (e.g., the prints
that output jwt and username and "TOKEN PARSE FAILED") and replace them with
non-sensitive logging: use the class logger to log only high-level events (e.g.,
"auth token parse failed for request" or "filter running for request URI")
without including the token or username, and for failures include
exception.getMessage() or stack at debug/trace only; also remove or sanitize
similar prints in the same class around the 83-86 region so no bearer tokens or
PII are written to logs.
- Around line 67-68: The filter currently throws a RuntimeException when
userRepository.findByUsername(username) returns empty, causing a 500; instead
treat a missing user as unauthenticated by checking the Optional result (from
userRepository.findByUsername) and if absent skip setting authentication and
continue the filter chain (or explicitly clear SecurityContextHolder) so
downstream security returns 401/403; update JwtAuthenticationFilter to avoid
orElseThrow and add a guard around the 'user' handling (use Optional.ifPresent
or if (user == null) { filterChain.doFilter(request, response); return; })
before creating the Authentication.

In `@src/main/java/org/example/alfs/security/SecurityUtils.java`:
- Around line 17-25: getCurrentUser currently calls
SecurityContextHolder.getContext().getAuthentication().getName() without
checking for a null Authentication, which can cause an NPE; update
getCurrentUser to first retrieve Authentication from
SecurityContextHolder.getContext(), verify it's non-null and isAuthenticated (or
throw a clear exception such as AuthenticationCredentialsNotFoundException or a
RuntimeException with a descriptive message), then call getName() safely and use
userRepository.findByUsername(username).orElseThrow(...) as before; reference
the getCurrentUser method and
SecurityContextHolder.getContext().getAuthentication() when making the
null/authenticated checks.

In `@src/main/java/org/example/alfs/services/AuthService.java`:
- Around line 31-36: Remove the three System.out.println debug statements in
AuthService that print the plaintext password, the DB password hash, and the
match result (the lines referencing "INPUT PASSWORD: " + password, "DB HASH: " +
user.getPasswordHash(), and "MATCH RESULT: " + matches). Replace them by either
no logging or a non-sensitive log entry (e.g., log only that a password check
occurred) using the application's logger; keep the actual password check using
passwordEncoder.matches(password, user.getPasswordHash()) intact and do not log
the password or hash itself.
- Around line 28-39: The code leaks user-existence via inconsistent exceptions
and debug logs: replace the RuntimeException thrown by
userRepository.findByUsername(...) with the same
ResponseStatusException(HttpStatus.UNAUTHORIZED, "Bad credentials") used after
passwordEncoder.matches(...), and remove the System.out.println debug lines
(INPUT PASSWORD, DB HASH, MATCH RESULT) to avoid leaking sensitive info; ensure
both failure paths (user not found in AuthService and password mismatch in
passwordEncoder.matches) return the identical ResponseStatusException to
normalize API responses.

In `@src/main/resources/application.properties`:
- Around line 19-20: Remove the hardcoded jwt.secret value and read it from an
external secret source: change the jwt.secret property to reference an
environment variable or secrets manager (e.g., use a placeholder like
${JWT_SECRET} in your configuration) and ensure no plaintext default is
committed; keep jwt.expiration as-is, and add a local-only development override
(e.g., application-dev.properties or CI/dev env) if needed, plus update
deployment manifests / secrets (Kubernetes secret, AWS Secrets Manager, etc.) to
inject JWT_SECRET and generate a strong 256-bit+ secret for production.

---

Nitpick comments:
In `@src/main/java/org/example/alfs/config/SecurityConfig.java`:
- Around line 6-7: The SecurityConfig file contains unused imports HttpMethod
and Customizer; remove the imports for HttpMethod and
org.springframework.security.config.Customizer from SecurityConfig (so only
actually used imports remain) to clean up the class and eliminate unused-import
warnings.

In `@src/main/java/org/example/alfs/controllers/TestController.java`:
- Around line 9-64: TestController and its demo endpoints (class TestController
with methods allRoles, createTicket, assignTicket, updateStatus, hello,
adminOnly, investigatorOnly, reporterOnly) must not be exposed in production;
either move the entire TestController source out of the main API surface into
the test source set (e.g., src/test/java) or restrict its bean registration with
a non-production profile/property. Concretely: remove TestController from the
main runtime classpath and relocate it to test sources OR annotate the class
with a conditional such as `@Profile`({"dev","test"}) or
`@ConditionalOnProperty`(name="app.enable-rbac-demo", havingValue="true",
matchIfMissing=false) so it is not created in production; update imports and
package as needed and verify endpoints no longer appear when running with the
production profile.

In `@src/main/java/org/example/alfs/dto/auth/SignupRequestDTO.java`:
- Around line 12-16: Update the SignupRequestDTO validation to enforce stronger
constraints: add `@Size`(min = 8) (and optionally max) to the password field on
class SignupRequestDTO to require a minimum length, and add `@Size`(min = X, max =
Y) and/or `@Pattern`(regexp = "...") to the username field to enforce allowed
length and format. Ensure you import the corresponding
javax.validation.constraints annotations (Size, Pattern) and adjust error
messages to reflect the new rules for the username and password fields.

In `@src/main/java/org/example/alfs/security/JwtService.java`:
- Around line 57-59: The method extractRole in JwtService is dead/unnecessary
given the design that token roles aren't used for authorization; either delete
the extractRole(String token) method to avoid confusion, or keep it but add a
clear Javadoc comment above extractRole explaining it is intentionally unused
(kept only for future extensibility or diagnostics) and referencing that
authorization intentionally uses another mechanism (see extractAllClaims
usage/design). Ensure the chosen change is applied only within JwtService and
that no external callers rely on extractRole before removal.

In `@src/main/resources/application.properties`:
- Around line 10-12: Move the H2 console settings out of the global
application.properties and into a dev-only profile file: create
application-dev.properties containing spring.h2.console.enabled=true and
spring.h2.console.path=/h2-console, then in the main application.properties set
spring.h2.console.enabled=false (or remove the keys) so the H2 console
(spring.h2.console.enabled and spring.h2.console.path) is only active when the
"dev" profile is used.
🪄 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: 1b4ee94d-31a7-41de-8112-bfa3c2568021

📥 Commits

Reviewing files that changed from the base of the PR and between 9f03d85 and 65f00fb.

📒 Files selected for processing (11)
  • pom.xml
  • 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/TestController.java
  • src/main/java/org/example/alfs/dto/auth/LoginResponseDTO.java
  • src/main/java/org/example/alfs/dto/auth/SignupRequestDTO.java
  • src/main/java/org/example/alfs/security/JwtAuthenticationFilter.java
  • src/main/java/org/example/alfs/security/JwtService.java
  • src/main/java/org/example/alfs/security/SecurityUtils.java
  • src/main/java/org/example/alfs/services/AuthService.java
  • src/main/resources/application.properties

Comment on lines +27 to +29
.csrf(csrf -> csrf.disable())

.headers(headers -> headers.frameOptions(frame -> frame.disable()))

@coderabbitai coderabbitai Bot Apr 9, 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:

#!/bin/bash
# Check if there are profile-specific configurations that might override this
fd -e properties -e yml | xargs rg -l 'h2.console|spring.profiles'

Repository: ithsjava25/project-backend-alfs

Length of output: 116


🏁 Script executed:

cat -n src/main/resources/application.properties

Repository: ithsjava25/project-backend-alfs

Length of output: 720


🏁 Script executed:

# Search for profile-specific property files
fd application- src/main/resources/

Repository: ithsjava25/project-backend-alfs

Length of output: 57


🏁 Script executed:

# Read the full SecurityConfig.java to understand the context
cat -n src/main/java/org/example/alfs/config/SecurityConfig.java

Repository: ithsjava25/project-backend-alfs

Length of output: 2876


Implement Spring profiles to prevent H2 console and disabled security headers from reaching production.

The current configuration exposes the H2 console with direct database access and disabled security headers in all environments. No profile-specific configurations exist to conditionally apply these settings only to development:

  • H2 console is globally enabled (spring.h2.console.enabled=true in application.properties)
  • CSRF and frame options are disabled unconditionally (lines 27, 29)
  • /h2-console/** is permitted without authentication (line 46)

These settings should only apply in development. Create application-dev.properties and application-prod.properties to conditionally enable H2 and relax security only when spring.profiles.active=dev.

Additionally, remove unused imports on lines 6 (HttpMethod) and 7 (Customizer).

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

In `@src/main/java/org/example/alfs/config/SecurityConfig.java` around lines 27 -
29, Security is currently relaxed for all environments; update configuration so
H2 console and disabled security headers apply only in dev: create
application-dev.properties (set spring.profiles.active=dev for local testing or
document how to activate) with spring.h2.console.enabled=true and
application-prod.properties with spring.h2.console.enabled=false, then change
SecurityConfig to apply .csrf(csrf -> csrf.disable()), .headers(...frame ->
frame.disable()) and the permit rule for "/h2-console/**" only when the "dev"
profile is active (use `@Profile`("dev") on a dedicated
WebSecurityConfigurerAdapter/Bean or conditionally build the HttpSecurity in a
method guarded by Environment/Profiles), leaving the stricter defaults for prod;
also remove the unused imports HttpMethod and Customizer from SecurityConfig.

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 are intentionally keeping this configuration for development only.

  • H2 console is enabled to simplify local development and testing
  • CSRF is disabled because we are building a stateless REST API using JWT
  • Frame options are disabled to allow the H2 console UI to load

This project is not targeting production deployment, and these settings are acceptable for the current scope.

We have added comments in the code to clarify that this is for development purposes only.

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, that's a clear and reasonable explanation — thank you for the context. For a development-only project with a stateless JWT-based REST API, disabling CSRF and frame options and enabling the H2 console are all justified, and adding clarifying comments in the code is a good practice.

One minor item still worth addressing from the original comment: the unused imports HttpMethod (Line 6) and Customizer (Line 7) in SecurityConfig.java can be removed to keep the file clean, since they are not referenced anywhere in the class.


✏️ Learnings added
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:08.771Z
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.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment thread src/main/java/org/example/alfs/controllers/AuthController.java Outdated
Comment thread src/main/java/org/example/alfs/security/JwtAuthenticationFilter.java Outdated
Comment thread src/main/java/org/example/alfs/security/JwtAuthenticationFilter.java Outdated
Comment thread src/main/java/org/example/alfs/security/SecurityUtils.java
Comment thread src/main/java/org/example/alfs/services/AuthService.java
Comment thread src/main/java/org/example/alfs/services/AuthService.java Outdated
Comment on lines +19 to +20
jwt.secret=bXlTdXBlclNlY3JldEtleU15U3VwZXJTZWNyZXRLZXk=
jwt.expiration=86400000 No newline at end of file

@coderabbitai coderabbitai Bot Apr 9, 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 | 🔴 Critical

Hardcoded JWT secret is a critical security vulnerability.

The JWT secret is committed directly in the properties file. This value (which decodes to "mySuperSecretKeyMySuperSecretKey") should never be in version control:

  • Anyone with repository access can forge valid JWTs
  • Rotating the secret requires a code change and deployment
  • This violates security best practices for secrets management

Use environment variables or a secrets manager instead.

🔒 Proposed fix using environment variable
-jwt.secret=bXlTdXBlclNlY3JldEtleU15U3VwZXJTZWNyZXRLZXk=
+jwt.secret=${JWT_SECRET}
 jwt.expiration=86400000

For local development, you can provide a default in application-dev.properties or set the environment variable. In production, inject the secret via your deployment configuration (Kubernetes secrets, AWS Secrets Manager, etc.).

Generate a strong secret (minimum 256 bits for HS256):

openssl rand -base64 32
📝 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
jwt.secret=bXlTdXBlclNlY3JldEtleU15U3VwZXJTZWNyZXRLZXk=
jwt.expiration=86400000
jwt.secret=${JWT_SECRET}
jwt.expiration=86400000
🧰 Tools
🪛 Betterleaks (1.1.1)

[high] 19-19: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

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

In `@src/main/resources/application.properties` around lines 19 - 20, Remove the
hardcoded jwt.secret value and read it from an external secret source: change
the jwt.secret property to reference an environment variable or secrets manager
(e.g., use a placeholder like ${JWT_SECRET} in your configuration) and ensure no
plaintext default is committed; keep jwt.expiration as-is, and add a local-only
development override (e.g., application-dev.properties or CI/dev env) if needed,
plus update deployment manifests / secrets (Kubernetes secret, AWS Secrets
Manager, etc.) to inject JWT_SECRET and generate a strong 256-bit+ secret for
production.

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 are aware that the JWT secret should not be hardcoded in a real-world application.

For this project (development/demo purposes), we are keeping it in application.properties
for simplicity, and have added a comment to clarify this.

In a production setup, the secret would be stored securely using environment variables
or a secret manager.

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! Thanks for the clarification. Since this is a development/demo project, keeping the secret in application.properties with a clarifying comment is a reasonable pragmatic choice. I'll record this for future reviews.


✏️ Learnings added
Learnt from: addee1
Repo: ithsjava25/project-backend-alfs PR: 9
File: src/main/resources/application.properties:19-20
Timestamp: 2026-04-09T10:02:49.016Z
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.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 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:08.771Z
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.

addee1 added 6 commits April 9, 2026 12:04
- Added comment explaining that the JWT secret is hardcoded for demo purposes
- Clarified that environment variables should be used in production
- Removed public BCrypt helper endpoint used for development
- Eliminates unnecessary attack surface
- Unified error response to prevent user enumeration
- Removed logging of sensitive data (passwords and hashes)
- Return consistent "Bad credentials" for invalid login attempts
- Removed logging of JWT tokens and user information
- Prevented server errors by handling missing users gracefully
- Treat invalid tokens as unauthenticated requests
- Added comments explaining disabled CSRF and frame options
- Clarified that configuration is intended for development only
- Prevent potential NullPointerException when authentication is missing
- Ensure user is authenticated before accessing SecurityContext

@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

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

43-46: Prefer explicit 201 Created contract for successful signup.

Returning void here currently defaults to 200 OK; for resource creation, explicit 201 Created is clearer for clients and API consistency.

✅ Suggested API response contract
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
...
-    `@PostMapping`("/signup")
-    public void signup(`@Valid` `@RequestBody` SignupRequestDTO request) {
-        authService.signup(request);
-    }
+    `@PostMapping`("/signup")
+    `@ResponseStatus`(HttpStatus.CREATED)
+    public void signup(`@Valid` `@RequestBody` SignupRequestDTO request) {
+        authService.signup(request);
+    }

You can also use ResponseEntity<Void> if you want explicit header control.

🤖 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
43 - 46, The signup endpoint in AuthController currently returns void causing a
200 OK; change the method signature from void to ResponseEntity<Void> (or use
`@ResponseStatus`) and return an explicit 201 Created response after calling
authService.signup(request) — e.g., return
ResponseEntity.status(HttpStatus.CREATED).build() or return
ResponseEntity.created(locationUri).build() if you can provide a Location
header; update the method name/signature and imports accordingly to reference
AuthController.signup and the authService.signup call.
🤖 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/AuthController.java`:
- Around line 40-42: The JavaDoc above the signup endpoint in AuthController
currently describes a login flow; update the comment to accurately document the
signup behavior (e.g., that the `@PostMapping`("/signup") method in class
AuthController creates a new user, validates signup input, persists the user,
and returns the created user or auth token), and replace the incorrect phrase
"Handles user login by validating credentials and returning user details" with a
concise description matching the signup method name (e.g., signUp / signupUser)
and its actual return semantics.

---

Nitpick comments:
In `@src/main/java/org/example/alfs/controllers/AuthController.java`:
- Around line 43-46: The signup endpoint in AuthController currently returns
void causing a 200 OK; change the method signature from void to
ResponseEntity<Void> (or use `@ResponseStatus`) and return an explicit 201 Created
response after calling authService.signup(request) — e.g., return
ResponseEntity.status(HttpStatus.CREATED).build() or return
ResponseEntity.created(locationUri).build() if you can provide a Location
header; update the method name/signature and imports accordingly to reference
AuthController.signup and the authService.signup call.
🪄 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: b3a94ba9-224f-484e-93e2-8214bc72d7f5

📥 Commits

Reviewing files that changed from the base of the PR and between 65f00fb and ebad5bb.

📒 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/security/JwtAuthenticationFilter.java
  • src/main/java/org/example/alfs/security/SecurityUtils.java
  • src/main/java/org/example/alfs/services/AuthService.java
  • src/main/resources/application.properties
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/main/java/org/example/alfs/security/SecurityUtils.java
  • src/main/java/org/example/alfs/config/SecurityConfig.java
  • src/main/java/org/example/alfs/services/AuthService.java
  • src/main/resources/application.properties
  • src/main/java/org/example/alfs/security/JwtAuthenticationFilter.java

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

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/org/example/alfs/controllers/AuthController.java (1)

24-26: ⚠️ Potential issue | 🟡 Minor

Update login JavaDoc to match actual response.

Line 25 still says login returns user details, but the method now returns a JWT token response.

✏️ Suggested doc fix
-    /**
-     * Handles user login by validating credentials and returning user details.
-     */
+    /**
+     * Handles user login by validating credentials and returning a JWT token.
+     */
🤖 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
24 - 26, The JavaDoc for AuthController's login method is outdated — it states
the method returns user details but the method now returns a JWT token response;
update the JavaDoc on the login (or authenticate) method in class AuthController
to describe that it validates credentials and returns a JWT token (including
token fields and response status), and remove or correct any mention of
returning user details so the comments match the actual JWT token response
structure.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/main/java/org/example/alfs/controllers/AuthController.java`:
- Around line 24-26: The JavaDoc for AuthController's login method is outdated —
it states the method returns user details but the method now returns a JWT token
response; update the JavaDoc on the login (or authenticate) method in class
AuthController to describe that it validates credentials and returns a JWT token
(including token fields and response status), and remove or correct any mention
of returning user details so the comments match the actual JWT token response
structure.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7683f84d-ae90-4f47-9992-1fb6d57e9c7f

📥 Commits

Reviewing files that changed from the base of the PR and between ebad5bb and d7e3c25.

📒 Files selected for processing (2)
  • src/main/java/org/example/alfs/config/SecurityConfig.java
  • src/main/java/org/example/alfs/controllers/AuthController.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/org/example/alfs/config/SecurityConfig.java

@addee1
addee1 merged commit 8d9a5ff into main Apr 9, 2026
2 checks passed
This was referenced Apr 21, 2026
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.

1 participant