Skip to content

Feat: Api key enable - #237

Open
DevendraPPatil wants to merge 2 commits into
Sunbird-ALL:lais-v1.1.2-api-keyfrom
DevendraPPatil:lais-v1.1.2-api-key
Open

Feat: Api key enable#237
DevendraPPatil wants to merge 2 commits into
Sunbird-ALL:lais-v1.1.2-api-keyfrom
DevendraPPatil:lais-v1.1.2-api-key

Conversation

@DevendraPPatil

@DevendraPPatil DevendraPPatil commented Jul 28, 2025

Copy link
Copy Markdown
Collaborator

Feat: Api key enable

Summary by CodeRabbit

  • New Features

    • Introduced API key validation for selected learner profile update and content retrieval endpoints. Requests to these endpoints now require a valid API key when API key validation is enabled.
  • Bug Fixes

    • Improved security by ensuring only authorized requests can access or update learner profiles and content when API key validation is active.

@coderabbitai

coderabbitai Bot commented Jul 28, 2025

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

A new NestJS interceptor, ValidateApiKeyInterceptor, is introduced to validate API keys on incoming HTTP requests. This interceptor is applied to several POST and GET endpoints in the ScoresController to enforce API key validation based on environment configuration, without altering the core logic of the controller methods.

Changes

Cohort / File(s) Change Summary
API Key Validation Interceptor
src/middlewares/verify.key.ts
Introduced ValidateApiKeyInterceptor class to handle API key extraction, validation via an external service, and error handling.
Controller Integration
src/mongodb/scores.controller.ts
Applied ValidateApiKeyInterceptor using @UseInterceptors to multiple endpoints; added necessary imports. No business logic changes.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ScoresController
    participant ValidateApiKeyInterceptor
    participant AuthService

    Client->>ScoresController: HTTP Request (e.g., POST /updateLearnerProfile/ta)
    ScoresController->>ValidateApiKeyInterceptor: Request intercepted
    ValidateApiKeyInterceptor->>ValidateApiKeyInterceptor: Check env for API key validation
    alt Validation enabled
        ValidateApiKeyInterceptor->>ValidateApiKeyInterceptor: Extract 'api-key' header
        ValidateApiKeyInterceptor->>AuthService: POST /validate with API key
        AuthService-->>ValidateApiKeyInterceptor: Validation response
        alt Key valid
            ValidateApiKeyInterceptor->>ScoresController: Proceed to controller logic
        else Key invalid
            ValidateApiKeyInterceptor-->>Client: 401 Unauthorized
        end
    else Validation disabled
        ValidateApiKeyInterceptor->>ScoresController: Proceed to controller logic
    end
    ScoresController-->>Client: Response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15 minutes

Poem

A rabbit hops through code so neat,
Guarding endpoints, swift and fleet.
With keys in paw, it checks each door,
Ensuring safety, evermore.
Interceptors stand in line,
Protecting data, by design.
🐇🔑

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@gouravmore

Copy link
Copy Markdown
Member

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 31, 2025

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 4

🧹 Nitpick comments (3)
src/middlewares/verify.key.ts (3)

17-19: Consider sanitizing the API key input.

While type checking is good, consider additional validation to prevent potential injection attacks or malformed keys.

 if (!clientApiKey || typeof clientApiKey !== 'string') {
     throw new HttpException('API key missing or invalid', HttpStatus.UNAUTHORIZED);
 }
+if (clientApiKey.length > 256 || !/^[a-zA-Z0-9\-_\.]+$/.test(clientApiKey)) {
+    throw new HttpException('API key format invalid', HttpStatus.UNAUTHORIZED);
+}

20-26: Consider implementing API key caching for better performance.

Each request triggers an external API call, which could impact performance and reliability. Consider caching valid API keys with TTL.

You could implement a simple in-memory cache with TTL or use Redis for distributed caching:

private cache = new Map<string, { isValid: boolean; expires: number }>();

private isValidCached(apiKey: string): boolean | null {
    const cached = this.cache.get(apiKey);
    if (cached && cached.expires > Date.now()) {
        return cached.isValid;
    }
    return null;
}

37-37: Consider removing redundant default export.

The class is already exported as a named export. The default export might be unnecessary unless specifically required by the consuming code.

-export default ValidateApiKeyInterceptor;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d61b3ca and 6a251b0.

