Udap.Server
0.8.1
dotnet add package Udap.Server --version 0.8.1
NuGet\Install-Package Udap.Server -Version 0.8.1
<PackageReference Include="Udap.Server" Version="0.8.1" />
<PackageVersion Include="Udap.Server" Version="0.8.1" />
<PackageReference Include="Udap.Server" />
paket add Udap.Server --version 0.8.1
#r "nuget: Udap.Server, 0.8.1"
#:package Udap.Server@0.8.1
#addin nuget:?package=Udap.Server&version=0.8.1
#tool nuget:?package=Udap.Server&version=0.8.1
Udap.Server
📦 Nuget Package: Udap.Server
This package adds UDAP Dynamic Client Registration (DCR) and metadata capabilities to an authorization server built on Duende IdentityServer. It provides the .well-known/udap metadata endpoint and the /connect/register DCR endpoint as extensions to the IdentityServer pipeline.
Note: Duende IdentityServer requires a license for production use above $1M annual revenue.
Features
- UDAP metadata endpoint (
.well-known/udap) - Dynamic Client Registration (create, update, cancel)
- Multi-community trust anchor support
- Authorization Extension Object (AEO) enforcement via
IUdapAuthorizationExtensionValidator - Tiered OAuth support
Profile-Specific Validation
For SSRAA or TEFCA community-specific validation rules, add the corresponding packages:
Udap.Ssraa.Server— HL7 v3 PurposeOfUse enforcementUdap.Tefca.Server— TEFCA Exchange Purpose (XP) code validation, SAN matchingUdap.Tefca.Model— TEFCA extension models (tefca-ias, XP constants)
Full Example
Below is a full example. See also the Udap.Auth.Server example project.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddIdentityServer()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlite(connectionString,
dbOpts => dbOpts.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlite(connectionString,
dbOpts => dbOpts.MigrationsAssembly(migrationsAssembly));
})
.AddResourceStore<ResourceStore>()
.AddClientStore<ClientStore>()
.AddTestUsers(TestUsers.Users)
.AddUdapServer(
options =>
{
var udapServerOptions = builder.Configuration.GetOption<ServerSettings>("ServerSettings");
options.DefaultSystemScopes = udapServerOptions.DefaultSystemScopes;
options.DefaultUserScopes = udapServerOptions.DefaultUserScopes;
options.ForceStateParamOnAuthorizationCode = udapServerOptions
.ForceStateParamOnAuthorizationCode;
},
options =>
options.UdapDbContext = b =>
b.UseSqlite(connectionString,
dbOpts =>
dbOpts.MigrationsAssembly(typeof(Program).Assembly.FullName)),
baseUrl: "https://localhost:5002/connect/register"
);
var app = builder.Build();
app.UseStaticFiles();
app.UseRouting();
app.UseUdapServer();
app.UseIdentityServer();
app.UseAuthorization();
app.MapRazorPages().RequireAuthorization();
app.Run();
Community Validation Rules
UDAP supports multiple trust communities, each with its own validation rules for token requests and client registration. The validation pipeline is pluggable via ICommunityTokenValidator and ICommunityRegistrationValidator.
Built-in profiles
Two profile packages are available:
| Package | Communities | POU codes | Max POU | Registration checks |
|---|---|---|---|---|
Udap.Ssraa.Server |
SSRAA / standard UDAP | 62 HL7 v3 codes | unlimited | none |
Udap.Tefca.Server |
TEFCA | 12 XP codes | 1 | SAN URI XP code validation |
Registering community validators
Add the profile packages and map communities to their validation pipelines:
// SSRAA rules for standard UDAP communities
builder.Services.AddUdapSsraaValidation(options =>
{
options.Communities.Add("udap://fhirlabs.net");
});
// TEFCA rules (register model extensions first)
builder.Services.AddUdapTefcaExtensions();
builder.Services.AddUdapTefcaValidation(options =>
{
options.Communities.Add("tefca://test-community");
});
How it works at runtime
- A client requests a token with authorization extensions (e.g.,
hl7-b2bwithpurpose_of_use) DefaultUdapAuthorizationExtensionValidatorresolves the client's community from the registration store- Iterates through registered
ICommunityTokenValidatorimplementations until one matches viaAppliesToCommunity() - The matching validator returns
CommunityValidationRulesspecifying required extensions, allowed POU codes, and max POU count - The framework enforces those rules, then calls the validator's
ValidateAsync()for any domain-specific checks
Custom community validators
Implement ICommunityTokenValidator for custom rules:
public class MyValidator : ICommunityTokenValidator
{
public bool AppliesToCommunity(string communityName)
=> communityName == "udap://my-community";
public CommunityValidationRules? GetValidationRules(string? grantType)
=> new CommunityValidationRules
{
RequiredExtensions = grantType == "client_credentials"
? new HashSet<string> { "hl7-b2b" } : null,
AllowedPurposeOfUse = new HashSet<string> { /* your codes */ },
MaxPurposeOfUseCount = 1
};
public Task<AuthorizationExtensionValidationResult> ValidateAsync(
UdapAuthorizationExtensionValidationContext context)
=> Task.FromResult(AuthorizationExtensionValidationResult.Success());
}
// Register it
builder.Services.AddSingleton<ICommunityTokenValidator, MyValidator>();
See the Udap.Ssraa.Server and Udap.Tefca.Server READMEs for detailed documentation on each profile.
Client Storage During Registration
When a client registers via UDAP Dynamic Client Registration, the server creates a Duende IdentityServer Client entity with UDAP-specific secrets and properties. Understanding what is stored and when it is updated is important for admin tooling and certificate lifecycle management.
What is stored
| Storage Type | Duende Type | Key / Type Field | Value | Expiration |
|---|---|---|---|---|
| Client Secret | ClientSecret |
UDAP_SAN_URI_ISS_NAME |
The URI Subject Alternative Name (SAN) from the client's X.509 certificate — used as the issuer identity | Certificate NotAfter |
| Client Secret | ClientSecret |
UDAP_COMMUNITY |
The community ID (integer as string) the client registered under | Certificate NotAfter |
| Client Secret | ClientSecret |
X509CertificateBase64 (UDAP_X509_CERTIFICATE) |
Base64 DER-encoded public certificate from the client's x5c chain — stored for admin visibility (expiration monitoring, revocation checking) | Certificate NotAfter |
| Client Property | ClientProperty |
org |
Organization identifier from the registration endpoint query parameters | — |
| Client Property | ClientProperty |
data_holder |
Data holder identifier from the registration endpoint query parameters | — |
Standard Duende Client fields are also populated: ClientId (generated), ClientName, AllowedGrantTypes, AllowedScopes, RedirectUris, LogoUri, RequirePkce, RequireDPoP, Created.
Client identity matching
A client is uniquely identified by the combination of four values: SAN URI (UDAP_SAN_URI_ISS_NAME), community (UDAP_COMMUNITY), organization (org), and data holder (data_holder). When a registration request matches an existing client on all four, the server performs an upsert — updating scopes, grant types, redirect URIs, and the stored certificate rather than creating a new client.
Certificate rollover
UDAP allows certificate rotation without re-registration. When a client authenticates at the token endpoint with a new certificate (different from the one used at registration), the RolloverClientSecrets method is invoked by UdapJwtSecretValidator. This updates:
- The
Expirationon theUDAP_SAN_URI_ISS_NAMEandUDAP_COMMUNITYsecrets to match the new certificate'sNotAfter - The
ValueandExpirationon theX509CertificateBase64secret to reflect the new certificate
Rollover only occurs if the new certificate is currently valid (NotBefore < now < NotAfter). The existing PKI chain validation against community trust anchors is unchanged — rollover is purely a metadata update.
What is NOT stored
- The client's private key — only the public certificate is stored
- The full certificate chain — intermediates and anchors are managed separately in the UDAP trust store
- Certificate thumbprint — not stored as a separate field (can be derived from the stored certificate)
Database Configuration
EF Core migration projects are available for both database providers:
- UdapDb.SqlServer — SQL Server migrations
- UdapDb.Postgres — PostgreSQL migrations
These projects create all UDAP and Duende IdentityServer tables and seed data needed for running local tests. See SeedData.cs for details.
Examples
- FHIR® is the registered trademark of HL7 and is used with the permission of HL7. Use of the FHIR trademark does not constitute endorsement of the contents of this repository by HL7.
- UDAP® and the UDAP gear logo, ecosystem gears, and green lock designs are trademarks of UDAP.org.
| 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
- Duende.IdentityServer (>= 7.4.7)
- Duende.IdentityServer.AspNetIdentity (>= 7.4.7)
- Duende.IdentityServer.EntityFramework.Storage (>= 7.4.7)
- Microsoft.AspNetCore.Authentication.OpenIdConnect (>= 10.0.8)
- Microsoft.AspNetCore.DataProtection.EntityFrameworkCore (>= 10.0.8)
- Microsoft.Bcl.Memory (>= 10.0.8)
- Microsoft.EntityFrameworkCore (>= 10.0.8)
- System.IdentityModel.Tokens.Jwt (>= 8.18.0)
- Udap.Client (>= 0.8.1)
- Udap.Common (>= 0.8.1)
- Udap.Model (>= 0.8.1)
- Udap.Server.Storage (>= 0.8.1)
-
net8.0
- Duende.IdentityServer (>= 7.4.7)
- Duende.IdentityServer.AspNetIdentity (>= 7.4.7)
- Duende.IdentityServer.EntityFramework.Storage (>= 7.4.7)
- Microsoft.AspNetCore.Authentication.OpenIdConnect (>= 8.0.27)
- Microsoft.AspNetCore.DataProtection.EntityFrameworkCore (>= 8.0.27)
- Microsoft.Bcl.Memory (>= 10.0.8)
- Microsoft.EntityFrameworkCore (>= 9.0.16)
- System.IdentityModel.Tokens.Jwt (>= 8.18.0)
- Udap.Client (>= 0.8.1)
- Udap.Common (>= 0.8.1)
- Udap.Model (>= 0.8.1)
- Udap.Server.Storage (>= 0.8.1)
-
net9.0
- Duende.IdentityServer (>= 7.4.7)
- Duende.IdentityServer.AspNetIdentity (>= 7.4.7)
- Duende.IdentityServer.EntityFramework.Storage (>= 7.4.7)
- Microsoft.AspNetCore.Authentication.OpenIdConnect (>= 9.0.16)
- Microsoft.AspNetCore.DataProtection.EntityFrameworkCore (>= 9.0.16)
- Microsoft.Bcl.Memory (>= 10.0.8)
- Microsoft.EntityFrameworkCore (>= 9.0.16)
- System.IdentityModel.Tokens.Jwt (>= 8.18.0)
- Udap.Client (>= 0.8.1)
- Udap.Common (>= 0.8.1)
- Udap.Model (>= 0.8.1)
- Udap.Server.Storage (>= 0.8.1)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Udap.Server:
| Package | Downloads |
|---|---|
|
Udap.UI
Package is a part of the UDAP reference implementation for .NET. |
|
|
Udap.Tefca.Server
TEFCA community-specific validators for UDAP registration and token issuance. |
|
|
Udap.Ssraa.Server
SSRAA community-specific validators for UDAP token issuance with HL7 v3 PurposeOfUse enforcement. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.8.1 | 72 | 5/20/2026 |
| 0.8.0 | 125 | 5/15/2026 |
| 0.7.13 | 119 | 5/15/2026 |
| 0.7.12 | 361 | 4/1/2026 |
| 0.7.11 | 158 | 3/31/2026 |
| 0.7.10 | 146 | 3/31/2026 |
| 0.7.9 | 163 | 3/31/2026 |
| 0.7.8 | 161 | 3/30/2026 |
| 0.7.7 | 151 | 3/30/2026 |
| 0.7.6 | 153 | 3/30/2026 |
| 0.7.5 | 161 | 3/30/2026 |
| 0.7.4 | 143 | 3/29/2026 |
| 0.7.3 | 136 | 3/29/2026 |
| 0.7.2 | 148 | 3/28/2026 |
| 0.7.1 | 121 | 3/23/2026 |
| 0.7.0 | 117 | 3/22/2026 |
| 0.6.16 | 125 | 3/22/2026 |
| 0.6.14 | 140 | 3/16/2026 |
| 0.6.13 | 130 | 3/15/2026 |
| 0.6.12 | 126 | 3/14/2026 |