Skip to content

ConnectSoft Identity Platform Development Alignment

This document is the implementation plan for bringing the ConnectSoft Identity Platform target architecture into the runtime templates and reusable libraries.

The canonical architecture pages remain normative. This page explains how to implement the architecture across repositories, in phased review gates, without introducing duplicate contracts or framework layers that the platform already owns.

Realization Readiness

This document is the implementation source of truth before code realization. It is intended to be used phase by phase by an implementer after the architecture documentation has been reviewed.

Realization rules:

  • implement one phase at a time;
  • stop after each phase for review;
  • do not commit or push implementation changes;
  • do not pack or promote NuGet packages locally;
  • do not update submodules automatically;
  • later phases consume packages/templates only after the user reviews and promotes the previous phase.

Current Decisions

  • Gateway is custom controller/use-case based, not YARP.
  • Gateway can use ConnectSoft.ApiCompositionOrchestration, but must not require it.
  • API composition/orchestration must support identity and tenant propagation when it is used by any host.
  • Identity already exposes service-to-service APIs through IInternalIdentityService.
  • Identity internal service has both REST and code-first gRPC implementations.
  • Identity and Authorization Server internal API backward compatibility is not required.
  • Identity/Auth Server service method names, DTOs, REST routes, and gRPC contracts may change when the target contract is cleaner.
  • Authorization Server is OpenIddict-based.
  • BaseTemplate already uses Microsoft.AspNetCore.HeaderPropagation.
  • SaaS libraries already provide tenant primitives and must be reused.
  • Each implementation phase stops for review.
  • The implementing agent must not commit, push, promote NuGets, or update submodules.

Architecture

flowchart LR
    B["Blazor Shell / MFEs"] --> G["Custom API Gateway Controllers"]
    B --> AS["Authorization Server / OpenIddict"]

    G -->|optional| AC["ConnectSoft.ApiCompositionOrchestration"]
    G -->|direct HttpClient or gRPC| MS["Backend Microservices"]
    AC -->|HttpClient / workflow calls| MS

    AS -->|gRPC primary: IInternalIdentityService| ID["Identity Service"]
    AS -->|OIDC/OAuth external auth| FP["Google / Facebook / Keycloak / Azure AD"]
    ID -->|optional adapter| LDAP["LDAP / AD"]

    G --> SAAS["ConnectSoft SaaS Tenant Libraries"]
    AC --> SAAS
    MS --> SAAS

    LIB["ConnectSoft.Extensions.IdentityPlatform"] --> AS
    LIB --> ID
    LIB --> G
    LIB --> AC
    LIB --> MS
    LIB --> B
Hold "Alt" / "Option" to enable pan & zoom

Responsibility Model

Component Responsibility
Blazor Shell / MFEs Login UX, auth state, tenant UX, Gateway API calls
Authorization Server OpenIddict token issuance, federation broker, MFA orchestration
Identity Service Users, credentials, roles, claims, MFA factors, federation links
API Gateway External API boundary, AuthN/AuthZ, controller-level composition entrypoint
ApiCompositionOrchestration Optional multi-service aggregation, workflow orchestration, retries, partial success
BaseTemplate Backend identity context, trusted header validation, propagation foundation
SaaS libraries Tenant context, tenant resolution, tenant transport constants
Backend services Resource authorization, tenant-scoped business logic

Shared Identity Platform Library

Create a new reusable library solution from ConnectSoft.LibraryTemplate:

dotnet new connectsoft-library `
  -n ConnectSoft.Extensions.IdentityPlatform `
  --UseDI true `
  --UseLogging true `
  --UseOptions true `
  --UseMetrics false `
  --UseActivitySource false

Projects:

  • ConnectSoft.Extensions.IdentityPlatform.Abstractions
  • ConnectSoft.Extensions.IdentityPlatform.Options
  • ConnectSoft.Extensions.IdentityPlatform.AspNetCore
  • optional later: ConnectSoft.Extensions.IdentityPlatform.Blazor

