diff --git a/src/Identity/Core/src/Data/InfoResponse.cs b/src/Identity/Core/src/Data/InfoResponse.cs
index a58c195aba55..05e4483ce253 100644
--- a/src/Identity/Core/src/Data/InfoResponse.cs
+++ b/src/Identity/Core/src/Data/InfoResponse.cs
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Security.Claims;
-using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
namespace Microsoft.AspNetCore.Identity.Data;
@@ -21,9 +19,4 @@ public sealed class InfoResponse
/// Indicates whether or not the has been confirmed yet.
///
public required bool IsEmailConfirmed { get; init; }
-
- ///
- /// The from the authenticated .
- ///
- public required IDictionary Claims { get; init; }
}
diff --git a/src/Identity/Core/src/IdentityApiEndpointRouteBuilderExtensions.cs b/src/Identity/Core/src/IdentityApiEndpointRouteBuilderExtensions.cs
index 8a9ed5ae1431..115d151bdf56 100644
--- a/src/Identity/Core/src/IdentityApiEndpointRouteBuilderExtensions.cs
+++ b/src/Identity/Core/src/IdentityApiEndpointRouteBuilderExtensions.cs
@@ -340,7 +340,7 @@ await signInManager.ValidateSecurityStampAsync(refreshTicket.Principal) is not T
return TypedResults.NotFound();
}
- return TypedResults.Ok(await CreateInfoResponseAsync(user, claimsPrincipal, userManager));
+ return TypedResults.Ok(await CreateInfoResponseAsync(user, userManager));
});
accountGroup.MapPost("/info", async Task, ValidationProblem, NotFound>>
@@ -382,7 +382,7 @@ await signInManager.ValidateSecurityStampAsync(refreshTicket.Principal) is not T
}
}
- return TypedResults.Ok(await CreateInfoResponseAsync(user, claimsPrincipal, userManager));
+ return TypedResults.Ok(await CreateInfoResponseAsync(user, userManager));
});
async Task SendConfirmationEmailAsync(TUser user, UserManager userManager, HttpContext context, string email, bool isChange = false)
@@ -452,14 +452,13 @@ private static ValidationProblem CreateValidationProblem(IdentityResult result)
return TypedResults.ValidationProblem(errorDictionary);
}
- private static async Task CreateInfoResponseAsync(TUser user, ClaimsPrincipal claimsPrincipal, UserManager userManager)
+ private static async Task CreateInfoResponseAsync(TUser user, UserManager userManager)
where TUser : class
{
return new()
{
Email = await userManager.GetEmailAsync(user) ?? throw new NotSupportedException("Users must have an email."),
IsEmailConfirmed = await userManager.IsEmailConfirmedAsync(user),
- Claims = claimsPrincipal.Claims.ToDictionary(c => c.Type, c => c.Value),
};
}
diff --git a/src/Identity/Core/src/PublicAPI.Unshipped.txt b/src/Identity/Core/src/PublicAPI.Unshipped.txt
index 8b9f4af02588..83d4283afbdd 100644
--- a/src/Identity/Core/src/PublicAPI.Unshipped.txt
+++ b/src/Identity/Core/src/PublicAPI.Unshipped.txt
@@ -12,8 +12,6 @@ Microsoft.AspNetCore.Identity.Data.InfoRequest.NewPassword.init -> void
Microsoft.AspNetCore.Identity.Data.InfoRequest.OldPassword.get -> string?
Microsoft.AspNetCore.Identity.Data.InfoRequest.OldPassword.init -> void
Microsoft.AspNetCore.Identity.Data.InfoResponse
-Microsoft.AspNetCore.Identity.Data.InfoResponse.Claims.get -> System.Collections.Generic.IDictionary!
-Microsoft.AspNetCore.Identity.Data.InfoResponse.Claims.init -> void
Microsoft.AspNetCore.Identity.Data.InfoResponse.Email.get -> string!
Microsoft.AspNetCore.Identity.Data.InfoResponse.Email.init -> void
Microsoft.AspNetCore.Identity.Data.InfoResponse.InfoResponse() -> void
diff --git a/src/Identity/test/Identity.FunctionalTests/MapIdentityApiTests.cs b/src/Identity/test/Identity.FunctionalTests/MapIdentityApiTests.cs
index 57ac19d7fccf..a531c7162767 100644
--- a/src/Identity/test/Identity.FunctionalTests/MapIdentityApiTests.cs
+++ b/src/Identity/test/Identity.FunctionalTests/MapIdentityApiTests.cs
@@ -13,7 +13,6 @@
using Identity.DefaultUI.WebSite;
using Identity.DefaultUI.WebSite.Data;
using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity.UI.Services;
@@ -862,7 +861,7 @@ public async Task CanResetRecoveryCodes()
client.DefaultRequestHeaders.Authorization = new("Bearer", recoveryAccessToken);
var updated2faResponse = await client.PostAsJsonAsync("/identity/manage/2fa", new object());
- var updated2faContent = await updated2faResponse.Content.ReadFromJsonAsync();;
+ var updated2faContent = await updated2faResponse.Content.ReadFromJsonAsync();
Assert.Equal(8, updated2faContent.GetProperty("recoveryCodesLeft").GetInt32());
Assert.Null(updated2faContent.GetProperty("recoveryCodes").GetString());
@@ -1013,25 +1012,6 @@ public async Task CanResetPassword()
AssertOk(await client.PostAsJsonAsync("/identity/login", new { Email = confirmedEmail, Password = newPassword }));
}
- [Fact]
- public async Task CanGetClaims()
- {
- await using var app = await CreateAppAsync();
- using var client = app.GetTestClient();
-
- await RegisterAsync(client);
- await LoginAsync(client);
-
- var infoResponse = await client.GetFromJsonAsync("/identity/manage/info");
- Assert.Equal(Email, infoResponse.GetProperty("email").GetString());
-
- var claims = infoResponse.GetProperty("claims");
- Assert.Equal(Email, claims.GetProperty(ClaimTypes.Name).GetString());
- Assert.Equal(Email, claims.GetProperty(ClaimTypes.Email).GetString());
- Assert.Equal("pwd", claims.GetProperty("amr").GetString());
- Assert.NotNull(claims.GetProperty(ClaimTypes.NameIdentifier).GetString());
- }
-
[Theory]
[MemberData(nameof(AddIdentityModes))]
public async Task CanChangeEmail(string addIdentityModes)
@@ -1058,12 +1038,12 @@ public async Task CanChangeEmail(string addIdentityModes)
Assert.Equal(Email, infoResponse.GetProperty("email").GetString());
Assert.True(infoResponse.GetProperty("isEmailConfirmed").GetBoolean());
- var infoClaims = infoResponse.GetProperty("claims");
- Assert.Equal("pwd", infoClaims.GetProperty("amr").GetString());
- Assert.Equal(Email, infoClaims.GetProperty(ClaimTypes.Name).GetString());
- Assert.Equal(Email, infoClaims.GetProperty(ClaimTypes.Email).GetString());
+ var infoClaims = await client.GetFromJsonAsync("/auth/claims");
+ Assert.Equal("pwd", GetSingleClaim(infoClaims, "amr"));
+ Assert.Equal(Email, GetSingleClaim(infoClaims, ClaimTypes.Name));
+ Assert.Equal(Email, GetSingleClaim(infoClaims, ClaimTypes.Email));
- var originalNameIdentifier = infoResponse.GetProperty("claims").GetProperty(ClaimTypes.NameIdentifier).GetString();
+ var originalNameIdentifier = GetSingleClaim(infoClaims, ClaimTypes.NameIdentifier);
var newEmail = $"New-{Email}";
// The email must pass DataAnnotations validation by EmailAddressAttribute.
@@ -1077,10 +1057,10 @@ public async Task CanChangeEmail(string addIdentityModes)
Assert.True(infoPostContent.GetProperty("isEmailConfirmed").GetBoolean());
// And none of the claims have yet been updated.
- var infoPostClaims = infoPostContent.GetProperty("claims");
- Assert.Equal(Email, infoPostClaims.GetProperty(ClaimTypes.Name).GetString());
- Assert.Equal(Email, infoPostClaims.GetProperty(ClaimTypes.Email).GetString());
- Assert.Equal(originalNameIdentifier, infoClaims.GetProperty(ClaimTypes.NameIdentifier).GetString());
+ var infoPostClaims = await client.GetFromJsonAsync("/auth/claims");
+ Assert.Equal(Email, GetSingleClaim(infoPostClaims, ClaimTypes.Name));
+ Assert.Equal(Email, GetSingleClaim(infoPostClaims, ClaimTypes.Email));
+ Assert.Equal(originalNameIdentifier, GetSingleClaim(infoPostClaims, ClaimTypes.NameIdentifier));
// We cannot log in with the new email until we confirm the email change.
await AssertProblemAsync(await client.PostAsJsonAsync("/identity/login", new { Email = newEmail, Password }),
@@ -1103,10 +1083,10 @@ public async Task CanChangeEmail(string addIdentityModes)
Assert.Equal(newEmail, infoAfterEmailChange.GetProperty("email").GetString());
// The email still won't be available as a claim until we get a new token.
- var claimsAfterEmailChange = infoAfterEmailChange.GetProperty("claims");
- Assert.Equal(Email, claimsAfterEmailChange.GetProperty(ClaimTypes.Name).GetString());
- Assert.Equal(Email, claimsAfterEmailChange.GetProperty(ClaimTypes.Email).GetString());
- Assert.Equal(originalNameIdentifier, infoClaims.GetProperty(ClaimTypes.NameIdentifier).GetString());
+ var claimsAfterEmailChange = await client.GetFromJsonAsync("/auth/claims");
+ Assert.Equal(Email, GetSingleClaim(claimsAfterEmailChange, ClaimTypes.Name));
+ Assert.Equal(Email, GetSingleClaim(claimsAfterEmailChange, ClaimTypes.Email));
+ Assert.Equal(originalNameIdentifier, GetSingleClaim(claimsAfterEmailChange, ClaimTypes.NameIdentifier));
// And now the email has changed, the refresh token is invalidated by the security stamp.
AssertUnauthorizedAndEmpty(await client.PostAsJsonAsync("/identity/refresh", new { RefreshToken = originalRefreshToken }));
@@ -1118,10 +1098,10 @@ public async Task CanChangeEmail(string addIdentityModes)
Assert.Equal(newEmail, infoAfterFinalLogin.GetProperty("email").GetString());
Assert.True(infoAfterFinalLogin.GetProperty("isEmailConfirmed").GetBoolean());
- var claimsAfterFinalLogin = infoAfterFinalLogin.GetProperty("claims");
- Assert.Equal(newEmail, claimsAfterFinalLogin.GetProperty(ClaimTypes.Name).GetString());
- Assert.Equal(newEmail, claimsAfterFinalLogin.GetProperty(ClaimTypes.Email).GetString());
- Assert.Equal(originalNameIdentifier, infoClaims.GetProperty(ClaimTypes.NameIdentifier).GetString());
+ var claimsAfterFinalLogin = await client.GetFromJsonAsync("/auth/claims");
+ Assert.Equal(newEmail, GetSingleClaim(claimsAfterFinalLogin, ClaimTypes.Name));
+ Assert.Equal(newEmail, GetSingleClaim(claimsAfterFinalLogin, ClaimTypes.Email));
+ Assert.Equal(originalNameIdentifier, GetSingleClaim(claimsAfterFinalLogin, ClaimTypes.NameIdentifier));
}
[Fact]
@@ -1152,12 +1132,13 @@ public async Task CannotUpdateClaimsDuringInfoPostWithCookies()
var infoResponse = await client.GetFromJsonAsync("/identity/manage/info");
Assert.Equal(Email, infoResponse.GetProperty("email").GetString());
- var infoClaims = infoResponse.GetProperty("claims");
- Assert.Equal("pwd", infoClaims.GetProperty("amr").GetString());
- Assert.Equal(Email, infoClaims.GetProperty(ClaimTypes.Name).GetString());
- Assert.Equal(Email, infoClaims.GetProperty(ClaimTypes.Email).GetString());
- var originalNameIdentifier = infoResponse.GetProperty("claims").GetProperty(ClaimTypes.NameIdentifier).GetString();
+ var infoClaims = await client.GetFromJsonAsync("/auth/claims");
+ Assert.Equal("pwd", GetSingleClaim(infoClaims, "amr"));
+ Assert.Equal(Email, GetSingleClaim(infoClaims, ClaimTypes.Name));
+ Assert.Equal(Email, GetSingleClaim(infoClaims, ClaimTypes.Email));
+
+ var originalNameIdentifier = GetSingleClaim(infoClaims, ClaimTypes.NameIdentifier);
var newEmail = $"NewEmailPrefix-{Email}";
var infoPostResponse = await client.PostAsJsonAsync("/identity/manage/info", new { newEmail });
@@ -1169,9 +1150,9 @@ public async Task CannotUpdateClaimsDuringInfoPostWithCookies()
Assert.Equal(Email, infoPostContent.GetProperty("email").GetString());
// The claims have not been updated to match.
- var infoPostClaims = infoPostContent.GetProperty("claims");
- Assert.Equal(Email, infoPostClaims.GetProperty(ClaimTypes.Email).GetString());
- Assert.Equal(originalNameIdentifier, infoClaims.GetProperty(ClaimTypes.NameIdentifier).GetString());
+ var infoPostClaims = await client.GetFromJsonAsync("/auth/claims");
+ Assert.Equal(Email, GetSingleClaim(infoPostClaims, ClaimTypes.Email));
+ Assert.Equal(originalNameIdentifier, GetSingleClaim(infoPostClaims, ClaimTypes.NameIdentifier));
// Two emails have now been sent. The first was sent during registration. And the second for the email change.
Assert.Equal(2, emailSender.Emails.Count);
@@ -1191,9 +1172,9 @@ public async Task CannotUpdateClaimsDuringInfoPostWithCookies()
Assert.Equal(newEmail, infoAfterEmailChange.GetProperty("email").GetString());
// The email still won't be available as a claim until we get a new cookie.
- var claimsAfterEmailChange = infoAfterEmailChange.GetProperty("claims");
- Assert.Equal(Email, claimsAfterEmailChange.GetProperty(ClaimTypes.Email).GetString());
- Assert.Equal(originalNameIdentifier, infoClaims.GetProperty(ClaimTypes.NameIdentifier).GetString());
+ var claimsAfterEmailChange = await client.GetFromJsonAsync("/auth/claims");
+ Assert.Equal(Email, GetSingleClaim(claimsAfterEmailChange, ClaimTypes.Email));
+ Assert.Equal(originalNameIdentifier, GetSingleClaim(claimsAfterEmailChange, ClaimTypes.NameIdentifier));
// We will finally see all the claims updated after logging in again.
var secondLoginResponse = await client.PostAsJsonAsync("/identity/login?useCookies=true", new { Email = newEmail, Password });
@@ -1202,10 +1183,10 @@ public async Task CannotUpdateClaimsDuringInfoPostWithCookies()
var infoAfterFinalLogin = await client.GetFromJsonAsync("/identity/manage/info");
Assert.Equal(newEmail, infoAfterFinalLogin.GetProperty("email").GetString());
- var claimsAfterFinalLogin = infoAfterFinalLogin.GetProperty("claims");
- Assert.Equal(newEmail, claimsAfterFinalLogin.GetProperty(ClaimTypes.Name).GetString());
- Assert.Equal(newEmail, claimsAfterFinalLogin.GetProperty(ClaimTypes.Email).GetString());
- Assert.Equal(originalNameIdentifier, infoClaims.GetProperty(ClaimTypes.NameIdentifier).GetString());
+ var claimsAfterFinalLogin = await client.GetFromJsonAsync("/auth/claims");
+ Assert.Equal(newEmail, GetSingleClaim(claimsAfterFinalLogin, ClaimTypes.Name));
+ Assert.Equal(newEmail, GetSingleClaim(claimsAfterFinalLogin, ClaimTypes.Email));
+ Assert.Equal(originalNameIdentifier, GetSingleClaim(claimsAfterFinalLogin, ClaimTypes.NameIdentifier));
}
[Fact]
@@ -1321,6 +1302,8 @@ private async Task CreateAppAsync(Action $"Hello, {user.Identity?.Name}!");
+ authGroup.MapGet("/claims", (ClaimsPrincipal user) => user.Claims.Select(c => new { c.Type, c.Value }));
+
await dbConnection.OpenAsync();
await app.Services.GetRequiredService().Database.EnsureCreatedAsync();
@@ -1367,6 +1350,9 @@ private Task CreateAppAsync(Action? configur
public static object[][] AddIdentityModes => AddIdentityActions.Keys.Select(key => new object[] { key }).ToArray();
+ private static string? GetSingleClaim(JsonElement claims, string name)
+ => claims.EnumerateArray().Single(e => e.GetProperty("type").GetString() == name).GetProperty("value").GetString();
+
private static string GetEmailConfirmationLink(TestEmail email)
{
// Update if we add more links to the email.