Skip to content

PR: Add workflow to check for allowlist#16

Open
ahn-nath wants to merge 8 commits into
kinde-starter-kits:mainfrom
ahn-nath:check-ip-allowlist-for-access
Open

PR: Add workflow to check for allowlist#16
ahn-nath wants to merge 8 commits into
kinde-starter-kits:mainfrom
ahn-nath:check-ip-allowlist-for-access

Conversation

@ahn-nath
Copy link
Copy Markdown
Contributor

@ahn-nath ahn-nath commented Sep 17, 2025

Explain your changes

Summary
Adds a Post-Authentication workflow that enforces an IP allowlist. The workflow validates the configured allowlist, extracts and validates the incoming client IP from the authentication event, supports a developer test override mode, and either allows the session to continue or denies access via denyAccess(...). It includes clear logging and centralized error handling.


Files changed

  • checkIPAgainstAllowlistWorkflow.ts.ts (new workflow implementation)

What this implements

  • Runs on PostAuthentication events (workflow id: "onPostUserAuthentication", name: "checkIPAgainstAllowlist").

  • Primary behavior

    • Validates that allowList is a non-empty array of valid IPv4 addresses (validateAllowList).
    • Extracts the client's IP from event.request.ip.
    • Validates the IP format and rejects 'unknown', 'localhost', and '127.0.0.1'.
    • If testFalsePositive is true, overrides the IP with a known test IP (dev-only convenience).
    • If the IP is not present in allowList, denies access by calling platform denyAccess(...).
    • Centralized unexpected-exception handling via handleExceptionError (logs error and denies access).
  • Workflow settings

    • trigger: WorkflowTrigger.PostAuthentication
    • failurePolicy: { action: 'stop' }
    • bindings: { "kinde.auth": {} }
  • Logging & errors

    • Logs info / warning / error messages at key points to aid debugging and auditing.
    • Denies access on invalid allowlist, invalid IP, not-in-allowlist, and unexpected runtime errors.
  • In-file configuration

    • allowList array and testFalsePositive flag are currently defined in-file (clear comments recommend moving to env/config).

Why this change

This enforces a simple, deterministic allowlist check as part of post-authentication flows. It's useful when you want to restrict access to a known set of client IP addresses (e.g., corporate networks, specific partners) and fail closed (deny access) when there are configuration problems or runtime errors.


Checklist

  • I have read the project Pull Requests and Contributing guidelines and followed the project’s code style.
  • This change is limited to the scope described above and is safe to enable/disable by configuration.
  • I added notes about further improvements and risk mitigations (see Notes & follow-ups).

Summary by CodeRabbit

  • New Features
    • Enforces an IP allowlist after sign-in: only requests from approved IPv4 addresses may continue.
    • Shows clear access-denied messages when the client IP is missing, invalid, localhost, private range, or not on the allowlist.
    • Adds a test mode to simulate/override client IP for verification and troubleshooting.
    • Improves logging and error handling for access checks and unexpected failures.

A workflow was added as an example of checking against an allowlist for IP addresses to restrict authentication.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 17, 2025

Warning

Rate limit exceeded

@ahn-nath has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 3 minutes and 15 seconds before requesting another review.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 812ba40 and 669f4a4.

📒 Files selected for processing (1)
  • postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (1 hunks)

Walkthrough

Adds a new post-authentication workflow that enforces an IPv4 allowlist: exposes workflowSettings and a default handlePostAuth handler, validates a non-empty allowlist, extracts and validates client IP from event.request.ip, and denies access when IP is invalid or not allowlisted.

Changes

