Skip to content

implement usual user login functionality with validation and auditing#1851

Merged
Artuomka merged 1 commit into
mainfrom
backend-frontend_agent
Jun 30, 2026
Merged

implement usual user login functionality with validation and auditing#1851
Artuomka merged 1 commit into
mainfrom
backend-frontend_agent

Conversation

@Artuomka

@Artuomka Artuomka commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Added a new SaaS login endpoint for email/password sign-in.
    • Login responses now return user details, including 2FA status when applicable.
  • Bug Fixes

    • Improved handling for invalid credentials, unknown users, and missing authentication for the login route.
    • Added stricter validation for login requests and company/domain matching.
  • Tests

    • Added end-to-end coverage for successful and failed SaaS login flows.

Copilot AI review requested due to automatic review settings June 30, 2026 07:59
@Artuomka Artuomka enabled auto-merge June 30, 2026 07:59
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a POST /saas/user/login endpoint to the SaaS microservice. A new SaasUsualLoginUseCase resolves users by companyId, custom domain, or single-company email fallback, validates the domain and password, audits sign-in attempts, and returns FoundUserDto. The use case is registered under a new SAAS_USUAL_LOGIN_USER token and covered by AVA E2E tests.

Changes

SaaS Usual Login Bridge

Layer / File(s) Summary
Token and interface contract
backend/src/common/data-injection.tokens.ts, backend/src/microservices/saas-microservice/use-cases/saas-use-cases.interface.ts
Adds SAAS_USUAL_LOGIN_USER enum member and exports ISaasUsualLoginUser interface with an execute(UsualLoginDs, inTransaction?) => Promise<FoundUserDto> signature.
SaasUsualLoginUseCase implementation
backend/src/microservices/saas-microservice/use-cases/saas-usual-login.use.case.ts
Implements user lookup by companyId, SaaS domain mapping via SaasCompanyGatewayService, or single-company email fallback; validates request domain; verifies password via Encryptor; records sign-in audit entries; builds and returns FoundUserDto with is_2fa_enabled.
Controller endpoint and module wiring
backend/src/microservices/saas-microservice/saas.controller.ts, backend/src/microservices/saas-microservice/saas.module.ts
Adds POST user/login handler to SaasController, registers SaasUsualLoginUseCase as the SAAS_USUAL_LOGIN_USER provider, and extends SaaSAuthMiddleware to protect the new route.
E2E tests
backend/test/ava-tests/saas-tests/saas-user-login-e2e.test.ts
AVA suite covering successful login, OTP flag exposure, wrong password (400), unknown user (404), and missing microservice JWT (401).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • gugu
  • lyubov-voloshko

Poem

🐇 A bunny hops to login's gate,
With email, password, domain straight,
The use case checks the domain's claim,
Audits failures, wins the game,
FoundUserDto hops back with glee —
SaaS auth flows, as it should be! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Security Check ⚠️ Warning POST /saas/user/login still takes raw @Body fields, and the use case calls userData.email.toLowerCase(), so missing email can become a 500. Add a validated DTO or explicit guards for required login fields (email/password/request_domain/companyId as needed) before invoking the use case, and cover malformed payloads in tests.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding usual user login with validation and auditing.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 backend-frontend_agent

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.

@coderabbitai coderabbitai Bot requested review from gugu and lyubov-voloshko June 30, 2026 08:02

Copilot AI left a comment

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.

Pull request overview

Adds a SaaS “usual login” bridge endpoint (POST /saas/user/login) to the backend microservice layer. This lets the SaaS control plane verify email/password (including request-domain validation and sign-in auditing) and return FoundUserDto without minting an end-user token/cookie (left to rocketadmin-saas).

Changes:

  • Introduces SaasUsualLoginUseCase that mirrors OSS UsualLoginUseCase login verification + domain validation + sign-in audit recording, but returns FoundUserDto instead of signing JWTs.
  • Wires the new use case into SaasModule/DI and exposes POST /saas/user/login in SaasController.
  • Adds AVA e2e coverage for the new SaaS login bridge behavior (success, 2FA flag surfaced, wrong password, unknown user, missing microservice JWT).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
