Open Closed

Infinite Redirect Loop After Deploying ABP Angular App with Separate Auth API on IIS (Same Port Hosting) #9274


User avatar
0
binh.luongthanh@gmail.com created
  • ABP Framework version: v9.1.1
  • UI Type: Angular
  • Database System: SQL Server
  • Deployment: IIS Service

We're trying to host Front-end and Back-end in the same port using IIS Hosting. We're using two separate projects: 1 for the main app's APIs, and 1 for the Authentication APIs (Identity & OpenIddict, etc.).

The issue we're encountering is that when we run the application locally (FE at localhost:4200, BE at localhost:44365, Auth at localhost:44310), everything works just fine. But when we deploying that application into IIS environment, and trying to access the site at the root url (https://www.domain.com:port/), this happens:

  1. The site loads to orgchart endpoint with some query string parameters like code, redirect_urls, etc.
  2. Then it redirects me to https://www.domain.com:port/?iss=<issuer>
  3. Then it redirects me to https://www.domain.com:port/?
  4. And then back to 1, create an infinite redirecting loops.

If I try to stop the application at a specific site (I'm not sure if it's 1,2 or 3), it shows on the console this message:

Could you give me any ideas on which can be the cause of this issue? P/s: We've added some middlewares like UseDefaultFiles, UseStaticFiles and reconfigured web.config for some url rewrite rules to be able to host the frontend inside wwwRoot folder.

Sincerely.

  • Exception message and full stack trace:
  • Steps to reproduce the issue:

5 Answer(s)
  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    Hi,

    Can you get the response from AuthServer (44310) for the path /.well-known/openid-configuration path?

    Can you check this documentation for IIS? https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-9.0#iisiis-express-and-aspnet-core-module

    Sometimes headers cannot be passed to the application directly when they're running behind a load-balander or a proxy server. Check forwarded headers too https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-9.0#forwarded-headers-middleware-order

  • User Avatar
    0
    binh.luongthanh@gmail.com created

    This is the response from https://192.168.200.18:44310/.well-known/openid-configuration

    {
      "issuer": "https://192.168.200.18:44310/",
      "authorization_endpoint": "https://192.168.200.18:44310/connect/authorize",
      "token_endpoint": "https://192.168.200.18:44310/connect/token",
      "introspection_endpoint": "https://192.168.200.18:44310/connect/introspect",
      "end_session_endpoint": "https://192.168.200.18:44310/connect/logout",
      "revocation_endpoint": "https://192.168.200.18:44310/connect/revocat",
      "userinfo_endpoint": "https://192.168.200.18:44310/connect/userinfo",
      "device_authorization_endpoint": "https://192.168.200.18:44310/device",
      "jwks_uri": "https://192.168.200.18:44310/.well-known/jwks",
      "grant_types_supported": [
        "authorization_code",
        "implicit",
        "password",
        "client_credentials",
        "refresh_token",
        "urn:ietf:params:oauth:grant-type:device_code",
        "LinkLogin",
        "Impersonation",
        "ApiKeyExtensionGrant"
      ],
      "response_types_supported": [
        "code",
        "code id_token",
        "code id_token token",
        "code token",
        "id_token",
        "id_token token",
        "token",
        "none"
      ],
      "response_modes_supported": [
        "form_post",
        "fragment",
        "query"
      ],
      "scopes_supported": [
        "openid",
        "offline_access",
        "email",
        "profile",
        "phone",
        "roles",
        "address",
        "WF2025",
        "Orgchart",
        "eRequest"
      ],
      "claims_supported": [
        "aud",
        "exp",
        "iat",
        "iss",
        "sub"
      ],
      "id_token_signing_alg_values_supported": [
        "RS256"
      ],
      "code_challenge_methods_supported": [
        "plain",
        "S256"
      ],
      "subject_types_supported": [
        "public"
      ],
      "token_endpoint_auth_methods_supported": [
        "client_secret_post",
        "private_key_jwt",
        "client_secret_basic"
      ],
      "introspection_endpoint_auth_methods_supported": [
        "client_secret_post",
        "private_key_jwt",
        "client_secret_basic"
      ],
      "revocation_endpoint_auth_methods_supported": [
        "client_secret_post",
        "private_key_jwt",
        "client_secret_basic"
      ],
      "device_authorization_endpoint_auth_methods_supported": [
        "client_secret_post",
        "private_key_jwt",
        "client_secret_basic"
      ],
      "claims_parameter_supported": false,
      "request_parameter_supported": false,
      "request_uri_parameter_supported": false,
      "authorization_response_iss_parameter_supported": true
    }
    

    Additional information, the version of the AuthServer is 8.3.2. I've manually added some columns in one/more table for it to make the main backend run normally.

    • No proxy server or load balancer is used; each application (Frontend, Backend, AuthServer) runs as a single instance.
    • The site is accessed directly via IIS.

    The AuthServer is working fine for one site hosted at port 44360, using ABP version 8.3.2. So the problem may not be related to IIS. For this project, I could run everything normally from FE, BE and AuthServer. The issue only appears after deployed to IIS. Also, the backend can be ran in Swagger normally, such as Authorize and execute the endpoints. For more context, we used the same configuration for Front-end and Backend as the previously working site (8.3.2). We also adjusted the web.config to host the Angular app inside wwwRoot:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <location path="." inheritInChildApplications="false">
        <system.webServer>
          <handlers>
            <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
          </handlers>
    			<aspNetCore processPath="dotnet" arguments=".\MEVN.FA.WF2025.HttpApi.Host.dll" stdoutLogEnabled="false" stdoutLogFile=".\Logs\stdout" hostingModel="inprocess">
    				<environmentVariables>
    					<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
    				</environmentVariables>
    			</aspNetCore>
    		</system.webServer>
    	</location>
    	<system.webServer>
    		<httpProtocol>
    			<customHeaders>
    				<remove name="x-powered-by" />
    			</customHeaders>
    		</httpProtocol>
    		<rewrite>
    			<rules>
    				<!-- Explicitly pass backend routes to ASP.NET Core -->
    				<rule name="Backend Routes" stopProcessing="true">
    					<match url="^(app|abp|api|swagger|connect|Account|_vs|.well-known)(.*)$" />
    					<action type="None" />
    				</rule>
    				<!-- Serve static assets for Angular -->
    				<rule name="Static Assets" stopProcessing="true">
    					<match url="([\S]+\.(html|htm|svg|js|css|png|gif|jpg|jpeg|eot|ttf|woff2|svg|xlsx|ico|txt))" />
    					<action type="Rewrite" url="/{R:1}" />
    				</rule>
    				<!-- Route frontend requests to Angular index.html -->
    				<rule name="AngularRouter Routes" stopProcessing="true">
    					<match url=".*" />
    					<conditions logicalGrouping="MatchAll">
    						<add input="{REQUEST_URI}" pattern="^/api(.*)$" negate="true" />
    						<add input="{REQUEST_URI}" pattern="^/.well-known(.*)$" negate="true" />
    						<add input="{REQUEST_URI}" pattern="^/Account(.*)$" negate="true" />
    						<add input="{REQUEST_URI}" pattern="/Error\?(.*)$" negate="true" />
    						<add input="{REQUEST_URI}" pattern="/connect(.*)$" negate="true" />
    						<add input="{REQUEST_URI}" pattern="/swagger(.*)$" negate="true" />
    						<add input="{REQUEST_URI}" pattern="/_vs(.*)$" negate="true" />
    						<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
    						<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
    					</conditions>
    					<action type="Rewrite" url="/wwwRoot/index.html" />
    				</rule>
    			</rules>
    		</rewrite>
    	</system.webServer>
    </configuration>
    

    Please let me know if you need more information. Thank you

  • User Avatar
    0
    binh.luongthanh@gmail.com created

    More information, this is the code where it logs the errors at the Frontend site:

    AND

  • User Avatar
    0
    binh.luongthanh@gmail.com created

    Hi, I’ve resolved the infinite redirect loop issue in WF2025 (ABP v9.1.1, Angular tiered) independently. The problem stemmed from a SecurityTokenSignatureKeyNotFoundException (IDX10503) due to a kid mismatch between the AuthServer (192.168.200.18:44310) and backend (192.168.200.18:44321). I fixed it by syncing the CertificatePassPhrase with the one configured in the AuthServer and generating a new openiddict.pfx for the backend. The issue is resolved, and the app works with both FE at localhost:4200 and FE hosted at wwwRoot. Please close this ticket.

    Thanks, Kien

  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    Sorry for the late reply, I was trying to check case,

    Yes openiddict.pfx is ignored on Git by default and if you clone your project from zero to publish or use a pipleine that file will not be included. You need to manually copy it.

    I'm not sure if that file has an expiration date, but nice to hear that re-generating fixes the problem. Also always make sure the PassPhrase is always correct in the published server-side

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v9.3.0-preview. Updated on May 14, 2025, 07:53