Swagger UI access is controlled by IP address in non-production environments for security purposes. Only requests from whitelisted IP addresses can access the Swagger documentation and testing interface.
Applies to:
Both services implement the same IP whitelisting middleware and require separate configuration in their respective appsettings.{Environment}.json files.
Environment Access:
┌─────────────────────────────────────────────────────────────┐
│ IP WHITELIST VALIDATION FLOW │
└─────────────────────────────────────────────────────────────┘
┌──────────────┐
│ Developer │
│ Browser │
└──────┬───────┘
│
│ Request: GET /swagger
▼
┌──────────────────────────┐
│ API Service │
│ (Behind Azure Proxy) │
└──────┬───────────────────┘
│
│ Middleware intercepts
│ /swagger/* requests
▼
┌──────────────────────────────┐
│ IP Whitelist Middleware │
└──────┬───────────────────────┘
│
│ Extract client IP:
│ - Check RemoteIpAddress
│ - Check X-Forwarded-For header
▼
┌──────────────────────────────┐
│ Compare against whitelist │
└──────┬───────────────────────┘
│
├─── IP Allowed ───┐ IP Blocked ───┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Continue │ │ Serve │ │ 403 │
│ to Swagger │ │ Swagger UI │ │ Forbidden │
└──────────────┘ └──────────────┘ └──────────────┘
Location:
ApiService/Program.cs:331-385IntegrationServiceAPI/Program.cs:210-259The middleware intercepts requests to protected paths and validates the client IP address against the configured whitelist. When behind a proxy (like Azure App Service), it uses the X-Forwarded-For header to determine the real client IP.
Protected Paths:
/swagger - Swagger UI interface/scalar - Scalar API documentation/openapi - OpenAPI specification JSONvar remoteIp = context.Connection.RemoteIpAddress;
// Check X-Forwarded-For header for real client IP (when behind Azure proxy)
if (context.Request.Headers.TryGetValue("X-Forwarded-For", out var forwardedFor))
{
var firstIp = forwardedFor.ToString().Split(',')[0].Trim();
if (System.Net.IPAddress.TryParse(firstIp, out var parsedIp))
{
remoteIp = parsedIp;
}
}
if (remoteIp == null || !IpWhitelistHelper.IsIpAllowed(remoteIp, allowedIPs))
{
context.Response.StatusCode = 403;
await context.Response.WriteAsync("Access to Swagger is restricted. Your IP: " + remoteIp);
return;
}
The following IPs are currently configured in appsettings.json for both ApiService and IntegrationServiceAPI:
{
"Swagger": {
"AllowedIPs": [
"46.21.99.50/24", // EG Sweden 1
"213.115.39.74", // EG Sweden 2
"212.112.154.248/24", // EG Denmark 1
"185.128.100.29", // EG Denmark 2
"185.128.103.244", // EG Denmark 3
"202.131.131.48/29", // EG India 1
"202.131.139.48/29", // EG India 2
"203.193.141.104/29", // EG India 3
"203.193.140.104/29" // EG India 4
]
}
}
To add a new IP address:
Swagger:AllowedIPs array in appsettings.json (or environment-specific file)Supported formats:
"192.168.1.100""2001:0db8:85a3::7334""192.168.1.0/24"When blocked, the error message displays your IP:
Access to Swagger is restricted. Your IP: 203.0.113.45
This is the IP address you need to add to the whitelist.
Alternatively, use a command:
(Invoke-WebRequest -Uri "https://api.ipify.org").Contentcurl https://api.ipify.orgWhen the API is deployed behind Azure App Service or reverse proxies, RemoteIpAddress shows the proxy's IP, not the client's real IP. The X-Forwarded-For header contains the original client IP address.
Client (203.0.113.45)
→ Azure Load Balancer
→ API Service (sees 10.0.0.1 as RemoteIpAddress)
Without X-Forwarded-For:
With X-Forwarded-For:
X-Forwarded-For: client-ip, proxy1-ip, proxy2-ip
The middleware takes the first IP in the list (the original client).
Error Message:
Access to Swagger is restricted. Your IP: 203.0.113.45
Solution:
appsettings.{Environment}.jsonCauses and Solutions:
appsettings.{Environment}.json filehttps://192.168.1.100, http://192.168.1.100192.168.1.100, 192.168.1.0/24When behind VPN, proxy, or NAT, your public IP differs from your local IP. The API sees your public IP, not your local machine IP (192.168.x.x). Add the IP shown in the error message.
Use individual IPs or small CIDR ranges:
"AllowedIPs": ["203.0.113.45", "192.168.1.0/24"]
Never allow all IPs:
"AllowedIPs": ["0.0.0.0/0"] // Defeats the purpose!
Add comments explaining why each IP is whitelisted:
{
"Swagger": {
"AllowedIPs": [
"203.0.113.45", // Main office - Added 2025-01-15
"198.51.100.50", // QA team - Added 2025-02-01
"192.0.2.0/24" // VPN range - Added 2025-02-10
]
}
}
Monthly review:
Never rely on IP whitelisting alone for production. Swagger is completely disabled in production environments.
| Environment | Swagger Access | IP Restrictions | Configuration File |
|---|---|---|---|
| Development (Local) | Fully Open | None | N/A |
| Testing | IP Whitelist | Required | appsettings.Testing.json |
| Staging | IP Whitelist | Required | appsettings.Staging.json |
| UAT | IP Whitelist | Required | appsettings.UAT.json |
| Production | Disabled | N/A | N/A |
Source/EGU.PartnerPortal.ApiService/Program.cs:331-385Source/EGU.PartnerPortal.IntegrationServiceAPI/Program.cs:210-259Source/EGU.PartnerPortal.Shared/Utilities/IpWhitelistHelper.csSource/EGU.PartnerPortal.ApiService/appsettings.{Environment}.jsonSource/EGU.PartnerPortal.IntegrationServiceAPI/appsettings.{Environment}.json