Cohort / File(s) Summary
Post-auth IP allowlist workflow
postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts
New file exporting workflowSettings: WorkflowSettings and default handlePostAuth(event: onPostAuthenticationEvent). Validates a non-empty IPv4 allowlist, extracts client IP (first CSV entry) with optional testFalsePositive override and default allowList (64.227.0.197), rejects unknown/localhost/127.0.0.1 and private ranges, denies access when IP is invalid or not in allowlist, logs outcomes, and includes helpers validateAllowList, isValidIpAddress, and handleExceptionError.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant AuthSvc as Authentication Service
  participant Workflow as PostAuth Allowlist Workflow
  participant Validator as IP/Allowlist Validator
  participant Logger as Logger
  participant Policy as Access Control

  AuthSvc->>Workflow: onPostAuthentication(event)
  Workflow->>Validator: validateAllowList(allowList)
  Validator-->>Workflow: valid / invalid
  alt allowlist invalid
    Workflow->>Logger: error("Allowlist misconfigured")
    Workflow->>Policy: denyAccess("Allowlist misconfigured")
    Policy-->>AuthSvc: Deny
  else allowlist valid
    Workflow->>Workflow: extractClientIp(event.request.ip, testFalsePositive?)
    alt IP missing or malformed
      Workflow->>Logger: warn("Missing/invalid IP")
      Workflow->>Policy: denyAccess("IP invalid or not allowed")
      Policy-->>AuthSvc: Deny
    else IP parsed
      Workflow->>Validator: isValidIpAddress(ip)
      Validator-->>Workflow: valid / invalid
      alt IP invalid
        Workflow->>Logger: warn("Invalid or private IP")
        Workflow->>Policy: denyAccess("IP invalid")
        Policy-->>AuthSvc: Deny
      else IP valid
        Workflow->>Validator: isAllowed(ip, allowList)
        alt not allowlisted
          Workflow->>Policy: denyAccess("IP not allowlisted")
          Policy-->>AuthSvc: Deny
        else allowlisted
          Workflow-->>AuthSvc: Continue (no deny)
        end
      end
    end
  end
  opt unexpected exception
    Workflow->>Logger: error("Exception")
    Workflow->>Policy: denyAccess("Unexpected error")
    Policy-->>AuthSvc: Deny
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review IP validation correctness (edge cases, private ranges).
  • Verify testFalsePositive behavior and default allowList usage.
  • Confirm logging and failurePolicy semantics in workflowSettings.

Suggested reviewers

  • DanielRivers
  • DaveOrDead

Poem

I hop past keys and guarded gates,
Nose twitch — an IP checks its fates.
Allowed? I bound and skip with glee;
Denied? I thump — no entry, see.
A rabbit's guard: small, swift, and spry. 🐇

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add workflow to check for allowlist' accurately describes the main change: introducing a new post-authentication IP allowlist workflow.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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.

Actionable comments posted: 4

🧹 Nitpick comments (4)
postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (4)

84-87: Fix typo and standardize error log.

Spelling: “Againts” → “Against”.

-  console.error(`Check Againts IP Address Workflow Error: ${errorMessage}`, error); 
+  console.error(`Check Against IP Address Workflow Error: ${errorMessage}`, error);

106-106: Add explicit return type for handler.

Improves clarity and prevents accidental return type drift.