Public API:

  • IdentityPlatformOptions
  • ValidateIdentityPlatformOptions
  • IdentityPlatformClaimTypes
  • IdentityPlatformHeaderNames
  • IdentityPlatformPolicyNames
  • IdentityPlatformErrorCodes
  • IdentityPlatformContext
  • IIdentityPlatformContextAccessor
  • IIdentityPlatformPrincipalAccessor
  • IdentityPlatformPrincipalAccessor
  • IdentityPlatformTrustedHeaderFactory
  • TrustedGatewayHeaderSanitizer

Core options:

public sealed class IdentityPlatformOptions
{
    public const string SectionName = "IdentityPlatform";

    public bool Enabled { get; set; } = true;
    public bool TrustedGatewayHeadersEnabled { get; set; } = true;
    public bool RequireTenantForAuthenticatedRequests { get; set; } = true;

    public IList<string> AcceptedTenantClaimTypes { get; set; } =
        ["tid", "tenant", "http://schemas.microsoft.com/identity/claims/tenantid"];

    public IList<string> AcceptedUserIdClaimTypes { get; set; } =
        ["sub", ClaimTypes.NameIdentifier];

    public IList<string> AcceptedClientIdClaimTypes { get; set; } =
        ["client_id", "azp"];
}

Register options using the existing ConnectSoft options pattern:

services.AddOptionsWithValidation<IdentityPlatformOptions, ValidateIdentityPlatformOptions>(
    configuration,
    IdentityPlatformOptions.SectionName);

Reuse:

  • ConnectSoft.Extensions.Options.AddOptionsWithValidation
  • ASP.NET Core authentication and authorization abstractions
  • Microsoft.AspNetCore.HeaderPropagation
  • ConnectSoft.Extensions.Saas.Abstractions
  • ConnectSoft.Extensions.Saas.AspNetCore
  • ConnectSoft.Extensions.Logging

Do not duplicate tenant primitives. Use:

  • ITenantContext
  • SaasClaimTypes.TenantId = "tid"
  • SaasTransportConstants.HttpTenantHeaderName = "X-Tenant-Id"

Identity Platform Library Usage By Template

BaseTemplate

BaseTemplate consumes ConnectSoft.Extensions.IdentityPlatform.AspNetCore as the backend foundation.

It provides:

  • identity platform options registration
  • authenticated principal normalization
  • trusted gateway header validation
  • tenant-required enforcement
  • SaaS tenant context integration
  • trace/correlation and identity header propagation for outbound HttpClient

Backend templates inherit this behavior after BaseTemplate promotion and submodule/template propagation.

Backend Microservice Templates

Backend services use Identity Platform through BaseTemplate.

Each backend:

  • reads IdentityPlatformContext
  • uses ITenantContext
  • rejects missing tenant when configured
  • rejects spoofed trusted identity headers unless the call came from a trusted gateway path
  • performs resource-level authorization locally

API Gateway Template

Gateway consumes Identity Platform directly.

Gateway may consume ConnectSoft.ApiCompositionOrchestration when a controller/use case needs API aggregation or workflow orchestration, but Gateway does not require it for simple direct downstream calls.

Gateway must not be redesigned around composition. Composition is an optional implementation tool for complex actions.

ApiCompositionOrchestration Library

ConnectSoft.ApiCompositionOrchestration consumes Identity Platform for propagation only.

It must not authenticate callers. Host applications authenticate.

It must not authorize routes/actions. Gateway or backend controllers authorize.

It must only propagate already trusted context supplied by host middleware/accessors.

Authorization Server Template

Authorization Server consumes Identity Platform for:

  • canonical claim names
  • token claim normalization
  • tenant claim normalization
  • MFA amr and acr semantics
  • Identity internal API alignment

It remains OpenIddict-based.

Identity Template

Identity consumes Identity Platform for canonical claim names and normalized service model output.

Existing internal services remain canonical:

  • IInternalIdentityService
  • GrpcInternalIdentityService
  • InternalIdentityController

Do not add duplicate credentials/claims endpoints. Reshape the existing internal service into the target service-to-service contract, even if that means replacing current request/response DTOs or method names.

Blazor Templates

Blazor uses only frontend-safe constants/contracts/helpers.

Blazor must not create trusted gateway headers.

Blazor calls Gateway only.

ApiCompositionOrchestration Integration

ConnectSoft.ApiCompositionOrchestration is optional for Gateway but must be identity-aware for any host that uses it.

