Created
February 6, 2026 13:24
-
-
Save wcabus/8572d45f0235a9dda14f3811960fe01e to your computer and use it in GitHub Desktop.
C#14 extensions for the ClaimsPrincipal, ClaimsIdentity and AuthenticationProperties types, adding both static methods and useful properties.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Security.Claims; | |
| using Microsoft.AspNetCore.Authentication; | |
| namespace Duende.Extensions; | |
| internal static class SecurityExtensions | |
| { | |
| private static readonly ClaimsPrincipal Anonymous = new(new ClaimsIdentity()); | |
| extension(ClaimsPrincipal) | |
| { | |
| /// <summary> | |
| /// Gets an anonymous <see cref="ClaimsPrincipal"/> instance with an empty <see cref="ClaimsIdentity"/>. | |
| /// </summary> | |
| /// <remarks> | |
| /// This can be used as a placeholder for unauthenticated users or in scenarios where you want to represent an | |
| /// anonymous user without any claims or authentication information. | |
| /// </remarks> | |
| public static ClaimsPrincipal Anonymous => Anonymous; | |
| /// <summary> | |
| /// Creates a new authenticated <see cref="ClaimsPrincipal"/> with the specified authentication type and claims. | |
| /// </summary> | |
| /// <param name="authenticationType">The type of authentication used.</param> | |
| /// <param name="claims">The claims with which to populate the inner <see cref="ClaimsIdentity"/>.</param> | |
| public static ClaimsPrincipal CreateAuthenticatedPrincipal(string authenticationType, params Claim[] claims) | |
| { | |
| return new ClaimsPrincipal(new ClaimsIdentity(claims, authenticationType)); | |
| } | |
| /// <summary> | |
| /// Creates a new authenticated <see cref="ClaimsPrincipal"/> with the specified authentication type, claims, | |
| /// name claim type and role claim type. | |
| /// </summary> | |
| /// <param name="authenticationType">The type of authentication used.</param> | |
| /// <param name="nameClaimType">The claim type to use for the user's name (e.g., "name", "preferred_username", etc.).</param> | |
| /// <param name="roleClaimType">The claim type to use for the user's roles (e.g., "role", "roles", etc.).</param> | |
| /// <param name="claims">The claims with which to populate the inner <see cref="ClaimsIdentity"/>.</param> | |
| public static ClaimsPrincipal CreateAuthenticatedPrincipal(string authenticationType, string nameClaimType, string roleClaimType, params Claim[] claims) | |
| { | |
| return new ClaimsPrincipal(new ClaimsIdentity(claims, authenticationType, nameClaimType, roleClaimType)); | |
| } | |
| } | |
| internal const string SubjectClaimType = "sub"; | |
| internal const string NameClaimType = "name"; | |
| internal const string GivenNameClaimType = "given_name"; | |
| internal const string FamilyNameClaimType = "family_name"; | |
| internal const string UsernameClaimType = "preferred_username"; | |
| internal const string EmailClaimType = "email"; | |
| internal const string RoleClaimType = "role"; | |
| extension(ClaimsPrincipal user) | |
| { | |
| /// <summary> | |
| /// Returns <c>true</c> if the user is authenticated; otherwise, <c>false</c>. | |
| /// </summary> | |
| /// <remarks> | |
| /// This checks the <see cref="ClaimsPrincipal.Identity"/> property and its <see cref="ClaimsIdentity.IsAuthenticated"/> property. | |
| /// </remarks> | |
| public bool IsAuthenticated => user.Identity?.IsAuthenticated ?? false; | |
| /// <summary> | |
| /// Returns the value of the "sub" claim, which is commonly used to represent the user's unique identifier (subject ID) in authentication systems. | |
| /// </summary> | |
| public string SubjectId => user.FindFirst(SubjectClaimType)?.Value ?? ""; | |
| /// <summary> | |
| /// Returns the value of the "name" claim, which is commonly used to represent the user's full name or display name in authentication systems. | |
| /// </summary> | |
| public string Name => user.FindFirst(NameClaimType)?.Value ?? ""; | |
| /// <summary> | |
| /// Returns the value of the "given_name" claim, which is commonly used to represent the user's first name in authentication systems. | |
| /// </summary> | |
| public string GivenName => user.FindFirst(GivenNameClaimType)?.Value ?? ""; | |
| /// <summary> | |
| /// Returns the value of the "family_name" claim, which is commonly used to represent the user's last name or surname in authentication systems. | |
| /// </summary> | |
| public string FamilyName => user.FindFirst(FamilyNameClaimType)?.Value ?? ""; | |
| /// <summary> | |
| /// Returns the value of the "preferred_username" claim, which is commonly used to represent the user's username or login name in authentication systems. | |
| /// </summary> | |
| public string UserName => user.FindFirst(UsernameClaimType)?.Value ?? ""; | |
| /// <summary> | |
| /// Returns the value of the "email" claim, which is commonly used to represent the user's email address in authentication systems. | |
| /// </summary> | |
| public string Email => user.FindFirst(EmailClaimType)?.Value ?? ""; | |
| /// <summary> | |
| /// Returns an enumeration of role claim values for the user, based on claims of the "role" claim type. | |
| /// </summary> | |
| public IEnumerable<string> Roles => user.Claims.Where(c => c.Type == RoleClaimType && !string.IsNullOrEmpty(c.Value)).Select(c => c.Value); | |
| } | |
| extension(ClaimsIdentity identity) | |
| { | |
| /// <summary> | |
| /// Returns the value of the "sub" claim, which is commonly used to represent the user's unique identifier (subject ID) in authentication systems. | |
| /// </summary> | |
| public string SubjectId => identity.FindFirst(SubjectClaimType)?.Value ?? ""; | |
| /// <summary> | |
| /// Returns the value of the "name" claim, which is commonly used to represent the user's full name or display name in authentication systems. | |
| /// </summary> | |
| public string Name => identity.FindFirst(NameClaimType)?.Value ?? ""; | |
| /// <summary> | |
| /// Returns the value of the "given_name" claim, which is commonly used to represent the user's first name in authentication systems. | |
| /// </summary> | |
| public string GivenName => identity.FindFirst(GivenNameClaimType)?.Value ?? ""; | |
| /// <summary> | |
| /// Returns the value of the "family_name" claim, which is commonly used to represent the user's last name or surname in authentication systems. | |
| /// </summary> | |
| public string FamilyName => identity.FindFirst(FamilyNameClaimType)?.Value ?? ""; | |
| /// <summary> | |
| /// Returns the value of the "preferred_username" claim, which is commonly used to represent the user's username or login name in authentication systems. | |
| /// </summary> | |
| public string UserName => identity.FindFirst(UsernameClaimType)?.Value ?? ""; | |
| /// <summary> | |
| /// Returns the value of the "email" claim, which is commonly used to represent the user's email address in authentication systems. | |
| /// </summary> | |
| public string Email => identity.FindFirst(EmailClaimType)?.Value ?? ""; | |
| /// <summary> | |
| /// Returns an enumeration of role claim values for the user, based on claims of the "role" claim type. | |
| /// </summary> | |
| public IEnumerable<string> Roles => identity.Claims.Where(c => c.Type == RoleClaimType && !string.IsNullOrEmpty(c.Value)).Select(c => c.Value); | |
| } | |
| internal const string SessionIdKey = "session_id"; | |
| extension(AuthenticationProperties properties) | |
| { | |
| /// <summary> | |
| /// Gets or sets the user's session identifier, stored using the "session_id" key in <see cref="AuthenticationProperties.Items"/>. | |
| /// </summary> | |
| public string? SessionId | |
| { | |
| get => properties.Items.TryGetValue(SessionIdKey, out var value) == true ? value : null; | |
| // Example of a setter. Careful with this, as it will overwrite any existing value for the "session_id" key in the Items dictionary! | |
| set => properties.Items[SessionIdKey] = value; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment