marcominerva/SimpleAuthentication

Add Refresh Token Implementation

Opened this issue · 1 comments

There is no feature to have a refresh token during the login phase.
It would be nice to have a configurable parameter in the settings that enables the functionality.
If it is enabled, the methods for saving and verifying the valid refresh token could be added through extension methods.

This is the first time he has collaborated on a public project, so... be patient please! :-)

Proposal

I propose to:

  • add an option in the "JwtBearerSettings" named "EnableJwtBearerService" as a boolean parameter.
  • add "SimpleAuthenticationOptions" which contains 2 delegate methods "CreateAndGetRefreshTokenMethod" and "VerifyRefreshTokenMethod"
  • add to "AddSimpleAuthentication" extensions methods the "SimpleAuthenticationOptions" (maybe it can incorporate the configuration "sectionName" parameter?)
  • add 2 methods in "JwtBearerService" named "CreateTokenAndRefreshTokenAsync" and "RefreshTokenAsync"
  • update jwt sample project

I've made an implementation in this repository: https://github.com/Valecass/SimpleAuthentication/tree/RefreshTokenImplementation

How to use

1 - Add the options when AddSimpleAuthentication is called, with the "CreateAndGetRefreshTokenMethod" and "VerifyRefreshTokenMethod" implementation:

...
builder.Services.AddSimpleAuthentication(builder.Configuration, setupAction: options =>
{
    options.CreateAndGetRefreshTokenMethod = async (username) =>
    {
        await Task.Delay(100);
        //create refresh token
        //store refresh token

        //in this sample we return the username as the refresh token
        return username;
    };

    options.VerifyRefreshTokenMethod = async (refreshToken, userName) =>
    {
        //verify refresk token
        await Task.Delay(100);
        //in this sample refresh token has to be the username
        return refreshToken == userName;
    };
});
...

2 - Add "LoginWithRefreshTokenAsync" in IdentityController

[HttpPost("loginWithRefreshToken")]
[ProducesResponseType(typeof(LoginResponse), StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<ActionResult<LoginResponse>> LoginWithRefreshTokenAsync(LoginRequest loginRequest, DateTime? expiration = null)
{
    // Check for login rights...

    // Add custom claims (optional).
    var claims = new List<Claim>
{
    new(ClaimTypes.GivenName, "Marco"),
    new(ClaimTypes.Surname, "Minerva")
};

    var tokens = await jwtBearerService.CreateTokenAndRefreshTokenAsync(loginRequest.UserName, claims, absoluteExpiration: expiration);
    return new LoginResponse(tokens.token, tokens.refreshToken);
}

3 - Add "RefreshWithRefreshTokenAsync" method in IdentityController

[HttpPost("refreshWithRefreshToken")]
[ProducesResponseType(typeof(LoginResponse), StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<ActionResult<LoginResponse>> RefreshWithRefreshTokenAsync(string token, string refreshToken, DateTime? expiration = null)
{
    var newToken = await jwtBearerService.RefreshTokenAsync(token, refreshToken, expiration);
    return new LoginResponse(newToken.token, newToken.refreshToken);
}

5 - Enjoy!

What do you think?