1
votes

I am pretty new to this.. so any help would be greatly appreciated. I have a WebApi service that uses OAUTH token and refresh token authentication. All works well at the moment:

step1: I send in the user and password and it generates an authentication token and a refresh token. The refresh token is saved in the DB.

step2. I can now use the refresh token and i receive the authentication token and a new refresh token. I want a way to use the same refresh token i sent and not reuse a new one.

This is my code for the refresh token:

public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
{
    public async Task CreateAsync(AuthenticationTokenCreateContext context)
    {
        RefreshTokensRepository _repo = new RefreshTokensRepository();

        var clientid = context.Ticket.Properties.Dictionary["as:client_id"];

        //HERE I regenerate the token, but I have no idea how to retrieve the already sent one.
        var refreshTokenId = Guid.NewGuid().ToString("n");

        //saving in BD:
        var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime"); 

        var token = new RefreshTokens()
        {
            Id = Helper.GetHash(refreshTokenId),
            ClientId = clientid,
            Subject = context.Ticket.Identity.Name,
            IssuedUtc = DateTime.UtcNow,
            ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime))
        };

        context.Ticket.Properties.IssuedUtc = DateTime.UtcNow;
        context.Ticket.Properties.ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime));

        token.ProtectedTicket = context.SerializeTicket();
        var result = _repo.Add(token);
        if(!string.IsNullOrEmpty(result))
            context.SetToken(refreshTokenId);
    }

    public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
    {
        var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

        string hashedTokenId = Helper.GetHash(context.Token);

        RefreshTokensRepository _repo = new RefreshTokensRepository();
        var refreshToken = _repo.FindById(hashedTokenId);
        if (refreshToken != null)
        {
            //Get protectedTicket from refreshToken class
            context.DeserializeTicket(refreshToken.ProtectedTicket);
            _repo.Remove(hashedTokenId);
        }
    }

    void IAuthenticationTokenProvider.Create(AuthenticationTokenCreateContext context)
    {
        throw new NotImplementedException();
    }

    void IAuthenticationTokenProvider.Receive(AuthenticationTokenReceiveContext context)
    {
        throw new NotImplementedException();
    }
}   

My code is based on this samples: http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/

I would like to use the same sent refresh token, but I have no idea how to use the already sent one in this context. Any ideas?

1

1 Answers

0
votes

Disclaimer: I don't condone reusing refresh tokens. However, this does provide a good opportunity for everyone to improve knowledge of how this process works and there could be a good reason for reusing past refresh tokens in certain scenarios. I'm basing my answer upon:

  1. Question: "I want a way to use the same refresh token i sent and not reuse a new one."
  2. Code comment, "//HERE I regenerate the token, but I have no idea how to retrieve the already sent one."

PseudoCode Steps:

  • Store a user identifier as a property in AuthenticationProperties in the GrantResourceOwnerCredentials() method. From the sample code, it looks like you may already be doing this with "userName":

    var props = new AuthenticationProperties(new Dictionary<string, string> { { "as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId },{ "userName", context.UserName } });

  • Retrieve the user identifier in the CreateAsync() method of your IAuthenticationTokenProvider implementation (e.g. "SimpleRefreshTokenProvider" in your case). This would look something like:

public async Task CreateAsync(AuthenticationTokenCreateContext context) { var userName = context.Ticket.Properties.Dictionary["userName"]; ...

  • Still in the CreateAsync() method use the user identifier to lookup the existing refresh token. This would look something like:

var existingRefreshToken = await _repo.FindRefreshTokenByUserNameAsync(userName);

Note: You would need to write the above method into your AuthRepository class from the example code. The "FindRefreshTokenByUserNameAsync(userName) implementation might include something like this if you're using Entity Framework and have a "RefreshToken" table that is being used to persist the granted refresh token:

var existingToken = RefreshToken.Where(r => r.UserName == userName).SingleOrDefault();

  • At this point, you have the existing token and should be able to re-use that refresh token value instead of Guid.NewGuid():

var refreshTokenId = existingToken.Token;

Taking a look at the tutorial's example code, however, indicates that a HashAlgorithm is being used to store the refresh token's value. That could complicate things a bit for you as storing a hash value is better security, but the process of hashing here is meant to be one-way.

If you really want to reuse the original token value when all you have persisted is the hashed token, would need to implement code that captures the non-hashed token value in the ReceiveAsync() method. It would have to temporarily persist the non-hashed value long enough for you to use it in the CreateAsync() method. In other words, you would have to save/persist the "context.Token" in ReceiveAsync(), associate it with your userName (from context.Ticket.Properties.Dictionary["userName"]), and use it later in the CreateAsync() method. It's hacky and I don't like it, but you would do it around this line of code in ReceiveAsync():

string hashedTokenId = Helper.GetHash(context.Token);