backend/test/ava-tests/saas-tests/saas-user-login-e2e.test.ts New e2e tests for the SaaS login bridge endpoint behavior (no token/cookie, 2FA flag, auth required).
backend/src/microservices/saas-microservice/use-cases/saas-usual-login.use.case.ts New SaaS login use case that verifies credentials, validates request domain, and records sign-in audits, returning FoundUserDto.
backend/src/microservices/saas-microservice/use-cases/saas-use-cases.interface.ts Adds ISaasUsualLoginUser interface for the new use case.
backend/src/microservices/saas-microservice/saas.module.ts Registers the new use case provider and applies SaaS auth middleware to the new route.
backend/src/microservices/saas-microservice/saas.controller.ts Adds POST /saas/user/login handler delegating to the new use case.
backend/src/common/data-injection.tokens.ts Adds a new UseCaseType token for SaaS usual login.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +176 to +181
@ApiOperation({ summary: 'User login webhook' })
@ApiResponse({
status: 200,
description: 'Credentials verified; user info returned (no token is signed here — the caller signs the cookie).',
type: FoundUserDto,
})
@@ -0,0 +1,183 @@
import { faker } from '@faker-js/faker';

@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 (3)
backend/test/ava-tests/saas-tests/saas-user-login-e2e.test.ts (3)

95-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a template literal for the error message.

