[Question] How is ProfileDataRequestContext.RequestedClaimTypes populated? #1067
Comments
Whenever you request a scope that has associated claims. |
Hi, I know my post is quite late, but I m running in the same issue and all the info on the internet are not helping me much. I am probably missing out something, here is my current code: public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "My API"),
new ApiResource
{
Name = "organisation",
UserClaims =
{
"workspace"
},
Scopes =
{
new Scope
{
Name = "orga"
}
}
}
};
} Then I have my client configuration as follow: // MVC client
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
ClientSecrets =
{
new Secret("secret".Sha256())
},
RedirectUris = { "http://localhost:5002/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"organisation",
"orga",
"api1"
},
AllowOfflineAccess = true,
AlwaysIncludeUserClaimsInIdToken = true,
UpdateAccessTokenClaimsOnRefresh = true
},
// SPA Client
new Client
{
ClientId = "js",
ClientName = "JavaScript Client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
AlwaysIncludeUserClaimsInIdToken = true,
UpdateAccessTokenClaimsOnRefresh = true,
RedirectUris = { "http://localhost:5003/callback.html" },
PostLogoutRedirectUris = { "http://localhost:5003/index.html" },
AllowedCorsOrigins = { "http://localhost:5003" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"organisation",
"orga",
"api1"
}
} and in my Startup.cs I have:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
services.AddTransient<IProfileService, ProfileService>();
services.AddMvc();
// configure identity server with in-memory stores, keys, clients and scopes
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
//.AddTestUsers(Config.GetUsers());
.AddProfileService<ProfileService>();
services.AddAuthentication()
.AddOpenIdConnect("oidc", "OpenID Connect", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.Authority = "https://demo.identityserver.io/";
options.ClientId = "implicit";
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
});
} Finally, I have IProfileService implemented as follow public class ProfileService : IProfileService
{
private IUserLogic _userLogic;
public ProfileService(IUserLogic userLogic)
{
_userLogic = userLogic;
}
//Get user profile date in terms of claims when calling /connect/userinfo
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
try
{
//depending on the scope accessing the user data.
if (!string.IsNullOrEmpty(context.Subject.Identity.Name))
{
//get user from db (in my case this is by email)
var user = await _userLogic.GetByEmail(context.Subject.Identity.Name);
if (user != null)
{
var claims = GetUserClaims(user);
//set issued claims to return
context.IssuedClaims = claims.Where(x => context.RequestedClaimTypes.Contains(x.Type)).ToList();
}
}
else
{
//where and subject was set to my user id.
var userEmail = context.Subject.Claims.FirstOrDefault(x => x.Type == "sub");
if (!string.IsNullOrEmpty(userEmail?.Value))
{
//get user from db (find user by user id)
var user = await _userLogic.GetByEmail(userEmail.Value);
// issue the claims for the user
if (user != null)
{
var claims = GetUserClaims(user);
context.IssuedClaims = claims.Where(x => context.RequestedClaimTypes.Contains(x.Type)).ToList();
}
}
}
}
catch (Exception ex)
{
//log your error
}
}
//check if user account is active.
public async Task IsActiveAsync(IsActiveContext context)
{
//[...]
}
public static Claim[] GetUserClaims(User user)
{
return new Claim[]
{
new Claim("user_id", user.Id.ToString()),//("user_id", user.UserId.ToString() ?? ""),
new Claim(JwtClaimTypes.Name, $"{user.FirstName} {user.LastName}"),//(!string.IsNullOrEmpty(user.Firstname) && !string.IsNullOrEmpty(user.Lastname)) ? (user.Firstname + " " + user.Lastname) : ""),
new Claim(JwtClaimTypes.Email, user.Email),
new Claim("workspace", "wx|wz")
};
}
} So now, according to my understanding of the doc, the line I think I'm missing a pretty important point, but I cannot gasp which one. |
I have the same issue with empty Is it expected that |
Any updates ? |
You could try:
Check the properies of the context . There can be different content for "caller"
|
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
I've red the documentation, checked the samples but I couldn't find any detailed info about
ProfileDataRequestContext.RequestedClaimTypes
inIProfileService
implementation. I've tried different client/scope/resource combinations butcontext.ProfileDataRequestContext
is always empty. When does this property contains data?The text was updated successfully, but these errors were encountered: