Skip to content

Implement login with DTO and secure password validation#7

Merged
addee1 merged 10 commits intomainfrom
feature/auth-login
Apr 2, 2026
Merged

Implement login with DTO and secure password validation#7
addee1 merged 10 commits intomainfrom
feature/auth-login

Conversation

@addee1
Copy link
Copy Markdown
Contributor

@addee1 addee1 commented Apr 2, 2026

🔐 Authentication (Login)

This PR implements a basic login flow for users.

✅ What’s included

  • AuthController with POST /auth/login endpoint
  • AuthService with login logic
  • Integration with UserRepository
  • Password validation using BCrypt
  • Proper HTTP status handling (401 Unauthorized for invalid credentials)

📦 DTOs

  • LoginRequestDTO
  • LoginResponseDTO

Uses DTOs for request and response to ensure type safety and a clean API design.

🔒 Security improvements

  • Passwords are validated using BCrypt (PasswordEncoder)
  • Generic error message for invalid login to avoid user enumeration
  • Uses correct HTTP status codes instead of generic exceptions

🚀 Notes

  • This is a base for upcoming JWT implementation
  • No token handling included yet

Ready to extend with JWT authentication next 🔐

Summary by CodeRabbit

  • New Features

    • Added user authentication: users can log in with username and password via a new login API that returns username and role on success.
    • Secure password handling using BCrypt-backed password encoding.
    • Repository support for finding users by username.
    • New request/response payloads for login.
  • Bug Fixes

    • Ensure new users get a default role when first saved.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

Adds password encoding and credential-based login: a BCrypt PasswordEncoder bean, AuthService that validates credentials against UserRepository, DTOs and AuthController exposing POST /auth/login, and a default role pre-persist on User.

Changes

Cohort / File(s) Summary
Configuration & Beans
src/main/java/org/example/alfs/config/PasswordConfig.java
New Spring @Configuration registering a PasswordEncoder bean (BCryptPasswordEncoder).
Service & Repository
src/main/java/org/example/alfs/services/AuthService.java, src/main/java/org/example/alfs/repositories/UserRepository.java
Adds AuthService.login(username,password) performing user lookup and password verification (throws 401 on failure); adds Optional<User> findByUsername(String) to repository.
DTOs
src/main/java/org/example/alfs/dto/auth/LoginRequestDTO.java, src/main/java/org/example/alfs/dto/auth/LoginResponseDTO.java
Adds LoginRequestDTO (username, password) with @NotBlank validations and LoginResponseDTO (username, role) with Lombok-generated accessors.
REST Controller
src/main/java/org/example/alfs/controllers/AuthController.java
Adds AuthController mapped to /auth with POST /auth/login that validates input, calls AuthService.login, and returns LoginResponseDTO.
Entities
src/main/java/org/example/alfs/entities/User.java
Marks role column nullable = false and adds @PrePersist to set default Role.REPORTER when role is null.

Sequence Diagram

sequenceDiagram
    actor Client
    participant AuthController
    participant AuthService
    participant UserRepository
    participant PasswordEncoder
    participant Database

    Client->>AuthController: POST /auth/login {username, password}
    AuthController->>AuthService: login(username, password)
    AuthService->>UserRepository: findByUsername(username)
    UserRepository->>Database: query user by username
    Database-->>UserRepository: user or empty

    alt user not found
        AuthService-->>AuthController: throw 401 Unauthorized
        AuthController-->>Client: 401 Unauthorized
    else user found
        AuthService->>PasswordEncoder: matches(plain, storedHash)
        PasswordEncoder-->>AuthService: boolean
        alt mismatch
            AuthService-->>AuthController: throw 401 Unauthorized
            AuthController-->>Client: 401 Unauthorized
        else match
            AuthService-->>AuthController: User
            AuthController->>AuthController: build LoginResponseDTO(username, role)
            AuthController-->>Client: 200 OK {username, role}
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Poem

🐇 I nibble code and hum debug tunes,
BCrypt blossoms under midnight moons,
A login hop, a hashed embrace,
Repo, service, controller in place,
Hooray — secure paws in the race!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% 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 'Implement login with DTO and secure password validation' accurately and clearly summarizes the main changes: a login feature with DTOs and BCrypt password security.

✏️ 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/auth-login

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/main/java/org/example/alfs/dto/auth/LoginRequestDTO.java (1)

6-11: Consider adding bean validation annotations.

The DTO lacks input validation. Adding @NotBlank constraints would reject malformed requests early at the controller layer, avoiding unnecessary service calls and database queries.

♻️ Proposed validation enhancement
 package org.example.alfs.dto.auth;
 
 import lombok.Getter;
 import lombok.Setter;
+import jakarta.validation.constraints.NotBlank;
 
 `@Getter`
 `@Setter`
 public class LoginRequestDTO {
+    `@NotBlank`(message = "Username is required")
     private String username;
+    `@NotBlank`(message = "Password is required")
     private String password;
 
 }

Note: Requires adding @Valid to the controller's @RequestBody parameter.