-export default async function handlePostAuth(event: onPostAuthenticationEvent) {
+export default async function handlePostAuth(event: onPostAuthenticationEvent): Promise<void> {

41-44: Externalize configuration (allowList and test toggle).

Hardcoding IPs and a test flag in code risks drift and accidental exposure. Move to env/config/bindings with validation and safe defaults.

I can refactor to read from workflow bindings or environment, validate on startup, and surface configuration errors via deployment logs rather than at request time.


127-137: Observability: structured logs and context.

Use structured logs (JSON) with fields like workflowId, userId (if available), requestId, ip, decision to improve traceability.

I can wire a small helper logDecision({ ip, decision, reason }) to standardize messages and avoid leaking details to users.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60edde8 and 4aa9182.

📒 Files selected for processing (1)
  • postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (1 hunks)
🔇 Additional comments (2)
postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (2)

120-136: Confirm denyAccess contract (return/await semantics).

If denyAccess is async or throws, consider return denyAccess(...) or await denyAccess(...) to guarantee early termination. You currently call then return;.

Would you confirm the function type of denyAccess from @kinde/infrastructure? If it returns a Promise, wrapping with return await (or just return) clarifies intent.


94-102: IPv6 handling (verify requirements).

event.request.ip may be IPv6 or IPv4‑mapped (e.g., ::ffff:64.227.0.197). Current validator rejects these, potentially denying legitimate users.

If IPv6 must be supported now, I can provide a compact IPv6 validator and normalization for IPv4‑mapped IPv6 before allowlist comparison. Preferably, allowlist entries should support both canonical IPv6 and IPv4‑mapped forms.

Comment thread postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts Outdated
Comment thread postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts
Comment thread postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts Outdated
Comment thread postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts Outdated
@onderay onderay requested review from a team and removed request for DaveOrDead October 29, 2025 01:48
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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4aa9182 and 4ef5f5a.

📒 Files selected for processing (1)
  • postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: alex72508
Repo: kinde-starter-kits/workflow-examples PR: 9
File: postUserAuthentication/checkIPWithAbuseIPDBWorkflow.ts:107-115
Timestamp: 2025-07-21T05:31:53.656Z
Learning: The workflow-examples repository uses IPv4-only validation in IP address checking functions because IPv6 is not supported across all systems in their infrastructure.
📚 Learning: 2025-07-21T05:31:53.656Z
Learnt from: alex72508
Repo: kinde-starter-kits/workflow-examples PR: 9
File: postUserAuthentication/checkIPWithAbuseIPDBWorkflow.ts:107-115
Timestamp: 2025-07-21T05:31:53.656Z
Learning: The workflow-examples repository uses IPv4-only validation in IP address checking functions because IPv6 is not supported across all systems in their infrastructure.

Applied to files:

  • postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts

Comment thread postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts
Comment thread postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts Outdated
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

♻️ Duplicate comments (5)
postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (5)

85-85: Fix typo in error log message.

"Againts" should be "Against".

Apply this diff:

-  console.error(`Check Againts IP Address Workflow Error: ${errorMessage}`, error); 
+  console.error(`Check Against IP Address Workflow Error: ${errorMessage}`, error);

84-87: Avoid exposing internal error details to end users.

The denyAccess call includes the raw errorMessage which may leak implementation details. Log technical details for ops but return a generic message to users.

Apply this diff:

 function handleExceptionError(errorMessage: string, error?: any): void {
   console.error(`Check Against IP Address Workflow Error: ${errorMessage}`, error);
-  denyAccess(`Access blocked due to an issue: ${errorMessage}`);
+  denyAccess('Access denied due to a configuration or validation error.');
 }

123-123: Bug: Possible crash when event.request is undefined.

event.request.ip?.split(…) still dereferences request before checking ip, which can throw if request is undefined.

Apply this diff:

-    let ip = event.request.ip?.split(',')[0].trim() ?? 'unknown';
+    const rawIp = event.request?.ip ?? '';
+    let ip = rawIp.split(',')[0]?.trim() || 'unknown';

131-132: Avoid exposing IPs in end-user messages (privacy/compliance).

The actual IP address is included in the user-facing denyAccess message. Log the IP for ops but return a generic message to users.

Apply this diff:

-      console.warn(`Invalid or private IP address detected: ${ip}. Access denied.`);
-      denyAccess(`Access denied: Invalid or private IP address.`);
+      console.warn(`Invalid or private IP address detected: ${ip}. Denying access.`);
+      denyAccess('Access denied: Invalid IP address.');

140-141: Avoid exposing IPs in end-user messages (privacy/compliance).

The actual IP address is included in the user-facing denyAccess message. This may violate privacy policies. Log the IP internally but provide a generic denial message to users.

Apply this diff:

-      console.warn(`IP address ${ip} is not in the allowlist. Access denied.`);
-      denyAccess(`Access denied: IP address ${ip} is not in the allowlist.`);
+      console.warn(`IP not in allowlist: ${ip}. Denying access.`);
+      denyAccess('Access denied: Your IP is not authorized.');
🧹 Nitpick comments (3)
postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (3)

45-45: Good fix: testFalsePositive now defaults to false.

The previous blocker (testFalsePositive = true) has been resolved. For additional production safety, consider reading from environment variables with explicit guards:

-const testFalsePositive = false;  
+const testFalsePositive = 
+  process.env.ALLOWLIST_TEST_FALSE_POSITIVE === 'true' &&
+  process.env.NODE_ENV !== 'production';

94-111: Good implementation of private IP range validation.

The private and reserved IPv4 range checks requested in previous reviews have been properly implemented. The function now correctly rejects private (RFC1918), loopback, and link-local addresses.

For completeness, consider also rejecting these additional reserved ranges:

   if (a === 169 && b === 254) return false;      // 169.254.0.0/16
+  if (a === 0) return false;                      // 0.0.0.0/8
+  if (a >= 224) return false;                     // 224.0.0.0/4 (multicast) and above
   return true;

Based on learnings.


124-127: Use console.warn for test override to highlight non-production usage.

The test override currently uses console.log, but console.warn would better signal this is a development-only feature that should not appear in production logs.

Apply this diff:

     if (testFalsePositive) {
       ip = '64.227.0.197'; // A known "allowed" IP for testing purposes
-      console.log('Test false positive is enabled. Overriding IP for testing purposes.');
+      console.warn('testFalsePositive is enabled. Overriding client IP for DEV verification ONLY.');
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ef5f5a and 7cce1b3.

📒 Files selected for processing (1)
  • postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: alex72508
Repo: kinde-starter-kits/workflow-examples PR: 9
File: postUserAuthentication/checkIPWithAbuseIPDBWorkflow.ts:107-115
Timestamp: 2025-07-21T05:31:53.656Z
Learning: The workflow-examples repository uses IPv4-only validation in IP address checking functions because IPv6 is not supported across all systems in their infrastructure.
📚 Learning: 2025-07-21T05:31:53.656Z
Learnt from: alex72508
Repo: kinde-starter-kits/workflow-examples PR: 9
File: postUserAuthentication/checkIPWithAbuseIPDBWorkflow.ts:107-115
Timestamp: 2025-07-21T05:31:53.656Z
Learning: The workflow-examples repository uses IPv4-only validation in IP address checking functions because IPv6 is not supported across all systems in their infrastructure.

Applied to files:

  • postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts
🔇 Additional comments (3)
postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (3)

33-38: LGTM!

Imports are appropriate and all are used in the implementation.


49-57: LGTM!

Workflow settings are correctly configured for post-authentication with appropriate failure policy and bindings.


66-77: LGTM!

Validation logic is sound and provides clear error messages for configuration issues.

Comment thread postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts Outdated
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: 0

♻️ Duplicate comments (5)
postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (5)

20-21: Documentation mentions environment variable but implementation uses hardcoded constant.

The documentation references ALLOWLIST_TEST_FALSE_POSITIVE environment variable, but the implementation uses a hardcoded testFalsePositive constant on line 45. This inconsistency has been previously flagged.


85-85: Fix typo in error log message.

"Againts" should be "Against". This issue was previously flagged.


84-87: Avoid exposing internal error details to end users.

The denyAccess call includes the raw errorMessage which may leak implementation details. This issue was previously flagged.


132-135: Avoid exposing IPs in end-user messages (privacy/compliance).

The IP address is included in the denyAccess message shown to end users. This issue was previously flagged.


141-145: Avoid exposing IPs in end-user messages (privacy/compliance).

The IP address is included in the denyAccess message shown to end users. This issue was previously flagged.

🧹 Nitpick comments (2)
postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (2)

94-111: LGTM! Private IP range validation is now implemented.

The function correctly validates IPv4 format and rejects private/reserved ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, 169.254.0.0/16). IPv4-only validation is intentional for this infrastructure.

Optional enhancement: Consider adding checks for multicast (224.0.0.0/4), broadcast (255.255.255.255), and 0.0.0.0/8 ranges for completeness.


126-129: Use console.warn for security override notification.

The test override bypasses IP validation, which is a security-sensitive operation. Using console.warn instead of console.log ensures better visibility in production logs.

Apply this diff:

     if (testFalsePositive) {
       ip = '64.227.0.197'; // A known "allowed" IP for testing purposes
-      console.log('Test false positive is enabled. Overriding IP for testing purposes.');
+      console.warn('Test false positive is enabled. Overriding IP for testing purposes.');
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cce1b3 and 812ba40.

📒 Files selected for processing (1)
  • postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: alex72508
Repo: kinde-starter-kits/workflow-examples PR: 9
File: postUserAuthentication/checkIPWithAbuseIPDBWorkflow.ts:107-115
Timestamp: 2025-07-21T05:31:53.656Z
Learning: The workflow-examples repository uses IPv4-only validation in IP address checking functions because IPv6 is not supported across all systems in their infrastructure.
📚 Learning: 2025-07-21T05:31:53.656Z
Learnt from: alex72508
Repo: kinde-starter-kits/workflow-examples PR: 9
File: postUserAuthentication/checkIPWithAbuseIPDBWorkflow.ts:107-115
Timestamp: 2025-07-21T05:31:53.656Z
Learning: The workflow-examples repository uses IPv4-only validation in IP address checking functions because IPv6 is not supported across all systems in their infrastructure.

Applied to files:

  • postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts
🔇 Additional comments (5)
postUserAuthentication/checkIPAgainstAllowlistWorkflow.ts (5)

33-45: LGTM! Configuration defaults are secure.

The imports are correct and the testFalsePositive flag now defaults to false, addressing the critical security concern from previous reviews. The allowlist structure is clear and ready for production IP addresses.


49-57: LGTM! Workflow settings are correctly configured.

The workflow settings appropriately use WorkflowTrigger.PostAuthentication with a stop failure policy, which is the correct choice for a security-critical IP allowlist check.


66-77: LGTM! Allowlist validation is thorough.

The function correctly validates both the array structure and each IP address entry. The error messages are descriptive for troubleshooting.


123-124: LGTM! IP extraction is now safe.

The optional chaining on event.request?.ip and safe string handling with fallback to 'unknown' correctly addresses the previous crash risk.


150-152: LGTM! Error handling structure is appropriate.

The catch block correctly delegates to the centralized error handler, ensuring consistent logging and access denial for unexpected errors.

@ahn-nath
Copy link
Copy Markdown
Contributor Author

ahn-nath commented Nov 7, 2025

@onderay
I have addressed all the CodeRabbit comments.

Copy link
Copy Markdown
Contributor

@Koosha-Owji Koosha-Owji left a comment

Choose a reason for hiding this comment

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

Looks good to me!

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