Arcturus.MassTransit.Security
1.0.0
dotnet add package Arcturus.MassTransit.Security --version 1.0.0
NuGet\Install-Package Arcturus.MassTransit.Security -Version 1.0.0
<PackageReference Include="Arcturus.MassTransit.Security" Version="1.0.0" />
<PackageVersion Include="Arcturus.MassTransit.Security" Version="1.0.0" />
<PackageReference Include="Arcturus.MassTransit.Security" />
paket add Arcturus.MassTransit.Security --version 1.0.0
#r "nuget: Arcturus.MassTransit.Security, 1.0.0"
#:package Arcturus.MassTransit.Security@1.0.0
#addin nuget:?package=Arcturus.MassTransit.Security&version=1.0.0
#tool nuget:?package=Arcturus.MassTransit.Security&version=1.0.0
Arcturus.MassTransit.Security
A security framework for MassTransit message buses. It adds:
- Identity propagation — forwards a service JWT (machine identity) and/or a user JWT (delegated end-user identity) alongside published/sent messages, via dedicated headers.
- Identity validation — consume-side filters that validate those JWTs against pluggable
identity providers (Keycloak, Azure AD, etc.) and expose the resulting
ClaimsPrincipals to the rest of the pipeline. - Policy-based authorization — a fluent, compile-time-checked DSL for declaring per-message authorization policies (role/claim/client checks, conditional rules, custom rules), enforced by a consume filter before your consumer ever runs.
Table of contents
- Installation
- Core concepts
- Getting started
- Propagating identity (publisher side)
- Validating identity (consumer side)
- Policy-based authorization
- Full example
- Reference
Installation
dotnet add package Arcturus.MassTransit.Security
Targets net8.0 and depends on MassTransit, Microsoft.AspNetCore.Authorization,
Microsoft.AspNetCore.Http.Abstractions, Microsoft.Net.Http.Headers and
System.IdentityModel.Tokens.Jwt.
Core concepts
| Concept | Description |
|---|---|
| Service identity | A ClaimsPrincipal representing the calling service (e.g. obtained via an OAuth client-credentials flow). Carried in the X-Service-Token header. |
| User identity | A ClaimsPrincipal representing the end user on whose behalf a message is being processed. Carried in the X-User-Token header. |
SecurityPayload |
A per-message MassTransit payload (Arcturus.MassTransit.Security.Identity) holding the validated Service and User ClaimsPrincipal?s. Populated by the identity filters. |
SecurityMode |
ServiceOnly, UserOnly, or ServiceAndUser — declares which identities a message requires. |
Policy<T, TMode> |
A per-message-type authorization policy. TMode is a phantom type (ServiceOnly / UserOnly / ServiceAndUser) that statically restricts which rules can be attached, so mode/rule mismatches are compile errors. |
Getting started
1. Register the core services
using Arcturus.MassTransitSecurity;
builder.Services.AddMassTransitSecurity()
.AddServiceIdentityFilter()
.AddUserIdentityFilter();
AddMassTransitSecurity()registers:IPolicyRegistry→PolicyRegistry(singleton)PolicyConfigurator(singleton)IAuthorizationPolicyProvider→AuthorizationPolicyProvider(singleton)IIdentityProviderResolver→IdentityProviderResolver(singleton)PolicyAuthorizationFilter<>(scoped, open generic)
AddServiceIdentityFilter()registersServiceIdentityFilter<>(scoped, open generic).AddUserIdentityFilter()registersUserIdentityFilter<>(scoped, open generic).
2. Register at least one identity provider
IIdentityProviderResolver picks an IIdentityProvider for an incoming token based on its
iss/aud claims. You must register at least one implementation:
using Arcturus.MassTransit.Security.Identity;
builder.Services.AddHttpClient<IIdentityProvider, KeycloakIdentityProvider>();
See Implementing IIdentityProvider for a worked example.
3. Wire the consume filters into the bus
using Arcturus.MassTransit.Security.Identity;
builder.Services.AddMassTransit(x =>
{
x.SetKebabCaseEndpointNameFormatter();
x.AddConsumer<CreatePaymentCommandConsumer>();
x.UsingRabbitMq((context, cfg) =>
{
cfg.Host("localhost", "/", h =>
{
h.Username("guest");
h.Password("guest");
});
cfg.UseConsumeFilter(typeof(ServiceIdentityFilter<>), context);
cfg.UseConsumeFilter(typeof(UserIdentityFilter<>), context);
cfg.UseConsumeFilter(typeof(PolicyAuthorizationFilter<>), context);
cfg.ConfigureEndpoints(context);
});
});
Order matters. The identity filters must run before PolicyAuthorizationFilter<>, since it
relies on the SecurityPayload they populate.
4. Define policies
using Arcturus.MassTransit.Security.Policy;
builder.Services.AddPolicies(cfg =>
{
cfg.Policy<CreatePaymentCommand, ServiceAndUser>("create-payment")
.RequireClient("payment-service")
.RequireRole("payment:initiator")
.RequireClaim("scope", "initiator");
});
The
configurecallback passed toAddPoliciesruns when the DI container starts the registeredIHostedServices (i.e. during host startup), viaPolicyInitCompletedService.
If no policy is registered for a message type, PolicyAuthorizationFilter<T> falls back to a
default Policy<T> with SecurityMode.ServiceOnly and no rules.
Propagating identity (publisher side)
Token accessors
Two small interfaces in Arcturus.MassTransit.Security.TokenAccessors abstract how to obtain
the outgoing tokens:
public interface IServiceTokenAccessor
{
ValueTask<string?> GetTokenAsync(CancellationToken cancellationToken = default);
}
public interface IUserTokenAccessor
{
ValueTask<string?> GetTokenAsync(CancellationToken cancellationToken = default);
}
Built-in implementations:
| Type | Implements | Behavior |
|---|---|---|
ClientCredentialsTokenAccessor |
IServiceTokenAccessor |
Delegates to your ITokenClient.GetAccessTokenAsync() (e.g. an OAuth client-credentials exchange). |
HttpContextTokenAccessor |
IUserTokenAccessor |
Reads the inbound Authorization: Bearer <token> header off IHttpContextAccessor. |
GrpcTokenAccessor |
IUserTokenAccessor |
Same idea as above, for gRPC call contexts. |
ITokenClient (in Arcturus.MassTransit.Security.TokenClients) is the seam you implement to
fetch a service token:
public interface ITokenClient
{
ValueTask<string?> GetAccessTokenAsync(CancellationToken cancellationToken);
}
Example registration (matches SourceTestApplication):
using Arcturus.MassTransit.Security.TokenAccessors;
using Arcturus.MassTransit.Security.TokenClients;
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<ITokenClient, KeycloakTokenClient>();
builder.Services.AddScoped<IServiceTokenAccessor, ClientCredentialsTokenAccessor>();
builder.Services.AddScoped<IUserTokenAccessor, HttpContextTokenAccessor>();
Where KeycloakTokenClient implements ITokenClient by calling Keycloak's token endpoint with
a client_credentials grant.
Publish/Send filters
Arcturus.MassTransit.Security.Filters provides four filters that attach the tokens produced by
the accessors above to outgoing messages:
| Filter | Pipe | Reads |
|---|---|---|
SecurityPublishServiceFilter<T> |
PublishContext<T> |
IServiceTokenAccessor |
SecurityPublishUserFilter<T> |
PublishContext<T> |
IUserTokenAccessor |
SecuritySendServiceFilter<T> |
SendContext<T> |
IServiceTokenAccessor |
SecuritySendUserFilter<T> |
SendContext<T> |
IUserTokenAccessor |
Each filter calls GetTokenAsync() and, if a non-empty token is returned, sets the
X-Service-Token or X-User-Token header on the outgoing context. If the accessor returns
null/empty, the header is simply not set.
Register the publish filters (for IPublishEndpoint.Publish(...)):
using Arcturus.MassTransit.Security.Filters;
builder.Services.AddMassTransit(x =>
{
x.UsingRabbitMq((context, cfg) =>
{
cfg.Host("localhost", "/", h =>
{
h.Username("guest");
h.Password("guest");
});
cfg.UsePublishFilter(typeof(SecurityPublishServiceFilter<>), context);
cfg.UsePublishFilter(typeof(SecurityPublishUserFilter<>), context);
});
});
For point-to-point Send, use cfg.UseSendFilter(typeof(SecuritySendServiceFilter<>), context)
and/or SecuritySendUserFilter<> the same way.
Validating identity (consumer side)
ServiceIdentityFilter<T> / UserIdentityFilter<T>
Both filters live in Arcturus.MassTransit.Security.Identity and run as consume filters:
ServiceIdentityFilter<T>— theX-Service-Tokenheader is optional.
If the header is not present, the filter simply callsnextand skips service identity processing. If present, it strips aBearerprefix, inspects the token'siss/aud(viaTokenInspector), resolves anIIdentityProvider, validates the token, and stores the resultingClaimsPrincipalasSecurityPayload.Service.UserIdentityFilter<T>— theX-User-Tokenheader is optional.
If the header is not present, the filter simply callsnextand skips user identity processing. If present, it strips aBearerprefix, inspects the token'siss/aud(viaTokenInspector), resolves anIIdentityProvider, validates the token, and stores the resultingClaimsPrincipalasSecurityPayload.User.
Both filters use context.AddOrUpdatePayload<SecurityPayload>(...) so they can run in either
order and compose into the same payload.
Implementing IIdentityProvider
namespace Arcturus.MassTransit.Security.Identity
{
public interface IIdentityProvider
{
string Name { get; }
bool CanHandle(IdentityProviderContext context);
Task<ClaimsPrincipal> ValidateAsync(IdentityProviderContext context);
}
public class IdentityProviderContext
{
public string? Issuer { get; set; }
public string? Audience { get; set; }
public string? Token { get; set; }
}
}
Issuer/Audience are read directly off the (unvalidated) JWT by TokenInspector.Inspect and
are used purely to route the token to the right provider via CanHandle. Actual signature/
issuer/audience validation happens in ValidateAsync.
A minimal Keycloak-backed provider:
public class KeycloakIdentityProvider : IIdentityProvider
{
private readonly IConfigurationManager<OpenIdConnectConfiguration> _configManager;
public string Name => "keycloak";
public KeycloakIdentityProvider(HttpClient httpClient)
{
_configManager = new ConfigurationManager<OpenIdConnectConfiguration>(
"http://localhost:8080/realms/test-realm/.well-known/openid-configuration",
new OpenIdConnectConfigurationRetriever(),
new HttpDocumentRetriever { RequireHttps = false }); // DEV ONLY
}
public bool CanHandle(IdentityProviderContext context) =>
context.Issuer?.Contains(
"http://localhost:8080/realms/test-realm",
StringComparison.OrdinalIgnoreCase) == true;
public async Task<ClaimsPrincipal> ValidateAsync(IdentityProviderContext context)
{
var config = await _configManager.GetConfigurationAsync(CancellationToken.None);
var parameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "http://localhost:8080/realms/test-realm",
ValidateAudience = true,
ValidAudience = "payment-service",
IssuerSigningKeys = config.SigningKeys
};
return new JwtSecurityTokenHandler().ValidateToken(context.Token, parameters, out _);
}
}
Register it as IIdentityProvider (e.g. AddHttpClient<IIdentityProvider, KeycloakIdentityProvider>()).
You can register multiple providers — IdentityProviderResolver picks the one whose
CanHandle returns true, and throws if zero or more than one match:
public class IdentityProviderResolver : IIdentityProviderResolver
{
public IIdentityProvider Resolve(IdentityProviderContext context)
{
var providers = _providers.Where(p => p.CanHandle(context)).ToList();
return providers.Count switch
{
0 => throw new UnauthorizedAccessException("No identity provider found."),
1 => providers[0],
_ => throw new InvalidOperationException(
$"Multiple identity providers matched: {string.Join(", ", providers.Select(x => x.Name))}.")
};
}
}
Policy-based authorization
SecurityMode and compile-time-checked modes
SecurityMode (in Arcturus.MassTransit.Security.Policies) is a plain enum:
public enum SecurityMode
{
ServiceOnly,
UserOnly,
ServiceAndUser
}
Rather than passing this enum around at runtime, policies are built with phantom mode
types (in Arcturus.MassTransit.Security.Policy):
public interface IPolicyMode { static abstract SecurityMode Value { get; } }
public interface IRequiresService { }
public interface IRequiresUser { }
public sealed class ServiceOnly : IPolicyMode, IRequiresService { /* Value = SecurityMode.ServiceOnly */ }
public sealed class UserOnly : IPolicyMode, IRequiresUser { /* Value = SecurityMode.UserOnly */ }
public sealed class ServiceAndUser : IPolicyMode, IRequiresService, IRequiresUser
{ /* Value = SecurityMode.ServiceAndUser */ }
Policy<T, TMode> derives Mode from TMode.Value. Each rule-attaching extension method
constrains TMode to the marker interface(s) it needs:
| Method | Constraint | Usable with |
|---|---|---|
RequireRole(role) |
TMode : IRequiresUser |
UserOnly, ServiceAndUser |
RequireClaim(type, value) |
TMode : IRequiresUser |
UserOnly, ServiceAndUser |
RequireClient(client) |
TMode : IRequiresService |
ServiceOnly, ServiceAndUser |
IfElse(...) |
TMode : IPolicyMode |
all modes |
DenyIf(...) |
TMode : IPolicyMode |
all modes |
This means an incompatible combination is rejected at compile time:
cfg.Policy<CreatePaymentCommand, ServiceOnly>("create-payment")
.RequireRole("payment:initiator"); // ❌ CS0311: 'ServiceOnly' does not satisfy 'IRequiresUser'
cfg.Policy<CreatePaymentCommand, UserOnly>("create-payment")
.RequireClient("payment-service"); // ❌ CS0311: 'UserOnly' does not satisfy 'IRequiresService'
Use ServiceAndUser whenever a policy needs both user-only rules (RequireRole,
RequireClaim) and service-only rules (RequireClient).
Defining policies
using Arcturus.MassTransit.Security.Policy;
builder.Services.AddPolicies(cfg =>
{
cfg.Policy<CreatePaymentCommand, ServiceAndUser>("create-payment")
.RequireClient("payment-service")
.RequireRole("payment:initiator")
.RequireClaim("scope", "payer");
cfg.Policy<ApprovePaymentCommand, UserOnly>("approve-payment")
.RequireRole("payment:approver");
});
cfg.Policy<T, TMode>(name):
- Creates
new Policy<T, TMode>(name)viaPolicyFactory.For<T, TMode>(name). - Registers it in the
IPolicyRegistry, keyed bytypeof(T). - Returns the policy so you can chain rule-attaching extension methods.
Built-in rules
All rule extension methods live in Arcturus.MassTransit.Security.Policy.PolicyExtensions and
return the policy for chaining (policy.AttachRule(...)).
RequireRole(string role)
Passes if context.User!.IsInRole(role). Requires IRequiresUser (UserOnly /
ServiceAndUser).
cfg.Policy<ApprovePaymentCommand, UserOnly>("approve-payment")
.RequireRole("payment:approver");
RequireClaim(string type, string value)
Passes if context.User!.HasClaim(type, value). Requires IRequiresUser.
cfg.Policy<CreatePaymentCommand, ServiceAndUser>("create-payment")
.RequireClaim("scope", "payer");
RequireClient(string client)
Passes if context.Service?.FindFirst("client_id")?.Value == client. Requires
IRequiresService (ServiceOnly / ServiceAndUser).
cfg.Policy<CreatePaymentCommand, ServiceAndUser>("create-payment")
.RequireClient("payment-service");
DenyIf(Func<PolicyContext<T>, Task<bool>> predicate)
Fails the policy when predicate(context) returns true (and passes otherwise). Available on
every mode.
cfg.Policy<ApprovePaymentCommand, UserOnly>("approve-payment")
.RequireRole("payment:senior-approver")
.DenyIf(async ctx => ctx.Message.Amount > 50_000);
IfElse(condition, truePredicate, falsePredicate)
public static Policy<T, TMode> IfElse<T, TMode>(
this Policy<T, TMode> policy,
Func<PolicyContext<T>, Task<bool>> condition,
Action<Policy<T, TMode>> truePredicate = null!,
Action<Policy<T, TMode>> falsePredicate = null!)
where T : class where TMode : IPolicyMode
condition is evaluated against the live PolicyContext<T> (so it can inspect context.Message,
context.User, context.Service, etc.). Whichever branch matches (truePredicate or
falsePredicate) is invoked with a fresh nested Policy<T, TMode>; any rules it attaches
must all pass for the IfElse rule to pass. A null branch (or a branch that attaches no
rules) means "allow" for that branch.
// Amounts over 1000 require an "senior-approver" role; smaller amounts only need "approver".
cfg.Policy<ApprovePaymentCommand, UserOnly>("approve-payment")
.IfElse(
condition: async ctx => ctx.Message.Amount > 1000,
truePredicate: p => p.RequireRole("payment:senior-approver"),
falsePredicate: p => p.RequireRole("payment:approver"));
IfElse branches can be nested, e.g. to layer extra conditions on top of the "true" branch:
cfg.Policy<ApprovePaymentCommand, UserOnly>("approve-payment")
.IfElse(
condition: async ctx => ctx.Message.Amount > 1000,
truePredicate: p => p.IfElse(
condition: async ctx => ctx.Message.Amount > 10_000,
truePredicate: inner => inner.RequireRole("payment:senior-approver"),
falsePredicate: inner => inner.RequireRole("payment:approver")),
falsePredicate: p => p.RequireRole("payment:junior-approver"));
Writing custom rules
A rule is any IPolicyRule<T>:
namespace Arcturus.MassTransit.Security.Policy
{
public interface IPolicyRule<T> where T : class
{
Task<bool> Evaluate(PolicyContext<T> context);
}
}
PolicyContext<T> exposes everything a rule typically needs:
public class PolicyContext<T> where T : class
{
public ConsumeContext<T> MessageContext { get; }
public ClaimsPrincipal? Service => Payload.Service;
public ClaimsPrincipal? User => Payload.User;
public SecurityPayload Payload { get; }
public IServiceProvider ServiceProvider { get; } // resolve scoped app services
public T Message => MessageContext.Message;
}
Pair a rule with an extension method constrained to the modes where it makes sense — this keeps the same compile-time safety for your own rules:
using Arcturus.MassTransit.Security.Policy;
public static class CustomRules
{
public static Policy<T, TMode> RequireActiveUser<T, TMode>(this Policy<T, TMode> policy)
where T : class
where TMode : IPolicyMode, IRequiresUser
{
policy.AttachRule(new RequireActiveUserRule<T>());
return policy;
}
}
public class RequireActiveUserRule<T> : IPolicyRule<T> where T : class
{
public async Task<bool> Evaluate(PolicyContext<T> context)
{
var userService = context.ServiceProvider.GetRequiredService<IUserService>();
var userId = context.User!.FindFirst(ClaimTypes.NameIdentifier)?.Value;
return userId is not null && await userService.IsUserActive(userId);
}
}
Usage:
cfg.Policy<CreatePaymentCommand, ServiceAndUser>("create-payment")
.RequireClient("payment-service")
.RequireRole("payment:initiator")
.RequireActiveUser();
Enforcement: PolicyAuthorizationFilter<T>
For every consumed message of type T, this consume filter:
- Reads the
SecurityPayloadfrom the consume context (throwsUnauthorizedAccessException("Missing security context")if the identity filters never ran). - Looks up
Policy<T>fromIPolicyRegistry(or theServiceOnly/no-rules default). - Checks
policy.Modeagainst the payload:ServiceOnly→payload.Servicemust be non-null, else"Service required".UserOnly→payload.Usermust be non-null, else"User required".ServiceAndUser→ both must be non-null, else"Service and user required".
- Builds a
PolicyContext<T>and evaluatespolicy.Rulesin order, throwingUnauthorizedAccessException($"Policy '{policy.Name}' failed")on the first rule that returnsfalse. - Calls
nextonly if every check passed.
Full example
Consumer (DestinationTestApplication)
using Arcturus.MassTransit.Security.Identity;
using Arcturus.MassTransit.Security.Policy;
using Arcturus.MassTransitSecurity;
var builder = WebApplication.CreateBuilder(args);
// 1. Core services + identity filters
builder.Services.AddMassTransitSecurity()
.AddServiceIdentityFilter()
.AddUserIdentityFilter();
// 2. Identity provider(s)
builder.Services.AddHttpClient<IIdentityProvider, KeycloakIdentityProvider>();
// Application services used by custom rules
builder.Services.AddScoped<IUserService, UserService>();
// 3. MassTransit + consume filter pipeline
builder.Services.AddMassTransit(x =>
{
x.SetKebabCaseEndpointNameFormatter();
x.AddConsumer<CreatePaymentCommandConsumer>();
x.AddConsumer<ApprovePaymentCommandConsumer>();
x.UsingRabbitMq((context, cfg) =>
{
cfg.Host("localhost", "/", h =>
{
h.Username("guest");
h.Password("guest");
});
cfg.UseConsumeFilter(typeof(ServiceIdentityFilter<>), context);
cfg.UseConsumeFilter(typeof(UserIdentityFilter<>), context);
cfg.UseConsumeFilter(typeof(PolicyAuthorizationFilter<>), context);
cfg.ConfigureEndpoints(context);
cfg.UseMessageRetry(r => r.Interval(5, 2));
});
});
// 4. Policies
builder.Services.AddPolicies(cfg =>
{
cfg.Policy<CreatePaymentCommand, ServiceAndUser>("create-payment")
.RequireClient("payment-service")
.RequireRole("payment:initiator")
.RequireClaim("scope", "payer")
.RequireActiveUser();
cfg.Policy<ApprovePaymentCommand, UserOnly>("approve-payment")
.IfElse(
condition: async ctx => ctx.Message.Amount > 10000,
truePredicate: p => p.RequireRole("payment:senior-approver"),
falsePredicate: p => p.RequireRole("payment:approver"));
});
var app = builder.Build();
app.Run();
Publisher (SourceTestApplication)
using Arcturus.MassTransit.Security.Filters;
using Arcturus.MassTransit.Security.TokenAccessors;
using Arcturus.MassTransit.Security.TokenClients;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpContextAccessor();
// Token accessors: service token via client-credentials, user token from the inbound request
builder.Services.AddScoped<ITokenClient, KeycloakTokenClient>();
builder.Services.AddScoped<IServiceTokenAccessor, ClientCredentialsTokenAccessor>();
builder.Services.AddScoped<IUserTokenAccessor, HttpContextTokenAccessor>();
builder.Services.AddMassTransit(x =>
{
x.SetKebabCaseEndpointNameFormatter();
x.UsingRabbitMq((context, cfg) =>
{
cfg.Host("localhost", "/", h =>
{
h.Username("guest");
h.Password("guest");
});
cfg.UsePublishFilter(typeof(SecurityPublishServiceFilter<>), context);
cfg.UsePublishFilter(typeof(SecurityPublishUserFilter<>), context);
});
});
var app = builder.Build();
app.Run();
// Controller action: publishing attaches X-Service-Token and X-User-Token automatically.
[HttpPost]
[Authorize]
public async Task<IActionResult> CreatePayment([FromServices] IPublishEndpoint publishEndpoint)
{
await publishEndpoint.Publish(new CreatePaymentCommand
{
Id = Guid.NewGuid(),
Amount = 100_000
}, HttpContext.RequestAborted);
return Ok();
}
Reference
Namespace map
| Namespace | Contains |
|---|---|
Arcturus.MassTransitSecurity |
DependencyInjectionRegistrationExtensions (AddMassTransitSecurity, AddServiceIdentityFilter, AddUserIdentityFilter, AddPolicies) |
Arcturus.MassTransit.Security.Policy |
Policy<T>, Policy<T, TMode>, IPolicyRule<T>, PolicyContext<T>, IPolicyRegistry, PolicyRegistry, PolicyFactory, PolicyExtensions, IPolicyMode, IRequiresService, IRequiresUser, ServiceOnly, UserOnly, ServiceAndUser |
Arcturus.MassTransit.Security.Policies |
SecurityMode, PolicyBuilder, PolicyConfigurator, PolicyInitCompletedService, IAuthorizationPolicyProvider, AuthorizationPolicyProvider |
Arcturus.MassTransit.Security.Rules |
RequireRoleRule<T>, RequireClaimRule<T>, RequireClientRule<T>, DenyIfRule<T>, ConditionalRule<T, TMode> |
Arcturus.MassTransit.Security.Identity |
SecurityPayload, SecurityHeaders, IIdentityProvider, IIdentityProviderResolver, IdentityProviderResolver, IdentityProviderContext, TokenInspector, ServiceIdentityFilter<T>, UserIdentityFilter<T>, PolicyAuthorizationFilter<T> |
Arcturus.MassTransit.Security.Filters |
SecurityPublishServiceFilter<T>, SecurityPublishUserFilter<T>, SecuritySendServiceFilter<T>, SecuritySendUserFilter<T> |
Arcturus.MassTransit.Security.TokenAccessors |
IServiceTokenAccessor, IUserTokenAccessor, ClientCredentialsTokenAccessor, HttpContextTokenAccessor, GrpcTokenAccessor |
Arcturus.MassTransit.Security.TokenClients |
ITokenClient |
Headers
public static class SecurityHeaders
{
public const string ServiceToken = "X-Service-Token";
public const string UserToken = "X-User-Token";
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- MassTransit (>= 8.5.10)
- System.IdentityModel.Tokens.Jwt (>= 8.19.1)
-
net8.0
- MassTransit (>= 8.5.10)
- System.IdentityModel.Tokens.Jwt (>= 8.19.1)
-
net9.0
- MassTransit (>= 8.5.10)
- System.IdentityModel.Tokens.Jwt (>= 8.19.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 123 | 6/15/2026 |