🤖 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/LoginRequestDTO.java` around lines 6
- 11, The LoginRequestDTO currently has no validation; annotate the username and
password fields in class LoginRequestDTO with `@NotBlank` (from
javax.validation.constraints.NotBlank or jakarta equivalent) to enforce
non-empty input, and ensure the controller method that accepts this DTO uses
`@Valid` on the `@RequestBody` parameter so validation is triggered; keep the
existing `@Getter/`@Setter (Lombok) and add the necessary import for the NotBlank
annotation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/main/java/org/example/alfs/dto/auth/LoginRequestDTO.java`:
- Around line 6-11: The LoginRequestDTO currently has no validation; annotate
the username and password fields in class LoginRequestDTO with `@NotBlank` (from
javax.validation.constraints.NotBlank or jakarta equivalent) to enforce
non-empty input, and ensure the controller method that accepts this DTO uses
`@Valid` on the `@RequestBody` parameter so validation is triggered; keep the
existing `@Getter/`@Setter (Lombok) and add the necessary import for the NotBlank
annotation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ddf5cf04-143a-437d-86b8-cb3ad7487c46

📥 Commits

Reviewing files that changed from the base of the PR and between 51bd77c and c139707.

📒 Files selected for processing (6)
  • src/main/java/org/example/alfs/config/PasswordConfig.java
  • src/main/java/org/example/alfs/controllers/AuthController.java
  • src/main/java/org/example/alfs/dto/auth/LoginRequestDTO.java
  • src/main/java/org/example/alfs/dto/auth/LoginResponseDTO.java
  • src/main/java/org/example/alfs/repositories/UserRepository.java
  • src/main/java/org/example/alfs/services/AuthService.java

@simonforsberg
Copy link
Copy Markdown
Contributor

Nice work on the PR! Will there be a SecurityConfig in the next PR/when you move on to JWT authentication?

@addee1
Copy link
Copy Markdown
Contributor Author

addee1 commented Apr 2, 2026

Nice work on the PR! Will there be a SecurityConfig in the next PR/when you move on to JWT authentication?

Yesbox

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

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/AuthController.java`:
- Around line 34-37: In AuthController where you build the LoginResponseDTO from
user (the block calling user.getRole().name()), guard against a null role by
using a null-safe expression to pass either a default string (e.g., "UNKNOWN" or
"USER") or null to LoginResponseDTO when user.getRole() is null; update the code
that constructs the response in AuthController to check user.getRole() before
calling .name(); alternatively enforce non-null at the entity level by adding
`@Column`(nullable = false) to User.role and ensure a default role is set on user
creation (update User entity and user creation flow) so user.getRole() can never
be null.
🪄 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: 1bf90207-8d22-4aef-a834-d0cc4f4991c3

📥 Commits

Reviewing files that changed from the base of the PR and between c139707 and bdcbf05.

📒 Files selected for processing (4)
  • src/main/java/org/example/alfs/controllers/AuthController.java
  • src/main/java/org/example/alfs/dto/auth/LoginRequestDTO.java
  • src/main/java/org/example/alfs/dto/auth/LoginResponseDTO.java
  • src/main/java/org/example/alfs/services/AuthService.java
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/org/example/alfs/dto/auth/LoginResponseDTO.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/java/org/example/alfs/dto/auth/LoginRequestDTO.java
  • src/main/java/org/example/alfs/services/AuthService.java

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

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/entities/User.java`:
- Around line 30-31: The User.role field was changed to `@Column`(nullable =
false) which will break migrations if existing user rows have NULL and can cause
NPE in AuthController.login() where user.getRole().name() is called; before
enforcing this constraint, add a data migration (Flyway/Liquibase or raw SQL)
that sets a sensible default for existing null roles (e.g., update users set
role='REPORTER' where role is null) and then apply the schema change, ensuring
AuthController.login() and the User entity are safe from null roles.
🪄 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: 66251dff-d530-4472-abaa-6c7ce37f5dea

📥 Commits

Reviewing files that changed from the base of the PR and between bdcbf05 and 6e95838.

📒 Files selected for processing (1)
  • src/main/java/org/example/alfs/entities/User.java

Comment on lines +30 to 31
@Column(nullable = false)
private Role role;
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Apr 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Ensure existing users have roles before applying this constraint.

Adding nullable = false to an existing column requires that no null values exist in the database. If there are existing users with null roles, the schema migration will fail or existing users will cause NullPointerException in AuthController.login() when calling user.getRole().name().

Consider adding a data migration (e.g., Flyway/Liquibase script or a SQL update) to set a default role for any existing null values before this constraint is enforced:

UPDATE users SET role = 'REPORTER' WHERE role IS NULL;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/alfs/entities/User.java` around lines 30 - 31, The
User.role field was changed to `@Column`(nullable = false) which will break
migrations if existing user rows have NULL and can cause NPE in
AuthController.login() where user.getRole().name() is called; before enforcing
this constraint, add a data migration (Flyway/Liquibase or raw SQL) that sets a
sensible default for existing null roles (e.g., update users set role='REPORTER'
where role is null) and then apply the schema change, ensuring
AuthController.login() and the User entity are safe from null roles.

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 dont have any existing database or persisted users yet, so this wont cause issues in our current setup. We'll handle migrations properly when we introduce a real database.

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 makes sense — since there's no existing database or persisted users yet, the nullable = false constraint won't cause any migration issues right now, and the @PrePersist callback already guards against null roles on new entities.

Just a reminder for when you introduce a real database: before applying this schema constraint in a migration script, make sure to run a backfill like the one suggested (e.g., UPDATE users SET role = 'REPORTER' WHERE role IS NULL;) before or alongside the ALTER TABLE step to avoid migration failures on any pre-existing data.

@addee1 addee1 merged commit 9f03d85 into main Apr 2, 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.

2 participants