22

I am developing a Web API 2 project. For authentication I am using bearer token. On successful authentication the API returns a JSON object.

{"access_token":"Vn2kwVz...",
   "token_type":"bearer",
   "expires_in":1209599,
   "userName":"username",
   ".issued":"Sat, 07 Jun 2014 10:43:05 GMT",
   ".expires":"Sat, 21 Jun 2014 10:43:05 GMT"}

Now I want to return the user roles as well in this JSON object. What changes do I need to make in order to get the user roles from JSON response?

shA.t
  • 16,580
  • 5
  • 54
  • 111
Sachin Trivedi
  • 2,033
  • 4
  • 28
  • 57

2 Answers2

53

After searching a lot i found that i can create some custom properties and can set them with the authentication ticket. In this way you can customize the response so that it can have the custom values which may be required at the caller end.

Here is the code to send the user roles along with the token. which was my requirement. one can modify the code to send the required data.

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        using (UserManager<ApplicationUser> userManager = _userManagerFactory())
        {
            ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);

            if (user == null)
            {
                context.SetError("invalid_grant", "The user name or password is incorrect.");
                return;
            }

            ClaimsIdentity oAuthIdentity = await userManager.CreateIdentityAsync(user,
                context.Options.AuthenticationType);

            ClaimsIdentity cookiesIdentity = await userManager.CreateIdentityAsync(user,
                CookieAuthenticationDefaults.AuthenticationType);
            List<Claim> roles = oAuthIdentity.Claims.Where(c => c.Type == ClaimTypes.Role).ToList();
            AuthenticationProperties properties = CreateProperties(user.UserName, Newtonsoft.Json.JsonConvert.SerializeObject(roles.Select(x=>x.Value)));

            AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
            context.Validated(ticket);
            context.Request.Context.Authentication.SignIn(cookiesIdentity);
        }
    }


 public static AuthenticationProperties CreateProperties(string userName, string Roles)
    {
        IDictionary<string, string> data = new Dictionary<string, string>
        {
            { "userName", userName },
            {"roles",Roles}
        };
        return new AuthenticationProperties(data);
    }

This will return me the out put as

`{"access_token":"Vn2kwVz...",
 "token_type":"bearer",
 "expires_in":1209599,
 "userName":"username",
 ".issued":"Sat, 07 Jun 2014 10:43:05 GMT",
 ".expires":"Sat, 21 Jun 2014 10:43:05 GMT"
 "roles"=["Role1","Role2"] }`

Hope this information will be helpful to some one. :)

Sachin Trivedi
  • 2,033
  • 4
  • 28
  • 57
  • Hmm this doesn't work for me yet. I try creating the `AuthenticationProperties` object with the extra parameters, but it still returns only the access_token, the token_type and the expires_in values. Did you have to configure anything else for this to work? – Mark Vincze Oct 01 '14 at 15:26
  • The .issued and .expires values are not set down either in my case. – Mark Vincze Oct 01 '14 at 15:31
  • 5
    @MarkVincze You have to override TokenEndpoint as well, as in this answer: http://stackoverflow.com/a/24389232/224087 – quentin-starin Oct 15 '14 at 17:30
  • @Sachin, value for roles is another string (not json array) i.e. "roles":"[\"Role1\",\"Role2\"]", is there any way i could return an extended response property as json object? – Haider Oct 27 '14 at 13:03
  • 1
    @Haider You can parse this roles string as per your need wherever you are consuming it. Or may be you can serialize the Roles object when you are adding it to directory. {"roles",Roles}. I am not sure of that but that will definitely help you to return json object. – Sachin Trivedi Oct 29 '14 at 03:29
  • I don't know why this is not the default. Thanks a bunch. – Matt Sep 02 '15 at 04:21
  • I have similar problem as Haider. I need json collection but i receive string.If i pass List i receive error that jsonSerializer cannot serialize complex objects such Lists. Is there any way to customize overall object that return to client after successful Authentication? – Nikita Nov 25 '15 at 17:08
  • 1
    @qes I then used `foreach (KeyValuePair pair in context.Properties.Dictionary) context.AdditionalResponseParameters.Add(new KeyValuePair(pair.Key, pair.Value));` in the overridden `TokenEndpoint` method to add the properties that were set in `GrantResourceOwnerCredentials` per Sachin's answer. – Eric Eskildsen Jan 17 '16 at 01:21
  • Thank you, you have no idea how much time I spent on this! – Pinch Jan 19 '16 at 04:00
  • If you need an array of items instead of string, just override the response stream https://stackoverflow.com/questions/40841971/asp-net-oauth-authorization-server-add-an-array-as-additional-response-paramete – Artur A Apr 08 '18 at 20:13
5

Above changes are good to return roles as expected with one additional method in AuthorizationProvider as below: (Add this method and rock with roles...)

public override Task TokenEndpoint(OAuthTokenEndpointContext context)
        {
            foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
            {
                context.AdditionalResponseParameters.Add(property.Key, property.Value);
            }

            return Task.FromResult<object>(null);
        }
Nirav Desai
  • 51
  • 1
  • 2