Using Hangfire Dashboard in ABP API Website 🚀
Introduction
In this article, I'll show you how to integrate and use the Hangfire Dashboard in an ABP API website.
Typically, API websites use JWT Bearer authentication, but the Hangfire Dashboard isn't compatible with JWT Bearer authentication. Therefore, we need to implement Cookies and OpenIdConnect authentication for the Hangfire Dashboard access.
Creating a New ABP Demo Project 🛠️
We'll create a new ABP Demo Tiered project that includes AuthServer, API, and Web projects.
abp new AbpHangfireDemoApp -t app --tiered
Now let's add the Hangfire Dashboard to the API project and configure it to use Cookies and OpenIdConnect authentication for accessing the dashboard.
Adding a New Hangfire Application 🔧
We need to add a new Hangfire application to the appsettings.json file in the DbMigrator project:
Note: Replace
44371with yourAPIproject's port.
"OpenIddict": {
"Applications": {
//...
"AbpHangfireDemoApp_Hangfire": {
"ClientId": "AbpHangfireDemoApp_Hangfire",
"RootUrl": "https://localhost:44371/"
}
//...
}
}
- Update the
OpenIddictDataSeedContributor'sCreateApplicationsAsyncmethod in theDomainproject to seed the new Hangfire application.
//Hangfire Client
var hangfireClientId = configurationSection["AbpHangfireDemoApp_Hangfire:ClientId"];
if (!hangfireClientId.IsNullOrWhiteSpace())
{
var hangfireClientRootUrl = configurationSection["AbpHangfireDemoApp_Hangfire:RootUrl"]!.EnsureEndsWith('/');
await CreateApplicationAsync(
applicationType: OpenIddictConstants.ApplicationTypes.Web,
name: hangfireClientId!,
type: OpenIddictConstants.ClientTypes.Confidential,
consentType: OpenIddictConstants.ConsentTypes.Implicit,
displayName: "Hangfire Application",
secret: configurationSection["AbpHangfireDemoApp_Hangfire:ClientSecret"] ?? "1q2w3e*",
grantTypes: new List<string> //Hybrid flow
{
OpenIddictConstants.GrantTypes.AuthorizationCode, OpenIddictConstants.GrantTypes.Implicit
},
scopes: commonScopes,
redirectUris: new List<string> { $"{hangfireClientRootUrl}signin-oidc" },
postLogoutRedirectUris: new List<string> { $"{hangfireClientRootUrl}signout-callback-oidc" },
clientUri: hangfireClientRootUrl,
logoUri: "/images/clients/aspnetcore.svg"
);
}
- Run the
DbMigratorproject to seed the new Hangfire application.
Adding Hangfire Dashboard to the API Project 📦
- Add the following packages and modules dependencies to the
APIproject:
<PackageReference Include="Volo.Abp.BackgroundJobs.HangFire" Version="9.2.0" />
<PackageReference Include="Volo.Abp.AspNetCore.Authentication.OpenIdConnect" Version="9.2.0" />
<PackageReference Include="Hangfire.SqlServer" Version="1.8.20" />
typeof(AbpBackgroundJobsHangfireModule),
typeof(AbpAspNetCoreAuthenticationOpenIdConnectModule)
- Add the
HangfireClientIdandHangfireClientSecretto theappsettings.jsonfile in theAPIproject:
"AuthServer": {
"Authority": "https://localhost:44358",
"RequireHttpsMetadata": true,
"MetaAddress": "https://localhost:44358",
"SwaggerClientId": "AbpHangfireDemoApp_Swagger",
"HangfireClientId": "AbpHangfireDemoApp_Hangfire",
"HangfireClientSecret": "1q2w3e*"
}
- Add the
ConfigureHangfiremethod to theAPIproject to configure Hangfire:
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
var hostingEnvironment = context.Services.GetHostingEnvironment();
//...
//Add Hangfire
ConfigureHangfire(context, configuration);
//...
}
private void ConfigureHangfire(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.AddHangfire(config =>
{
config.UseSqlServerStorage(configuration.GetConnectionString("Default"));
});
}
- Modify the
ConfigureAuthenticationmethod to add newCookiesandOpenIdConnectauthentication schemes:
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddAbpJwtBearer(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = configuration.GetValue<bool>("AuthServer:RequireHttpsMetadata");
options.Audience = "AbpHangfireDemoApp";
options.ForwardDefaultSelector = httpContext => httpContext.Request.Path.StartsWithSegments("/hangfire", StringComparison.OrdinalIgnoreCase)
? CookieAuthenticationDefaults.AuthenticationScheme
: null;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddAbpOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]);
options.ResponseType = OpenIdConnectResponseType.Code;
options.ClientId = configuration["AuthServer:HangfireClientId"];
options.ClientSecret = configuration["AuthServer:HangfireClientSecret"];
options.UsePkce = true;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("roles");
options.Scope.Add("email");
options.Scope.Add("phone");
options.Scope.Add("AbpHangfireDemoApp");
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
});
//...
}
- Add a custom middleware and
UseAbpHangfireDashboardafterUseAuthorizationin theOnApplicationInitializationmethod:
//...
app.UseAuthorization();
app.Use(async (httpContext, next) =>
{
if (httpContext.Request.Path.StartsWithSegments("/hangfire", StringComparison.OrdinalIgnoreCase))
{
var authenticateResult = await httpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
if (!authenticateResult.Succeeded)
{
await httpContext.ChallengeAsync(
OpenIdConnectDefaults.AuthenticationScheme,
new AuthenticationProperties
{
RedirectUri = httpContext.Request.Path + httpContext.Request.QueryString
});
return;
}
}
await next.Invoke();
});
app.UseAbpHangfireDashboard("/hangfire", options =>
{
options.AsyncAuthorization = new[]
{
new AbpHangfireAuthorizationFilter()
};
});
//...
Perfect! 🎉 Now you can run the AuthServer and API projects and access the Hangfire Dashboard at https://localhost:44371/hangfire.
Note: Replace
44371with yourAPIproject's port.
The first time you access the Hangfire Dashboard, you'll be redirected to the login page of the AuthServer project. After you log in, you'll be redirected back to the Hangfire Dashboard.