As per coding guidelines, **/*.{js,ts,jsx,tsx} should “Use template literals instead of string concatenation.”

Proposed fix
-		console.error('After tests error ' + e);
+		console.error(`After tests error ${e}`);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/test/ava-tests/saas-tests/saas-user-login-e2e.test.ts` at line 95,
The error logging in saas-user-login-e2e.test.ts uses string concatenation
instead of the required template literal. Update the console.error call in the
test’s after-tests error handling to use a template literal while preserving the
same message and error value, following the project guideline for all
js/ts/jsx/tsx code.

Source: Coding guidelines


32-43: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align test helpers with the TypeScript style rules.

Use arrow-function helpers and named interfaces for the options/fixture shapes. As per coding guidelines, **/*.{js,ts,jsx,tsx} should “Prefer arrow functions over function declarations” and **/*.{ts,tsx} should “Use interfaces for object shapes and type for unions and primitives.”

Proposed refactor
-function microserviceAuthHeader(): string {
+const microserviceAuthHeader = (): string => {
 	const token = jwt.sign({ request_id: faker.string.uuid() }, appConfig.auth.microserviceJwtSecret);
 	return `Bearer ${token}`;
-}
+};

-async function createCoreUser(opts: { isOTPEnabled?: boolean } = {}): Promise<{
+interface CoreUserOptions {
+	isOTPEnabled?: boolean;
+}
+
+interface CoreUserFixture {
 	email: string;
 	password: string;
 	companyId: string;
 	userId: string;
-}> {
+}
+
+const createCoreUser = async (opts: CoreUserOptions = {}): Promise<CoreUserFixture> => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/test/ava-tests/saas-tests/saas-user-login-e2e.test.ts` around lines
32 - 43, The test helper definitions are not following the TypeScript style
rules: `microserviceAuthHeader` is a function declaration and the inline object
shapes in `createCoreUser` use anonymous types. Refactor these helpers to use
arrow functions, and introduce named interfaces for the options and returned
fixture shapes used by `createCoreUser` so the test file matches the project’s
TS conventions.

Source: Coding guidelines


101-166: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover the non-companyId resolution paths.

The new use case has separate branches for custom-domain lookup and single-company email fallback, but the e2e suite only exercises the explicit companyId path. Add success/failure coverage for those branches to protect the login bridge contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/test/ava-tests/saas-tests/saas-user-login-e2e.test.ts` around lines
101 - 166, The saas user login e2e suite only covers the explicit companyId
branch, so the custom-domain lookup and single-company email fallback paths in
the login flow are untested. Add test coverage in saas-user-login-e2e.test.ts
around the existing test.serial cases for /saas/user/login to verify both
successful and failing resolution when companyId is omitted, using
createCoreUser and the current login request setup. Include assertions for the
resolved user response on success and the expected rejection behavior on failure
so the bridge contract is protected across all resolution branches.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/src/microservices/saas-microservice/saas.controller.ts`:
- Around line 183-194: Validate the request body in usualUserLogin before
calling usualLoginUserUseCase.execute by introducing a DTO or explicit guards
for required fields like email, password, and request_domain. Update the
controller method to accept the validated object instead of raw `@Body` fields,
and ensure missing/invalid inputs are rejected early so
userData.email.toLowerCase() is never reached with undefined.

---

Nitpick comments:
In `@backend/test/ava-tests/saas-tests/saas-user-login-e2e.test.ts`:
- Line 95: The error logging in saas-user-login-e2e.test.ts uses string
concatenation instead of the required template literal. Update the console.error
call in the test’s after-tests error handling to use a template literal while
preserving the same message and error value, following the project guideline for
all js/ts/jsx/tsx code.
- Around line 32-43: The test helper definitions are not following the
TypeScript style rules: `microserviceAuthHeader` is a function declaration and
the inline object shapes in `createCoreUser` use anonymous types. Refactor these
helpers to use arrow functions, and introduce named interfaces for the options
and returned fixture shapes used by `createCoreUser` so the test file matches
the project’s TS conventions.
- Around line 101-166: The saas user login e2e suite only covers the explicit
companyId branch, so the custom-domain lookup and single-company email fallback
paths in the login flow are untested. Add test coverage in
saas-user-login-e2e.test.ts around the existing test.serial cases for
/saas/user/login to verify both successful and failing resolution when companyId
is omitted, using createCoreUser and the current login request setup. Include
assertions for the resolved user response on success and the expected rejection
behavior on failure so the bridge contract is protected across all resolution
branches.
🪄 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: 10ccf2a5-0847-4b73-915d-766b9c91d5a9

📥 Commits

Reviewing files that changed from the base of the PR and between caea992 and 583247b.

📒 Files selected for processing (6)
  • backend/src/common/data-injection.tokens.ts
  • backend/src/microservices/saas-microservice/saas.controller.ts
  • backend/src/microservices/saas-microservice/saas.module.ts
  • backend/src/microservices/saas-microservice/use-cases/saas-use-cases.interface.ts
  • backend/src/microservices/saas-microservice/use-cases/saas-usual-login.use.case.ts
  • backend/test/ava-tests/saas-tests/saas-user-login-e2e.test.ts

Comment on lines +183 to +194
async usualUserLogin(
@Body('email') email: string,
@Body('password') password: string,
@Body('companyId') companyId: string,
@Body('request_domain') request_domain: string,
@Body('ipAddress') ipAddress: string,
@Body('userAgent') userAgent: string,
): Promise<FoundUserDto> {
return await this.usualLoginUserUseCase.execute(
{ email, password, companyId, request_domain, ipAddress, userAgent, gclidValue: null },
InTransactionEnum.OFF,
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Validate the login body before invoking the use case.

The handler passes raw body fields into the use case; a missing email reaches userData.email.toLowerCase() and can turn a bad request into a 500. Use a DTO with runtime validators or explicit checks for required email, password, and request_domain.

Proposed direction
-	async usualUserLogin(
-		`@Body`('email') email: string,
-		`@Body`('password') password: string,
-		`@Body`('companyId') companyId: string,
-		`@Body`('request_domain') request_domain: string,
-		`@Body`('ipAddress') ipAddress: string,
-		`@Body`('userAgent') userAgent: string,
-	): Promise<FoundUserDto> {
+	async usualUserLogin(`@Body`() loginData: SaasUsualLoginDto): Promise<FoundUserDto> {
 		return await this.usualLoginUserUseCase.execute(
-			{ email, password, companyId, request_domain, ipAddress, userAgent, gclidValue: null },
+			{ ...loginData, gclidValue: null },
 			InTransactionEnum.OFF,
 		);
 	}
📝 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
async usualUserLogin(
@Body('email') email: string,
@Body('password') password: string,
@Body('companyId') companyId: string,
@Body('request_domain') request_domain: string,
@Body('ipAddress') ipAddress: string,
@Body('userAgent') userAgent: string,
): Promise<FoundUserDto> {
return await this.usualLoginUserUseCase.execute(
{ email, password, companyId, request_domain, ipAddress, userAgent, gclidValue: null },
InTransactionEnum.OFF,
);
async usualUserLogin(`@Body`() loginData: SaasUsualLoginDto): Promise<FoundUserDto> {
return await this.usualLoginUserUseCase.execute(
{ ...loginData, gclidValue: null },
InTransactionEnum.OFF,
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/microservices/saas-microservice/saas.controller.ts` around lines
183 - 194, Validate the request body in usualUserLogin before calling
usualLoginUserUseCase.execute by introducing a DTO or explicit guards for
required fields like email, password, and request_domain. Update the controller
method to accept the validated object instead of raw `@Body` fields, and ensure
missing/invalid inputs are rejected early so userData.email.toLowerCase() is
never reached with undefined.

@Artuomka Artuomka merged commit ad48b86 into main Jun 30, 2026
17 of 18 checks passed
@Artuomka Artuomka deleted the backend-frontend_agent branch June 30, 2026 08:08
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