How to make IdentityServer to add user identity to the access token?
Asked Answered
F

1

14

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:

  • switched from hybrid to implicit flow (random attempt)
  • 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);
Fun answered 9/4, 2016 at 21:12 Comment(5)
If you're unsure what's in the access_token, copy and paste it into jwt.io and see that claims.Evocator
Here's what I get in access_token: { "iss": "localhost:22530", "aud": "localhost:22530/resources", "exp": 1460323801, "nbf": 1460320201, "client_id": "borrow_node", "scope": "borrow.slave", "sub": "88421113", "auth_time": 1460320200, "idp": "idsvr" } - no nameidentity claimFun
BTW, I don't want nameidentity to be "42", that was just an attempt to see if that changes anything.Fun
Checked IdentityServer source code (did not debug): it seems, that this line would filter nameidentity out: var claims = FilterProtocolClaims(context.IssuedClaims);Fun
Line is in DefaultClaimsProvider.cs . It looks like it is by design, that access_token does not include user identity in IdentityServer. If so, do I have to pass both id_token and access_token to the API endpoint? How could that be done with Bearer?Fun
F
13

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.

Fun answered 11/4, 2016 at 5:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.