I'm using an abstract class from a third party library (FastEndpoints). I want to override some of the functions which I did but the main function to generate tokens should be the same.
Currently my service looks like this, I override the persistTokenAsync, RefreshRequestValidationAsync and SetRenewalPrivilegesAsync.
public class UserTokenService : RefreshTokenService<TokenRequest, AuthTokenResponse>
{
private readonly UserContext _dbContext;
public UserTokenService(IConfiguration config, UserContext context)
{
_dbContext = context;
Setup(x =>
{
x.TokenSigningKey = config["JWTSigningKey"];
x.AccessTokenValidity = TimeSpan.FromMinutes(1);
x.RefreshTokenValidity = TimeSpan.FromHours(1);
x.Endpoint("/user/auth/refresh-token", ep =>
{
ep.Summary(s => s.Description = "this is the refresh token endpoint");
});
});
}
public override Task PersistTokenAsync(AuthTokenResponse rsp)
{
return StoreToken(rsp.UserId, rsp.RefreshExpiry, rsp.RefreshToken);
}
public override async Task RefreshRequestValidationAsync(TokenRequest req)
{
if (!await TokenIsValid(req.UserId, req.RefreshToken))
AddError("The refresh token is not valid!");
}
public override async Task SetRenewalPrivilegesAsync(TokenRequest request, UserPrivileges privileges)
{
privileges.Claims.Add(new("UserID", request.UserId));
privileges.Permissions.AddRange(new UserPermissions().AllCodes());
}
private async Task<bool> TokenIsValid(string userId, string refreshToken)
{
var result = await _dbContext.Tokens
.Where(t => t.Token == refreshToken && t.Id == userId)
.FirstOrDefaultAsync();
return result is not null;
}
private async Task StoreToken(string userId, DateTime refreshExpiry, string refreshToken)
{
var token = _dbContext.Tokens.Where(t => t.Id == userId).FirstOrDefaultAsync();
_dbContext.Remove(token);
await _dbContext.Tokens.AddAsync(new RefreshToken{ExpiryDate = refreshExpiry, Token = refreshToken, Id = userId});
await _dbContext.SaveChangesAsync();
}
}
I want to use the CreateToken function from the RefreshTokenService provider by FastEndpoints. IN the last part where I want to create a token as response it's telling me
The type 'Authentication.Api.Services.Authentication.UserTokenService' must be convertible to 'FastEndpoints.IRefreshTokenService<Authentication.Api.Contracts.Responses.UserResponse>' in order to use it as parameter 'TService' in the generic method 'Task FastEndpoints.Endpoint<TRequest,TResponse>.CreateTokenWith(string, Action)'
public class LoginEndpoint : Endpoint<LoginRequest, UserResponse>
{
private readonly IAuthService _authService;
private readonly IUserService _userService;
public LoginEndpoint(IAuthService authService, IUserService userService)
{
_authService = authService;
_userService = userService;
}
public override async Task HandleAsync(LoginRequest req, CancellationToken ct)
{
var user = await _userService.GetByEmailAsync(req.Email);
var hasMatchingPassword = _authService.IsMatchingPassword(user.Salt,req.Password, user.Password);
if (!hasMatchingPassword)
{
await SendNotFoundAsync(ct);
}
var result = user.ToUserResponse();
Response = await CreateTokenWith<UserTokenService>("userID", p =>
{
p.Claims.Add(new("UserID", "userID"));
});
}
}
How do I make my implementation of the RefreshTokenService use the base function to create the token?
i believe your problem stems from the fact that the second generic argument (type of the response dto) doesn't match between your endpoint class and the token service class:
the response dto type must be the same to be able to call
CreateTokenWith<TService>()
method.if your initial login response is drastically different from the refresh token response shape, upgrade to the latest beta version
v5.13.0.8-beta
and create a custom token within your login endpoint like this: