diff --git a/controller/api/apiUtil_test.go b/controller/api/apiUtil_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..bea1ab20500ea125eaf1cea3e557bf615b67f0a9
--- /dev/null
+++ b/controller/api/apiUtil_test.go
@@ -0,0 +1,114 @@
+package api
+
+import (
+	rbacImpl "code.fbi.h-da.de/danet/gosdn/controller/rbac"
+	"github.com/google/uuid"
+)
+
+// Name of this file requires _test at the end, because of how the availability of varibales is handled in test files of go packages.
+// Does not include actual file tests!
+
+const adminID = "5c248a22-8eb7-48cf-b392-45680a1863a5"
+const userID = "57005d13-7a4d-493d-a02b-50ca51c40197"
+const adminRoleID = "126683ae-5ff2-43ee-92f7-0e2b936f8c77"
+const randomRoleName = "bertram"
+
+var adminRoleMap = map[string]string{pndID: "admin"}
+var userRoleMap = map[string]string{pndID: "user"}
+
+func clearAndCreateAuthTestSetup() error {
+	//clear setup if changed
+	storedUsers, err := userService.GetAll()
+	if err != nil {
+		return err
+	}
+	for _, u := range storedUsers {
+		err = userService.Delete(u)
+		if err != nil {
+			return err
+		}
+	}
+
+	storedRoles, err := roleService.GetAll()
+	if err != nil {
+		return err
+	}
+	for _, r := range storedRoles {
+		err = roleService.Delete(r)
+		if err != nil {
+			return err
+		}
+	}
+
+	// create dataset
+	err = createTestUsers()
+	if err != nil {
+		return err
+	}
+
+	err = createTestRoles()
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+//TODO(faseid): change password to hashed/encrypted one
+func createTestUsers() error {
+	randomRoleMap := map[string]string{pndID: randomRoleName}
+
+	users := []rbacImpl.User{
+		{UserID: uuid.MustParse(adminID), UserName: "testAdmin", Roles: adminRoleMap, Password: "admin"},
+		{UserID: uuid.MustParse(userID), UserName: "testUser", Roles: userRoleMap, Password: "user"},
+		{UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: "aurelius", Token: "wrong token"},
+	}
+
+	for _, u := range users {
+		err := userService.Add(rbacImpl.NewUser(u.ID(), u.Name(), u.Roles, u.Password, ""))
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func createTestRoles() error {
+	roles := []rbacImpl.Role{
+		{
+			RoleID:      uuid.MustParse(adminRoleID),
+			RoleName:    "adminTestRole",
+			Description: "Admin",
+			Permissions: []string{
+				"/gosdn.core.CoreService/GetPnd",
+				"/gosdn.core.CoreService/GetPndList",
+			},
+		},
+		{
+			RoleID:      uuid.New(),
+			RoleName:    "userTestRole",
+			Description: "User",
+			Permissions: []string{
+				"/gosdn.pnd.PndService/GetChangeList",
+			},
+		},
+		{
+			RoleID:      uuid.New(),
+			RoleName:    randomRoleName,
+			Description: "Not a role",
+			Permissions: []string{
+				"nope",
+			},
+		},
+	}
+
+	for _, r := range roles {
+		err := roleService.Add(rbacImpl.NewRole(r.ID(), r.Name(), r.Description, r.Permissions))
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
diff --git a/controller/api/auth_test.go b/controller/api/auth_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8012d03cb55effe57e0e34fcba4cbd3d19455539
--- /dev/null
+++ b/controller/api/auth_test.go
@@ -0,0 +1,105 @@
+package api
+
+import (
+	"context"
+	"testing"
+
+	apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
+)
+
+func TestLogin(t *testing.T) {
+	type args struct {
+		ctx      context.Context
+		addr     string
+		username string
+		pwd      string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.LoginResponse
+		wantErr bool
+	}{
+		{
+			name: "default",
+			args: args{
+				ctx:      context.TODO(),
+				addr:     testAPIEndpoint,
+				username: "testAdmin",
+				pwd:      "admin",
+			},
+			want: &apb.LoginResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+		{
+			name: "wrong login credentials",
+			args: args{
+				ctx:      context.TODO(),
+				addr:     testAPIEndpoint,
+				username: "testAdmin",
+				pwd:      "nope",
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := Login(tt.args.ctx, tt.args.addr, tt.args.username, tt.args.pwd)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Login() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil {
+				if got.Status != apb.Status_STATUS_OK || got.Token == "" {
+					t.Errorf("Auth.Login() = %v, want non empty token", got)
+				}
+			}
+		})
+	}
+}
+
+func TestLogout(t *testing.T) {
+	type args struct {
+		ctx      context.Context
+		addr     string
+		username string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.LogoutResponse
+		wantErr bool
+	}{
+		{
+			name: "default log out",
+			args: args{
+				ctx:      context.TODO(),
+				addr:     testAPIEndpoint,
+				username: "testAdmin",
+			},
+			want: &apb.LogoutResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := Logout(tt.args.ctx, tt.args.addr, tt.args.username)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Logout() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("Role.CreateRoles() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/controller/api/initialise_test.go b/controller/api/initialise_test.go
index a927efd228f43b7ab048bec326df6cd8b8484e59..f36fd54bbca7b892bee841c17b4ab27be654bd40 100644
--- a/controller/api/initialise_test.go
+++ b/controller/api/initialise_test.go
@@ -10,6 +10,7 @@ import (
 
 	cpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/core"
 	ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd"
+	apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
 	tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
 	"code.fbi.h-da.de/danet/gosdn/controller/config"
 	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/device"
@@ -84,6 +85,7 @@ func bootstrapUnitTest() {
 	sbiStore = nucleus.NewMemorySbiStore()
 	userService = rbacImpl.NewUserService(rbacImpl.NewMemoryUserStore())
 	roleService = rbacImpl.NewRoleService(rbacImpl.NewMemoryRoleStore())
+	clearAndCreateAuthTestSetup()
 
 	previousHostname := "previousHostname"
 	intendedHostname := "intendedHostname"
@@ -132,9 +134,18 @@ func bootstrapUnitTest() {
 	if err := pndStore.Add(&mockPnd); err != nil {
 		log.Fatal(err)
 	}
+
+	jwtManager := rbacImpl.NewJWTManager("", (10000 * time.Hour))
+
 	northbound := nbi.NewNBI(pndStore, userService, roleService)
+	northbound.Auth = nbi.NewAuthServer(jwtManager)
+
 	cpb.RegisterCoreServiceServer(s, northbound.Core)
 	ppb.RegisterPndServiceServer(s, northbound.Pnd)
+	apb.RegisterAuthServiceServer(s, northbound.Auth)
+	apb.RegisterUserServiceServer(s, northbound.User)
+	apb.RegisterRoleServiceServer(s, northbound.Role)
+
 	go func() {
 		if err := s.Serve(lis); err != nil {
 			log.Fatalf("Server exited with error: %v", err)
diff --git a/controller/api/roles.go b/controller/api/role.go
similarity index 100%
rename from controller/api/roles.go
rename to controller/api/role.go
diff --git a/controller/api/role_test.go b/controller/api/role_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..c98b0d277579b2376b86aa5b03d7e2e051b09a50
--- /dev/null
+++ b/controller/api/role_test.go
@@ -0,0 +1,378 @@
+package api
+
+import (
+	"context"
+	"reflect"
+	"testing"
+
+	apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
+	"github.com/google/uuid"
+)
+
+func TestCreateRoles(t *testing.T) {
+	type args struct {
+		ctx   context.Context
+		addr  string
+		roles []*apb.Role
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.CreateRolesResponse
+		wantErr bool
+	}{
+		{
+			name: "default create roles",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				roles: []*apb.Role{
+					{
+						Name:        "new role 1",
+						Description: "Role 1",
+						Permissions: []string{"permission 1", "permission 2"},
+					},
+				},
+			},
+			want: &apb.CreateRolesResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := CreateRoles(tt.args.ctx, tt.args.addr, tt.args.roles)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("CreateRoles() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("Role.CreateRoles() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestGetRole(t *testing.T) {
+	type args struct {
+		ctx  context.Context
+		addr string
+		name string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.GetRoleResponse
+		wantErr bool
+	}{
+		{
+			name: "default get role",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				name: "adminTestRole",
+			},
+			want: &apb.GetRoleResponse{
+				Status: apb.Status_STATUS_OK,
+				Role: &apb.Role{
+					Name:        "adminTestRole",
+					Description: "Admin",
+				},
+			},
+			wantErr: false,
+		},
+		{
+			name: "error get role",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				name: "not role",
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := GetRole(tt.args.ctx, tt.args.addr, tt.args.name)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("GetRole() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status == tt.want.Status {
+				if got.Role.Name != tt.want.Role.Name || got.Role.Description != tt.want.Role.Description {
+					t.Errorf("Role.GetRole() = %v, want %v", got, tt.want)
+				}
+			} else {
+				if got != nil {
+					t.Errorf("Role.GetRole() = %v, want %v", got, tt.want)
+				}
+			}
+		})
+	}
+}
+
+func TestGetRoles(t *testing.T) {
+	err := clearAndCreateAuthTestSetup()
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	type args struct {
+		ctx  context.Context
+		addr string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.GetRolesResponse
+		wantLen int
+		wantErr bool
+	}{
+		{
+			name: "default get roles",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+			},
+			want: &apb.GetRolesResponse{
+				Status: apb.Status_STATUS_OK,
+				Roles: []*apb.Role{
+					{
+						Name:        "adminTestRole",
+						Description: "Admin",
+						Permissions: []string{
+							"/gosdn.core.CoreService/GetPnd",
+							"/gosdn.core.CoreService/GetPndList",
+						}},
+					{
+						Name:        "userTestRole",
+						Description: "User",
+						Permissions: []string{
+							"/gosdn.pnd.PndService/GetChangeList",
+						}},
+					{
+						Name:        randomRoleName,
+						Description: "Not a role",
+						Permissions: []string{
+							"nope",
+						},
+					},
+				},
+			},
+			wantLen: 3,
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := GetRoles(tt.args.ctx, tt.args.addr)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("GetRoles() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status == tt.want.Status {
+				if len(got.Roles) != 3 {
+					t.Errorf("Role.GetRoles() = %v, want %v", got, tt.want)
+				}
+				for _, gotR := range got.Roles {
+					containsExpected := false
+					for _, wantR := range tt.want.Roles {
+						gotPerm := gotR.Permissions
+						wantPerm := wantR.Permissions
+						if gotR.Description == wantR.Description && gotR.Name == wantR.Name &&
+							reflect.DeepEqual(gotPerm, wantPerm) {
+							containsExpected = true
+							break
+						}
+					}
+					if !containsExpected {
+						t.Errorf("Role.GetRoles() = %v, want %v", got, tt.want)
+					}
+				}
+			}
+		})
+	}
+}
+
+func TestUpdateRoles(t *testing.T) {
+	type args struct {
+		ctx   context.Context
+		addr  string
+		roles []*apb.Role
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.UpdateRolesResponse
+		wantErr bool
+	}{
+		{
+			name: "default update roles",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				roles: []*apb.Role{
+					{
+						Id:   adminRoleID,
+						Name: "New Name",
+					},
+				},
+			},
+			want: &apb.UpdateRolesResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+		{
+			name: "error update roles",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				roles: []*apb.Role{
+					{
+						Id:   uuid.NewString(),
+						Name: "New Name",
+					},
+				},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := UpdateRoles(tt.args.ctx, tt.args.addr, tt.args.roles)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("UpdateRoles() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("Role.UpdateRoles() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestDeletePermissionForRole(t *testing.T) {
+	clearAndCreateAuthTestSetup()
+
+	type args struct {
+		ctx                 context.Context
+		addr                string
+		name                string
+		permissionsToDelete []string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.DeletePermissionsForRoleResponse
+		wantErr bool
+	}{
+		{
+			name: "default delete permissions for role",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				name: "adminTestRole",
+				permissionsToDelete: []string{
+					"/gosdn.core.CoreService/GetPnd",
+					"/gosdn.core.CoreService/GetPndList",
+				},
+			},
+			want: &apb.DeletePermissionsForRoleResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+		{
+			name: "error delete permissions for role",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				name: "adminTestRole",
+				permissionsToDelete: []string{
+					"foo",
+				},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := DeletePermissionForRole(tt.args.ctx, tt.args.addr, tt.args.name, tt.args.permissionsToDelete)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("DeletePermissionForRole() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("Role.DeletePermissionsForRole() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestDeleteRoles(t *testing.T) {
+	type args struct {
+		ctx      context.Context
+		addr     string
+		roleName []string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.DeleteRolesResponse
+		wantErr bool
+	}{
+		{
+			name: "default delete roles",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				roleName: []string{
+					"userTestRole",
+					"adminTestRole",
+				},
+			},
+			want: &apb.DeleteRolesResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+		{
+			name: "error delete roles",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				roleName: []string{
+					"no",
+				},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			clearAndCreateAuthTestSetup()
+
+			got, err := DeleteRoles(tt.args.ctx, tt.args.addr, tt.args.roleName)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("DeleteRoles() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("Role.DeleteRoles() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/controller/api/users.go b/controller/api/user.go
similarity index 100%
rename from controller/api/users.go
rename to controller/api/user.go
diff --git a/controller/api/user_test.go b/controller/api/user_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..edfb703d39db2473093139264eca102191283097
--- /dev/null
+++ b/controller/api/user_test.go
@@ -0,0 +1,291 @@
+package api
+
+import (
+	"context"
+	"reflect"
+	"testing"
+
+	apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
+	"github.com/google/uuid"
+)
+
+func TestCreateUsers(t *testing.T) {
+	type args struct {
+		ctx   context.Context
+		addr  string
+		users []*apb.User
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    apb.Status
+		wantErr bool
+	}{
+		{
+			name: "default create users",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				users: []*apb.User{
+					{
+						Name:     "foo",
+						Roles:    map[string]string{pndID: "s"},
+						Password: "roh",
+						Token:    "da",
+					},
+				},
+			},
+			want:    apb.Status_STATUS_OK,
+			wantErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := CreateUsers(tt.args.ctx, tt.args.addr, tt.args.users)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("CreateUsers() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got.Status, tt.want) {
+				t.Errorf("CreateUsers() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestGetUser(t *testing.T) {
+	type args struct {
+		ctx  context.Context
+		addr string
+		name string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.GetUserResponse
+		wantErr bool
+	}{
+		{
+			name: "default get user",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				name: "testAdmin",
+			},
+			want: &apb.GetUserResponse{
+				Status: apb.Status_STATUS_OK,
+				User: &apb.User{
+					Id:   adminID,
+					Name: "testAdmin",
+				},
+			},
+			wantErr: false,
+		},
+		{
+			name: "fail get user",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				name: "foos",
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := GetUser(tt.args.ctx, tt.args.addr, tt.args.name)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("GetUser() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status == tt.want.Status {
+				if got.User.Name != tt.want.User.Name || got.User.Id != tt.want.User.Id {
+					t.Errorf("GetUser() = %v, want %v", got, tt.want)
+				}
+			} else {
+				if got != nil {
+					t.Errorf("GetUser() = %v, want %v", got, tt.want)
+				}
+			}
+		})
+	}
+}
+
+func TestGetAllUsers(t *testing.T) {
+	err := clearAndCreateAuthTestSetup()
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	type args struct {
+		ctx  context.Context
+		addr string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.GetUsersResponse
+		wantLen int
+		wantErr bool
+	}{
+		{
+			name: "default get users",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+			},
+			want: &apb.GetUsersResponse{
+				Status: apb.Status_STATUS_OK,
+				User: []*apb.User{
+					{Name: "testAdmin"},
+					{Name: "testUser"},
+					{Name: "testRandom"}},
+			},
+			wantLen: 3,
+			wantErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := GetAllUsers(tt.args.ctx, tt.args.addr)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("GetAllUsers() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status == apb.Status_STATUS_OK {
+				if len(got.User) != tt.wantLen {
+					t.Errorf("User.GetUsers() = %v, want %v", got, tt.want)
+				}
+
+				for _, gotU := range got.User {
+					containsExpected := false
+					for _, wantU := range tt.want.User {
+						if gotU.Name == wantU.Name {
+							containsExpected = true
+							break
+						}
+					}
+					if !containsExpected {
+						t.Errorf("User.GetUsers() = %v, want %v", got, tt.want)
+					}
+				}
+			}
+		})
+	}
+}
+
+func TestUpdateUsers(t *testing.T) {
+	type args struct {
+		ctx   context.Context
+		addr  string
+		users []*apb.User
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.UpdateUsersResponse
+		wantErr bool
+	}{
+		{
+			name: "default update user",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				users: []*apb.User{
+					{
+						Id:   adminID,
+						Name: "sth Else",
+					},
+				},
+			},
+			want: &apb.UpdateUsersResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+		{
+			name: "error update user",
+			args: args{
+				ctx:  context.TODO(),
+				addr: testAPIEndpoint,
+				users: []*apb.User{
+					{
+						Id:   uuid.NewString(),
+						Name: "not a User",
+					},
+				},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := UpdateUsers(tt.args.ctx, tt.args.addr, tt.args.users)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("UpdateUsers() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("UpdateUsers() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestDeleteUsers(t *testing.T) {
+	type args struct {
+		ctx       context.Context
+		addr      string
+		userNames []string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.DeleteUsersResponse
+		wantErr bool
+	}{
+		{
+			name: "default delete users",
+			args: args{
+				ctx:       context.TODO(),
+				addr:      testAPIEndpoint,
+				userNames: []string{"testUser", "testAdmin"},
+			},
+			want: &apb.DeleteUsersResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+		{
+			name: "error delete users",
+			args: args{
+				ctx:       context.TODO(),
+				addr:      testAPIEndpoint,
+				userNames: []string{"no User"},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := DeleteUsers(tt.args.ctx, tt.args.addr, tt.args.userNames)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("DeleteUsers() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("User.DeleteUsers() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/controller/controller.go b/controller/controller.go
index d579f1f8a488074ddb4be07497ef0045ebe5a1a1..c3c49d2cc589faa686d40106a0842512e043636d 100644
--- a/controller/controller.go
+++ b/controller/controller.go
@@ -178,17 +178,17 @@ func ensureDefaultRoleExists() error {
 			"/gosdn.core.CoreService/GetPndList",
 			"/gosdn.core.CoreService/CreatePndList",
 			"/gosdn.core.CoreService/DeletePnd",
-			"/gosdn.rbac.AuthService/CreateUsers",
-			"/gosdn.rbac.AuthService/GetUser",
-			"/gosdn.rbac.AuthService/GetUsers",
-			"/gosdn.rbac.AuthService/UpdateUsers",
-			"/gosdn.rbac.AuthService/DeleteUsers",
-			"/gosdn.rbac.AuthService/CreateRoles",
-			"/gosdn.rbac.AuthService/GetRole",
-			"/gosdn.rbac.AuthService/GetRoles",
-			"/gosdn.rbac.AuthService/UpdateRoles",
-			"/gosdn.rbac.AuthService/DeletePermissionsForRole",
-			"/gosdn.rbac.AuthService/DeleteRoles",
+			"/gosdn.rbac.UserService/CreateUsers",
+			"/gosdn.rbac.UserService/GetUser",
+			"/gosdn.rbac.UserService/GetUsers",
+			"/gosdn.rbac.UserService/UpdateUsers",
+			"/gosdn.rbac.UserService/DeleteUsers",
+			"/gosdn.rbac.RoleService/CreateRoles",
+			"/gosdn.rbac.RoleService/GetRole",
+			"/gosdn.rbac.RoleService/GetRoles",
+			"/gosdn.rbac.RoleService/UpdateRoles",
+			"/gosdn.rbac.RoleService/DeletePermissionsForRole",
+			"/gosdn.rbac.RoleService/DeleteRoles",
 			"/gosdn.pnd.PndService/GetOnd",
 			"/gosdn.pnd.PndService/GetOndList",
 			"/gosdn.pnd.PndService/GetSbi",
diff --git a/controller/northbound/server/auth.go b/controller/northbound/server/auth.go
index 4c159193a9e65bd2e56698ba2c11da7a7cb47202..4507b5f1d1711d740bfaf96130cf0268e8c53f9c 100644
--- a/controller/northbound/server/auth.go
+++ b/controller/northbound/server/auth.go
@@ -8,9 +8,7 @@ import (
 	"code.fbi.h-da.de/danet/gosdn/controller/metrics"
 	"code.fbi.h-da.de/danet/gosdn/controller/rbac"
 	"code.fbi.h-da.de/danet/gosdn/controller/store"
-	"github.com/google/uuid"
 	"github.com/prometheus/client_golang/prometheus"
-	log "github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
@@ -87,145 +85,6 @@ func (s Auth) Logout(ctx context.Context, request *apb.LogoutRequest) (*apb.Logo
 	}, nil
 }
 
-// CreateUsers creates new users, can be 1 or more
-func (s Auth) CreateUsers(ctx context.Context, request *apb.CreateUsersRequest) (*apb.CreateUsersResponse, error) {
-	labels := prometheus.Labels{"service": "auth", "rpc": "post"}
-	start := metrics.StartHook(labels, grpcRequestsTotal)
-	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
-
-	// TODO: implement check if user is allowed to create users with this role
-	// e.g. non-admin shouldn't be allowed to create admin users
-	for _, u := range request.User {
-		roles := map[string]string{}
-		for key, elem := range u.Roles {
-			_, err := uuid.Parse(key)
-			if err != nil {
-				return nil, handleRPCError(labels, err)
-			}
-			roles[key] = elem
-		}
-
-		user := rbac.NewUser(uuid.New(), u.Name, roles, u.Password, u.Token)
-		err := userc.Add(user)
-		if err != nil {
-			log.Error(err)
-			return nil, status.Errorf(codes.Aborted, "%v", err)
-		}
-	}
-
-	return &apb.CreateUsersResponse{
-		Timestamp: time.Now().UnixNano(),
-		Status:    apb.Status_STATUS_OK,
-	}, nil
-}
-
-// GetUser returns one user by name.
-func (s Auth) GetUser(ctx context.Context, request *apb.GetUserRequest) (*apb.GetUserResponse, error) {
-	labels := prometheus.Labels{"service": "auth", "rpc": "get"}
-	start := metrics.StartHook(labels, grpcRequestsTotal)
-	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
-
-	// TODO: implement check if user is allowed to get this user data; only their own if not admin
-	userData, err := userc.Get(store.Query{Name: request.Name})
-	if err != nil {
-		return nil, err
-	}
-
-	user := &apb.User{
-		Id:    userData.ID().String(),
-		Name:  userData.Name(),
-		Roles: userData.GetRoles(),
-	}
-
-	return &apb.GetUserResponse{
-		Timestamp: time.Now().UnixNano(),
-		Status:    apb.Status_STATUS_OK,
-		User:      user,
-	}, nil
-}
-
-// GetUsers returns all availbale users
-func (s Auth) GetUsers(ctx context.Context, request *apb.GetUsersRequest) (*apb.GetUsersResponse, error) {
-	labels := prometheus.Labels{"service": "auth", "rpc": "get"}
-	start := metrics.StartHook(labels, grpcRequestsTotal)
-	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
-
-	userList, err := userc.GetAll()
-	if err != nil {
-		return nil, err
-	}
-
-	users := []*apb.User{}
-	for _, u := range userList {
-		users = append(users, &apb.User{
-			Id:    u.ID().String(),
-			Name:  u.Name(),
-			Roles: u.GetRoles(),
-		})
-	}
-
-	return &apb.GetUsersResponse{
-		Timestamp: time.Now().UnixNano(),
-		Status:    apb.Status_STATUS_OK,
-		User:      users,
-	}, nil
-}
-
-// UpdateUsers updates the user data of one or more users provided in the request
-func (s Auth) UpdateUsers(ctx context.Context, request *apb.UpdateUsersRequest) (*apb.UpdateUsersResponse, error) {
-	labels := prometheus.Labels{"service": "auth", "rpc": "post"}
-	start := metrics.StartHook(labels, grpcRequestsTotal)
-	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
-
-	// TODO: check if current user is allowed to update the user they try to update; only their own if not admin
-	for _, u := range request.User {
-		uid, err := uuid.Parse(u.Id)
-		if err != nil {
-			return nil, handleRPCError(labels, err)
-		}
-
-		_, err = userc.Get(store.Query{ID: uid})
-		if err != nil {
-			return nil, status.Errorf(codes.Canceled, "user not found %v", err)
-		}
-
-		userToUpdate := rbac.NewUser(uid, u.Name, u.Roles, u.Password, u.Token)
-
-		err = userc.Update(userToUpdate)
-		if err != nil {
-			return nil, status.Errorf(codes.Aborted, "could not update user %v", err)
-		}
-	}
-
-	return &apb.UpdateUsersResponse{
-		Timestamp: time.Now().UnixNano(),
-		Status:    apb.Status_STATUS_OK,
-	}, nil
-}
-
-// DeleteUsers deletes one or more users provided in the request
-func (s Auth) DeleteUsers(ctx context.Context, request *apb.DeleteUsersRequest) (*apb.DeleteUsersResponse, error) {
-	labels := prometheus.Labels{"service": "auth", "rpc": "delete"}
-	start := metrics.StartHook(labels, grpcRequestsTotal)
-	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
-
-	for _, u := range request.Username {
-		userToDelete, err := userc.Get(store.Query{Name: u})
-		if err != nil {
-			return nil, status.Errorf(codes.Canceled, "user not found %v", err)
-		}
-
-		err = userc.Delete(userToDelete)
-		if err != nil {
-			return nil, status.Errorf(codes.Aborted, "error deleting user %v", err)
-		}
-	}
-	return &apb.DeleteUsersResponse{
-		Timestamp: time.Now().UnixNano(),
-		Status:    apb.Status_STATUS_OK,
-	}, nil
-}
-
 func (s Auth) isValidUser(user rbac.User) (bool, error) {
 	storedUser, err := userc.Get(store.Query{Name: user.Name()})
 	if err != nil {
@@ -242,175 +101,3 @@ func (s Auth) isValidUser(user rbac.User) (bool, error) {
 
 	return false, status.Errorf(codes.Unauthenticated, "incorrect user name or password")
 }
-
-// CreateRoles creates roles with permissions for the roles used in rbac.
-func (s Auth) CreateRoles(ctx context.Context, request *apb.CreateRolesRequest) (*apb.CreateRolesResponse, error) {
-	labels := prometheus.Labels{"service": "auth", "rpc": "post"}
-	start := metrics.StartHook(labels, grpcRequestsTotal)
-	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
-
-	for _, r := range request.Roles {
-		role := rbac.NewRole(uuid.New(), r.Name, r.Description, r.Permissions)
-
-		err := rolec.Add(role)
-		if err != nil {
-			log.Error(err)
-			return nil, status.Errorf(codes.Aborted, "%v", err)
-		}
-	}
-
-	return &apb.CreateRolesResponse{
-		Timestamp: time.Now().UnixNano(),
-		Status:    apb.Status_STATUS_OK,
-	}, nil
-}
-
-// GetRole returns one role with its permissions found by name.
-func (s Auth) GetRole(ctx context.Context, request *apb.GetRoleRequest) (*apb.GetRoleResponse, error) {
-	labels := prometheus.Labels{"service": "auth", "rpc": "get"}
-	start := metrics.StartHook(labels, grpcRequestsTotal)
-	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
-
-	roleData, err := rolec.Get(store.Query{Name: request.RoleName})
-	if err != nil {
-		return nil, err
-	}
-
-	role := &apb.Role{
-		Id:          roleData.ID().String(),
-		Name:        roleData.Name(),
-		Description: roleData.GetDescription(),
-		Permissions: roleData.GetPermissions(),
-	}
-
-	return &apb.GetRoleResponse{
-		Timestamp: time.Now().UnixNano(),
-		Status:    apb.Status_STATUS_OK,
-		Role:      role,
-	}, nil
-}
-
-// GetRoles returns all roles with their permissions.
-func (s Auth) GetRoles(ctx context.Context, request *apb.GetRolesRequest) (*apb.GetRolesResponse, error) {
-	labels := prometheus.Labels{"service": "auth", "rpc": "get"}
-	start := metrics.StartHook(labels, grpcRequestsTotal)
-	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
-
-	roleList, err := rolec.GetAll()
-	if err != nil {
-		return nil, err
-	}
-
-	roles := []*apb.Role{}
-	for _, r := range roleList {
-		roles = append(roles, &apb.Role{
-			Id:          r.ID().String(),
-			Name:        r.Name(),
-			Description: r.GetDescription(),
-			Permissions: r.GetPermissions(),
-		})
-	}
-
-	return &apb.GetRolesResponse{
-		Timestamp: time.Now().UnixNano(),
-		Status:    apb.Status_STATUS_OK,
-		Roles:     roles,
-	}, nil
-}
-
-// UpdateRoles updates data of the provided roles.
-func (s Auth) UpdateRoles(ctx context.Context, request *apb.UpdateRolesRequest) (*apb.UpdateRolesResponse, error) {
-	labels := prometheus.Labels{"service": "auth", "rpc": "post"}
-	start := metrics.StartHook(labels, grpcRequestsTotal)
-	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
-
-	// TODO: check if current user is allowed to update the role they try to update; only their own if not admin
-	for _, r := range request.Roles {
-		rid, err := uuid.Parse(r.Id)
-		if err != nil {
-			return nil, handleRPCError(labels, err)
-		}
-
-		_, err = rolec.Get(store.Query{ID: rid})
-		if err != nil {
-			return nil, status.Errorf(codes.Canceled, "role not found %v", err)
-		}
-
-		roleToUpdate := rbac.NewRole(rid, r.Name, r.Description, r.Permissions)
-		err = rolec.Update(roleToUpdate)
-		if err != nil {
-			return nil, status.Errorf(codes.Aborted, "could not update role %v", err)
-		}
-	}
-
-	return &apb.UpdateRolesResponse{
-		Timestamp: time.Now().UnixNano(),
-		Status:    apb.Status_STATUS_OK,
-	}, nil
-}
-
-// DeletePermissionsForRole deletes the provided permissions from one role found by name.
-func (s Auth) DeletePermissionsForRole(ctx context.Context, request *apb.DeletePermissionsForRoleRequest) (*apb.DeletePermissionsForRoleResponse, error) {
-	labels := prometheus.Labels{"service": "auth", "rpc": "delete"}
-	start := metrics.StartHook(labels, grpcRequestsTotal)
-	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
-
-	roleToUpdate, err := rolec.Get(store.Query{Name: request.RoleName})
-	if err != nil {
-		return nil, status.Errorf(codes.Canceled, "role not found %v", err)
-	}
-
-	// checks if there is at least one valid permission to delete
-	// in the provided set of permissions to delete
-	nonFound := true
-	for _, perm := range roleToUpdate.GetPermissions() {
-		for _, permToDelete := range request.PermissionsToDelete {
-			if perm == permToDelete {
-				nonFound = false
-				break
-			}
-		}
-		if !nonFound {
-			break
-		}
-	}
-	if nonFound {
-		return nil, status.Errorf(codes.Canceled, "no fitting permissions")
-	}
-
-	// updates the existing role with the trimmed set of permissions
-	roleToUpdate.RemovePermissionsFromRole(request.PermissionsToDelete)
-	err = rolec.Update(roleToUpdate)
-	if err != nil {
-		return nil, status.Errorf(codes.Aborted, "could not update role %v", err)
-	}
-
-	return &apb.DeletePermissionsForRoleResponse{
-		Timestamp: time.Now().UnixNano(),
-		Status:    apb.Status_STATUS_OK,
-	}, nil
-}
-
-// DeleteRoles deletes all the provided roles with their permissions.
-func (s Auth) DeleteRoles(ctx context.Context, request *apb.DeleteRolesRequest) (*apb.DeleteRolesResponse, error) {
-	labels := prometheus.Labels{"service": "auth", "rpc": "delete"}
-	start := metrics.StartHook(labels, grpcRequestsTotal)
-	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
-
-	for _, r := range request.RoleName {
-		roleToDelete, err := rolec.Get(store.Query{Name: r})
-		if err != nil {
-			return nil, status.Errorf(codes.Canceled, "role not found")
-		}
-
-		err = rolec.Delete(roleToDelete)
-		if err != nil {
-			return nil, status.Errorf(codes.Aborted, "error deleting role %v", err)
-		}
-	}
-
-	return &apb.DeleteRolesResponse{
-		Timestamp: time.Now().UnixNano(),
-		Status:    apb.Status_STATUS_OK,
-	}, nil
-}
diff --git a/controller/northbound/server/auth_interceptor.go b/controller/northbound/server/auth_interceptor.go
index 45768c5bcadde8442d897dcb388671b5b319e6dd..47c80e02379a1c71127683caeba362116ea580b5 100644
--- a/controller/northbound/server/auth_interceptor.go
+++ b/controller/northbound/server/auth_interceptor.go
@@ -131,10 +131,12 @@ func (auth *AuthInterceptor) verifyUserRoleAndRequestedCall(userRole, requestedM
 			if err != nil {
 				return err
 			}
+
+			return nil
 		}
 	}
 
-	return nil
+	return status.Errorf(codes.PermissionDenied, "wrong permissions")
 }
 
 func (auth *AuthInterceptor) compareRequestedPermissionWithRolePermissions(requestedMethod string, storedRolePermissions []string) error {
diff --git a/controller/northbound/server/auth_interceptor_test.go b/controller/northbound/server/auth_interceptor_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..2d975d9191ad0c6c84ecf396e2e07df87046b43b
--- /dev/null
+++ b/controller/northbound/server/auth_interceptor_test.go
@@ -0,0 +1,248 @@
+package server
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"net"
+	"testing"
+
+	apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
+	spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials/insecure"
+	"google.golang.org/grpc/metadata"
+	"google.golang.org/grpc/test/bufconn"
+)
+
+func dialer() func(context.Context, string) (net.Conn, error) {
+	listener := bufconn.Listen(1024 * 1024)
+
+	interceptor := NewAuthInterceptor(jwt)
+	server := grpc.NewServer(grpc.UnaryInterceptor(interceptor.Unary()), grpc.StreamInterceptor(interceptor.Stream()))
+
+	apb.RegisterUserServiceServer(server, &User{})
+	spb.RegisterSbiServiceServer(server, &sbiServer{})
+
+	go func() {
+		if err := server.Serve(listener); err != nil {
+			log.Fatal(err)
+		}
+	}()
+
+	return func(context.Context, string) (net.Conn, error) {
+		return listener.Dial()
+	}
+}
+
+func TestAuthInterceptor_Unary(t *testing.T) {
+	validToken, err := createTestUserToken("testAdmin", true)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	wrongUserToken, err := createTestUserToken("foo", false)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	ctx := context.Background()
+	conn, err := grpc.DialContext(ctx, "", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithContextDialer(dialer()))
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer conn.Close()
+
+	client := apb.NewUserServiceClient(conn)
+
+	type args struct {
+		ctx     context.Context
+		request *apb.GetUsersRequest
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.GetUsersResponse
+		wantErr bool
+	}{
+		{
+			name: "default unary interceptor",
+			args: args{
+				ctx:     metadata.NewOutgoingContext(context.Background(), metadata.Pairs("authorize", validToken)),
+				request: &apb.GetUsersRequest{},
+			},
+			want: &apb.GetUsersResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+		{
+			name: "error unary invalid user token",
+			args: args{
+				ctx:     metadata.NewOutgoingContext(context.Background(), metadata.Pairs("authorize", wrongUserToken)),
+				request: &apb.GetUsersRequest{},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+		{
+			name: "error unary invalid token string",
+			args: args{
+				ctx:     metadata.NewOutgoingContext(context.Background(), metadata.Pairs("authorize", "foo")),
+				request: &apb.GetUsersRequest{},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+		{
+			name: "error unary no token in metadata",
+			args: args{
+				ctx:     metadata.NewOutgoingContext(context.Background(), metadata.Pairs("foo", "foo")),
+				request: &apb.GetUsersRequest{},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := client.GetUsers(tt.args.ctx, tt.args.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("AuthInterceptor.Unary() = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("AuthInterceptor.Unary() = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+		})
+	}
+}
+
+func TestAuthInterceptor_Stream(t *testing.T) {
+	validToken, err := createTestUserToken("testAdmin", true)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	ctx := context.Background()
+	conn, err := grpc.DialContext(ctx, "", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithContextDialer(dialer()))
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer conn.Close()
+
+	client := spb.NewSbiServiceClient(conn)
+
+	type args struct {
+		ctx     context.Context
+		request *spb.GetSchemaRequest
+	}
+	tests := []struct {
+		name string
+		args args
+		want bool
+	}{
+		{
+			name: "default stream interceptor",
+			args: args{
+				ctx: metadata.NewOutgoingContext(context.Background(), metadata.Pairs("authorize", validToken)),
+				request: &spb.GetSchemaRequest{
+					Pid: pndID,
+					Sid: sbiID,
+				},
+			},
+			want: true,
+		},
+		{
+			name: "error stream interceptor",
+			args: args{
+				ctx: metadata.NewOutgoingContext(context.Background(), metadata.Pairs("authorize", "foo")),
+				request: &spb.GetSchemaRequest{
+					Pid: pndID,
+					Sid: sbiID,
+				},
+			},
+			want: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := client.GetSchema(tt.args.ctx, tt.args.request)
+			if err != nil {
+				t.Errorf("AuthInterceptor.Stream() = %v", err)
+				return
+			}
+
+			payload, _ := got.Recv()
+			if (payload != nil) != tt.want {
+				t.Errorf("AuthInterceptor.Stream() = %v", tt.want)
+				return
+			}
+		})
+	}
+}
+
+func TestAuthInterceptor_authorize(t *testing.T) {
+	validToken, err := createTestUserToken("testAdmin", true)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	wrongUserToken, err := createTestUserToken("foo", false)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	md := metadata.Pairs("authorize", validToken)
+	fmt.Println(md.Get("authorize"))
+
+	type args struct {
+		ctx    context.Context
+		method string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		wantErr bool
+	}{
+		{
+			name: "default authorize",
+			args: args{
+				ctx:    metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorize", validToken)),
+				method: "/gosdn.rbac.UserService/GetUsers",
+			},
+			wantErr: false,
+		},
+		{
+			name: "error invalid token",
+			args: args{
+				ctx:    metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorize", wrongUserToken)),
+				method: "/gosdn.rbac.UserService/GetUsers",
+			},
+			wantErr: true,
+		},
+		{
+			name: "error no permission for request",
+			args: args{
+				ctx:    metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorize", validToken)),
+				method: "/gosdn.pnd.PndService/DeleteOnd",
+			},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			auth := &AuthInterceptor{
+				jwtManager: jwt,
+			}
+
+			if err := auth.authorize(tt.args.ctx, tt.args.method); (err != nil) != tt.wantErr {
+				t.Errorf("AuthInterceptor.authorize() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
diff --git a/controller/northbound/server/auth_test.go b/controller/northbound/server/auth_test.go
index 8681ca7cb016d73c9ffcb9859a36be747655229d..0c25776247e69ae087ced41f22f6be073515baef 100644
--- a/controller/northbound/server/auth_test.go
+++ b/controller/northbound/server/auth_test.go
@@ -1,26 +1,12 @@
 package server
 
 import (
-	"bytes"
 	"context"
-	"log"
-	"reflect"
 	"testing"
 
 	apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
-	"code.fbi.h-da.de/danet/gosdn/controller/rbac"
-	"github.com/google/uuid"
 )
 
-const adminID = "5c248a22-8eb7-48cf-b392-45680a1863a5"
-const userID = "57005d13-7a4d-493d-a02b-50ca51c40197"
-const adminRoleID = "126683ae-5ff2-43ee-92f7-0e2b936f8c77"
-const randomRoleName = "bertram"
-
-var adminRoleMap = map[string]string{pndID: "admin"}
-var userRoleMap = map[string]string{pndID: "user"}
-var jwt *rbac.JWTManager
-
 func TestAuth_Login(t *testing.T) {
 	type args struct {
 		ctx     context.Context
@@ -87,766 +73,34 @@ func TestAuth_Logout(t *testing.T) {
 		args    args
 		want    *apb.LogoutResponse
 		wantErr bool
-	}{
-		// TODO: Add test cases.
-		// Implement after session hdanling was added
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			s := Auth{}
-			got, err := s.Logout(tt.args.ctx, tt.args.request)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Auth.Logout() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-			if !reflect.DeepEqual(got, tt.want) {
-				t.Errorf("Auth.Logout() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestAuth_CreateUsers(t *testing.T) {
-	type args struct {
-		ctx     context.Context
-		request *apb.CreateUsersRequest
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    apb.Status
-		wantErr bool
 	}{
 		{
-			name: "default create users",
-			args: args{ctx: context.TODO(),
-				request: &apb.CreateUsersRequest{
-					User: []*apb.User{
-						{
-							Name:     "asdf",
-							Roles:    map[string]string{pndID: "asdf"},
-							Password: "asdf",
-							Token:    "",
-						},
-					},
-				},
-			},
-			want:    apb.Status_STATUS_OK,
-			wantErr: false,
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			s := Auth{}
-			got, err := s.CreateUsers(tt.args.ctx, tt.args.request)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Auth.CreateUsers() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-
-			if !reflect.DeepEqual(got.Status, tt.want) {
-				t.Errorf("Auth.CreateUsers() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestAuth_GetUser(t *testing.T) {
-	patchLogger(t)
-	type args struct {
-		ctx     context.Context
-		request *apb.GetUserRequest
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    *apb.GetUserResponse
-		wantErr bool
-	}{
-		{
-			name: "default get user",
+			name: "default log out",
 			args: args{
 				ctx: context.TODO(),
-				request: &apb.GetUserRequest{
-					Name: "testAdmin",
-				},
-			},
-			want: &apb.GetUserResponse{Status: apb.Status_STATUS_OK,
-				User: &apb.User{Id: adminID,
-					Name: "testAdmin"}},
-			wantErr: false,
-		},
-		{
-			name: "fail get user",
-			args: args{
-				ctx: context.TODO(),
-				request: &apb.GetUserRequest{
-					Name: "nope",
-				},
-			},
-			want:    nil,
-			wantErr: true,
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			s := Auth{}
-			got, err := s.GetUser(tt.args.ctx, tt.args.request)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Auth.GetUser() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-
-			if got != nil && got.Status == tt.want.Status {
-				if got.User.Name != tt.want.User.Name || got.User.Id != tt.want.User.Id {
-					t.Errorf("Auth.GetUser() = %v, want %v", got, tt.want)
-				}
-			} else {
-				if got != nil {
-					t.Errorf("Auth.GetUser() = %v, want %v", got, tt.want)
-				}
-			}
-		})
-	}
-}
-
-func TestAuth_GetUsers(t *testing.T) {
-	err := clearAndCreateAuthTestSetup()
-	if err != nil {
-		t.Fatalf("%v", err)
-	}
-	type args struct {
-		ctx     context.Context
-		request *apb.GetUsersRequest
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    *apb.GetUsersResponse
-		wantLen int
-		wantErr bool
-	}{
-		{
-			name: "default get users",
-			args: args{ctx: context.TODO(),
-				request: &apb.GetUsersRequest{},
-			},
-			want: &apb.GetUsersResponse{Status: apb.Status_STATUS_OK,
-				User: []*apb.User{
-					{Name: "testAdmin"},
-					{Name: "testUser"},
-					{Name: "testRandom"}},
-			},
-			wantLen: 3,
-			wantErr: false,
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			s := Auth{}
-			got, err := s.GetUsers(tt.args.ctx, tt.args.request)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Auth.GetUsers() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-
-			if got != nil && got.Status == apb.Status_STATUS_OK {
-				if len(got.User) != tt.wantLen {
-					t.Errorf("Auth.GetUsers() = %v, want %v", got, tt.want)
-				}
-
-				for _, gotU := range got.User {
-					containsExpected := false
-					for _, wantU := range tt.want.User {
-						if gotU.Name == wantU.Name {
-							containsExpected = true
-							break
-						}
-					}
-					if !containsExpected {
-						t.Errorf("Auth.GetUsers() = %v, want %v", got, tt.want)
-					}
-				}
-			}
-		})
-	}
-}
-
-func TestAuth_UpdateUsers(t *testing.T) {
-	type args struct {
-		ctx     context.Context
-		request *apb.UpdateUsersRequest
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    *apb.UpdateUsersResponse
-		wantErr bool
-	}{
-		{
-			name: "default update user",
-			args: args{ctx: context.TODO(),
-				request: &apb.UpdateUsersRequest{User: []*apb.User{
-					{Id: adminID,
-						Name: "sth Else"},
-				},
-				},
-			},
-			want: &apb.UpdateUsersResponse{
-				Status: apb.Status_STATUS_OK},
-			wantErr: false,
-		},
-		{
-			name: "error update user",
-			args: args{ctx: context.TODO(),
-				request: &apb.UpdateUsersRequest{User: []*apb.User{
-					{Id: uuid.NewString(),
-						Name: "not a user"},
-				},
-				},
-			},
-			want:    nil,
-			wantErr: true,
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			s := Auth{}
-			got, err := s.UpdateUsers(tt.args.ctx, tt.args.request)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Auth.UpdateUsers() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-			if got != nil && got.Status != tt.want.Status {
-				t.Errorf("Auth.UpdateUsers() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestAuth_DeleteUsers(t *testing.T) {
-	type args struct {
-		ctx     context.Context
-		request *apb.DeleteUsersRequest
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    *apb.DeleteUsersResponse
-		wantErr bool
-	}{
-		{
-			name: "default delete users",
-			args: args{ctx: context.TODO(),
-				request: &apb.DeleteUsersRequest{Username: []string{"testUser"}},
-			},
-			want:    &apb.DeleteUsersResponse{Status: apb.Status_STATUS_OK},
-			wantErr: false,
-		},
-		{
-			name: "error delete users",
-			args: args{ctx: context.TODO(),
-				request: &apb.DeleteUsersRequest{Username: []string{"no user"}},
-			},
-			want:    &apb.DeleteUsersResponse{Status: apb.Status_STATUS_OK},
-			wantErr: true,
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			s := Auth{}
-			got, err := s.DeleteUsers(tt.args.ctx, tt.args.request)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Auth.DeleteUsers() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-			if got != nil && got.Status != tt.want.Status {
-				t.Errorf("Auth.DeleteUsers() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestAuth_CreateRoles(t *testing.T) {
-	type args struct {
-		ctx     context.Context
-		request *apb.CreateRolesRequest
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    *apb.CreateRolesResponse
-		wantErr bool
-	}{
-		{
-			name: "default create roles",
-			args: args{ctx: context.TODO(),
-				request: &apb.CreateRolesRequest{
-					Roles: []*apb.Role{
-						{
-							Name:        "new role 1",
-							Description: "Role 1",
-							Permissions: []string{"permission 1", "permission 2"},
-						},
-					},
-				},
-			},
-			want:    &apb.CreateRolesResponse{Status: apb.Status_STATUS_OK},
-			wantErr: false,
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			s := Auth{}
-			got, err := s.CreateRoles(tt.args.ctx, tt.args.request)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Auth.CreateRoles() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-
-			if got != nil && got.Status != tt.want.Status {
-				t.Errorf("Auth.CreateRoles() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestAuth_GetRole(t *testing.T) {
-	type args struct {
-		ctx     context.Context
-		request *apb.GetRoleRequest
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    *apb.GetRoleResponse
-		wantErr bool
-	}{
-		{
-			name: "default get role",
-			args: args{
-				ctx: context.TODO(),
-				request: &apb.GetRoleRequest{
-					RoleName: "adminTestRole",
+				request: &apb.LogoutRequest{
+					Username: "testAdmin",
 				},
 			},
-			want: &apb.GetRoleResponse{
-				Role: &apb.Role{
-					Name:        "adminTestRole",
-					Description: "Admin",
-				},
+			want: &apb.LogoutResponse{
 				Status: apb.Status_STATUS_OK,
 			},
 			wantErr: false,
 		},
-		{
-			name: "error get role",
-			args: args{
-				ctx: context.TODO(),
-				request: &apb.GetRoleRequest{
-					RoleName: "not role",
-				},
-			},
-			want:    nil,
-			wantErr: true,
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			s := Auth{}
-			got, err := s.GetRole(tt.args.ctx, tt.args.request)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Auth.GetRole() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-			if got != nil && got.Status == tt.want.Status {
-				if got.Role.Name != tt.want.Role.Name || got.Role.Description != tt.want.Role.Description {
-					t.Errorf("Auth.GetRole() = %v, want %v", got, tt.want)
-				}
-			} else {
-				if got != nil {
-					t.Errorf("Auth.GetRole() = %v, want %v", got, tt.want)
-				}
-			}
-		})
-	}
-}
-
-func TestAuth_GetRoles(t *testing.T) {
-	err := clearAndCreateAuthTestSetup()
-	if err != nil {
-		t.Fatalf("%v", err)
 	}
 
-	type args struct {
-		ctx     context.Context
-		request *apb.GetRolesRequest
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    *apb.GetRolesResponse
-		wantLen int
-		wantErr bool
-	}{
-		{
-			name: "default get roles",
-			args: args{
-				ctx:     context.TODO(),
-				request: &apb.GetRolesRequest{},
-			},
-			want: &apb.GetRolesResponse{
-				Status: apb.Status_STATUS_OK,
-				Roles: []*apb.Role{
-					{
-						Name:        "adminTestRole",
-						Description: "Admin",
-						Permissions: []string{
-							"/gosdn.core.CoreService/GetPnd",
-							"/gosdn.core.CoreService/GetPndList",
-						}},
-					{
-						Name:        "userTestRole",
-						Description: "User",
-						Permissions: []string{
-							"/gosdn.pnd.PndService/GetChangeList",
-						}},
-					{
-						Name:        randomRoleName,
-						Description: "Not a role",
-						Permissions: []string{
-							"nope",
-						},
-					},
-				},
-			},
-			wantLen: 3,
-			wantErr: false,
-		},
-	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			s := Auth{}
-			got, err := s.GetRoles(tt.args.ctx, tt.args.request)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Auth.GetRoles() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-			if got != nil && got.Status == tt.want.Status {
-				if len(got.Roles) != 3 {
-					t.Errorf("Auth.GetRoles() = %v, want %v", got, tt.want)
-				}
-				for _, gotR := range got.Roles {
-					containsExpected := false
-					for _, wantR := range tt.want.Roles {
-						gotPerm := gotR.Permissions
-						wantPerm := wantR.Permissions
-						if gotR.Description == wantR.Description && gotR.Name == wantR.Name &&
-							reflect.DeepEqual(gotPerm, wantPerm) {
-							containsExpected = true
-							break
-						}
-					}
-					if !containsExpected {
-						t.Errorf("Auth.GetRoles() = %v, want %v", got, tt.want)
-					}
-				}
-			}
-		})
-	}
-}
-
-func TestAuth_UpdateRoles(t *testing.T) {
-	type args struct {
-		ctx     context.Context
-		request *apb.UpdateRolesRequest
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    *apb.UpdateRolesResponse
-		wantErr bool
-	}{
-		{
-			name: "default update roles",
-			args: args{
-				ctx: context.TODO(),
-				request: &apb.UpdateRolesRequest{
-					Roles: []*apb.Role{
-						{
-							Id:   adminRoleID,
-							Name: "New Name",
-						},
-					},
-				},
-			},
-			want: &apb.UpdateRolesResponse{
-				Status: apb.Status_STATUS_OK,
-			},
-			wantErr: false,
-		},
-		{
-			name: "error update roles",
-			args: args{
-				ctx: context.TODO(),
-				request: &apb.UpdateRolesRequest{
-					Roles: []*apb.Role{
-						{
-							Id:   uuid.NewString(),
-							Name: "New Name",
-						},
-					},
-				},
-			},
-			want:    nil,
-			wantErr: true,
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			s := Auth{}
-			got, err := s.UpdateRoles(tt.args.ctx, tt.args.request)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Auth.UpdateRoles() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
-			if got != nil && got.Status != tt.want.Status {
-				t.Errorf("Auth.UpdateRoles() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
-
-func TestAuth_DeletePermissionsForRole(t *testing.T) {
-	clearAndCreateAuthTestSetup()
-	type args struct {
-		ctx     context.Context
-		request *apb.DeletePermissionsForRoleRequest
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    *apb.DeletePermissionsForRoleResponse
-		wantErr bool
-	}{
-		{
-			name: "default delete permissions for role",
-			args: args{
-				ctx: context.TODO(),
-				request: &apb.DeletePermissionsForRoleRequest{
-					RoleName: "adminTestRole",
-					PermissionsToDelete: []string{
-						"/gosdn.core.CoreService/GetPnd",
-						"/gosdn.core.CoreService/GetPndList",
-					},
-				},
-			},
-			want: &apb.DeletePermissionsForRoleResponse{
-				Status: apb.Status_STATUS_OK,
-			},
-			wantErr: false,
-		},
-		{
-			name: "error delete permissions for role no proper permissions provided",
-			args: args{
-				ctx: context.TODO(),
-				request: &apb.DeletePermissionsForRoleRequest{
-					RoleName: "adminTestRole",
-					PermissionsToDelete: []string{
-						"no",
-					},
-				},
-			},
-			want: &apb.DeletePermissionsForRoleResponse{
-				Status: apb.Status_STATUS_OK,
-			},
-			wantErr: true,
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			s := Auth{}
-			got, err := s.DeletePermissionsForRole(tt.args.ctx, tt.args.request)
+			got, err := s.Logout(tt.args.ctx, tt.args.request)
 			if (err != nil) != tt.wantErr {
-				t.Errorf("Auth.DeletePermissionsForRole() error = %v, wantErr %v", err, tt.wantErr)
+				t.Errorf("Auth.Logout() error = %v, wantErr %v", err, tt.wantErr)
 				return
 			}
-			if got != nil && got.Status != tt.want.Status {
-				t.Errorf("Auth.DeletePermissionsForRole() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
 
-func TestAuth_DeleteRoles(t *testing.T) {
-	type args struct {
-		ctx     context.Context
-		request *apb.DeleteRolesRequest
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    *apb.DeleteRolesResponse
-		wantErr bool
-	}{
-		{
-			name: "default delete roles",
-			args: args{
-				ctx: context.TODO(),
-				request: &apb.DeleteRolesRequest{
-					RoleName: []string{
-						"userTestRole",
-					},
-				},
-			},
-			want: &apb.DeleteRolesResponse{
-				Status: apb.Status_STATUS_OK,
-			},
-			wantErr: false,
-		},
-		{
-			name: "error delete roles",
-			args: args{
-				ctx: context.TODO(),
-				request: &apb.DeleteRolesRequest{
-					RoleName: []string{
-						"no",
-					},
-				},
-			},
-			want: &apb.DeleteRolesResponse{
-				Status: apb.Status_STATUS_OK,
-			},
-			wantErr: true,
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			s := Auth{}
-			got, err := s.DeleteRoles(tt.args.ctx, tt.args.request)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("Auth.DeleteRoles() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
 			if got != nil && got.Status != tt.want.Status {
-				t.Errorf("Auth.DeleteRoles() = %v, want %v", got, tt.want)
+				t.Errorf("Role.CreateRoles() = %v, want %v", got, tt.want)
 			}
 		})
 	}
 }
-
-func clearAndCreateAuthTestSetup() error {
-	//clear setup if changed
-	storedUsers, err := userc.GetAll()
-	if err != nil {
-		return err
-	}
-	for _, u := range storedUsers {
-		err = userc.Delete(u)
-		if err != nil {
-			return err
-		}
-	}
-
-	storedRoles, err := rolec.GetAll()
-	if err != nil {
-		return err
-	}
-	for _, r := range storedRoles {
-		err = rolec.Delete(r)
-		if err != nil {
-			return err
-		}
-	}
-
-	// create dataset
-	err = createTestUsers()
-	if err != nil {
-		return err
-	}
-
-	err = createTestRoles()
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-//TODO(faseid): change password to hashed/encrypted one
-func createTestUsers() error {
-	randomRoleMap := map[string]string{pndID: randomRoleName}
-
-	users := []rbac.User{
-		{UserID: uuid.MustParse(adminID), UserName: "testAdmin", Roles: adminRoleMap, Password: "admin"},
-		{UserID: uuid.MustParse(userID), UserName: "testUser", Roles: userRoleMap, Password: "user"},
-		{UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: "aurelius", Token: "wrong token"},
-	}
-
-	for _, u := range users {
-		err := userc.Add(rbac.NewUser(u.ID(), u.Name(), u.Roles, u.Password, ""))
-		if err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-func createTestRoles() error {
-	roles := []rbac.Role{
-		{
-			RoleID:      uuid.MustParse(adminRoleID),
-			RoleName:    "adminTestRole",
-			Description: "Admin",
-			Permissions: []string{
-				"/gosdn.core.CoreService/GetPnd",
-				"/gosdn.core.CoreService/GetPndList",
-			},
-		},
-		{
-			RoleID:      uuid.New(),
-			RoleName:    "userTestRole",
-			Description: "User",
-			Permissions: []string{
-				"/gosdn.pnd.PndService/GetChangeList",
-			},
-		},
-		{
-			RoleID:      uuid.New(),
-			RoleName:    randomRoleName,
-			Description: "Not a role",
-			Permissions: []string{
-				"nope",
-			},
-		},
-	}
-
-	for _, r := range roles {
-		err := rolec.Add(rbac.NewRole(r.ID(), r.Name(), r.Description, r.Permissions))
-		if err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-// This is needed as a workaround for a bug where the output of the getUser test falsely was
-// that it failed while actually passing. Apparantely, this can happen when loggers write
-// the output of test cases.
-// Solution found here: https://github.com/gotestyourself/gotestsum/issues/141#issuecomment-686243110
-func patchLogger(t *testing.T) {
-	orig := log.Writer()
-	buf := new(bytes.Buffer)
-	log.SetOutput(buf)
-
-	t.Cleanup(func() {
-		// optionally check t.Failed here if you only want to print logs on failure
-
-		t.Log(buf.String())
-		log.SetOutput(orig)
-	})
-}
diff --git a/controller/northbound/server/pnd_test.go b/controller/northbound/server/pnd_test.go
index 797b5d52b3626cfe29d23c5241ebb70d5b7cd7ce..c64620fbdb1984a1242b2609686af0a5ee413b9e 100644
--- a/controller/northbound/server/pnd_test.go
+++ b/controller/northbound/server/pnd_test.go
@@ -103,7 +103,7 @@ func TestMain(m *testing.M) {
 	mockPnd.On("GetName").Return("test")
 	mockPnd.On("GetDescription").Return("test")
 	mockPnd.On("GetSBIs").Return(sbiStore)
-	mockPnd.On("GetSBI").Return(mockDevice.SBI(), nil)
+	mockPnd.On("GetSBI", mock.Anything).Return(mockDevice.SBI(), nil)
 	mockPnd.On("Devices").Return([]uuid.UUID{deviceUUID})
 	mockPnd.On("PendingChanges").Return([]uuid.UUID{pendingChangeUUID})
 	mockPnd.On("CommittedChanges").Return([]uuid.UUID{committedChangeUUID})
diff --git a/controller/northbound/server/role_test.go b/controller/northbound/server/role_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..9fdbe2e5f86714ca952df1734c4c804f0fd18d28
--- /dev/null
+++ b/controller/northbound/server/role_test.go
@@ -0,0 +1,387 @@
+package server
+
+import (
+	"context"
+	"reflect"
+	"testing"
+
+	apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
+	"github.com/google/uuid"
+)
+
+func TestRole_CreateRoles(t *testing.T) {
+	type args struct {
+		ctx     context.Context
+		request *apb.CreateRolesRequest
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.CreateRolesResponse
+		wantErr bool
+	}{
+		{
+			name: "default create roles",
+			args: args{ctx: context.TODO(),
+				request: &apb.CreateRolesRequest{
+					Roles: []*apb.Role{
+						{
+							Name:        "new role 1",
+							Description: "Role 1",
+							Permissions: []string{"permission 1", "permission 2"},
+						},
+					},
+				},
+			},
+			want:    &apb.CreateRolesResponse{Status: apb.Status_STATUS_OK},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := Role{}
+			got, err := s.CreateRoles(tt.args.ctx, tt.args.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Role.CreateRoles() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("Role.CreateRoles() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestRole_GetRole(t *testing.T) {
+	type args struct {
+		ctx     context.Context
+		request *apb.GetRoleRequest
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.GetRoleResponse
+		wantErr bool
+	}{
+		{
+			name: "default get role",
+			args: args{
+				ctx: context.TODO(),
+				request: &apb.GetRoleRequest{
+					RoleName: "adminTestRole",
+				},
+			},
+			want: &apb.GetRoleResponse{
+				Role: &apb.Role{
+					Name:        "adminTestRole",
+					Description: "Admin",
+				},
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+		{
+			name: "error get role",
+			args: args{
+				ctx: context.TODO(),
+				request: &apb.GetRoleRequest{
+					RoleName: "not role",
+				},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := Role{}
+			got, err := s.GetRole(tt.args.ctx, tt.args.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Role.GetRole() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status == tt.want.Status {
+				if got.Role.Name != tt.want.Role.Name || got.Role.Description != tt.want.Role.Description {
+					t.Errorf("Role.GetRole() = %v, want %v", got, tt.want)
+				}
+			} else {
+				if got != nil {
+					t.Errorf("Role.GetRole() = %v, want %v", got, tt.want)
+				}
+			}
+		})
+	}
+}
+
+func TestRole_GetRoles(t *testing.T) {
+	err := clearAndCreateAuthTestSetup()
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	type args struct {
+		ctx     context.Context
+		request *apb.GetRolesRequest
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.GetRolesResponse
+		wantLen int
+		wantErr bool
+	}{
+		{
+			name: "default get roles",
+			args: args{
+				ctx:     context.TODO(),
+				request: &apb.GetRolesRequest{},
+			},
+			want: &apb.GetRolesResponse{
+				Status: apb.Status_STATUS_OK,
+				Roles: []*apb.Role{
+					{
+						Name:        "adminTestRole",
+						Description: "Admin",
+						Permissions: []string{
+							"/gosdn.core.CoreService/GetPnd",
+							"/gosdn.core.CoreService/GetPndList",
+							"/gosdn.rbac.UserService/GetUsers",
+							"/gosdn.southbound.SbiService/GetSchema",
+						}},
+					{
+						Name:        "userTestRole",
+						Description: "User",
+						Permissions: []string{
+							"/gosdn.pnd.PndService/GetChangeList",
+						}},
+					{
+						Name:        randomRoleName,
+						Description: "Not a role",
+						Permissions: []string{
+							"nope",
+						},
+					},
+				},
+			},
+			wantLen: 3,
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := Role{}
+			got, err := s.GetRoles(tt.args.ctx, tt.args.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Role.GetRoles() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status == tt.want.Status {
+				if len(got.Roles) != 3 {
+					t.Errorf("Role.GetRoles() = %v, want %v", got, tt.want)
+				}
+				for _, gotR := range got.Roles {
+					containsExpected := false
+					for _, wantR := range tt.want.Roles {
+						gotPerm := gotR.Permissions
+						wantPerm := wantR.Permissions
+						if gotR.Description == wantR.Description && gotR.Name == wantR.Name &&
+							reflect.DeepEqual(gotPerm, wantPerm) {
+							containsExpected = true
+							break
+						}
+					}
+					if !containsExpected {
+						t.Errorf("Role.GetRoles() = %v, want %v", got, tt.want)
+					}
+				}
+			}
+		})
+	}
+}
+
+func TestRole_UpdateRoles(t *testing.T) {
+	type args struct {
+		ctx     context.Context
+		request *apb.UpdateRolesRequest
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.UpdateRolesResponse
+		wantErr bool
+	}{
+		{
+			name: "default update roles",
+			args: args{
+				ctx: context.TODO(),
+				request: &apb.UpdateRolesRequest{
+					Roles: []*apb.Role{
+						{
+							Id:   adminRoleID,
+							Name: "New Name",
+						},
+					},
+				},
+			},
+			want: &apb.UpdateRolesResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+		{
+			name: "error update roles",
+			args: args{
+				ctx: context.TODO(),
+				request: &apb.UpdateRolesRequest{
+					Roles: []*apb.Role{
+						{
+							Id:   uuid.NewString(),
+							Name: "New Name",
+						},
+					},
+				},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := Role{}
+			got, err := s.UpdateRoles(tt.args.ctx, tt.args.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Role.UpdateRoles() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("Role.UpdateRoles() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestRole_DeletePermissionsForRole(t *testing.T) {
+	clearAndCreateAuthTestSetup()
+
+	type args struct {
+		ctx     context.Context
+		request *apb.DeletePermissionsForRoleRequest
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.DeletePermissionsForRoleResponse
+		wantErr bool
+	}{
+		{
+			name: "default delete permissions for role",
+			args: args{
+				ctx: context.TODO(),
+				request: &apb.DeletePermissionsForRoleRequest{
+					RoleName: "adminTestRole",
+					PermissionsToDelete: []string{
+						"/gosdn.core.CoreService/GetPnd",
+						"/gosdn.core.CoreService/GetPndList",
+					},
+				},
+			},
+			want: &apb.DeletePermissionsForRoleResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+		{
+			name: "error delete permissions for role no proper permissions provided",
+			args: args{
+				ctx: context.TODO(),
+				request: &apb.DeletePermissionsForRoleRequest{
+					RoleName: "adminTestRole",
+					PermissionsToDelete: []string{
+						"no",
+					},
+				},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := Role{}
+			got, err := s.DeletePermissionsForRole(tt.args.ctx, tt.args.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Role.DeletePermissionsForRole() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("Role.DeletePermissionsForRole() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestRole_DeleteRoles(t *testing.T) {
+	type args struct {
+		ctx     context.Context
+		request *apb.DeleteRolesRequest
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.DeleteRolesResponse
+		wantErr bool
+	}{
+		{
+			name: "default delete roles",
+			args: args{
+				ctx: context.TODO(),
+				request: &apb.DeleteRolesRequest{
+					RoleName: []string{
+						"userTestRole",
+						"adminTestRole",
+					},
+				},
+			},
+			want: &apb.DeleteRolesResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: false,
+		},
+		{
+			name: "error delete roles",
+			args: args{
+				ctx: context.TODO(),
+				request: &apb.DeleteRolesRequest{
+					RoleName: []string{
+						"no",
+					},
+				},
+			},
+			want: &apb.DeleteRolesResponse{
+				Status: apb.Status_STATUS_OK,
+			},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := Role{}
+			clearAndCreateAuthTestSetup()
+
+			got, err := s.DeleteRoles(tt.args.ctx, tt.args.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("Role.DeleteRoles() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("Role.DeleteRoles() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/controller/northbound/server/test_util_test.go b/controller/northbound/server/test_util_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..96992775cf3d5a1033dae8fd20ab021658bdd9e0
--- /dev/null
+++ b/controller/northbound/server/test_util_test.go
@@ -0,0 +1,163 @@
+package server
+
+import (
+	"bytes"
+	"log"
+	"testing"
+
+	"code.fbi.h-da.de/danet/gosdn/controller/rbac"
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+	"github.com/google/uuid"
+)
+
+// Name of this file requires _test at the end, because of how the availability of varibales is handled in test files of go packages.
+// Does not include actual file tests!
+
+const adminID = "5c248a22-8eb7-48cf-b392-45680a1863a5"
+const userID = "57005d13-7a4d-493d-a02b-50ca51c40197"
+const adminRoleID = "126683ae-5ff2-43ee-92f7-0e2b936f8c77"
+const randomRoleName = "bertram"
+
+var adminRoleMap = map[string]string{pndID: "adminTestRole"}
+var userRoleMap = map[string]string{pndID: "userTestRole"}
+var jwt *rbac.JWTManager
+
+func clearAndCreateAuthTestSetup() error {
+	//clear setup if changed
+	storedUsers, err := userc.GetAll()
+	if err != nil {
+		return err
+	}
+	for _, u := range storedUsers {
+		err = userc.Delete(u)
+		if err != nil {
+			return err
+		}
+	}
+
+	storedRoles, err := rolec.GetAll()
+	if err != nil {
+		return err
+	}
+	for _, r := range storedRoles {
+		err = rolec.Delete(r)
+		if err != nil {
+			return err
+		}
+	}
+
+	// create dataset
+	err = createTestUsers()
+	if err != nil {
+		return err
+	}
+
+	err = createTestRoles()
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+//TODO(faseid): change password to hashed/encrypted one
+func createTestUsers() error {
+	randomRoleMap := map[string]string{pndID: randomRoleName}
+
+	users := []rbac.User{
+		{UserID: uuid.MustParse(adminID), UserName: "testAdmin", Roles: adminRoleMap, Password: "admin"},
+		{UserID: uuid.MustParse(userID), UserName: "testUser", Roles: userRoleMap, Password: "user"},
+		{UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: "aurelius", Token: "wrong token"},
+	}
+
+	for _, u := range users {
+		err := userc.Add(rbac.NewUser(u.ID(), u.Name(), u.Roles, u.Password, ""))
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func createTestRoles() error {
+	roles := []rbac.Role{
+		{
+			RoleID:      uuid.MustParse(adminRoleID),
+			RoleName:    "adminTestRole",
+			Description: "Admin",
+			Permissions: []string{
+				"/gosdn.core.CoreService/GetPnd",
+				"/gosdn.core.CoreService/GetPndList",
+				"/gosdn.rbac.UserService/GetUsers",
+				"/gosdn.southbound.SbiService/GetSchema",
+			},
+		},
+		{
+			RoleID:      uuid.New(),
+			RoleName:    "userTestRole",
+			Description: "User",
+			Permissions: []string{
+				"/gosdn.pnd.PndService/GetChangeList",
+			},
+		},
+		{
+			RoleID:      uuid.New(),
+			RoleName:    randomRoleName,
+			Description: "Not a role",
+			Permissions: []string{
+				"nope",
+			},
+		},
+	}
+
+	for _, r := range roles {
+		err := rolec.Add(rbac.NewRole(r.ID(), r.Name(), r.Description, r.Permissions))
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+// This is needed as a workaround for a bug where the output of the getUser test falsely was
+// that it failed while actually passing. Apparantely, this can happen when loggers write
+// the output of test cases.
+// Solution found here: https://github.com/gotestyourself/gotestsum/issues/141#issuecomment-686243110
+func patchLogger(t *testing.T) {
+	orig := log.Writer()
+	buf := new(bytes.Buffer)
+	log.SetOutput(buf)
+
+	t.Cleanup(func() {
+		// optionally check t.Failed here if you only want to print logs on failure
+
+		t.Log(buf.String())
+		log.SetOutput(orig)
+	})
+}
+
+// Creates a token to be used in auth interceptor tests. If validTokenRequired is set as true, the generated token will also
+// 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) (string, error) {
+	token, err := jwt.GenerateToken(rbac.User{UserName: userName})
+	if err != nil {
+		return token, err
+	}
+
+	if validTokenRequired {
+		user, err := userc.Get(store.Query{Name: userName})
+		if err != nil {
+			return token, err
+		}
+		user.SetToken(token)
+
+		err = userc.Update(user)
+		if err != nil {
+			return token, err
+		}
+	}
+
+	return token, nil
+}
diff --git a/controller/northbound/server/user_test.go b/controller/northbound/server/user_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..6611486e18eab780b319b4c10db8f0d8645d838d
--- /dev/null
+++ b/controller/northbound/server/user_test.go
@@ -0,0 +1,276 @@
+package server
+
+import (
+	"context"
+	"reflect"
+	"testing"
+
+	apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"
+	"github.com/google/uuid"
+)
+
+func TestUser_CreateUsers(t *testing.T) {
+	type args struct {
+		ctx     context.Context
+		request *apb.CreateUsersRequest
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    apb.Status
+		wantErr bool
+	}{
+		{
+			name: "default create users",
+			args: args{ctx: context.TODO(),
+				request: &apb.CreateUsersRequest{
+					User: []*apb.User{
+						{
+							Name:     "asdf",
+							Roles:    map[string]string{pndID: "asdf"},
+							Password: "asdf",
+							Token:    "",
+						},
+					},
+				},
+			},
+			want:    apb.Status_STATUS_OK,
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := User{}
+			got, err := s.CreateUsers(tt.args.ctx, tt.args.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("User.CreateUsers() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if !reflect.DeepEqual(got.Status, tt.want) {
+				t.Errorf("User.CreateUsers() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestUser_GetUser(t *testing.T) {
+	patchLogger(t)
+	type args struct {
+		ctx     context.Context
+		request *apb.GetUserRequest
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.GetUserResponse
+		wantErr bool
+	}{
+		{
+			name: "default get user",
+			args: args{
+				ctx: context.TODO(),
+				request: &apb.GetUserRequest{
+					Name: "testAdmin",
+				},
+			},
+			want: &apb.GetUserResponse{Status: apb.Status_STATUS_OK,
+				User: &apb.User{Id: adminID,
+					Name: "testAdmin"}},
+			wantErr: false,
+		},
+		{
+			name: "fail get user",
+			args: args{
+				ctx: context.TODO(),
+				request: &apb.GetUserRequest{
+					Name: "nope",
+				},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := User{}
+			got, err := s.GetUser(tt.args.ctx, tt.args.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("User.GetUser() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status == tt.want.Status {
+				if got.User.Name != tt.want.User.Name || got.User.Id != tt.want.User.Id {
+					t.Errorf("User.GetUser() = %v, want %v", got, tt.want)
+				}
+			} else {
+				if got != nil {
+					t.Errorf("User.GetUser() = %v, want %v", got, tt.want)
+				}
+			}
+		})
+	}
+}
+
+func TestUser_GetUsers(t *testing.T) {
+	err := clearAndCreateAuthTestSetup()
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+	type args struct {
+		ctx     context.Context
+		request *apb.GetUsersRequest
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.GetUsersResponse
+		wantLen int
+		wantErr bool
+	}{
+		{
+			name: "default get users",
+			args: args{ctx: context.TODO(),
+				request: &apb.GetUsersRequest{},
+			},
+			want: &apb.GetUsersResponse{Status: apb.Status_STATUS_OK,
+				User: []*apb.User{
+					{Name: "testAdmin"},
+					{Name: "testUser"},
+					{Name: "testRandom"}},
+			},
+			wantLen: 3,
+			wantErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := User{}
+			got, err := s.GetUsers(tt.args.ctx, tt.args.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("User.GetUsers() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status == apb.Status_STATUS_OK {
+				if len(got.User) != tt.wantLen {
+					t.Errorf("User.GetUsers() = %v, want %v", got, tt.want)
+				}
+
+				for _, gotU := range got.User {
+					containsExpected := false
+					for _, wantU := range tt.want.User {
+						if gotU.Name == wantU.Name {
+							containsExpected = true
+							break
+						}
+					}
+
+					if !containsExpected {
+						t.Errorf("User.GetUsers() = %v, want %v", got, tt.want)
+					}
+				}
+			}
+		})
+	}
+}
+
+func TestUser_UpdateUsers(t *testing.T) {
+	type args struct {
+		ctx     context.Context
+		request *apb.UpdateUsersRequest
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.UpdateUsersResponse
+		wantErr bool
+	}{
+		{
+			name: "default update user",
+			args: args{ctx: context.TODO(),
+				request: &apb.UpdateUsersRequest{User: []*apb.User{
+					{Id: adminID,
+						Name: "sth Else"},
+				},
+				},
+			},
+			want: &apb.UpdateUsersResponse{
+				Status: apb.Status_STATUS_OK},
+			wantErr: false,
+		},
+		{
+			name: "error update user",
+			args: args{ctx: context.TODO(),
+				request: &apb.UpdateUsersRequest{User: []*apb.User{
+					{Id: uuid.NewString(),
+						Name: "not a user"},
+				},
+				},
+			},
+			want:    nil,
+			wantErr: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := User{}
+			got, err := s.UpdateUsers(tt.args.ctx, tt.args.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("User.UpdateUsers() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("User.UpdateUsers() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestUser_DeleteUsers(t *testing.T) {
+	type args struct {
+		ctx     context.Context
+		request *apb.DeleteUsersRequest
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *apb.DeleteUsersResponse
+		wantErr bool
+	}{
+		{
+			name: "default delete users",
+			args: args{ctx: context.TODO(),
+				request: &apb.DeleteUsersRequest{Username: []string{"testUser"}},
+			},
+			want:    &apb.DeleteUsersResponse{Status: apb.Status_STATUS_OK},
+			wantErr: false,
+		},
+		{
+			name: "error delete users",
+			args: args{ctx: context.TODO(),
+				request: &apb.DeleteUsersRequest{Username: []string{"no user"}},
+			},
+			want:    &apb.DeleteUsersResponse{Status: apb.Status_STATUS_OK},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := User{}
+			got, err := s.DeleteUsers(tt.args.ctx, tt.args.request)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("User.DeleteUsers() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+
+			if got != nil && got.Status != tt.want.Status {
+				t.Errorf("User.DeleteUsers() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}