📒 Files selected for processing (2)
  • src/middlewares/verify.key.ts (1 hunks)
  • src/mongodb/scores.controller.ts (14 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/mongodb/scores.controller.ts (1)

Learnt from: DevendraPPatil
PR: #238
File: src/mongodb/scores.controller.ts:6470-6499
Timestamp: 2025-07-28T08:57:10.283Z
Learning: For the project Sunbird-ALL/all-learner-ai-services, API documentation (Swagger decorators like @ApiBody, @apiresponse, @apioperation) is not required for new endpoints in the scores controller.

🔇 Additional comments (7)
src/middlewares/verify.key.ts (2)

1-6: LGTM! Proper NestJS interceptor setup.

The imports and class declaration follow NestJS conventions correctly with appropriate dependencies imported.


7-34: Audit API Key Interceptor Coverage Across Controllers

Based on the grep results:

  • The ValidateApiKeyInterceptor is applied on all routes in src/mongodb/scores.controller.ts.
  • No interceptor is used in src/mysql/scores.controller.ts.
  • The health‐check (app.controller.ts) and root (getHello) endpoints are unprotected.

Please verify:

• Which controllers/endpoints should enforce API-key validation (e.g., MySQL scores routes)?
• If protection is required, add @UseInterceptors(ValidateApiKeyInterceptor) at the class or method level.
• Ensure your deployment or .env file defines API_KEY_ENABLE='true' and a valid AUTH_SERVICE_API URL.

src/mongodb/scores.controller.ts (5)

14-14: LGTM! Import statement correctly added.

The UseInterceptors import is properly added to support the new API key validation functionality.


38-38: LGTM! ValidateApiKeyInterceptor import is correct.

The interceptor is imported from the expected location and follows standard NestJS import patterns.


114-114: Consistent API key validation applied to all updateLearnerProfile endpoints.

The @UseInterceptors(ValidateApiKeyInterceptor) decorator has been systematically applied to all seven language-specific POST endpoints for updating learner profiles (Tamil, Gujarati, Oriya, Hindi, Kannada, English, Telugu). This ensures consistent security enforcement across all profile update operations.

Also applies to: 480-480, 846-846, 1206-1206, 1579-1579, 2412-2412, 2973-2973


3962-3962: API key validation properly applied to GetContent endpoints.

The interceptor is correctly applied to all four GET endpoints that fetch user-specific content by different types (char, word, sentence, paragraph). This maintains consistent security for content retrieval operations.

Also applies to: 4140-4140, 4303-4303, 4476-4476


4691-4691: LGTM! getSetResult endpoint properly secured.

The @UseInterceptors(ValidateApiKeyInterceptor) decorator is correctly applied to the POST /getSetResult endpoint, which handles session result calculations and milestone updates. This is appropriate given the critical nature of this endpoint.

Comment thread src/middlewares/verify.key.ts Outdated
Comment on lines +10 to +12
const apiKeyEnabled = process.env.API_KEY_ENABLE === 'true';
const clientApiKey = request.headers['api-key'];
const validateUrl = process.env.AUTH_SERVICE_API || '';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation for AUTH_SERVICE_API environment variable.

The validateUrl could be empty if AUTH_SERVICE_API is not set, which would cause the axios request to fail unexpectedly.

 const apiKeyEnabled = process.env.API_KEY_ENABLE === 'true';
 const clientApiKey = request.headers['api-key'];
-const validateUrl = process.env.AUTH_SERVICE_API || '';
+const validateUrl = process.env.AUTH_SERVICE_API;

 if (!apiKeyEnabled) {
     return next.handle();
 }
+if (!validateUrl) {
+    throw new HttpException('AUTH_SERVICE_API not configured', HttpStatus.INTERNAL_SERVER_ERROR);
+}
📝 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
const apiKeyEnabled = process.env.API_KEY_ENABLE === 'true';
const clientApiKey = request.headers['api-key'];
const validateUrl = process.env.AUTH_SERVICE_API || '';
const apiKeyEnabled = process.env.API_KEY_ENABLE === 'true';
const clientApiKey = request.headers['api-key'];
- const validateUrl = process.env.AUTH_SERVICE_API || '';
+ const validateUrl = process.env.AUTH_SERVICE_API;
if (!apiKeyEnabled) {
return next.handle();
}
+ if (!validateUrl) {
+ throw new HttpException(
+ 'AUTH_SERVICE_API not configured',
+ HttpStatus.INTERNAL_SERVER_ERROR
+ );
+ }
🤖 Prompt for AI Agents
In src/middlewares/verify.key.ts around lines 10 to 12, the AUTH_SERVICE_API
environment variable is used without validation, which can lead to an empty URL
and cause axios requests to fail. Add a check to ensure AUTH_SERVICE_API is set
and not empty before using it; if it is missing, handle the error appropriately
by logging or throwing an error to prevent making a request with an invalid URL.

if (!clientApiKey || typeof clientApiKey !== 'string') {
throw new HttpException('API key missing or invalid', HttpStatus.UNAUTHORIZED);
}
const responseFromAuth = await axios.post(validateUrl, { apiKey: clientApiKey });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add timeout and error handling for external API call.

The axios request lacks timeout configuration and could hang indefinitely, causing request timeouts. Also consider implementing retry logic for transient failures.

-const responseFromAuth = await axios.post(validateUrl, { apiKey: clientApiKey });
+const responseFromAuth = await axios.post(validateUrl, { apiKey: clientApiKey }, {
+    timeout: 5000, // 5 second timeout
+    validateStatus: (status) => status < 500, // Don't throw for 4xx errors
+});
📝 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
const responseFromAuth = await axios.post(validateUrl, { apiKey: clientApiKey });
const responseFromAuth = await axios.post(validateUrl, { apiKey: clientApiKey }, {
timeout: 5000, // 5 second timeout
validateStatus: (status) => status < 500, // Don't throw for 4xx errors
});
🤖 Prompt for AI Agents
In src/middlewares/verify.key.ts at line 20, the axios.post call to the external
API lacks a timeout setting and error handling, which can cause the request to
hang indefinitely. Add a timeout option to the axios request configuration to
limit wait time, and wrap the call in a try-catch block to handle errors
gracefully. Optionally, implement retry logic for transient failures by retrying
the request a few times before failing.

Comment on lines +22 to +26
if (responseFromAuth.data.isValid === true) {
return next.handle();
} else {
throw new HttpException('Unauthorized: API key invalid', HttpStatus.UNAUTHORIZED);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add response structure validation.

The code assumes the response has a specific structure without validation, which could cause runtime errors.

-if (responseFromAuth.data.isValid === true) {
+if (responseFromAuth.data && typeof responseFromAuth.data.isValid === 'boolean' && responseFromAuth.data.isValid === true) {
     return next.handle();
 } else {
     throw new HttpException('Unauthorized: API key invalid', HttpStatus.UNAUTHORIZED);
 }
📝 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
if (responseFromAuth.data.isValid === true) {
return next.handle();
} else {
throw new HttpException('Unauthorized: API key invalid', HttpStatus.UNAUTHORIZED);
}
if (responseFromAuth.data && typeof responseFromAuth.data.isValid === 'boolean' && responseFromAuth.data.isValid === true) {
return next.handle();
} else {
throw new HttpException('Unauthorized: API key invalid', HttpStatus.UNAUTHORIZED);
}
🤖 Prompt for AI Agents
In src/middlewares/verify.key.ts around lines 22 to 26, the code assumes
responseFromAuth.data has an isValid property without checking if
responseFromAuth or responseFromAuth.data exist. Add validation to confirm
responseFromAuth and responseFromAuth.data are defined and that isValid is a
boolean before accessing it. If the structure is invalid, handle it gracefully
by throwing an appropriate HttpException or error.

throw new HttpException('Unauthorized: API key invalid', HttpStatus.UNAUTHORIZED);
}
} catch (err) {
console.error('API key validation error:', err);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid logging sensitive information.

The error logging could potentially expose API keys or other sensitive data from the error object.

-console.error('API key validation error:', err);
+console.error('API key validation error:', err.message);
📝 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
console.error('API key validation error:', err);
console.error('API key validation error:', err.message);
🤖 Prompt for AI Agents
In src/middlewares/verify.key.ts at line 28, the current error logging statement
outputs the entire error object, which may contain sensitive information like
API keys. Modify the logging to avoid printing the full error object; instead,
log a generic error message or sanitize the error details to exclude sensitive
data before logging.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
20.4% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

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