title: Web API Authorization with ClientId and ClientSecret
body: <p>Im using OWIN/Katana middleware in my web api authorization.</p>
  
  <p>The flow. </p>
  
  <p>I am issuing <code>acess_token</code> and <code>refresh_token</code> to the requesting client.</p>
  
  <p>The <code>access_token</code> has short-lived lifespan while the <code>refresh_token</code> has long expiry.</p>
  
  <p>As usual, if the access_token expires, it will request for another access_token using the refresh_token.</p>
  
  <p>Now, my question. Since my refresh_token has long lifespan, it looks like its defeats the purpose of the short-lived access_token.Let say if the refresh_token is compromised, the hacker can still get the access_token, right?</p>
  
  <p>I looked at OAuth implementation of google and microsoft and seems like they have this additional parameter that you need to supply in addition to the <code>refresh_token</code>. And this are the <strong><code>client_id</code></strong> and the <strong><code>client_secret</code></strong>. Seems like it is generated when they sign in on the API's developer page.</p>
  
  <p>Now, How can I implement it in my project? Im thinking of overriding the token creation and make the token hash base on the <code>ClientId</code> and the <code>ClientSecret</code>.</p>
  
  <p>I'm using the basic OWIN/Katana authentication of the latest web api and I don't plan to use other Authorization Server like Thinktecture. I just want to use the basic one that is provided by default by ASP.NET Web API 2</p>
  
  <p><strong>Startup.OAuth.cs</strong></p>
  
  <pre><code>public partial class Startup
  {
     static Startup()
     {
        PublicClientId = "self";
        UserManagerFactory = () =&gt; new UserManager&lt;IdentityUser&gt;(new AppUserStore());
        var tokenExpiry = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["ApiTokenExpiry"]);
  
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(tokenExpiry),
            AllowInsecureHttp = true,
            RefreshTokenProvider = new AuthenticationTokenProvider
            {
                 OnCreate = CreateRefreshToken,
                 OnReceive = ReceiveRefreshToken,
            }
        };
     }
  
     private static void CreateRefreshToken(AuthenticationTokenCreateContext context)
     {
         var tokenExpiry = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["ApiTokenExpiry"]);
         var refreshTokenExpiry = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["ApiRefreshTokenExpiry"]);
  
         var refreshTokenProperties = new AuthenticationProperties(context.Ticket.Properties.Dictionary)
         {
             IssuedUtc = context.Ticket.Properties.IssuedUtc,
             ExpiresUtc = DateTime.UtcNow.AddMinutes(tokenExpiry + refreshTokenExpiry) // add 3 minutes to the access token expiry
         };
  
         var refreshTokenTicket = new AuthenticationTicket(context.Ticket.Identity, refreshTokenProperties);
  
         OAuthOptions.RefreshTokenFormat.Protect(refreshTokenTicket);
         context.SetToken(context.SerializeTicket());
     }
  
     private static void ReceiveRefreshToken(AuthenticationTokenReceiveContext context)
     {
         context.DeserializeTicket(context.Token);
     }
  }
  </code></pre>
  
  <p><strong>ApplicationOAuthProvider.cs</strong></p>
  
  <pre><code>public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
  {
      private readonly string _publicClientId;
      private readonly Func&lt;UserManager&lt;IdentityUser&gt;&gt; _userManagerFactory;
  
      public ApplicationOAuthProvider(string publicClientId, Func&lt;UserManager&lt;IdentityUser&gt;&gt; userManagerFactory)
      {
          if (publicClientId == null)
          {
              throw new ArgumentNullException("publicClientId");
          }
  
          if (userManagerFactory == null)
          {
              throw new ArgumentNullException("userManagerFactory");
          }
  
          _publicClientId = publicClientId;
          _userManagerFactory = userManagerFactory;
      }
  
      public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
      {
           using (UserManager&lt;IdentityUser&gt; userManager = _userManagerFactory())
           {
               IdentityUser 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);
               AuthenticationProperties properties = CreateProperties(user.UserName);
               AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
  
               context.Validated(ticket);
               context.Request.Context.Authentication.SignIn(cookiesIdentity);
           }
      }
  }
  </code></pre>