diff --git a/cmd/neofs-node/object.go b/cmd/neofs-node/object.go
index bc1303052..548873dce 100644
--- a/cmd/neofs-node/object.go
+++ b/cmd/neofs-node/object.go
@@ -177,7 +177,7 @@ func (x *coreClientConstructor) Get(info coreclient.NodeInfo) (coreclient.Client
 
 func initObjectService(c *cfg) {
 	ls := c.cfgObject.cfgLocalStorage.localStorage
-	keyStorage := util.NewKeyStorage(&c.key.PrivateKey, c.privateTokenStore)
+	keyStorage := util.NewKeyStorage(&c.key.PrivateKey, c.privateTokenStore, c.cfgNetmap.state)
 	nodeOwner := owner.NewID()
 
 	neo3Wallet, err := owner.NEO3WalletFromPublicKey((*ecdsa.PublicKey)(c.key.PublicKey()))
diff --git a/pkg/services/object/util/key.go b/pkg/services/object/util/key.go
index ae389d08f..74c8c05df 100644
--- a/pkg/services/object/util/key.go
+++ b/pkg/services/object/util/key.go
@@ -5,24 +5,31 @@ import (
 	"errors"
 
 	"github.com/nspcc-dev/neofs-api-go/pkg/session"
+	"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
 	"github.com/nspcc-dev/neofs-node/pkg/services/session/storage"
 )
 
-// todo(alexvanin): should be a part of status API
-var errNoSessionToken = errors.New("session token does not exist")
+var (
+	// todo(alexvanin): should be a part of status API
+	errNoSessionToken      = errors.New("session token does not exist")
+	errSessionTokenExpired = errors.New("session token has been expired")
+)
 
 // KeyStorage represents private key storage of the local node.
 type KeyStorage struct {
 	key *ecdsa.PrivateKey
 
 	tokenStore *storage.TokenStore
+
+	networkState netmap.State
 }
 
 // NewKeyStorage creates, initializes and returns new KeyStorage instance.
-func NewKeyStorage(localKey *ecdsa.PrivateKey, tokenStore *storage.TokenStore) *KeyStorage {
+func NewKeyStorage(localKey *ecdsa.PrivateKey, tokenStore *storage.TokenStore, net netmap.State) *KeyStorage {
 	return &KeyStorage{
-		key:        localKey,
-		tokenStore: tokenStore,
+		key:          localKey,
+		tokenStore:   tokenStore,
+		networkState: net,
 	}
 }
 
@@ -34,6 +41,9 @@ func (s *KeyStorage) GetKey(token *session.Token) (*ecdsa.PrivateKey, error) {
 	if token != nil {
 		pToken := s.tokenStore.Get(token.OwnerID(), token.ID())
 		if pToken != nil {
+			if pToken.ExpiredAt() <= s.networkState.CurrentEpoch() {
+				return nil, errSessionTokenExpired
+			}
 			return pToken.SessionKey(), nil
 		}
 		return nil, errNoSessionToken
diff --git a/pkg/services/object/util/key_test.go b/pkg/services/object/util/key_test.go
index 31585508a..19af7a19a 100644
--- a/pkg/services/object/util/key_test.go
+++ b/pkg/services/object/util/key_test.go
@@ -19,7 +19,7 @@ func TestNewKeyStorage(t *testing.T) {
 	require.NoError(t, err)
 
 	tokenStor := tokenStorage.New()
-	stor := util.NewKeyStorage(&nodeKey.PrivateKey, tokenStor)
+	stor := util.NewKeyStorage(&nodeKey.PrivateKey, tokenStor, mockedNetworkState{42})
 
 	t.Run("node key", func(t *testing.T) {
 		key, err := stor.GetKey(nil)
@@ -43,6 +43,12 @@ func TestNewKeyStorage(t *testing.T) {
 		require.Equal(t, pubKey.X, key.PublicKey.X)
 		require.Equal(t, pubKey.Y, key.PublicKey.Y)
 	})
+
+	t.Run("expired token", func(t *testing.T) {
+		tok := createToken(t, tokenStor, 30)
+		_, err := stor.GetKey(tok)
+		require.Error(t, err)
+	})
 }
 
 func generateToken(t *testing.T) *session.Token {
@@ -74,3 +80,11 @@ func createToken(t *testing.T, store *tokenStorage.TokenStore, exp uint64) *sess
 
 	return tok
 }
+
+type mockedNetworkState struct {
+	value uint64
+}
+
+func (m mockedNetworkState) CurrentEpoch() uint64 {
+	return m.value
+}
diff --git a/pkg/services/session/storage/types.go b/pkg/services/session/storage/types.go
index 0332a0512..76d61afe3 100644
--- a/pkg/services/session/storage/types.go
+++ b/pkg/services/session/storage/types.go
@@ -15,3 +15,8 @@ type PrivateToken struct {
 func (t *PrivateToken) SessionKey() *ecdsa.PrivateKey {
 	return t.sessionKey
 }
+
+// ExpiredAt returns epoch number until token is valid.
+func (t *PrivateToken) ExpiredAt() uint64 {
+	return t.exp
+}