Language: English Español
Get a method protected by UMS authorization in five minutes. Assumes you already have a UMS tenant and can call POST /api/v1/client/authenticate.
For full reference, see README.md.
dotnet add package Ums.Sdk.Authorization
dotnet add package Ums.Sdk.Authorization.Aop
For tests:
dotnet add package Ums.Sdk.Authorization.Testing
In Program.cs:
using Ums.Sdk.Authorization;
using Ums.Sdk.Authorization.Aop;
using BeyondNetCode.Shell.DI;
builder.Services.AddAop(aop => aop
.AddAspect<AuthorizationAspect>());
builder.Services.AddUmsSdkAuthorization(); // validator + default accessor
builder.Services.AddHttpContextAuthGraphAccessor(); // ASP.NET Core integration
Add the middleware that decodes the JWT body and stores the graph in HttpContext.Items:
app.UseUmsAuthGraph(); // before UseAuthorization
This middleware:
Authorization: Bearer ... header.POST /api/v1/client/authenticate if no cached graph or the cached one expired.AuthorizationGraph in HttpContext.Items["UmsAuthGraph"].schemaVersion against the SDK’s compatibility range; rejects with 401 on AUTH_205.Add an attribute to the interface method:
public interface IOrderService
{
[RequiresScope("PURCHASE_ORDER.APPROVE")]
Task<Result> ApproveOrderAsync(Guid orderId);
}
public class OrderService : IOrderService
{
public async Task<Result> ApproveOrderAsync(Guid orderId)
{
// your business logic — runs only if authorized
return Result.Success();
}
}
Register the AOP-proxied service:
builder.Services.AddAopProxy<IOrderService, OrderService>();
That’s it. IOrderService.ApproveOrderAsync is now protected. Calling it from an endpoint or another service:
app.MapPost("/orders/{id}/approve", async (Guid id, IOrderService svc) =>
{
var result = await svc.ApproveOrderAsync(id);
return result.IsSuccess ? Results.Ok() : Results.Forbid();
});
If the authenticated user lacks PURCHASE_ORDER.APPROVE, ApproveOrderAsync throws UnauthorizedAccessException before the body runs.
[Fact]
public async Task ApproveOrder_WithoutScope_ReturnsForbidden()
{
var graph = AuthGraphBuilder
.ForTenant("LOGISTICS_CORE")
.WithUser("ana.flores@example.com")
.WithScope("PURCHASE_ORDER.VIEW") // VIEW but not APPROVE
.Build();
var accessor = new TestAuthGraphAccessor(graph);
var service = AopProxyCreator.Create<IOrderService, OrderService>(
new OrderService(),
TestAspectExecutorFactory.Create(accessor));
await Assert.ThrowsAsync<UnauthorizedAccessException>(
() => service.ApproveOrderAsync(Guid.NewGuid()));
}
Result.Failure instead of throwing[RequiresScope("PURCHASE_ORDER.APPROVE", OnDenied = DenialBehavior.ReturnFailure)]
Task<Result> ApproveOrderAsync(Guid orderId);
builder.Services.Configure<AuthorizationOptions>(o =>
o.Mode = AuthorizationMode.AuditOnly);
Denials are logged but not blocked. Watch logs for AuthorizationDeniedEvent entries, fix gaps, then switch to Enforce.
public class OrderController(IAuthorizationValidator validator, IAuthGraphAccessor accessor)
{
public IActionResult Approve(Guid id)
{
var decision = validator.RequireScope(accessor.Current, "PURCHASE_ORDER.APPROVE");
if (decision.IsDenied) return Forbid();
// ...
}
}