Current library capabilities:

  • IApiComposer
  • ApiComposer
  • CompositionRequest
  • CompositionResponse
  • ApiCallDefinition
  • CompositionStrategy
  • ResponseMergeStrategy
  • ErrorHandlingStrategy
  • IOrchestrator
  • workflow state stores
  • retries
  • circuit breakers
  • metrics
  • options
  • tests

Required identity-platform integration:

  • outbound composition calls propagate trace/correlation headers
  • outbound composition calls propagate trusted identity headers when a trusted context exists
  • outbound composition calls propagate tenant header from IdentityPlatformContext or ITenantContext
  • spoofable inbound identity headers are stripped before call execution
  • orchestration workflow steps can carry identity/tenant context safely
  • metrics/traces include safe identity tags only, never secrets or tokens

Important design constraints:

  • Do not make ConnectSoft.ApiCompositionOrchestration depend directly on Gateway.
  • Do not make Gateway depend on composition unless a Gateway use case needs aggregation/workflow behavior.
  • Add propagation primitives to the composition library so it works in Gateway, BFF, backend orchestrator, worker, or any host.

Preferred implementation shape:

  • Add an optional identity propagation extension package or namespace inside the composition library.
  • Register a delegating handler or call enricher rather than changing all composition models.
  • Keep existing IApiComposer API stable if possible.
  • Use IdentityPlatformTrustedHeaderFactory to create trusted headers.
  • Use TrustedGatewayHeaderSanitizer to strip spoofed headers.
  • Use ITenantContext when available.

Possible API:

public sealed class ApiCompositionIdentityPropagationOptions
{
    public bool Enabled { get; set; } = true;
    public bool PropagateIdentityHeaders { get; set; } = true;
    public bool PropagateTenantHeader { get; set; } = true;
    public bool StripSpoofableHeaders { get; set; } = true;
}

If options are unnecessary, prefer convention-based registration:

services.AddApiComposition(configuration);
services.AddApiCompositionIdentityPropagation();

API Gateway Plan

Gateway remains controller/use-case based.

Gateway may use ConnectSoft.ApiCompositionOrchestration, but does not have to.

Gateway can implement any of these patterns per controller/action:

  1. Direct typed HttpClient call
  2. Direct gRPC client call
  3. IApiComposer for read aggregation
  4. IOrchestrator for multi-step workflow
  5. Domain/application use case that internally chooses one of the above

Gateway must not add:

  • YARP
  • generic proxy routing
  • a second composition engine
  • mandatory composition dependency for all routes

Gateway should add:

  • IdentityPlatformOptions
  • trusted header sanitizer middleware/filter
  • identity context accessor
  • principal accessor
  • SaaS tenant context integration
  • outbound propagation for direct HttpClient and gRPC calls
  • optional registration for ApiCompositionOrchestration when enabled by template parameter/package reference

Gateway flow without composition:

Client
  -> Gateway Controller
  -> AuthN/AuthZ
  -> sanitize inbound trusted headers
  -> resolve IdentityPlatformContext + TenantContext
  -> typed HttpClient/gRPC client
  -> trusted headers propagated
  -> Backend

Gateway flow with composition:

Client
  -> Gateway Controller
  -> AuthN/AuthZ
  -> sanitize inbound trusted headers
  -> resolve IdentityPlatformContext + TenantContext
  -> IApiComposer / IOrchestrator
  -> composition/orchestration propagates trusted identity + tenant headers
  -> Backend services

Gateway strips inbound:

  • X-User-Id
  • X-Client-Id
  • X-Tenant-Id
  • X-Scopes
  • X-Roles
  • X-Auth-Time

Gateway emits outbound only after successful authentication and authorization:

  • X-User-Id
  • X-Client-Id
  • X-Tenant-Id
  • X-Scopes
  • X-Roles
  • X-Auth-Time
  • X-TraceId
  • X-Correlation-Id
  • traceparent

Identity Internal API Plan

Current-state internal service contract:

public interface IInternalIdentityService
{
    Task<ValidateCredentialsResponse> ValidateCredentialsAsync(
        ValidateCredentialsRequest request,
        CancellationToken token = default);

    Task<UserClaimsResponse> GetUserClaimsAsync(
        GetUserClaimsRequest request,
        CancellationToken token = default);
}

