Sylin.Koan.Web.Auth.Services
0.8.0
dotnet add package Sylin.Koan.Web.Auth.Services --version 0.8.0
NuGet\Install-Package Sylin.Koan.Web.Auth.Services -Version 0.8.0
<PackageReference Include="Sylin.Koan.Web.Auth.Services" Version="0.8.0" />
<PackageVersion Include="Sylin.Koan.Web.Auth.Services" Version="0.8.0" />
<PackageReference Include="Sylin.Koan.Web.Auth.Services" />
paket add Sylin.Koan.Web.Auth.Services --version 0.8.0
#r "nuget: Sylin.Koan.Web.Auth.Services, 0.8.0"
#:package Sylin.Koan.Web.Auth.Services@0.8.0
#addin nuget:?package=Sylin.Koan.Web.Auth.Services&version=0.8.0
#tool nuget:?package=Sylin.Koan.Web.Auth.Services&version=0.8.0
Koan.Web.Auth.Services
Zero-configuration service-to-service authentication for the Koan Framework using OAuth 2.0 Client Credentials flow.
Features
- Zero Configuration: Works out-of-the-box with package reference
- Attribute-Driven: Declarative service definitions and dependencies
- Auto-Discovery: Automatic service registration and endpoint resolution
- OAuth 2.0 Compliant: Industry-standard client credentials flow
- Container-Aware: Smart service discovery for Docker/local development
- JWT Tokens: Self-contained authentication with scope-based authorization
Quick Start
Add Package Reference
<ProjectReference Include="Koan.Web.Auth.Services" />Declare Your Service
[ApiController] [KoanService("my-service", ProvidedScopes = new[] { "data:read", "data:write" })] public class MyController : ControllerBase { private readonly IKoanServiceClient _client; public MyController(IKoanServiceClient client) => _client = client; }Call Other Services
[HttpPost("process")] [CallsService("ai-service", RequiredScopes = new[] { "ml:inference" })] public async Task<IActionResult> Process([FromBody] ProcessRequest request) { // Automatic authentication with JWT Bearer token var result = await _client.PostAsync<ProcessResult>("ai-service", "/api/process", request); return Ok(result); }
That's it! The framework handles:
- JWT token acquisition and caching
- Service endpoint discovery
- Authorization header injection
- Token refresh and error handling
Configuration (Optional)
{
"Koan": {
"Auth": {
"Services": {
"ClientId": "my-service",
"ClientSecret": "production-secret",
"ServiceEndpoints": {
"ai-service": "https://ai.example.com",
"analytics-service": "https://analytics.example.com"
}
},
"TestProvider": {
"EnableClientCredentials": true,
"AllowedScopes": ["ml:inference", "analytics:write", "data:read"],
"RegisteredClients": {
"my-service": {
"ClientId": "my-service",
"ClientSecret": "production-secret",
"AllowedScopes": ["ml:inference", "analytics:write"]
}
}
}
}
}
}
Architecture
Browser → Web App (Cookie Auth) → Service A (JWT) → Service B (JWT)
↓ ↓ ↓
Session Cookie Bearer Token Bearer Token
- User Authentication: Secure HTTP-only cookies for browsers
- Service Authentication: JWT Bearer tokens for API calls
- Progressive Disclosure: Zero config → minimal config → full control
Development vs Production
Development
- Auto-generated client secrets
- Relaxed TLS validation
- Container-aware service discovery
- Verbose logging
Production
- Explicit configuration required
- Strict TLS validation
- Manual service endpoints
- Minimal logging
API Reference
Core Interfaces
IServiceAuthenticator
Handles JWT token acquisition and management.
public interface IServiceAuthenticator
{
Task<string> GetServiceTokenAsync(string targetService, string[]? scopes = null, CancellationToken ct = default);
Task<ServiceTokenInfo> GetServiceTokenInfoAsync(string targetService, string[]? scopes = null, CancellationToken ct = default);
Task InvalidateTokenAsync(string targetService, CancellationToken ct = default);
}
IServiceDiscovery
Resolves service endpoints using container-aware discovery.
public interface IServiceDiscovery
{
Task<ServiceEndpoint> ResolveServiceAsync(string serviceId, CancellationToken ct = default);
Task<ServiceEndpoint[]> DiscoverServicesAsync(CancellationToken ct = default);
Task RegisterServiceAsync(ServiceRegistration registration, CancellationToken ct = default);
}
IKoanServiceClient
Authenticated HTTP client with automatic token injection.
public interface IKoanServiceClient
{
Task<T?> GetAsync<T>(string serviceId, string endpoint, CancellationToken ct = default) where T : class;
Task<T?> PostAsync<T>(string serviceId, string endpoint, object? data = null, CancellationToken ct = default) where T : class;
Task<HttpResponseMessage> SendAsync(string serviceId, HttpRequestMessage request, CancellationToken ct = default);
}
Attributes
[KoanService]
Declares a controller as a service with provided scopes.
[KoanService("service-id", ProvidedScopes = new[] { "scope1", "scope2" }, Description = "Service description")]
[CallsService]
Declares service dependencies with required scopes.
[CallsService("target-service", RequiredScopes = new[] { "scope1" }, Optional = false)]
Configuration
ServiceAuthOptions
Core configuration for service authentication.
| Property | Type | Default | Description |
|---|---|---|---|
TokenCacheDuration |
TimeSpan |
55 minutes | Token cache lifetime |
TokenRefreshBuffer |
TimeSpan |
5 minutes | Refresh buffer before expiration |
EnableTokenCaching |
bool |
true |
Enable token caching |
EnableAutoDiscovery |
bool |
true (dev) |
Auto-discover service endpoints |
ClientId |
string |
Auto-generated | OAuth client ID |
ClientSecret |
string |
Auto-generated (dev) | OAuth client secret |
TokenEndpoint |
string |
/.testoauth/token |
Token endpoint URL |
ValidateServerCertificate |
bool |
true (prod) |
TLS certificate validation |
ServiceEndpoints |
Dictionary<string,string> |
Empty | Manual endpoint overrides |
ClientCredentialsClient
TestProvider client registration.
| Property | Type | Description |
|---|---|---|
ClientId |
string |
Client identifier |
ClientSecret |
string |
Client secret |
AllowedScopes |
string[] |
Permitted scopes |
Description |
string |
Client description |
Data Types
ServiceTokenInfo
public record ServiceTokenInfo(string AccessToken, DateTimeOffset ExpiresAt, string[] GrantedScopes);
ServiceEndpoint
public record ServiceEndpoint(string ServiceId, Uri BaseUrl, string[] SupportedScopes);
ServiceRegistration
public record ServiceRegistration(string ServiceId, Uri BaseUrl, string[] ProvidedScopes);
Exception Types
ServiceDiscoveryException
Thrown when service endpoint cannot be resolved.
public class ServiceDiscoveryException : Exception
{
public string ServiceId { get; }
}
ServiceAuthenticationException
Thrown when token acquisition fails.
public class ServiceAuthenticationException : Exception
{
public string ServiceId { get; }
public string[] RequestedScopes { get; }
}
Documentation
- Technical Documentation - Architecture and implementation details
- Usage Samples - Comprehensive usage examples
- Decision Document - Design decisions and rationale
Examples
See samples/S5.Recs/Controllers/ServiceDemoController.cs for complete examples.
| Product | Versions 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. |
-
net10.0
- Microsoft.Extensions.Caching.Memory (>= 10.0.0)
- Microsoft.Extensions.Http (>= 10.0.0)
- Sylin.Koan.Core (>= 0.8.0)
- Sylin.Koan.Web.Auth (>= 0.8.0)
- Sylin.Koan.Web.Auth.Connector.Test (>= 0.8.0)
- System.IdentityModel.Tokens.Jwt (>= 8.14.0)
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 |
|---|---|---|
| 0.8.0 | 92 | 5/16/2026 |
See release notes: https://github.com/sylin-labs/Koan-framework/releases