title: .Net Web API 2, OWIN, and OAuth: Scopes and roles. What are the differences?
body: <p>I would like to create a clearer picture in my mind as to what the differences are between roles and scopes in .NET Web API projects. This is more of a best-approach question than anything else, and I am finding myself to be a little confused as to how best authorize users that want to access my API. I come from a .NET MVC background, so I am familiar with roles and I am wondering if the same approaches apply to the web API framework. I am having difficulties putting scopes in the picture and how I should use them to allow access for a user using a particular client ID. Are scopes similar to access permissions? To illustrate my confusion, let's use this example:</p>
  
  <pre><code>Client A
  Native app: displays event calendar
  Role: Event
  User login required? No
  Allowed scopes: Read events
  
  Client B
  Web app: shows next upcoming event, displays registrant names
  Role: Event
  User login required? Yes
  Allowed scopes: Read events, read registrants
  
  Client C
  Native app: registers a person for an event
  Role: Registrant
  User login required? Yes
  Allowed scopes: Read events, read registrants, write registrants
  </code></pre>
  
  <p>Basically I would like to know if my above use of scopes is correct and what the best approach would be to grant resource owner credentials. I am using the token based authentication as outlined in <a href="http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/" rel="nofollow">Taiseers tutorial</a>. Below is my current incomplete code snippet that will take care of validating requested client and scope:</p>
  
  <pre><code>public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
  {
      ApiClient client = null;
      string clientId = string.Empty;
      string clientSecret = string.Empty;
  
      if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
          context.TryGetFormCredentials(out clientId, out clientSecret);
  
      if (context.ClientId == null)
      {
          context.Validated();
          context.SetError("invalid_clientId", "ClientId should be sent.");
          return Task.FromResult&lt;object&gt;(null);
      }
  
      using (ApiClientRepo _clientRepo = context.OwinContext.GetUserManager&lt;ApiClientRepo&gt;())
      {
          client = _clientRepo.FindClient(context.ClientId);
      }
  
      if (client == null)
      {
          context.SetError("invalid_clientId", string.Format("Client '{0}' is not registered in the system.", context.ClientId));
          return Task.FromResult&lt;object&gt;(null);
      }
  
      // Validate client secret
  
      if (string.IsNullOrWhiteSpace(clientSecret))
      {
          context.SetError("invalid_secret", "Client secret should be sent.");
          return Task.FromResult&lt;object&gt;(null);
      }
      else
      {
          WPasswordHasher passwordHasher = new WPasswordHasher();
          PasswordVerificationResult passwordResult = passwordHasher.VerifyHashedPassword(client.SecretHash, clientSecret);
  
          if (passwordResult == PasswordVerificationResult.Failed)
          {
              context.SetError("invalid_secret", "Client secret is invalid.");
              return Task.FromResult&lt;object&gt;(null);
          }
      }
  
      if (!client.Active)
      {
          context.SetError("invalid_clientId", "Client is inactive.");
          return Task.FromResult&lt;object&gt;(null);
      }
  
      context.OwinContext.Set&lt;int&gt;("as:clientRepoId", client.Id);
      context.OwinContext.Set&lt;string&gt;("as:clientAllowedOrigin", client.AllowedOrigin);
      context.OwinContext.Set&lt;string&gt;("as:clientRefreshTokenLifeTime", client.RefreshTokenLifeTime.ToString());
  
      context.Validated();
      return Task.FromResult&lt;object&gt;(null);
  }
  
  public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
  {
      IApiUser user = null;
      string scope = null;
  
      // Get parameters sent in body
      Dictionary&lt;string, string&gt; body = context.Request.GetBodyParameters();
  
      // Get API scope
      body.TryGetValue("scope", out scope);
  
      if (scope == null)
      {
          context.Validated();
          context.SetError("invalid_scope", "Invalid requested scope.");
          return;
      }
  
      var allowedOrigin = context.OwinContext.Get&lt;string&gt;("as:clientAllowedOrigin");
  
      context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });    
  
      // At this point I got the requested scope.
      // What should I do with it?
  
      if (user == null)
      {
          context.SetError("invalid_grant", "The user name or password is incorrect.");
          return;
      }      
  
      // create claims identity based on user info
      ClaimsIdentity identity = new ClaimsIdentity(context.Options.AuthenticationType);
      identity.AddClaim(new Claim(ClaimTypes.Name, user.FirstName + " " + user.LastName));
      identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Username));
      identity.AddClaim(new Claim(ClaimTypes.Role, scope));
  
      var props = new AuthenticationProperties(new Dictionary&lt;string, string&gt;
          {
              { 
                  "as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId
              },
              { 
                  "userName", context.UserName
              }
          });
  
      var ticket = new AuthenticationTicket(identity, props);
      context.Validated(ticket);
  }
  </code></pre>
  
  <p>Thanks ahead for all thoughts, suggestions and ideas!</p>