Key Points 🔑
1. Authentication Scheme Selection
The default authentication scheme in API websites is JWT Bearer. We've implemented Cookies and OpenIdConnect specifically for the Hangfire Dashboard.
We've configured the JwtBearerOptions's ForwardDefaultSelector to use CookieAuthenticationDefaults.AuthenticationScheme for Hangfire Dashboard requests.
This means that if the request path starts with /hangfire, the request will be authenticated using the Cookies authentication scheme; otherwise, it will use the JwtBearer authentication scheme.
options.ForwardDefaultSelector = httpContext => httpContext.Request.Path.StartsWithSegments("/hangfire", StringComparison.OrdinalIgnoreCase)
? CookieAuthenticationDefaults.AuthenticationScheme
: null;
2. Custom Middleware for Authentication
We've also implemented a custom middleware to handle Cookies authentication for the Hangfire Dashboard. If the current request isn't authenticated with the Cookies authentication scheme, it will be redirected to the login page.
app.Use(async (httpContext, next) =>
{
if (httpContext.Request.Path.StartsWithSegments("/hangfire", StringComparison.OrdinalIgnoreCase))
{
var authenticateResult = await httpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
if (!authenticateResult.Succeeded)
{
await httpContext.ChallengeAsync(
OpenIdConnectDefaults.AuthenticationScheme,
new AuthenticationProperties
{
RedirectUri = httpContext.Request.Path + httpContext.Request.QueryString
});
return;
}
}
await next.Invoke();
});
Comments
NH Support NH Support 18 weeks ago
Yes working with me, I was facing an issue before this article thanks
Liming Ma 18 weeks ago
Thanks : )