This contract is current state only. It is too narrow for token issuer integration because it separates credential validation from account state, MFA, federation, tenant membership, and security-stamp data.

Target contract may replace the current narrow contract. Backward compatibility is not required for Identity/Auth Server internal integration. The target model should optimize the Auth Server and Identity boundary, not preserve old method names or DTO shapes.

Use one cohesive internal contract for token-issuer flows:

public interface IInternalIdentityService
{
    Task<InternalSignInEvaluationResponse> EvaluateSignInAsync(
        InternalSignInEvaluationRequest request,
        CancellationToken token = default);

    Task<InternalUserClaimsResponse> GetUserClaimsAsync(
        InternalUserClaimsRequest request,
        CancellationToken token = default);

    Task<InternalMfaChallengeResponse> CreateMfaChallengeAsync(
        InternalMfaChallengeRequest request,
        CancellationToken token = default);

    Task<InternalMfaVerificationResponse> VerifyMfaChallengeAsync(
        InternalMfaVerificationRequest request,
        CancellationToken token = default);

    Task<InternalFederatedLoginResponse> ResolveFederatedLoginAsync(
        InternalFederatedLoginRequest request,
        CancellationToken token = default);

    Task<InternalFederationLinkResponse> LinkFederatedAccountAsync(
        InternalFederationLinkRequest request,
        CancellationToken token = default);
}

EvaluateSignInAsync is the required Auth Server sign-in integration method.

ValidateCredentialsAsync can be removed, renamed, or retained only as an implementation convenience behind EvaluateSignInAsync. Auth Server must not depend on a boolean-only credential API because token issuance needs:

  • valid/invalid credentials
  • local user id
  • account enabled/disabled status
  • lockout status
  • email/phone confirmation status when policy requires it
  • MFA requirement
  • MFA challenge continuation data
  • tenant membership context
  • security stamp/version for refresh-token revalidation

GetUserClaimsAsync remains the required normalized-claims integration point, but its request and response model may change. UserClaimsResponse can be replaced by InternalUserClaimsResponse if needed to normalize claim names, support multiple tenants, expose MFA evidence, or carry token-issuer-specific metadata.

Implement in:

  • GrpcInternalIdentityService
  • InternalIdentityController

Both REST and code-first gRPC implementations must expose the same target service model and behavior. REST may adapt transport-specific routes and status codes, but it must not define a different business contract from gRPC.

Update:

  • service model DTOs
  • domain model inputs/outputs
  • AutoMapper profile
  • validators
  • gRPC acceptance tests
  • REST acceptance tests

Authorization Server Flows

Authorization Code + PKCE

  1. Blazor redirects to Auth Server.
  2. OpenIddict handles authorization request.
  3. User signs in locally or via federation.
  4. For local sign-in, Auth Server calls Identity EvaluateSignInAsync.
  5. If MFA required, Auth Server calls CreateMfaChallengeAsync.
  6. After MFA success, Auth Server calls GetUserClaimsAsync.
  7. Auth Server creates OpenIddict principal.
  8. Token includes sub, tid, roles, scope, amr, acr, auth_time.

Password Flow For Trusted Clients

Only if explicitly enabled.

  1. Auth Server receives password grant.
  2. Calls Identity EvaluateSignInAsync.
  3. Invalid/locked/disabled users get OAuth error.
  4. MFA-required users get MFA continuation/challenge response.
  5. Successful users get claims through GetUserClaimsAsync.
  6. OpenIddict issues token.

MFA

  1. Identity determines MFA requirement.
  2. Auth Server creates Identity challenge.
  3. User submits TOTP/recovery code to Auth Server.
  4. Auth Server verifies challenge with Identity.
  5. Token includes amr=mfa.
  6. Step-up policies use acr/amr.

Federation

  1. Auth Server handles external provider protocol.
  2. Provider returns external subject/claims.
  3. Auth Server calls Identity ResolveFederatedLoginAsync.
  4. Identity links existing user or JIT provisions if enabled.
  5. Auth Server gets normalized claims.
  6. Auth Server issues local-user token.

