Skip to content

Fix Twilio request validation URL scheme mismatch#337

Merged
ucswift merged 1 commit intomasterfrom
develop
Apr 21, 2026
Merged

Fix Twilio request validation URL scheme mismatch#337
ucswift merged 1 commit intomasterfrom
develop

Conversation

@ucswift
Copy link
Copy Markdown
Member

@ucswift ucswift commented Apr 21, 2026

The UseTwilioRequestValidation() middleware was validating requests using the overridden 'https://' scheme (set by upstream middleware) while Twilio signed the webhook with the actual configured URL scheme (e.g. 'http://' in QA). This caused signature validation to fail for IncomingMessage and other Twilio endpoints, resulting in 403 responses reported by Twilio as timeouts.

Fix: set BaseUrlOverride to SystemBehaviorConfig.ResgridApiBaseUrl so the validation URL always matches the base URL Twilio uses when signing — the same URL registered as the webhook in the Twilio console.

Summary by CodeRabbit

  • Chores
    • Enhanced Twilio request validation middleware configuration to support improved URL handling in various deployment scenarios.

The UseTwilioRequestValidation() middleware was validating requests using
the overridden 'https://' scheme (set by upstream middleware) while Twilio
signed the webhook with the actual configured URL scheme (e.g. 'http://'
in QA). This caused signature validation to fail for IncomingMessage and
other Twilio endpoints, resulting in 403 responses reported by Twilio as
timeouts.

Fix: set BaseUrlOverride to SystemBehaviorConfig.ResgridApiBaseUrl so the
validation URL always matches the base URL Twilio uses when signing — the
same URL registered as the webhook in the Twilio console.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

📝 Walkthrough

Walkthrough

The Twilio request validation middleware configuration in Startup.cs is enhanced to conditionally override the base URL used for signature validation, applying the configured ResgridApiBaseUrl when available to ensure consistent validation across upstream scheme rewrites.

Changes

Cohort / File(s) Summary
Twilio Configuration
Web/Resgrid.Web.Services/Startup.cs
Extended Twilio request validation setup to conditionally assign options.BaseUrlOverride from system behavior configuration when non-empty, ensuring signature validation uses the configured base URL.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main change: fixing a URL scheme mismatch in Twilio request validation by overriding the base URL.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ 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 develop

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
Contributor

@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 `@Web/Resgrid.Web.Services/Startup.cs`:
- Around line 171-172: The current guard always sets options.BaseUrlOverride
because Config.SystemBehaviorConfig.ResgridApiBaseUrl defaults to the
placeholder "https://resgridapi.local"; change the condition so BaseUrlOverride
is only set when a real public URL is configured (e.g., non-empty AND not the
placeholder). Update the Startup.cs block that references
Config.SystemBehaviorConfig.ResgridApiBaseUrl and options.BaseUrlOverride to
check that ResgridApiBaseUrl is not null/whitespace and not equal to
"https://resgridapi.local" (and optionally not localhost/127.0.0.1 variants)
before assigning options.BaseUrlOverride.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5034f225-66ee-48c7-99a0-1ef32d3f1b7b

📥 Commits

Reviewing files that changed from the base of the PR and between 39c7d6b and b1d37fe.

📒 Files selected for processing (1)
  • Web/Resgrid.Web.Services/Startup.cs

Comment on lines +171 to +172
if (!string.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.ResgridApiBaseUrl))
options.BaseUrlOverride = Config.SystemBehaviorConfig.ResgridApiBaseUrl;
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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the default and any checked-in overrides. Expected: Twilio-enabled environments
# should provide a non-placeholder absolute http(s) ResgridApiBaseUrl.
rg -n -C2 'ResgridApiBaseUrl\s*='
rg -n -C2 'ResgridApiBaseUrl|RESGRID.*API.*BASE|Twilio(AuthToken|ApiUrl|Voice)' --iglob '*.json' --iglob '*.config' --iglob '*.cs'

Repository: Resgrid/Core

Length of output: 39189


Reject the placeholder Twilio base URL to prevent webhook validation failures.

The condition on line 171 is always true because SystemBehaviorConfig.ResgridApiBaseUrl defaults to https://resgridapi.local, a non-empty, non-whitespace string. When Twilio.AspNet.Core uses BaseUrlOverride for webhook signature validation, any environment with Twilio enabled but without an explicit public base URL will validate against https://resgridapi.local/api/Twilio/... instead of the actual public URL Twilio signed, causing all webhook requests to be rejected.

Replace the guard to explicitly validate that a real public URL is configured:

Proposed fix
-			if (!string.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.ResgridApiBaseUrl))
-				options.BaseUrlOverride = Config.SystemBehaviorConfig.ResgridApiBaseUrl;
+			var baseUrlOverride = Config.SystemBehaviorConfig.ResgridApiBaseUrl?.Trim();
+			if (!string.IsNullOrWhiteSpace(NumberProviderConfig.TwilioAuthToken))
+			{
+				if (string.IsNullOrWhiteSpace(baseUrlOverride) ||
+					string.Equals(baseUrlOverride, "https://resgridapi.local", StringComparison.OrdinalIgnoreCase) ||
+					!Uri.TryParse(baseUrlOverride, UriKind.Absolute, out var baseUri) ||
+					(baseUri.Scheme != Uri.UriSchemeHttp && baseUri.Scheme != Uri.UriSchemeHttps))
+				{
+					throw new InvalidOperationException("SystemBehaviorConfig.ResgridApiBaseUrl must be set to the public Twilio webhook base URL when Twilio request validation is enabled.");
+				}
+
+				options.BaseUrlOverride = baseUrlOverride.TrimEnd('/');
+			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Web/Resgrid.Web.Services/Startup.cs` around lines 171 - 172, The current
guard always sets options.BaseUrlOverride because
Config.SystemBehaviorConfig.ResgridApiBaseUrl defaults to the placeholder
"https://resgridapi.local"; change the condition so BaseUrlOverride is only set
when a real public URL is configured (e.g., non-empty AND not the placeholder).
Update the Startup.cs block that references
Config.SystemBehaviorConfig.ResgridApiBaseUrl and options.BaseUrlOverride to
check that ResgridApiBaseUrl is not null/whitespace and not equal to
"https://resgridapi.local" (and optionally not localhost/127.0.0.1 variants)
before assigning options.BaseUrlOverride.

@ucswift
Copy link
Copy Markdown
Member Author

ucswift commented Apr 21, 2026

Approve

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

This PR is approved.

@ucswift ucswift merged commit b32d621 into master Apr 21, 2026
19 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.

1 participant