Skip to content

AddingCustomClaimsToAccessTokenInDuende: migrate v6 to Duende.IdentityServer 8.0.5, net10.0 - #2083

Merged
CodeMazeBlog merged 1 commit into
CodeMazeBlog:mainfrom
vladimir-pecanac-main:seo/103970-duende-claims
Aug 12, 2026
Merged

AddingCustomClaimsToAccessTokenInDuende: migrate v6 to Duende.IdentityServer 8.0.5, net10.0#2083
CodeMazeBlog merged 1 commit into
CodeMazeBlog:mainfrom
vladimir-pecanac-main:seo/103970-duende-claims

Conversation

@vladimir-pecanac-main

Copy link
Copy Markdown
Collaborator

Migrates the quickstart sample from Duende.IdentityServer 6 to 8.0.5 on net10.0. Every store/service interface method gained a CancellationToken parameter; ProfileDataRequestContext.Client renamed to .Application (IConnectedApplication); IdentityModel namespace moved to Duende.IdentityModel. CustomProfileService rewritten (old version does not compile on v8, CS1061 twice). Registers a custom IProfileService and sets MapInboundClaims = false so [Authorize(Roles=...)] works against the JWT's role claim (the default inbound claim mapping renames it otherwise). Quickstart UI scaffold regenerated from Duende.Templates 1.3.0 rather than hand-patched. New minimal Api project added for the article's JWT-bearer block. 7/7 tests pass on net10.0, end-to-end PKCE login verified.

…rver 8 on net10.0

Retargets every project to net10.0 and moves the sample from Duende.IdentityServer
6.3.7 to 8.0.5, which is a real v6 -> v8 migration rather than a package bump.

IdentityServer v8 changes applied (per Duende's 7.4 -> 8.0 upgrade guide):

* Every store/service interface method gained a CancellationToken parameter, so
  IProfileService.GetProfileDataAsync/IsActiveAsync take one now.
* ProfileDataRequestContext.Client was renamed to .Application and retyped to
  IConnectedApplication, so the client id is read as Application?.Identifier
  rather than Client.ClientId.
* The IdentityModel package/namespace became Duende.IdentityModel.
* v8 requires .NET 10; nullable reference types are enabled across the assemblies.

Those changes cascade through the whole stock quickstart UI, so Pages/ and
wwwroot/ are regenerated from Duende's own v8 in-memory template (Duende.Templates
1.3.0) with the namespace adjusted. That also moves Pages/Home/Error to
Pages/Error and swaps bootstrap4-glyphicons for bootstrap-icons.

Article content added alongside the migration:

* Config.ApiResources declares a "paymentsapi" resource whose UserClaims include
  the role claim, so Duende requests the role claim type for that audience.
* CustomProfileService issues the role claim through AddRequestedClaims, because
  a custom IProfileService replaces the built-in one and is then the only source
  of user claims.
* A new Api project consumes the token with AddJwtBearer. MapInboundClaims is set
  to false there: with the default inbound claim mapping the "role" claim arrives
  under the legacy schemas.microsoft.com URI and RequireRole silently fails.
* One test covers the new ApiResource declaration.

Verified on .NET SDK 10.0.302 / ASP.NET Core runtime 10.0.10: solution builds in
Release, 7/7 tests pass, and an end-to-end authorization-code + PKCE login as
alice returns an access token carrying tenant, payments.discount and role claims
with paymentsapi in the audience; the role-protected API endpoint answers 200
with the token and 401 without it.
@CodeMazeBlog
CodeMazeBlog merged commit 56ae90f into CodeMazeBlog:main Aug 12, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants