-1

I Could not retrieve the data from OwinContext Environment that I store it after authenticate by token.

this is the Code:
[ValidateClientAuthentication] In thins Code I validate the ClientID of the User and then store the data of ApplicationClient in OwinContext in this line

public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        ...
        ApplicationClient App = new ApplicationClient();
        App.Id = clientId;
        App.ClientSecretHash = clientSecret;
        // Storing Client Data
        context.OwinContext.Set<ApplicationClient>("oauth:client", App);
        context.Validated(clientId);
    }

[GrantResourceOwnerCredentials] Here I Validate User Credentials and Add Climes to the Token

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
    ...
    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    if (Membership.ValidateUser(username, password))
    {          
        identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
        identity.AddClaim(new Claim(ClaimTypes.Name, username));
        context.Validated(identity);
    }
    else
    {
        context.SetError("Login Field", "Error username or password");
    }
}

[ControlerCode] Now Here is My Problem

[Authorize]
public class MyController : ApiController
{
    public IEnumerable<SelectedMenu> GetAllMenus() // Resturants ID
    {
        // client is Null
        ApplicationClient client = HttpContext.Current.GetOwinContext().Get<ApplicationClient>("oauth:client");
    }
}
Abdu Imam
  • 393
  • 3
  • 16
  • 1
    `GrantResourceOwnerCredentials` is called only when the user requests a new token. Are you trying to share your `ApplicationClient` between different requests? This is not possible at all without some sort of persisted session. I strongly advice you to avoid this approach and store those information inside the token using Claims. – Federico Dipuma Jun 07 '17 at 13:46
  • Also, can you clarify *why* you need both clientId and clientSecret inside your controller? What's the purpose of the clientSecret once the client is validated inside the Owin OAuth pipeline? – Federico Dipuma Jun 07 '17 at 14:06
  • Hi @FedericoDipuma thanks for the replay .. you are right I need just to share the client_id with my APIs .. I will remove the secret code. but I need the client ID to retrieve some client information in server side before run the API. few seconds ago I just added the application client to the claim by using JavaScriptSerializer then Deserialize it at the API Controller and its work fine. but the token now it to long :). so is there a better way to do that. – Abdu Imam Jun 07 '17 at 15:02
  • How long is the clientId? I do not think you need to serialize it, it usually is only a small string. – Federico Dipuma Jun 07 '17 at 15:05
  • Not just the ID there is about 5 properties in that class ApplicationClient – Abdu Imam Jun 07 '17 at 18:37

1 Answers1

1

You should really only add the clientId inside your token, so you may retrieve it anytime after the login process.

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
    // ...
    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    if (Membership.ValidateUser(username, password))
    {          
        identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
        identity.AddClaim(new Claim(ClaimTypes.Name, username));
        identity.AddClaim(new Claim("oauth-client", context.ClientId));
        context.Validated(identity);
    }
    else
    {
        context.SetError("Login Field", "Error username or password");
    }
}

You may also create an extension method to help you in retrieving the clientId:

public static class PrincipalExtensions
{
    public static string GetClientId(this IPrincipal principal)
    {
        return (principal.Identity as ClaimsIdentity)?
            .Claims
            .FirstOrDefault(c => c.Type == "oauth-client")?
            .Value;
    }    
}

And inside your controller:

[Authorize]
public class MyController : ApiController
{
    public IEnumerable<SelectedMenu> GetAllMenus() // Resturants ID
    {
        var clientId = User.GetClientId();
    }
}

Regarding the token size: if your clientId string is too long I suggest you to use another one and store any other client information (including a longer id if is needed) inside the database. The client identifier should be a small and unique string easy to transmit.

Federico Dipuma
  • 17,655
  • 4
  • 39
  • 56