I am using Identity Server 4 + ASP.NET Core Identity and have a setup where refresh tokens are used to request an access token for the application. These refresh tokens are configured as OneTimeOnly tokens. This means every time you use a refresh token to retrieve a new access token, the refresh token should be discarded and you receive a new refresh token.
The default implementation of Identity Server simply rejects subsequent token requests with an already used refresh token.
For security reasons however, having a refresh token being used multiple times could mean the token has been leaked. Therefor I'd like to revoke all tokens for that user, forcing him/her to log in again.
The documentation says I need a custom implementation of the DefaultRefreshTokenService
class' AcceptConsumedTokenAsync
virtual method. But what exactly should I implement?
To remove all refresh tokens for a given user, it is indeed needed to override the AcceptConsumedTokenAsync
virtual method. The DefaultRefreshTokenService
class has a property RefreshTokenStore
, which can be used to remove all tokens from the database:
public class RevokingDefaultRefreshTokenService : DefaultRefreshTokenService
{
public RevokingDefaultRefreshTokenService(
IRefreshTokenStore refreshTokenStore,
IProfileService profile,
ISystemClock clock,
ILogger<DefaultRefreshTokenService> logger)
:
base(refreshTokenStore, profile, clock, logger)
{
}
protected override async Task<bool> AcceptConsumedTokenAsync(RefreshToken refreshToken)
{
// Revoke all refresh tokens for this user
await RefreshTokenStore.RemoveRefreshTokensAsync(refreshToken.SubjectId, refreshToken.ClientId);
// Base impl
return await base.AcceptConsumedTokenAsync(refreshToken);
}
}
Do note, if the refresh token was leaked, the malicious user can still access your system for as long as the acces token he received from this refresh token is valid. Therefore, make sure your access token has a reasonable lifetime.