// Copyright (c) Microsoft. All rights reserved. using System; using System.Security.Claims; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.Agents.AI.Hosting; /// /// Extension methods for configuring AI hosting services in an . /// public static class ServiceCollectionExtensions { /// /// Registers a that uses claims from the current user's identity /// to generate session isolation keys. /// /// The to add services to. /// Optional configuration for the claims-based session isolation key provider. /// The so that additional calls can be chained. /// /// /// This method requires to be registered in the service collection. /// Ensure that services.AddHttpContextAccessor() has been called before using this method. /// /// /// When is not supplied, the isolation key is derived from the /// claim, a stable unique subject identifier. For OpenID /// Connect tokens (including Microsoft Entra ID), this is typically mapped from the sub claim /// by the default JWT inbound claim mapping. Authentication schemes that do not project a unique /// identifier onto (or hosts that require a different claim /// such as Entra's oid) should override /// ; otherwise the key may be /// absent, which causes strict-mode session stores to fail. /// /// /// Security warning: If you override /// , the chosen claim must /// uniquely identify the principal within the served population. Display names, usernames, email /// aliases, and other mutable or non-unique claims are unsafe isolation keys unless /// the host can prove their uniqueness across all callers, because distinct principals that share the /// same claim value would receive the same isolation key and could access one another's sessions. /// /// public static IServiceCollection UseClaimsBasedSessionIsolation( this IServiceCollection services, ClaimsIdentitySessionIsolationKeyProviderOptions? options = null) { options ??= new(); ServiceDescriptor descriptor = new(typeof(SessionIsolationKeyProvider), CreateIsolationKeyProvider, ServiceLifetime.Singleton); services.Add(descriptor); return services; object CreateIsolationKeyProvider(IServiceProvider serviceProvider) { IHttpContextAccessor contextAccessor = serviceProvider.GetRequiredService(); return new ClaimsIdentitySessionIsolationKeyProvider(contextAccessor, options); } } }