Short: My client retrieves an access token from IdentityServer sample server, and then passes it to my WebApi. In my controller, this.HttpContext.User.GetUserId() returns null (User has other claims though). I suspect access token does not have nameidentity claim in it. How do I make IdentityServer include it?
What I've tried so far:
in IdSvrHost scope definition I've added
Claims = { new ScopeClaim(ClaimTypes.NameIdentifier, alwaysInclude: true) }
in IdSvrHost client definition I've added
Claims = { new Claim(ClaimTypes.NameIdentifier, "42") }
(also a random attempt)
I've also tried other scopes in scope definition, and neither of them appeared. It seems, that nameidentity is usually included in identity token, but for most public APIs I am aware of, you don't provide identity token to the server.
More details: IdSrvHost and Api are on different hosts. Controller has [Authorize]. In fact, I can see other claims coming. Api is configured with
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
app.UseIdentityServerAuthentication(options => {
options.Authority = "http://localhost:22530/";
// TODO: how to use multiple optional scopes?
options.ScopeName = "borrow.slave";
options.AdditionalScopes = new[] { "borrow.receiver", "borrow.manager" };
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
});
Scope:
public static Scope Slave { get; } = new Scope {
Name = "borrow.slave",
DisplayName = "List assigned tasks",
Type = ScopeType.Resource,
Claims = {
new ScopeClaim(ClaimTypes.NameIdentifier, alwaysInclude: true),
},
};
And client:
new Client {
ClientId = "borrow_node",
ClientName = "Borrow Node",
Flow = Flows.Implicit,
RedirectUris = new List<string>
{
"borrow_node:redirect-target",
},
Claims = { new Claim(ClaimTypes.NameIdentifier, "42") },
AllowedScopes = {
StandardScopes.OpenId.Name,
//StandardScopes.OfflineAccess.Name,
BorrowScopes.Slave.Name,
},
}
Auth URI:
request.CreateAuthorizeUrl(
clientId: "borrow_node",
responseType: "token",
scope: "borrow.slave",
redirectUri: "borrow_node:redirect-target",
state: state,
nonce: nonce);
and I also tried
request.CreateAuthorizeUrl(
clientId: "borrow_node",
responseType: "id_token token",
scope: "openid borrow.slave",
redirectUri: "borrow_node:redirect-target",
state: state,
nonce: nonce);
Hooray, I found an answer, when I stumbled upon this page: https://github.com/IdentityServer/IdentityServer3.Samples/issues/173
Apparently, user identity is passed in "sub" claim in the access token. Because I blindly copied API sample, its configuration included
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
which essentially prevented my API from mapping "sub" claim to nameidentifier. After removing this line, HttpContext.User.GetUserId() of authenticated controller returns user ID correctly.