title: Web API refresh token not refreshing when access token is expired
body: <p>in my web API I am implementing owin bearer token based authentication, in my client app I want to refresh the access token using the refresh token whenever it gets expired that's why I have set expiry of my access token to only 15 minutes and refresh token to 1 hour. I am unable to refresh access token when my original access token gets expired even though my refresh token is till valid but it works fine when access token is valid.
  below is my code.</p>
  
  <pre><code>public override void Create(AuthenticationTokenCreateContext context)
          {
              Guid Token = Guid.NewGuid();
              using (InfoSystemEntities dbContext = new InfoSystemEntities())
              {
                  RefreshToken RToken = new RefreshToken()
                  {
                      Token = Token,
                      IssueDateUtc = DateTime.UtcNow,
                      ExpiryDateUtc = DateTime.UtcNow.AddMinutes(Params.RefreshPasswordExpiryInMinutes),
                      IssuedTo = context.Ticket.Identity.GetUserId&lt;int&gt;()
                  };
  
                  context.Ticket.Properties.IssuedUtc = RToken.IssueDateUtc;
                  context.Ticket.Properties.IssuedUtc = RToken.ExpiryDateUtc;
  
                  RToken.ProtectedTicket = context.SerializeTicket();
                  dbContext.RefreshTokens.Add(RToken);
  
                  if (dbContext.SaveChanges() &gt; 0)
                  {
                      context.SetToken(Token.ToString());
                      //context.SetToken(context.SerializeTicket());
                  }
              }
          }
  
          public override void Receive(AuthenticationTokenReceiveContext context)
          {
              using (InfoSystemEntities dbContext = new InfoSystemEntities())
              {
                  Guid Token = Guid.Parse(context.Token);
                  RefreshToken RToken = dbContext.RefreshTokens.Where(T =&gt; T.Token == Token).FirstOrDefault();
  
                  if (RToken != null)
                  {
                      if (RToken.ExpiryDateUtc &gt; DateTime.UtcNow)
                      {
                          context.DeserializeTicket(RToken.ProtectedTicket);
                      }
                      else
                      {
                          context.Response.Write("refresh_token not found or expired");
                      }
  
                      //dbContext.RefreshTokens.Attach(RToken);
                      //dbContext.RefreshTokens.Remove(RToken);
                      //dbContext.SaveChanges();
                  }
                  else
                  {
                      context.Response.Write("refresh_token not found or expired");
                  }
              }
          }
  
  public class OAuthProvider : OAuthAuthorizationServerProvider
      {
          public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
          {
              //context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
              //MyUserManager CustomUserManager = HttpContext.Current.GetOwinContext().GetUserManager&lt;MyUserManager&gt;();
              MyUserManager CustomUserManager = new MyUserManager();
  
              var user = await CustomUserManager.FindAsync(context.UserName, context.Password);
  
              if (user == null)
              {
                  context.SetError("invalid_grant", "The user name or password is incorrect.");
                  context.Rejected();
                  return;
              }
  
              if (!user.IsActive)
              {
                  context.SetError("invalid_grant", "The user account is disabled");
                  context.Rejected();
                  return;
              }
  
              var identity = new ClaimsIdentity(context.Options.AuthenticationType);
              identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.UserId.ToString()));
              identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
              identity.AddClaim(new Claim("FullName", user.FirstName + " " + user.LastName));
              // Optional : You can add a role based claim by uncommenting the line below.
              identity.AddClaim(new Claim("Role", user.Role));
              identity.AddClaim(new Claim(ClaimTypes.Role, user.Role));
  
              var props = new AuthenticationProperties(new Dictionary&lt;string, string&gt; { { "firstname", user.FirstName }, { "lastname", user.LastName }, { "email", user.UserName }, { "role", user.Role }, { "refresh_token_expires_in", (Params.RefreshPasswordExpiryInMinutes * 60).ToString() } });
  
              var ticket = new AuthenticationTicket(identity, props);
  
              context.Validated(ticket);
          }
  
  
          public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
          {
              if (context.ClientId == null)
                  context.Validated();
  
              return Task.FromResult&lt;object&gt;(null);
          }
  
          public override Task TokenEndpoint(OAuthTokenEndpointContext context)
          {
              foreach (KeyValuePair&lt;string, string&gt; property in context.Properties.Dictionary)
              {
                  context.AdditionalResponseParameters.Add(property.Key, property.Value);
              }
  
              return Task.FromResult&lt;object&gt;(null);
          }
  
          public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
          {
              var newIdentity = new ClaimsIdentity(context.Ticket.Identity);
              newIdentity.AddClaim(new Claim("newClaim", "newValue"));
  
              var newTicket = new AuthenticationTicket(newIdentity, context.Ticket.Properties);
              context.Validated(newTicket);
  
              return Task.FromResult&lt;object&gt;(null);
          }
      }
  </code></pre>