I have custom implementation of AuthenticationTokenProvider
abstraction. It has two methods to be overriden that I'm using: CreateAsync
, ReceiveAsync
.
In OAuthAuthorizationServerOptions
I have RefreshTokenProvider
set to my custom AuthenticationTokenProvider
implementation.
My access tokens expire in 20 minutes. My refresh tokens expire in 24 hours. When access token expires a request comes with grant_type=refresh_token
containing refresh token. I observe ReceiveAsync
is called. There is a logic of setting Ticket
property of AuthenticationTokenReceiveContext
. But afterwards CreateAsync
method is called, where there is a logic of setting token in AuthenticationTokenCreateContext
. The Ticket
property of AuthenticationTokenCreateContext
does not seem to be that one I have set previously in ReceiveAsync
method.
As a result I receive response with new access token and refresh token. I don't want refresh token to be reissued each time I want to exchange my access token, I already have one valid for 24 hours.
Eventually I have found how to answer my question. I can leverage OwinContext.Environment
to store a flag which tells that my refresh token is not expired yet so there is no need of creation a new one.
public class RefreshTokenProvider : AuthenticationTokenProvider
{
private const string IsRefreshTokenExpiredName = "IsRefreshTokenExpired";
#region ctor
public RefreshTokenProvider()
{
}
#endregion
public async override Task CreateAsync(AuthenticationTokenCreateContext context)
{
if (!context.OwinContext.Environment.ContainsKey(IsRefreshTokenExpiredName) || (bool)context.OwinContext.Environment[IsRefreshTokenExpiredName])
{
var hours = int.Parse(ConfigurationManager.AppSettings["RefreshTokenExpirationHours"]);
var now = DateTime.UtcNow;
context.Ticket.Properties.IssuedUtc = now;
context.Ticket.Properties.ExpiresUtc = now.AddHours(hours);
context.SetToken(context.SerializeTicket());
}
}
public async override Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { ConfigurationManager.AppSettings["CorsOrigins"] });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Method", new[] { "POST" });
context.DeserializeTicket(context.Token);
if (context.Ticket.Properties.ExpiresUtc > DateTime.UtcNow)
context.OwinContext.Environment[IsRefreshTokenExpiredName] = false;
}
}