Authlink.Policy.ServiceStack 1.5.0

dotnet add package Authlink.Policy.ServiceStack --version 1.5.0
                    
NuGet\Install-Package Authlink.Policy.ServiceStack -Version 1.5.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Authlink.Policy.ServiceStack" Version="1.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Authlink.Policy.ServiceStack" Version="1.5.0" />
                    
Directory.Packages.props
<PackageReference Include="Authlink.Policy.ServiceStack" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Authlink.Policy.ServiceStack --version 1.5.0
                    
#r "nuget: Authlink.Policy.ServiceStack, 1.5.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Authlink.Policy.ServiceStack@1.5.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Authlink.Policy.ServiceStack&version=1.5.0
                    
Install as a Cake Addin
#tool nuget:?package=Authlink.Policy.ServiceStack&version=1.5.0
                    
Install as a Cake Tool

Authlink.Policy.ServiceStack

ServiceStack integration for Authlink policy-based authorization. Provides attributes, request filters, and plugins for seamless integration with ServiceStack services.

Installation

dotnet add package Authlink.Policy.ServiceStack

Quick Start

1. Register Services

// Configure.cs or AppHost
public override void Configure(Container container)
{
    // Register the policy client (from Authlink.Policy.Client.Http)
    container.AddPolicyHttpClient(options =>
    {
        options.BaseUrl = AppSettings.GetString("PolicyApi:BaseUrl");
    });

    // Optional: Register resource attribute resolvers
    container.AddResourceAttributeResolver(
        new TenantResourceResolver(container.Resolve<ITenantService>()));

    // Add the plugin
    Plugins.Add(new PolicyAuthorizationFeature(options =>
    {
        options.DefaultResourceKey = "tenant";
        options.ThrowOnPolicyError = false;
    }));
}

2. Use the PolicyAuthorize Attribute

// Simple permission check
[PolicyAuthorize("reports:view")]
public class GetReports : IReturn<List<Report>> { }

// With resource attributes
[PolicyAuthorize("user:update", ResourceKey = "user", ResourceIdProperty = "Id")]
public class UpdateUser : IReturn<UserResponse>
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

// Apply to specific HTTP methods only
[PolicyAuthorize("item:delete", ApplyTo = ApplyTo.Delete)]
public class ManageItem : IReturn<ItemResponse>
{
    public Guid Id { get; set; }
}

Features

PolicyAuthorize Attribute

The [PolicyAuthorize] attribute provides declarative policy-based authorization:

Property Description
Permission Required. The permission key (e.g., "user:update")
ResourceKey Optional. The resource type for attribute resolution
ResourceIdProperty Optional. Property name on the request DTO containing the resource ID
ApplyTo Optional. HTTP methods to apply (default: All)

PolicyAuthorizationFeature Plugin

The PolicyAuthorizationFeature is a ServiceStack plugin that registers the authorization filter:

// With default options
Plugins.Add(new PolicyAuthorizationFeature());

// With options configured inline
Plugins.Add(new PolicyAuthorizationFeature(options =>
{
    options.DefaultResourceKey = "tenant";
    options.UseSessionUserAuthId = true;
}));

// With pre-configured options
var options = new ServiceStackPolicyAuthorizationOptions
{
    DefaultResourceKey = "tenant",
    ThrowOnPolicyError = true
};
Plugins.Add(new PolicyAuthorizationFeature(options));

Resource Attribute Resolution

Implement IResourceAttributeResolver to provide resource attributes for policy evaluation:

public class TenantResourceResolver : IResourceAttributeResolver
{
    private readonly ITenantService _tenantService;

    public TenantResourceResolver(ITenantService tenantService)
    {
        _tenantService = tenantService;
    }

    public string ResourceKey => "tenant";

    public async Task<Dictionary<string, string>> ResolveAsync(
        object resourceId,
        CancellationToken cancellationToken = default)
    {
        var tenantId = (Guid)resourceId;
        var tenant = await _tenantService.GetByIdAsync(tenantId, cancellationToken);

        return new Dictionary<string, string>
        {
            ["tier"] = tenant.Tier.ToString(),
            ["region"] = tenant.Region ?? "",
            ["status"] = tenant.Status.ToString()
        };
    }
}

// Register the resolver
container.AddResourceAttributeResolver(
    new TenantResourceResolver(container.Resolve<ITenantService>()));

Configuration Options

