Hi,
You can define permissions to your clients without requiring an account token.
https://abp.io/docs/latest/framework/fundamentals/authorization#permission-value-providers
ABP has ClientPermissionValueProvider implementation by default and you can give permissions to specific client. ClientId will be retrieved from AbpClaimTypes.ClientId claim.
Or, if you wish you can have a custom implementation:
public class SystemAdminPermissionValueProvider : PermissionValueProvider, ITransientDependency
{
public SystemAdminPermissionValueProvider(IPermissionStore permissionStore)
: base(permissionStore)
{
}
public override string Name => "SystemAdmin";
public async override Task<PermissionGrantResult>
CheckAsync(PermissionValueCheckContext context)
{
// Anything you want to check
if (context.Principal?.FindFirst("User_Type")?.Value == "SystemAdmin")
{
return PermissionGrantResult.Granted;
}
return PermissionGrantResult.Undefined;
}
}
-or-
If permissions and claims is not good at your case, you can check IntegrationServices. Integration services are built for inter-service communication and cannot be consumed from clients.You can check the documentation about more information and use-cases: https://abp.io/docs/latest/framework/api-development/integration-services
Hello @k-s-c,
Thanks for reaching out and providing such a clear description of your setup and the issue you're facing. This "Unauthorized" error in a tiered application with an API Gateway is a classic scenario, and we can definitely help you debug it.
Based on your description, the problem lies in the authentication flow between your Public Gateway and your Host API, specifically concerning JWT token validation when requests are proxied from HTTPS to HTTP.
Let's break down the potential causes and how to diagnose them:
1. RequireHttpsMetadata = false (Revisit this carefully!)
You've correctly identified RequireHttpsMetadata = false on the JwtBearerOptions as a potential fix for the Host API. This setting is crucial when your IdentityServer (which is your Host API in this case, acting as the token issuer) issues tokens with an iss (issuer) claim that is an HTTPS URL, but the token is then validated by an API (your Host API, when accessed via the gateway) that receives the request over HTTP.
Action:
Verify the iss claim: Inspect a JWT token issued by your Host API (you can get one from the working Swagger UI on the Host API, or by logging in from your MVC app). What is the value of the iss claim? If it's https://your-gateway-domain/, and your Host API is receiving requests over http://localhost:port/, then RequireHttpsMetadata = false is indeed necessary on the Host API's AddJwtBearer configuration.
Double-check placement: Ensure RequireHttpsMetadata = false is applied correctly within the ConfigureServices method of your Host API:
C#
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://your-gateway-domain/"; // Or your Host API's public URL if it's directly accessible for discovery
options.RequireHttpsMetadata = false; // <-- This is the key
options.Audience = "YourProjectName_Host"; // Or the audience of your Host API
});
Note: options.Authority should point to the public URL where the IdentityServer discovery document can be found, which would typically be your Public Gateway's HTTPS URL.
2. Audience Mismatch
Both the Public Gateway (if it validates) and the Host API must be configured to accept the correct audience (aud claim) in the JWT token. The audience for your Host API is typically its own unique identifier (e.g., "YourProjectName_Host").
Action:
Check OpenIddict configuration: In your Host API's PreConfigureServices, where you configure OpenIddict (ABP's default IdentityServer), ensure the client configuration for your Web MVC app (and any other clients) requests the correct scope/audience:
C#
PreConfigure<OpenIddictBuilder>(builder =>
{
builder.AddValidation(options =>
{
options.AddAudiences("YourApplicationName");
options.UseLocalServer();
options.UseAspNetCore();
});
});
Check client applications: Verify that your Web MVC application (or any client obtaining a token) is requesting the "YourProjectName_Host" scope.
Check appsettings.json in the DbMigrator: ABP layered template has data seeding logic with DbMigrator. Make sure your credentials is correct in the appsettings.json inside YourProjectName.DbMigrator folder and then execute DbMigrator once when your credentials ready to publish. ⚠️ The production database should be properly migrated
Check OpenIddictDataSeedContributor if any change requiremens: In the Domain project you'll see OpenIddict\OpenIddictDataSeedContributor.cs file that seeds all the openiddict configuration to the database. Check there and make sure all of your clients are added there.
3. Swagger UI and Token Injection
When using Swagger UI on the Public Gateway, the "Authorize" button injects the bearer token. The issue here might be how Swagger on the Gateway handles this, or if the token it's using is somehow different or malformed when forwarded.
Action:
Authorization header. Is the bearer token present? Is it the correct token?4. Logging (Your Best Friend!)
Enable detailed logging on both your Public Gateway and your Host API. Look for logs related to authentication, JWT validation, and authorization.
Action:
Configure Serilog (or default logging): Ensure appsettings.json has sufficient logging levels:JSON
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning",
"OpenIddict": "Debug", // Very useful for token validation issues
"Microsoft.AspNetCore.Authentication": "Debug", // Also very useful
"Volo.Abp": "Information"
}
}
}
Examine logs: Look for messages like "token validation failed," "issuer not found," "invalid audience," or "signature validation failed."
Troubleshooting Steps (Order of operations I'd recommend):
jwt.io.
iss (issuer), aud (audience), and exp (expiration) claims?Authorization).Example Scenario and Solution:
Often, the problem is that the Host API is configured to expect Authority = "https://public-gateway-domain/" (because that's where the discovery document is publicly available), but it's receiving requests over HTTP internally (from the gateway). In this case, RequireHttpsMetadata = false is critical on the Host API's JwtBearerOptions.
Let me know the results of these checks, especially the network tab analysis and any relevant log messages. With more details, we can narrow down the exact cause.
Best regards,
ABP Client-proxies use IHttpClientFactory to create HttpClient objects and it uses RemoteServiceName to create HttpClient for each of your remote service.
https://github.com/abpframework/abp/blob/9a43b9c9dfbc8b883c58a7acdb9c21619aa48dfc/framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/ClientProxying/ClientProxyBase.cs#L124
So you can easily use freshly defined a new HttpClient for your service:
context.Services.AddHttpClient("YourService") // Administrator, Identity etc.
.ConfigureHttpClient(client =>
{
client.BaseAddress = new Uri("https://api.example.com/");
client.Timeout = TimeSpan.FromMinutes(2);
});
This defines a new HttpClient instead trying to configure existing one, you can have all control on the HttpClient in this way
The error shows the permission isn't granted for the current request / current authenticated user. A couple of reasons can cause this issue:
The user really don't have the permission.
The cookie/token might be obsolete or created by another authentication server or application itself, you can try to clear cookies and everything and authenticate again from scratch.
If you deployment is distributed, you can also try clearing Redis cache, since permissions are cached in Redis in distributed solutions. The cached data might be wrong, outdated or corrupted.
Hi,
You have to create client-proxies into HttpApi.Client project:
Otherwise, you replace the original ApplicationService implementation and it cannot work. Whenever you need to consume by using client-proxies, you'll need to use HttpApi.Client and Application.Contracts project reference and use interfaces of your AppServices. Whenever you inject that interface, it'll use ClientProxy if the project has HttpApi.Client reference.
Hi,
We cannot know what is the exact reason of this behaviour.
Can you enable debug logs to check detailed logs to determine what is happenning exactly by following this steps:
https://abp.io/support/questions/8622/How-to-enable-Debug-logs-for-troubleshoot-problems
I think this is a similar case:
https://abp.io/support/questions/8325/How-to-increase-http-client-timeout
Can you try increasing YARP timeout from your Gateway, since gateway doesn't use ABP's client-proxy, it's a standalone proxy implementation by dotnet
Whenever you create a new project there'll be already a file for that purpose with an example:
You can uncomment that examnples and ready to go, there'll be no other changes. If you configured any EntityExtension, you'll need to create a database migration.
If you are not familiar with CLI commands you can do it in ABP Studio UI:

Hi,
Can you try running it on a different port by modifying appsettings.json with the following steps: https://abp.io/qa/questions/8189/3a15f274-2ef1-f039-e08c-32c2e6f25853