diff --git a/Makefile b/Makefile
index bdd980b1c2536c0635118a9dee2dbb5c50307afc..288f8dd941c3f969c78815aab47113f70c401a8b 100644
--- a/Makefile
+++ b/Makefile
@@ -97,7 +97,7 @@ generate-certs: generate-gnmi-target-certs generate-gosdn-certs
 integration-tests: generate-certs containerize-gosdn containerize-plugin-registry
 	docker-compose -f dev_env_data/docker-compose/integration-test_docker-compose.yml down
 	docker-compose -f dev_env_data/docker-compose/integration-test_docker-compose.yml up -d
-	go test -p 1 ./integration-tests/*
+	go test -p 1 -count=1 ./integration-tests/*
 	docker-compose -f dev_env_data/docker-compose/integration-test_docker-compose.yml down
 
 integration-tests-debug-up: generate-certs containerize-gosdn containerize-plugin-registry
diff --git a/controller/api/apiUtil_test.go b/controller/api/apiUtil_test.go
index 78ae66d8bfbcc64121370f53f05840feaf702f6f..ca87dfcc32963c0dc338434236d68d8b51aa80d5 100644
--- a/controller/api/apiUtil_test.go
+++ b/controller/api/apiUtil_test.go
@@ -76,14 +76,15 @@ func createTestUsers() error {
 	testUserPWD := createHashedAndSaltedPassword("user", salt)
 	testRandPWD := createHashedAndSaltedPassword("aurelius", salt)
 
+	wrongTokens := []string{"wrong token"}
 	users := []rbacImpl.User{
 		{UserID: uuid.MustParse(adminID), UserName: "testAdmin", Roles: adminRoleMap, Password: testAdminPWD},
 		{UserID: uuid.MustParse(userID), UserName: "testUser", Roles: userRoleMap, Password: testUserPWD},
-		{UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: testRandPWD, Token: "wrong token"},
+		{UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: testRandPWD, Tokens: wrongTokens},
 	}
 
 	for _, u := range users {
-		err := userService.Add(rbacImpl.NewUser(u.ID(), u.Name(), u.Roles, u.Password, "", salt, conflict.Metadata{ResourceVersion: 0}))
+		err := userService.Add(rbacImpl.NewUser(u.ID(), u.Name(), u.Roles, u.Password, wrongTokens, salt, conflict.Metadata{ResourceVersion: 0}))
 		if err != nil {
 			return err
 		}
@@ -146,7 +147,7 @@ func createTestUserToken(userName string, validTokenRequired bool) (string, erro
 		if err != nil {
 			return token, err
 		}
-		user.SetToken(token)
+		user.AddToken(token)
 
 		err = userService.Update(user)
 		if err != nil {
diff --git a/controller/config/config.go b/controller/config/config.go
index 29f8a9f28b2405298559720e474b04132357c089..cb2dc65c776ac3d3a216a36962f220a61b9497e1 100644
--- a/controller/config/config.go
+++ b/controller/config/config.go
@@ -19,6 +19,8 @@ const (
 	defaultJWTDuration              = time.Hour * 24
 	jwtSecretKey                    = "jwtSecret"
 	gNMISubscriptionsFilePathKey    = "gNMISubscriptionsPath"
+	maxTokensPerUserKey             = "maxTokensPerUser"
+	defaultMaxTokensPerUser         = 100
 
 	// RabbitMQ Broker.
 	amqpPrefixKey   = "amqpPrefix"
@@ -81,6 +83,9 @@ var CertFilePath string
 // KeyFilePath si the path to the private key that the controller should use for TLS connections.
 var KeyFilePath string
 
+// MaxTokensPerUser is the maximum number of tokens a user can have. This determines the maximum of concurrent logged in sessions per user.
+var MaxTokensPerUser int
+
 // Init gets called on module import.
 func Init() {
 	err := InitializeConfig()
@@ -107,9 +112,9 @@ func InitializeConfig() error {
 
 	setLogLevel()
 
-	DatabaseConnection = getStringFromViper(databaseConnectionKey)
+	DatabaseConnection = viper.GetString(databaseConnectionKey)
 
-	FilesystemPathToStores = getStringFromViper(filesystemPathToStores)
+	FilesystemPathToStores = viper.GetString(filesystemPathToStores)
 	if FilesystemPathToStores == "" {
 		FilesystemPathToStores = "stores"
 	}
@@ -121,15 +126,20 @@ func InitializeConfig() error {
 
 	JWTSecret = viper.GetString(jwtSecretKey)
 
-	GNMISubscriptionsFilePath = getStringFromViper(gNMISubscriptionsFilePathKey)
+	MaxTokensPerUser = viper.GetInt(maxTokensPerUserKey)
+	if MaxTokensPerUser == 0 {
+		MaxTokensPerUser = defaultMaxTokensPerUser
+	}
+
+	GNMISubscriptionsFilePath = viper.GetString(gNMISubscriptionsFilePathKey)
 
 	loadAMQPConfig()
 
-	CAFilePath = getStringFromViper(tlsCACertFileKey)
+	CAFilePath = viper.GetString(tlsCACertFileKey)
 
-	CertFilePath = getStringFromViper(tlsCertFileKey)
+	CertFilePath = viper.GetString(tlsCertFileKey)
 
-	KeyFilePath = getStringFromViper(tlsKeyFileKey)
+	KeyFilePath = viper.GetString(tlsKeyFileKey)
 
 	if err := viper.WriteConfig(); err != nil {
 		return err
@@ -161,12 +171,6 @@ func getUUIDFromViper(viperKey string) (uuid.UUID, error) {
 	return parsedUUID, nil
 }
 
-func getStringFromViper(viperKey string) string {
-	stringFromViper := viper.GetString(viperKey)
-
-	return stringFromViper
-}
-
 func setChangeTimeout() error {
 	e := os.Getenv(changeTimeoutKey)
 	if e != "" {
@@ -202,9 +206,9 @@ func getDurationFromViper(viperKey, unit string) (time.Duration, error) {
 }
 
 func loadAMQPConfig() {
-	AMQPPrefix = getStringFromViper(amqpPrefixKey)
-	AMQPUser = getStringFromViper(amqpUserKey)
-	AMQPPassword = getStringFromViper(amqpPasswordKey)
-	AMQPHost = getStringFromViper(amqpHostKey)
-	AMQPPort = getStringFromViper(amqpPortKey)
+	AMQPPrefix = viper.GetString(amqpPrefixKey)
+	AMQPUser = viper.GetString(amqpUserKey)
+	AMQPPassword = viper.GetString(amqpPasswordKey)
+	AMQPHost = viper.GetString(amqpHostKey)
+	AMQPPort = viper.GetString(amqpPortKey)
 }
diff --git a/controller/configs/basic-docker-compose.toml b/controller/configs/basic-docker-compose.toml
index 2708de32e81c6101ffcf2da807de72ee86065d4d..d14da89b04f9d107f22f9e237f0e68cf36ed2df8 100644
--- a/controller/configs/basic-docker-compose.toml
+++ b/controller/configs/basic-docker-compose.toml
@@ -16,6 +16,7 @@ plugin-folder = 'plugins'
 plugin-registry = 'plugin-registry:55057'
 security = 'insecure'
 socket = ':55055'
+maxTokensPerUser = 100
 tlscacertfile = '/ssl/ca.crt'
 tlscertfile = '/ssl/certs/gosdn-selfsigned.crt'
 tlskeyfile = '/ssl/private/gosdn-selfsigned.key'
diff --git a/controller/configs/containerlab-gosdn.toml.example b/controller/configs/containerlab-gosdn.toml.example
index e5ed6652053ef3f64a929e863cf05a8f07758032..4b3e0668ae77b65fc85b0ff2681efa018f174f67 100644
--- a/controller/configs/containerlab-gosdn.toml.example
+++ b/controller/configs/containerlab-gosdn.toml.example
@@ -10,6 +10,7 @@ gNMISubscriptionsPath = "configs/gNMISubscriptions.txt"
 tlscertfile = '/ssl/certs/gosdn-selfsigned.crt'
 tlskeyfile = '/ssl/private/gosdn-selfsigned.key'
 tlscacertfile = '/ssl/ca.crt'
+maxTokensPerUser = 100
 
 amqpPrefix = "amqp://"
 amqpUser = "guest"
diff --git a/controller/configs/development-gosdn.toml.example b/controller/configs/development-gosdn.toml.example
index 4845c082c2acb6476c48b4e313ee8578a13d3c87..56bc0f26184b2fcd9fd3e5787afe56c0ce4664e0 100644
--- a/controller/configs/development-gosdn.toml.example
+++ b/controller/configs/development-gosdn.toml.example
@@ -15,6 +15,7 @@ log-level = 'debug'
 plugin-folder = 'plugins'
 security = 'insecure'
 socket = ':55055'
+maxTokensPerUser = 100
 tlscertfile = '/ssl/certs/gosdn-selfsigned.crt'
 tlskeyfile = '/ssl/private/gosdn-selfsigned.key'
 tlscacertfile = '/ssl/ca.crt'
diff --git a/controller/configs/integration-test-gosdn.toml b/controller/configs/integration-test-gosdn.toml
index 2708de32e81c6101ffcf2da807de72ee86065d4d..d14da89b04f9d107f22f9e237f0e68cf36ed2df8 100644
--- a/controller/configs/integration-test-gosdn.toml
+++ b/controller/configs/integration-test-gosdn.toml
@@ -16,6 +16,7 @@ plugin-folder = 'plugins'
 plugin-registry = 'plugin-registry:55057'
 security = 'insecure'
 socket = ':55055'
+maxTokensPerUser = 100
 tlscacertfile = '/ssl/ca.crt'
 tlscertfile = '/ssl/certs/gosdn-selfsigned.crt'
 tlskeyfile = '/ssl/private/gosdn-selfsigned.key'
diff --git a/controller/controller.go b/controller/controller.go
index 4cb78c20be7ac1d1179b3c26b0b5fcda8631bfe9..65d692517d2a1d5005919b63e9ead1b431b2e9e2 100644
--- a/controller/controller.go
+++ b/controller/controller.go
@@ -10,6 +10,7 @@ import (
 	"os/signal"
 	"sync"
 	"syscall"
+	"time"
 
 	"github.com/google/uuid"
 	"github.com/sethvargo/go-password/password"
@@ -172,6 +173,10 @@ func initialize() error {
 		return err
 	}
 
+	if err := deleteAllExpiredUserTokens(); err != nil {
+		return err
+	}
+
 	if err := startGrpc(); err != nil {
 		return err
 	}
@@ -430,7 +435,7 @@ func ensureDefaultUserExists() error {
 
 		hashedPassword := base64.RawStdEncoding.EncodeToString(argon2.IDKey([]byte(usedPassword), []byte(salt), 1, 64*1024, 4, 32))
 
-		err = c.userService.Add(rbacImpl.NewUser(uuid.New(), defaultUserName, map[string]string{config.BasePndUUID.String(): "admin"}, string(hashedPassword), "", salt, conflict.Metadata{ResourceVersion: 0}))
+		err = c.userService.Add(rbacImpl.NewUser(uuid.New(), defaultUserName, map[string]string{config.BasePndUUID.String(): "admin"}, string(hashedPassword), []string{}, salt, conflict.Metadata{ResourceVersion: 0}))
 		if err != nil {
 			return err
 		}
@@ -441,6 +446,42 @@ func ensureDefaultUserExists() error {
 	return nil
 }
 
+func deleteAllExpiredUserTokens() error {
+	var usersToUpdate []rbac.User
+	// Temporary create JWT manager just to evaluate tokens here
+	jwtManager := rbacImpl.NewJWTManager(config.JWTSecret, config.JWTDuration)
+
+	users, err := c.userService.GetAll()
+	if err != nil {
+		return fmt.Errorf("error getting all users while deleting expired user tokens: %w", err)
+	}
+
+	for _, user := range users {
+		tokens := user.GetTokens()
+		for _, token := range tokens {
+			claims, err := jwtManager.GetClaimsFromToken(token)
+			if err != nil {
+				return fmt.Errorf("error getting claims from token while deleting expired user tokens: %w", err)
+			}
+			if claims.ExpiresAt < time.Now().Unix() {
+				err := user.RemoveToken(token)
+				if err != nil {
+					return fmt.Errorf("error removing token while deleting expired user tokens: %w", err)
+				}
+				usersToUpdate = append(usersToUpdate, user)
+			}
+		}
+	}
+
+	for _, user := range usersToUpdate {
+		err := c.userService.Update(user)
+		if err != nil {
+			return fmt.Errorf("error updating user while deleting expired user tokens: %w", err)
+		}
+	}
+	return nil
+}
+
 // Run calls initialize to start the controller.
 func Run(ctx context.Context) error {
 	var initError error
diff --git a/controller/interfaces/rbac/user.go b/controller/interfaces/rbac/user.go
index 2116e73be7c3346c43281812e167bc33d2504a5b..1dfe1d64a31233fc15209e9d819702cc24ea623c 100644
--- a/controller/interfaces/rbac/user.go
+++ b/controller/interfaces/rbac/user.go
@@ -12,8 +12,10 @@ type User interface {
 	Name() string
 	GetRoles() map[string]string
 	GetPassword() string
-	GetToken() string
-	SetToken(string)
+	GetTokens() []string
+	SetTokens([]string)
+	AddToken(string)
+	RemoveToken(string) error
 	GetSalt() string
 	GetMetadata() conflict.Metadata
 }
@@ -24,7 +26,7 @@ type LoadedUser struct {
 	UserName string            `json:"username"`
 	Roles    map[string]string `json:"roles,omitempty"`
 	Password string            `json:"password"`
-	Token    string            `json:"token,omitempty"`
+	Tokens   []string          `json:"tokens,omitempty"`
 	Salt     string            `json:"salt" bson:"salt"`
 	Metadata conflict.Metadata `json:"metadata" bson:"metadata"`
 }
diff --git a/controller/northbound/server/auth.go b/controller/northbound/server/auth.go
index 2569f854105ede5ce6b1f8578132993be939b72c..5ef41402341f632903ba2c17b37a5f40f11c8700 100644
--- a/controller/northbound/server/auth.go
+++ b/controller/northbound/server/auth.go
@@ -7,6 +7,7 @@ import (
 	"time"
 
 	apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
+	"code.fbi.h-da.de/danet/gosdn/controller/config"
 	rbacInterfaces "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac"
 	"code.fbi.h-da.de/danet/gosdn/controller/metrics"
 	"code.fbi.h-da.de/danet/gosdn/controller/rbac"
@@ -92,7 +93,10 @@ func (s AuthServer) Login(ctx context.Context, request *apb.LoginRequest) (*apb.
 		return nil, err
 	}
 
-	userToUpdate.SetToken(token)
+	err = addTokenAndEnsureTokenLimit(userToUpdate, token)
+	if err != nil {
+		return nil, err
+	}
 
 	err = s.userService.Update(userToUpdate)
 	if err != nil {
@@ -155,7 +159,7 @@ func (s AuthServer) isCorrectPassword(storedPassword, salt, loginPassword string
 }
 
 // handleLogout checks if the provided user name matches with the one associated with token and
-// replaces the stored token of the user with an empty string.
+// removes the token from all tokens of the user.
 func (s AuthServer) handleLogout(ctx context.Context, userName string) error {
 	md, ok := metadata.FromIncomingContext(ctx)
 	if !ok {
@@ -179,15 +183,16 @@ func (s AuthServer) handleLogout(ctx context.Context, userName string) error {
 			return err
 		}
 
-		if token != storedUser.GetToken() {
-			return status.Errorf(codes.Aborted, "missing match of token provied for user")
+		err = removeTokenFromUserIfExists(storedUser, token)
+		if err != nil {
+			return status.Errorf(codes.Aborted, "Error removing token from user, it was either already logged out or otherwise not found")
 		}
 
 		err = s.userService.Update(&rbac.User{UserID: storedUser.ID(),
 			UserName: storedUser.Name(),
 			Roles:    storedUser.GetRoles(),
 			Password: storedUser.GetPassword(),
-			Token:    " ",
+			Tokens:   storedUser.GetTokens(),
 			Salt:     storedUser.GetSalt(),
 			Metadata: storedUser.GetMetadata(),
 		})
@@ -199,3 +204,28 @@ func (s AuthServer) handleLogout(ctx context.Context, userName string) error {
 
 	return nil
 }
+
+func addTokenAndEnsureTokenLimit(userToUpdate rbacInterfaces.User, token string) error {
+	userToUpdate.AddToken(token)
+	for len(userToUpdate.GetTokens()) > config.MaxTokensPerUser {
+		err := userToUpdate.RemoveToken(userToUpdate.GetTokens()[0])
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func removeTokenFromUserIfExists(storedUser rbacInterfaces.User, token string) error {
+	storedTokens := storedUser.GetTokens()
+	for _, storedToken := range storedTokens {
+		if storedToken == token {
+			err := storedUser.RemoveToken(token)
+			if err != nil {
+				return errors.New("could not remove token from user")
+			}
+			return nil
+		}
+	}
+	return errors.New("token not found for user")
+}
diff --git a/controller/northbound/server/auth_interceptor.go b/controller/northbound/server/auth_interceptor.go
index 30ffa2ea982be33282ab3db1c86cfe2f6e22d06e..6437791aab91814949d215cb939bf5f17cb5af6e 100644
--- a/controller/northbound/server/auth_interceptor.go
+++ b/controller/northbound/server/auth_interceptor.go
@@ -97,7 +97,17 @@ func (auth *AuthInterceptor) authorize(ctx context.Context, method string) error
 			return err
 		}
 
-		if user.GetToken() != token {
+		storedTokens := user.GetTokens()
+
+		foundToken := false
+		for _, storedToken := range storedTokens {
+			if storedToken == token {
+				foundToken = true
+				break
+			}
+		}
+
+		if !foundToken {
 			return status.Errorf(codes.PermissionDenied, "invalid token")
 		}
 
diff --git a/controller/northbound/server/auth_test.go b/controller/northbound/server/auth_test.go
index 7716ec35873d48c2bfefc51da63b5a1605c2079b..8ad8cb6de1b5042d68debf09db1751507f5e3731 100644
--- a/controller/northbound/server/auth_test.go
+++ b/controller/northbound/server/auth_test.go
@@ -8,9 +8,13 @@ import (
 
 	"buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
 	apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
+	"code.fbi.h-da.de/danet/gosdn/controller/config"
+	"code.fbi.h-da.de/danet/gosdn/controller/conflict"
 	eventservice "code.fbi.h-da.de/danet/gosdn/controller/eventService"
 	"code.fbi.h-da.de/danet/gosdn/controller/rbac"
 	"github.com/bufbuild/protovalidate-go"
+	"github.com/google/uuid"
+	"github.com/stretchr/testify/assert"
 	"google.golang.org/grpc/metadata"
 )
 
@@ -291,3 +295,43 @@ func TestAuth_handleLogout(t *testing.T) {
 		})
 	}
 }
+
+func TestAuth_addTokenAndEnsureTokenLimit_addKey(t *testing.T) {
+	config.MaxTokensPerUser = 2
+	userID := uuid.New()
+	user := rbac.NewUser(userID, "testUser", map[string]string{}, "password", []string{"token1"}, "salt", conflict.Metadata{ResourceVersion: 0})
+	err := addTokenAndEnsureTokenLimit(user, "token2")
+	assert.Nil(t, err)
+
+	assert.Equal(t, 2, len(user.GetTokens()))
+	assert.Equal(t, "token1", user.GetTokens()[0])
+	assert.Equal(t, "token2", user.GetTokens()[1])
+}
+
+func TestAuth_addTokenAndEnsureTokenLimit_removeOldKey(t *testing.T) {
+	config.MaxTokensPerUser = 2
+	userID := uuid.New()
+	user := rbac.NewUser(userID, "testUser", map[string]string{}, "password", []string{"token1", "token2"}, "salt", conflict.Metadata{ResourceVersion: 0})
+	err := addTokenAndEnsureTokenLimit(user, "token3")
+	assert.Nil(t, err)
+
+	assert.Equal(t, 2, len(user.GetTokens()))
+	assert.Equal(t, "token2", user.GetTokens()[0])
+	assert.Equal(t, "token3", user.GetTokens()[1])
+}
+func Test_removeTokenFromUserIfExists(t *testing.T) {
+	config.MaxTokensPerUser = 100
+	user := rbac.NewUser(uuid.New(), "testUser", map[string]string{}, "password", []string{"token1", "token2", "token3"}, "salt", conflict.Metadata{ResourceVersion: 0})
+
+	err := removeTokenFromUserIfExists(user, "token2")
+	assert.Nil(t, err)
+	assert.Equal(t, []string{"token1", "token3"}, user.GetTokens())
+
+	err = removeTokenFromUserIfExists(user, "token4")
+	assert.NotNil(t, err)
+	assert.Equal(t, []string{"token1", "token3"}, user.GetTokens())
+
+	user = rbac.NewUser(uuid.New(), "testUser", map[string]string{}, "password", []string{}, "salt", conflict.Metadata{ResourceVersion: 0})
+	err = removeTokenFromUserIfExists(user, "token4")
+	assert.NotNil(t, err)
+}
diff --git a/controller/northbound/server/test_util_test.go b/controller/northbound/server/test_util_test.go
index 72ded5bc087c580b3829a1daff782eb86b23d2b0..82b68911ee29fe620ed30d96317ea0ca9e6a8ec5 100644
--- a/controller/northbound/server/test_util_test.go
+++ b/controller/northbound/server/test_util_test.go
@@ -98,14 +98,15 @@ func createTestUsers(userService rbacInterfaces.UserService) error {
 	testUserPWD := createHashedAndSaltedPassword("user", salt)
 	testRandPWD := createHashedAndSaltedPassword("aurelius", salt)
 
+	wrongTokens := []string{"Wrong token"}
 	users := []rbac.User{
 		{UserID: uuid.MustParse(adminID), UserName: "testAdmin", Roles: adminRoleMap, Password: testAdminPWD},
 		{UserID: uuid.MustParse(userID), UserName: "testUser", Roles: userRoleMap, Password: testUserPWD},
-		{UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: testRandPWD, Token: "wrong token"},
+		{UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: testRandPWD, Tokens: wrongTokens},
 	}
-
+	wrongTokens = []string{}
 	for _, u := range users {
-		err := userService.Add(rbac.NewUser(u.ID(), u.Name(), u.Roles, u.Password, "", salt, conflict.Metadata{ResourceVersion: 0}))
+		err := userService.Add(rbac.NewUser(u.ID(), u.Name(), u.Roles, u.Password, wrongTokens, salt, conflict.Metadata{ResourceVersion: 0}))
 		if err != nil {
 			return err
 		}
@@ -176,6 +177,7 @@ func patchLogger(t *testing.T) {
 // be attached to the provided user. Else the user won't have the token and can not be authorized.
 func createTestUserToken(userName string, validTokenRequired bool, userService rbacInterfaces.UserService, jwt *rbac.JWTManager) (string, error) {
 	token, err := jwt.GenerateToken(rbac.User{UserName: userName})
+	tokens := []string{token}
 	if err != nil {
 		return token, err
 	}
@@ -185,7 +187,7 @@ func createTestUserToken(userName string, validTokenRequired bool, userService r
 		if err != nil {
 			return token, err
 		}
-		user.SetToken(token)
+		user.SetTokens(tokens)
 
 		err = userService.Update(user)
 		if err != nil {
diff --git a/controller/northbound/server/user.go b/controller/northbound/server/user.go
index d37ae43a79bb7b0c1086687dfa4b2e44ee588318..000058d9c233eb34947493df99699c91e5f35f48 100644
--- a/controller/northbound/server/user.go
+++ b/controller/northbound/server/user.go
@@ -97,7 +97,7 @@ func (u UserServer) CreateUsers(ctx context.Context, request *apb.CreateUsersReq
 			userID = uuid.New()
 		}
 
-		user := rbac.NewUser(userID, user.Name, roles, string(hashedPassword), user.Token, salt, conflict.Metadata{ResourceVersion: 0})
+		user := rbac.NewUser(userID, user.Name, roles, string(hashedPassword), []string{}, salt, conflict.Metadata{ResourceVersion: 0})
 		err = u.userService.Add(user)
 		if err != nil {
 			log.Error(err)
@@ -204,7 +204,7 @@ func (u UserServer) UpdateUsers(ctx context.Context, request *apb.UpdateUsersReq
 
 		hashedPassword := base64.RawStdEncoding.EncodeToString(argon2.IDKey([]byte(user.Password), []byte(storedUser.GetSalt()), 1, 64*1024, 4, 32))
 
-		userToUpdate := rbac.NewUser(uid, user.Name, user.Roles, string(hashedPassword), user.Token, storedUser.GetSalt(), conflict.Metadata{
+		userToUpdate := rbac.NewUser(uid, user.Name, user.Roles, string(hashedPassword), []string{}, storedUser.GetSalt(), conflict.Metadata{
 			ResourceVersion: int(user.Metadata.ResourceVersion)})
 
 		usr, _ := userToUpdate.(*rbac.User)
diff --git a/controller/rbac/rbacService.go b/controller/rbac/rbacService.go
index d16505d703bac46c048f03f249f3754afe2b3972..b084ffaff40dec764914aac9787e73f62027e955 100644
--- a/controller/rbac/rbacService.go
+++ b/controller/rbac/rbacService.go
@@ -138,7 +138,7 @@ func (s *UserService) createUserFromStore(loadedUser rbac.LoadedUser) rbac.User
 		loadedUser.UserName,
 		loadedUser.Roles,
 		loadedUser.Password,
-		loadedUser.Token,
+		loadedUser.Tokens,
 		loadedUser.Salt,
 		loadedUser.Metadata,
 	)
diff --git a/controller/rbac/user.go b/controller/rbac/user.go
index d0b5ae14fa35d299db531500a0b0d286d127fc89..f7ce92c0a23c6a067694ca4399753ed9d70a62ac 100644
--- a/controller/rbac/user.go
+++ b/controller/rbac/user.go
@@ -2,6 +2,7 @@ package rbac
 
 import (
 	"encoding/json"
+	"errors"
 
 	"code.fbi.h-da.de/danet/gosdn/controller/conflict"
 	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac"
@@ -16,7 +17,7 @@ type User struct {
 	UserName string            `json:"username"`
 	Roles    map[string]string `json:"roles,omitempty"`
 	Password string            `json:"password"`
-	Token    string            `json:"token,omitempty"`
+	Tokens   []string          `json:"token,omitempty"`
 	Salt     string            `json:"salt"`
 }
 
@@ -25,7 +26,7 @@ func NewUser(id uuid.UUID,
 	name string,
 	roles map[string]string,
 	pw string,
-	token string,
+	tokens []string,
 	salt string,
 	metadata conflict.Metadata,
 ) rbac.User {
@@ -34,7 +35,7 @@ func NewUser(id uuid.UUID,
 		UserName: name,
 		Roles:    roles,
 		Password: pw,
-		Token:    token,
+		Tokens:   tokens,
 		Salt:     salt,
 		Metadata: metadata,
 	}
@@ -66,8 +67,8 @@ func (u *User) GetRoles() map[string]string {
 }
 
 // GetToken returns the token of the user.
-func (u *User) GetToken() string {
-	return u.Token
+func (u *User) GetTokens() []string {
+	return u.Tokens
 }
 
 // SetName sets the name of the user.
@@ -76,8 +77,25 @@ func (u *User) SetName(name string) {
 }
 
 // SetToken sets the token of the user.
-func (u *User) SetToken(token string) {
-	u.Token = token
+func (u *User) SetTokens(tokens []string) {
+	u.Tokens = tokens
+}
+
+// AddToken adds a token to the user.
+func (u *User) AddToken(token string) {
+	u.Tokens = append(u.Tokens, token)
+}
+
+// RemoveToken removes a token from the user.
+func (u *User) RemoveToken(inputToken string) error {
+	for i, token := range u.Tokens {
+		if token == inputToken {
+			u.Tokens = append(u.Tokens[:i], u.Tokens[i+1:]...)
+			return nil
+		}
+	}
+	err := errors.New("token not found")
+	return err
 }
 
 // GetSalt returns the salt of the user.
@@ -92,7 +110,7 @@ func (u *User) MarshalJSON() ([]byte, error) {
 		UserName string            `json:"username"`
 		Roles    map[string]string `json:"roles,omitempty"`
 		Password string            `json:"password"`
-		Token    string            `json:"token,omitempty"`
+		Tokens   []string          `json:"tokens,omitempty"`
 		Salt     string            `json:"salt"`
 		Metadata conflict.Metadata `json:"metadata"`
 	}{
@@ -100,7 +118,7 @@ func (u *User) MarshalJSON() ([]byte, error) {
 		UserName: u.Name(),
 		Roles:    u.Roles,
 		Password: u.Password,
-		Token:    u.Token,
+		Tokens:   u.Tokens,
 		Salt:     u.Salt,
 		Metadata: u.Metadata,
 	})
@@ -113,7 +131,7 @@ func (u *User) MarshalBSON() ([]byte, error) {
 		UserName string            `bson:"username"`
 		Roles    map[string]string `bson:"roles,omitempty"`
 		Password string            `bson:"password"`
-		Token    string            `bson:"token,omitempty"`
+		Tokens   []string          `bson:"tokens,omitempty"`
 		Salt     string            `bson:"salt"`
 		Metadata conflict.Metadata `bson:"metadata"`
 	}{
@@ -121,7 +139,7 @@ func (u *User) MarshalBSON() ([]byte, error) {
 		UserName: u.Name(),
 		Roles:    u.Roles,
 		Password: u.Password,
-		Token:    u.Token,
+		Tokens:   u.Tokens,
 		Salt:     u.Salt,
 		Metadata: u.Metadata,
 	})
diff --git a/controller/rbac/userFileSystemStore_test.go b/controller/rbac/userFileSystemStore_test.go
index 7ddeb6ee3eb96595d817fce27297aeec6ec753b3..b5c0d8885e64d12eef2c19161ca30287f9e7e09b 100644
--- a/controller/rbac/userFileSystemStore_test.go
+++ b/controller/rbac/userFileSystemStore_test.go
@@ -20,7 +20,8 @@ func TestFileSystemUserStore_Add(t *testing.T) {
 	}
 	var idtest uuid.UUID
 	var role map[string]string
-	testingUser := NewUser(idtest, "testUser", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw", conflict.Metadata{})
+	tokens := []string{"svsvsfbdwbwbev"}
+	testingUser := NewUser(idtest, "testUser", role, "xyz", tokens, "svswvasfbw", conflict.Metadata{})
 	tests := []struct {
 		name    string
 		args    args
@@ -51,7 +52,8 @@ func TestFileSystemUserStore_Delete(t *testing.T) {
 	}
 	var idtest uuid.UUID
 	var role map[string]string
-	testingUser := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw", conflict.Metadata{})
+	tokens := []string{"svsvsfbdwbwbev"}
+	testingUser := NewUser(idtest, "", role, "xyz", tokens, "svswvasfbw", conflict.Metadata{})
 	tests := []struct {
 		name    string
 		args    args
@@ -84,7 +86,8 @@ func TestFileSystemUserStore_Get(t *testing.T) {
 	}
 	var idtest uuid.UUID
 	var role map[string]string
-	testingUser := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw", conflict.Metadata{})
+	tokens := []string{"svsvsfbdwbwbev"}
+	testingUser := NewUser(idtest, "", role, "xyz", tokens, "svswvasfbw", conflict.Metadata{})
 	tests := []struct {
 		name    string
 		args    args
@@ -96,7 +99,7 @@ func TestFileSystemUserStore_Get(t *testing.T) {
 			args{
 				store.Query{ID: idtest, Name: "test"},
 			},
-			rbac.LoadedUser{ID: idtest.String(), UserName: "", Roles: role, Password: "xyz", Token: "svsvsfbdwbwbev", Salt: "svswvasfbw"},
+			rbac.LoadedUser{ID: idtest.String(), UserName: "", Roles: role, Password: "xyz", Tokens: tokens, Salt: "svswvasfbw"},
 			false,
 		},
 	}
@@ -123,9 +126,10 @@ func TestFileSystemUserStore_GetAll(t *testing.T) {
 
 	var idtest uuid.UUID
 	var role map[string]string
-	testingUser1 := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbevasf", "svswvasfbwasv", conflict.Metadata{})
-	testingUser2 := NewUser(idtest, "", role, "abc", "svsvsfbdwbwbevsav", "svswvasfbwadf", conflict.Metadata{})
-	testingUser3 := NewUser(idtest, "", role, "lmn", "svsvsfbdwbwbevscv", "svswvasfbwasd", conflict.Metadata{})
+	tokens := []string{"svsvsfbdwbwbev"}
+	testingUser1 := NewUser(idtest, "", role, "xyz", tokens, "svswvasfbwasv", conflict.Metadata{})
+	testingUser2 := NewUser(idtest, "", role, "abc", tokens, "svswvasfbwadf", conflict.Metadata{})
+	testingUser3 := NewUser(idtest, "", role, "lmn", tokens, "svswvasfbwasd", conflict.Metadata{})
 	tests := []struct {
 		name    string
 		want    []rbac.LoadedUser
@@ -133,7 +137,7 @@ func TestFileSystemUserStore_GetAll(t *testing.T) {
 	}{
 		{
 			"testUser",
-			[]rbac.LoadedUser{{ID: idtest.String(), UserName: "", Roles: role, Password: "xyz", Token: "svsvsfbdwbwbevasf", Salt: "svswvasfbwasv"}, {ID: idtest.String(), UserName: "", Roles: role, Password: "abc", Token: "svsvsfbdwbwbevsav", Salt: "svswvasfbwadf"}, {ID: idtest.String(), UserName: "", Roles: role, Password: "lmn", Token: "svsvsfbdwbwbevscv", Salt: "svswvasfbwasd"}},
+			[]rbac.LoadedUser{{ID: idtest.String(), UserName: "", Roles: role, Password: "xyz", Tokens: tokens, Salt: "svswvasfbwasv"}, {ID: idtest.String(), UserName: "", Roles: role, Password: "abc", Tokens: tokens, Salt: "svswvasfbwadf"}, {ID: idtest.String(), UserName: "", Roles: role, Password: "lmn", Tokens: tokens, Salt: "svswvasfbwasd"}},
 			false,
 		},
 	}
@@ -175,7 +179,8 @@ func TestFileSystemUserStore_Update(t *testing.T) {
 	}
 	var idtest uuid.UUID
 	var role map[string]string
-	testingUser := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw", conflict.Metadata{})
+	tokens := []string{"svsvsfbdwbwbev"}
+	testingUser := NewUser(idtest, "", role, "xyz", tokens, "svswvasfbw", conflict.Metadata{})
 	tests := []struct {
 		name    string
 		args    args
diff --git a/integration-tests/application_tests/application_test.go b/integration-tests/application_tests/application_test.go
index d5b69ae226115918d54656fd38cf4a2de150386f..9b3797a5540cb2c42231729a68b7fd6c6635c6e0 100644
--- a/integration-tests/application_tests/application_test.go
+++ b/integration-tests/application_tests/application_test.go
@@ -100,10 +100,10 @@ func TestMain(m *testing.M) {
 	// a user and role and update the user because of the login. After then only logins are done, no user and role creations.
 	// This means that this will block after trying once, because of the three attempts to read from eventChannels.
 
-	_ = <-application.addEventChannel
-	_ = <-application.addEventChannel
-	_ = <-application.addEventChannel
-	_ = <-application.updateEventChannel
+	<-application.addEventChannel
+	<-application.addEventChannel
+	<-application.addEventChannel
+	<-application.updateEventChannel
 
 	m.Run()
 }