Plugins.Add(new PolicyAuthorizationFeature(options =>
{
    // Default resource key when not specified on attribute
    options.DefaultResourceKey = "tenant";

    // Use session's UserAuthId as subject ID (default: true)
    options.UseSessionUserAuthId = true;

    // Custom claim types to search for subject ID (when not using session)
    options.SubjectClaimTypes = new[] { "sub", "user_id" };

    // Throw exceptions instead of returning 401/403
    options.ThrowOnMissingSubject = false;
    options.ThrowOnPolicyError = false;

    // Allow missing resource resolvers (logs warning, proceeds without attributes)
    options.AllowMissingResourceResolver = false;
}));

Subject ID Extraction

By default, the filter extracts the subject ID from the ServiceStack session's UserAuthId property. The UserAuthId must be a valid GUID string.

Session-Based (Default)
options.UseSessionUserAuthId = true;  // Default

The filter will use IAuthSession.UserAuthId from the authenticated session.

Claims-Based
options.UseSessionUserAuthId = false;
options.SubjectClaimTypes = new[] { "sub", "user_id", "nameidentifier" };

When disabled, the filter searches through OAuth access tokens' items for a matching claim.

HTTP Method Filtering

Apply authorization to specific HTTP methods using the ApplyTo property:

// Only authorize DELETE requests
[PolicyAuthorize("item:delete", ApplyTo = ApplyTo.Delete)]
public class ManageItem : IReturn<ItemResponse>
{
    public Guid Id { get; set; }
}

// Authorize GET and POST requests
[PolicyAuthorize("report:access", ApplyTo = ApplyTo.Get | ApplyTo.Post)]
public class AccessReport : IReturn<ReportResponse>
{
    public Guid ReportId { get; set; }
}

// Multiple attributes for different permissions
[PolicyAuthorize("item:read", ApplyTo = ApplyTo.Get)]
[PolicyAuthorize("item:write", ApplyTo = ApplyTo.Post | ApplyTo.Put)]
public class ItemRequest : IReturn<ItemResponse>
{
    public Guid Id { get; set; }
}

Error Handling

The filter responds with appropriate HTTP status codes:

Scenario Status Code Description
No subject ID 401 Unauthorized User not authenticated
No resolver found 403 Forbidden Resource resolver not registered
Resolver error 403 Forbidden Failed to resolve resource attributes
Policy denied 403 Forbidden Access denied by policy
Policy error 500 Internal Server Error Policy evaluation failed

Complete Example

// AppHost.cs
public class AppHost : AppHostBase
{
    public AppHost() : base("My Api", typeof(MyServices).Assembly) { }

    public override void Configure(Container container)
    {
        // Configure authentication
        Plugins.Add(new AuthFeature(() => new AuthUserSession(),
            new IAuthProvider[] { new JwtAuthProvider(AppSettings) }));

        // Register policy client
        container.AddPolicyHttpClient(options =>
        {
            options.BaseUrl = AppSettings.GetString("PolicyApi:BaseUrl");
        });

        // Register resource resolvers
        container.AddResourceAttributeResolver(
            new TenantResourceResolver(container.Resolve<ITenantService>()));
        container.AddResourceAttributeResolver(
            new ProjectResourceResolver(container.Resolve<IProjectService>()));

        // Add policy authorization plugin
        Plugins.Add(new PolicyAuthorizationFeature(options =>
        {
            options.DefaultResourceKey = "tenant";
            options.UseSessionUserAuthId = true;
        }));
    }
}

// Services
public class MyServices : Service
{
    // Simple permission check
    [PolicyAuthorize("tenant:list")]
    public async Task<List<TenantDto>> Get(GetTenants request)
    {
        return await TenantService.GetAllAsync();
    }

    // With resource attributes
    [PolicyAuthorize("tenant:read", ResourceKey = "tenant", ResourceIdProperty = "Id")]
    public async Task<TenantDto> Get(GetTenant request)
    {
        return await TenantService.GetByIdAsync(request.Id);
    }

    // Different permissions per HTTP method
    [PolicyAuthorize("project:read", ApplyTo = ApplyTo.Get)]
    [PolicyAuthorize("project:update", ApplyTo = ApplyTo.Put, ResourceKey = "project", ResourceIdProperty = "Id")]
    public async Task<ProjectDto> Any(ProjectRequest request)
    {
        // ...
    }
}

Requirements

  • .NET 9.0 or later
  • ServiceStack 8.x or later
  • Authlink.Policy.Client.Core (automatically included)
  • IPolicyClient implementation (e.g., Authlink.Policy.Client.Http)
  • Authlink.Policy.Client.Core - Core abstractions and DTOs
  • Authlink.Policy.Client.Http - HTTP client implementation
  • Authlink.Policy.AspNetCore - ASP.NET Core integration

License

MIT

Product Compatible and additional computed target framework versions.
.NET 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.5.0 115 9/17/2026