// revoke refresh token only if it belongs to client doing the request
        private async Task <bool> RevokeRefreshTokenAsync(string handle, Client client)
        {
            var token = await _grants.GetRefreshTokenAsync(handle);

            if (token != null)
            {
                if (token.ClientId == client.ClientId)
                {
                    _logger.LogDebug("Refresh token revoked");
                    await _grants.RemoveRefreshTokensAsync(token.SubjectId, token.ClientId);

                    await _grants.RemoveReferenceTokensAsync(token.SubjectId, token.ClientId);
                }
                else
                {
                    var message = string.Format("Client {clientId} tried to revoke a refresh token belonging to a different client: {clientId}", client.ClientId, token.ClientId);

                    _logger.LogWarning(message);
                    await RaiseFailureEventAsync(message);
                }

                return(true);
            }

            return(false);
        }
        private async Task <TokenRequestValidationResult> ValidateRefreshTokenRequestAsync(NameValueCollection parameters)
        {
            _logger.LogDebug("Start validation of refresh token request");

            var refreshTokenHandle = parameters.Get(OidcConstants.TokenRequest.RefreshToken);

            if (refreshTokenHandle.IsMissing())
            {
                var error = "Refresh token is missing";
                LogError(error);
                await RaiseRefreshTokenRefreshFailureEventAsync(null, error);

                return(Invalid(OidcConstants.TokenErrors.InvalidRequest));
            }

            if (refreshTokenHandle.Length > _options.InputLengthRestrictions.RefreshToken)
            {
                var error = "Refresh token too long";
                LogError(error);
                await RaiseRefreshTokenRefreshFailureEventAsync(null, error);

                return(Invalid(OidcConstants.TokenErrors.InvalidGrant));
            }

            _validatedRequest.RefreshTokenHandle = refreshTokenHandle;

            /////////////////////////////////////////////
            // check if refresh token is valid
            /////////////////////////////////////////////
            var refreshToken = await _grants.GetRefreshTokenAsync(refreshTokenHandle);

            if (refreshToken == null)
            {
                LogError("Refresh token cannot be found in store: {refreshToken}", refreshTokenHandle);
                var error = "Refresh token cannot be found in store: " + refreshTokenHandle;
                await RaiseRefreshTokenRefreshFailureEventAsync(refreshTokenHandle, error);

                return(Invalid(OidcConstants.TokenErrors.InvalidGrant));
            }

            /////////////////////////////////////////////
            // check if refresh token has expired
            /////////////////////////////////////////////
            if (refreshToken.CreationTime.HasExceeded(refreshToken.Lifetime))
            {
                var error = "Refresh token has expired";
                LogError(error);
                await RaiseRefreshTokenRefreshFailureEventAsync(refreshTokenHandle, error);

                await _grants.RemoveRefreshTokenAsync(refreshTokenHandle);

                return(Invalid(OidcConstants.TokenErrors.InvalidGrant));
            }

            /////////////////////////////////////////////
            // check if client belongs to requested refresh token
            /////////////////////////////////////////////
            if (_validatedRequest.Client.ClientId != refreshToken.ClientId)
            {
                LogError("{clientId} tries to refresh token belonging to {clientId}", _validatedRequest.Client.ClientId, refreshToken.ClientId);
                await RaiseRefreshTokenRefreshFailureEventAsync(refreshTokenHandle, "Invalid client binding");

                return(Invalid(OidcConstants.TokenErrors.InvalidGrant));
            }

            /////////////////////////////////////////////
            // check if client still has offline_access scope
            /////////////////////////////////////////////
            if (!_validatedRequest.Client.AllowAccessToAllScopes)
            {
                if (!_validatedRequest.Client.AllowedScopes.Contains(Constants.StandardScopes.OfflineAccess))
                {
                    LogError("{clientId} does not have access to offline_access scope anymore", _validatedRequest.Client.ClientId);
                    var error = "Client does not have access to offline_access scope anymore";
                    await RaiseRefreshTokenRefreshFailureEventAsync(refreshTokenHandle, error);

                    return(Invalid(OidcConstants.TokenErrors.InvalidGrant));
                }
            }

            _validatedRequest.RefreshToken = refreshToken;

            /////////////////////////////////////////////
            // make sure user is enabled
            /////////////////////////////////////////////
            var subject     = _validatedRequest.RefreshToken.Subject;
            var isActiveCtx = new IsActiveContext(subject, _validatedRequest.Client, IdentityServerConstants.ProfileIsActiveCallers.RefreshTokenValidation);
            await _profile.IsActiveAsync(isActiveCtx);

            if (isActiveCtx.IsActive == false)
            {
                LogError("{subjectId} has been disabled", _validatedRequest.RefreshToken.SubjectId);
                var error = "User has been disabled: " + _validatedRequest.RefreshToken.SubjectId;
                await RaiseRefreshTokenRefreshFailureEventAsync(refreshTokenHandle, error);

                return(Invalid(OidcConstants.TokenErrors.InvalidGrant));
            }

            _validatedRequest.Subject = subject;

            _logger.LogDebug("Validation of refresh token request success");
            return(Valid());
        }