Provider placement:

  • Google/Facebook: OAuth/OIDC through Authorization Server.
  • Keycloak/Azure AD/ADFS: OIDC first through Authorization Server.
  • LDAP/AD: Identity-side adapter, not direct Auth Server dependency.

Refresh Token

  1. OpenIddict validates refresh token.
  2. Auth Server optionally revalidates user state with Identity.
  3. Auth Server optionally refreshes claims.
  4. Tokens are renewed only when user/client remains allowed.

Client Credentials

No Identity user call by default.

Auth Server issues client token from OpenIddict application/client registry.

SaaS Integration

Gateway:

  • resolves tenant from validated token tid
  • optionally sets ITenantContext
  • rejects missing tenant when required
  • rejects token/path/body/header tenant mismatch
  • emits canonical X-Tenant-Id

ApiCompositionOrchestration:

  • propagates X-Tenant-Id from trusted context
  • does not accept browser-provided X-Tenant-Id
  • tags metrics/traces with tenant where safe

Backends:

  • validate tenant context
  • use tenant for persistence/routing
  • enforce resource tenant ownership

Blazor Plan

Shell

Shell owns:

  • OIDC login/logout
  • auth state
  • token/session refresh
  • tenant selector UX
  • MFE auth state distribution

Shell does not own:

  • token issuance
  • trusted headers
  • backend direct access

Blazor WASM MFEs

MFEs:

  • call Gateway only
  • use Authorization: Bearer
  • handle ProblemDetails:
  • 401 reauthenticate
  • 403 insufficient permissions
  • mfa_required step-up UX
  • missing_tenant tenant UX

Blazor Server / BFF

Server-side host:

  • uses cookie/OIDC session
  • calls Gateway server-side with downstream access token
  • never emits trusted identity headers from browser input

Identity MFEs

Identity Self-Service:

  • profile
  • password change
  • MFA setup
  • recovery codes
  • external account links

Identity Admin:

  • users
  • roles
  • claims
  • lock/unlock
  • federation links
  • tenant assignment if supported

Both call Gateway. Gateway may use direct clients or composition internally.

Realization Order

Realization follows strict promotion gates:

  1. Implement and review ConnectSoft.Extensions.IdentityPlatform.
  2. User commits and promotes IdentityPlatform packages.
  3. Implement and review ConnectSoft.ApiCompositionOrchestration propagation support.
  4. User commits and promotes ApiComposition packages.
  5. Implement and review BaseTemplate integration.
  6. User commits and promotes BaseTemplate and handles any submodule/template updates manually.
  7. Implement and review IdentityTemplate.
  8. User commits and promotes IdentityTemplate packages/templates.
  9. Implement and review AuthorizationServerTemplate.
  10. User commits and promotes AuthorizationServerTemplate packages/templates.
  11. Implement and review ApiGatewayTemplate.
  12. User commits and promotes ApiGatewayTemplate packages/templates.
  13. Implement and review Blazor template changes.
  14. User commits and promotes Blazor template changes.
  15. Implement and review end-to-end mock integration.

Phased Delivery

Phase 1: IdentityPlatform Library

Deliver:

  • new library from ConnectSoft.LibraryTemplate
  • options
  • constants
  • validators
  • principal accessor
  • context accessor
  • trusted header sanitizer/factory
  • ASP.NET Core registration extensions

Tests:

  • options validation
  • claim extraction
  • tenant claim precedence
  • trusted header creation
  • spoofed header stripping

Gate: stop for review. User commits/promotes NuGets.

Phase 2: ApiCompositionOrchestration Propagation

Deliver:

  • optional IdentityPlatform integration in composition/orchestration library
  • identity/tenant propagation extension or delegating handler
  • no hard dependency on Gateway
  • stable IApiComposer shape where possible
  • orchestration workflow context propagation

Tests:

  • composition strips spoofed trusted headers
  • composition emits generated identity headers
  • composition emits tenant header from trusted context
  • parallel calls all receive context
  • orchestration steps can propagate context
  • partial-success response does not leak auth internals

Gate: stop for review. User commits/promotes NuGets.

Phase 3: BaseTemplate

Deliver:

  • consume promoted IdentityPlatform packages
  • update header propagation
  • add identity context middleware/helpers
  • integrate SaaS tenant context
  • backend trusted-header validation

Tests:

  • build
  • options binding
  • header propagation
  • tenant required
  • SaaS tenant mismatch
  • spoofed trusted headers rejected

Gate: stop for review. User commits/promotes BaseTemplate and performs any submodule/template updates manually.

Phase 4: IdentityTemplate

Deliver:

  • consume promoted IdentityPlatform packages
  • normalize claims to tid
  • reshape IInternalIdentityService into the target Auth Server internal contract
  • implement gRPC + REST methods for MFA/federation
  • replace service model DTOs and method names where the target model is cleaner

Tests:

  • updated internal REST/gRPC tests pass
  • new gRPC MFA/federation tests
  • new REST parity tests
  • claims response emits canonical tenant

Gate: stop for review. User commits/promotes.

Phase 5: AuthorizationServerTemplate

Deliver:

  • consume promoted IdentityPlatform packages
  • update Identity client to call internal gRPC contract
  • update OpenIddict token creation
  • add MFA/federation flow orchestration
  • normalize token claims

Tests:

  • auth code + PKCE
  • password flow if enabled
  • MFA required/success
  • federation callback
  • refresh token user revalidation
  • client credentials no user call

Gate: stop for review. User commits/promotes.

Phase 6: ApiGatewayTemplate

Deliver:

  • consume promoted IdentityPlatform packages
  • optionally consume promoted ApiCompositionOrchestration if a sample/use case needs composition
  • controller pipeline sanitizer/context registration
  • outbound HttpClient/gRPC trusted header propagation
  • SaaS tenant integration
  • policy helpers for tenant/MFA/scope
  • optional composition example in controller/use-case flow

Do not deliver:

  • YARP
  • generic routing options
  • generic route resolver
  • mandatory composition dependency
  • new proxy framework

Tests:

  • controller protected by JWT
  • spoofed trusted headers stripped
  • downstream mock receives generated headers
  • direct client call receives generated headers
  • optional composition call receives generated headers
  • tenant required/mismatch
  • MFA policy
  • scope policy
  • ProblemDetails for 401/403/502/504

Gate: stop for review. User commits/promotes.

Phase 7: Blazor Templates

Deliver:

  • Shell auth integration documentation/config
  • Gateway API client conventions
  • identity platform constants where frontend-safe
  • ProblemDetails handling
  • tenant selection UX contract
  • Identity Self-Service/Admin MFE integration plan

Tests:

  • unauthenticated redirects/login prompt
  • authenticated Gateway call
  • forbidden state
  • MFA required state
  • tenant missing state
  • no trusted headers emitted by browser

Gate: stop for review. User commits/promotes.

Phase 8: End-To-End Mock Integration

Deliver mock scenario suite:

  • Blazor login
  • token issued by OpenIddict
  • Gateway validates token
  • Gateway calls backend directly
  • Gateway optionally invokes IApiComposer
  • composition calls backend with trusted headers
  • backend resolves identity/tenant
  • MFA login
  • federation login mock
  • service-to-service token
  • expired token
  • missing scope
  • missing tenant
  • spoofed header rejection

Acceptance Criteria

The platform is complete when:

  • one canonical claim/header contract is used everywhere
  • Identity internal gRPC is primary for Auth Server integration
  • Auth Server issues normalized OpenIddict tokens
  • Gateway uses controllers/use cases, not YARP/generic routing
  • Gateway can work with or without ApiCompositionOrchestration
  • ApiCompositionOrchestration propagates identity/tenant context when used
  • Gateway sanitizes inbound trusted headers
  • Gateway/direct clients/composition propagate trusted headers only after auth/authz
  • SaaS tenant context is aligned with token tenant
  • backends enforce tenant/resource authorization
  • Blazor calls Gateway only
  • all phases have tests and review gates

Plan Validation

Before implementation starts, validate this document by checking that:

  • no section requires backward compatibility for Identity/Auth Server internal APIs;
  • no section introduces YARP, generic proxy routing, or mandatory Gateway composition;
  • ConnectSoft.ApiCompositionOrchestration is optional for Gateway but identity/tenant propagation-aware when used;
  • Identity internal REST and gRPC APIs share the same target business contract;
  • each implementation phase has a review gate and does not require the implementer to commit, push, pack, promote NuGets, or update submodules.