Repository: owncloud/ocis
Pull request #5873 (2023-03-20 10:07:18)

No Notifications for own actions
Do not send notifications on `SpaceDeleted` and `SpaceDisabled` when user executed the actions herself.

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=5873)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=5873&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=5873&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=5873&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=5873&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=5873&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=5873&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=5873&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=5873&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=5873&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=5873&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=5873&resolved=false&types=CODE_SMELL) [3 Code Smells](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=5873&resolved=false&types=CODE_SMELL)

[![85.7%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/60-16px.png '85.7%')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=5873&metric=new_coverage&view=list) [85.7% Coverage](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=5873&metric=new_coverage&view=list)  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=5873&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=5873&metric=new_duplicated_lines_density&view=list)


ownclouders: E2E tests failed: https://drone.owncloud.com/owncloud/ocis/20572/66/1
<details><summary>:boom: To see the trace, please open the link in the console ...</summary>

<p>


#### npx playwright show-trace https://cache.owncloud.com/public/owncloud/ocis/20572/tracing/user-should-be-able-to-read-and-dismiss-notifications-alice-2023-3-20-10-46-05.zip 

#### npx playwright show-trace https://cache.owncloud.com/public/owncloud/ocis/20572/tracing/user-should-be-able-to-read-and-dismiss-notifications-brian-2023-3-20-10-46-12.zip 


</p></details>

<!-- id: pr-5873 -->


Patch:
diff --git a/.drone.env b/.drone.env
index 3b7ad84d41c..33e8d17b8f6 100644
--- a/.drone.env
+++ b/.drone.env
@@ -1,3 +1,3 @@
 # The test runner source for UI tests
-WEB_COMMITID=619dfc499f8d975200a13215acdd365dd9849c1f
-WEB_BRANCH=master
+WEB_COMMITID=abb16c5fdf7b7726969d2afa05aec72d017cca5a
+WEB_BRANCH=changeNotificationTest
diff --git a/changelog/unreleased/no-notification-own-action.md b/changelog/unreleased/no-notification-own-action.md
new file mode 100644
index 00000000000..c8b5f8cb9b0
--- /dev/null
+++ b/changelog/unreleased/no-notification-own-action.md
@@ -0,0 +1,5 @@
+Enhancement: No Notifications for own actions
+
+Don't send notifications on space events when the user has executed them herself.
+
+https://github.com/owncloud/ocis/pull/5871
diff --git a/go.mod b/go.mod
index 7c2e01d6862..cf5a5a1a5d8 100644
--- a/go.mod
+++ b/go.mod
@@ -86,7 +86,7 @@ require (
 	go.opentelemetry.io/otel/trace v1.14.0
 	golang.org/x/crypto v0.7.0
 	golang.org/x/exp v0.0.0-20221026004748-78e5e7837ae6
-	golang.org/x/image v0.6.0
+	golang.org/x/image v0.5.0
 	golang.org/x/net v0.8.0
 	golang.org/x/oauth2 v0.4.0
 	golang.org/x/term v0.6.0
diff --git a/go.sum b/go.sum
index 72d1cacad33..e07a366e0c9 100644
--- a/go.sum
+++ b/go.sum
@@ -1156,6 +1156,8 @@ github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
 github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
 github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/kobergj/gotext v0.0.0-20230309141732-b909eb0b8956 h1:b3MBTVgsfKXD/CdnAAqD7czu9Npx9QG+rHZycBIXJGE=
+github.com/kobergj/gotext v0.0.0-20230309141732-b909eb0b8956/go.mod h1:AT4NpQrOmyj1L/+hLja6aR0lk81yYYL4ePnj2kp7d6M=
 github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -1178,6 +1180,8 @@ github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c
 github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
 github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
 github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
+github.com/leonelquinteros/gotext v1.5.2 h1:T2y6ebHli+rMBCjcJlHTXyUrgXqsKBhl/ormgvt7lPo=
+github.com/leonelquinteros/gotext v1.5.2/go.mod h1:AT4NpQrOmyj1L/+hLja6aR0lk81yYYL4ePnj2kp7d6M=
 github.com/leonelquinteros/gotext v1.5.3-0.20230317130943-71a59c05b2c1 h1:k56sFOOJ0CYuQtGoRSeAMhP1R692+iNH+S1dC/CEz0w=
 github.com/leonelquinteros/gotext v1.5.3-0.20230317130943-71a59c05b2c1/go.mod h1:AT4NpQrOmyj1L/+hLja6aR0lk81yYYL4ePnj2kp7d6M=
 github.com/libregraph/idm v0.4.1-0.20230221143410-3503963047a5 h1:brLMXSjWoWhGXs8LpK+Lx+FQCtGLUa51Mq/ggHv9AV0=
@@ -1709,8 +1713,8 @@ golang.org/x/exp v0.0.0-20221026004748-78e5e7837ae6/go.mod h1:cyybsKvd6eL0RnXn6p
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4=
-golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0=
+golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
+golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1736,7 +1740,6 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
 golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1810,7 +1813,6 @@ golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfS
 golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
 golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
-golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
 golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1978,7 +1980,6 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@@ -1987,7 +1988,6 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
 golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
-golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
 golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -2085,7 +2085,6 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
 golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/services/proxy/pkg/autoprovision/creator.go b/services/proxy/pkg/autoprovision/creator.go
deleted file mode 100644
index 7714d78c19f..00000000000
--- a/services/proxy/pkg/autoprovision/creator.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package autoprovision
-
-import (
-	"context"
-	"encoding/json"
-
-	cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
-	types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
-	"github.com/cs3org/reva/v2/pkg/auth/scope"
-	"github.com/cs3org/reva/v2/pkg/token"
-	settingsService "github.com/owncloud/ocis/v2/services/settings/pkg/service/v0"
-)
-
-// Creator provides an interface to get a user or reva token with admin privileges
-type Creator interface {
-	// GetAutoProvisionAdmin returns a user with the Admin role assigned
-	GetAutoProvisionAdmin() (*cs3.User, error)
-	// GetAutoProvisionAdminToken returns a reva token with admin privileges
-	GetAutoProvisionAdminToken(ctx context.Context) (string, error)
-}
-
-// Options defines the available options for this package.
-type Options struct {
-	tokenManager token.Manager
-}
-
-// Option defines a single option function.
-type Option func(o *Options)
-
-// WithTokenManager sets the reva token manager
-func WithTokenManager(t token.Manager) Option {
-	return func(o *Options) {
-		o.tokenManager = t
-	}
-}
-
-type creator struct {
-	Options
-}
-
-// NewCreator returns a new Creator instance
-func NewCreator(opts ...Option) creator {
-	opt := Options{}
-	for _, o := range opts {
-		o(&opt)
-	}
-
-	return creator{
-		Options: opt,
-	}
-}
-
-// This returns an hardcoded internal User, that is privileged to create new User via
-// the Graph API. This user is needed for autoprovisioning of users from incoming OIDC
-// claims.
-func (c creator) GetAutoProvisionAdmin() (*cs3.User, error) {
-	roleIDsJSON, err := json.Marshal([]string{settingsService.BundleUUIDRoleAdmin})
-	if err != nil {
-		return nil, err
-	}
-
-	autoProvisionUserCreator := &cs3.User{
-		DisplayName: "Autoprovision User",
-		Username:    "autoprovisioner",
-		Id: &cs3.UserId{
-			Idp:      "internal",
-			OpaqueId: "autoprov-user-id00-0000-000000000000",
-		},
-		Opaque: &types.Opaque{
-			Map: map[string]*types.OpaqueEntry{
-				"roles": {
-					Decoder: "json",
-					Value:   roleIDsJSON,
-				},
-			},
-		},
-	}
-	return autoProvisionUserCreator, nil
-}
-
-func (c creator) GetAutoProvisionAdminToken(ctx context.Context) (string, error) {
-	userCreator, err := c.GetAutoProvisionAdmin()
-	if err != nil {
-		return "", err
-	}
-
-	s, err := scope.AddOwnerScope(nil)
-	if err != nil {
-		return "", err
-	}
-
-	token, err := c.tokenManager.MintToken(ctx, userCreator, s)
-	if err != nil {
-		return "", err
-	}
-	return token, nil
-}
diff --git a/services/proxy/pkg/command/server.go b/services/proxy/pkg/command/server.go
index d386ab49534..05a5b718ed8 100644
--- a/services/proxy/pkg/command/server.go
+++ b/services/proxy/pkg/command/server.go
@@ -20,7 +20,6 @@ import (
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
 	settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
 	storesvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/store/v0"
-	"github.com/owncloud/ocis/v2/services/proxy/pkg/autoprovision"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/config/parser"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/logging"
@@ -32,7 +31,6 @@ import (
 	proxyHTTP "github.com/owncloud/ocis/v2/services/proxy/pkg/server/http"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/tracing"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend"
-	"github.com/owncloud/ocis/v2/services/proxy/pkg/userroles"
 	"github.com/urfave/cli/v2"
 	"golang.org/x/oauth2"
 )
@@ -138,51 +136,22 @@ func Server(cfg *config.Config) *cli.Command {
 func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config) alice.Chain {
 	rolesClient := settingssvc.NewRoleService("com.owncloud.api.settings", grpc.DefaultClient())
 	revaClient, err := pool.GetGatewayServiceClient(cfg.Reva.Address, cfg.Reva.GetRevaOptions()...)
-	if err != nil {
-		logger.Fatal().Err(err).Msg("Failed to get gateway client")
-	}
-	tokenManager, err := jwt.New(map[string]interface{}{
-		"secret": cfg.TokenManager.JWTSecret,
-	})
-	if err != nil {
-		logger.Fatal().Err(err).
-			Msg("Failed to create token manager")
-	}
-	autoProvsionCreator := autoprovision.NewCreator(autoprovision.WithTokenManager(tokenManager))
 	var userProvider backend.UserBackend
 	switch cfg.AccountBackend {
 	case "cs3":
+		tokenManager, err := jwt.New(map[string]interface{}{
+			"secret": cfg.TokenManager.JWTSecret,
+		})
+		if err != nil {
+			logger.Error().Err(err).
+				Msg("Failed to create token manager")
+		}
 
-		userProvider = backend.NewCS3UserBackend(
-			backend.WithLogger(logger),
-			backend.WithRevaAuthenticator(revaClient),
-			backend.WithMachineAuthAPIKey(cfg.MachineAuthAPIKey),
-			backend.WithOIDCissuer(cfg.OIDC.Issuer),
-			backend.WithAutoProvisonCreator(autoProvsionCreator),
-		)
+		userProvider = backend.NewCS3UserBackend(rolesClient, revaClient, cfg.MachineAuthAPIKey, cfg.OIDC.Issuer, tokenManager, logger)
 	default:
 		logger.Fatal().Msgf("Invalid accounts backend type '%s'", cfg.AccountBackend)
 	}
 
-	var roleAssigner userroles.UserRoleAssigner
-	switch cfg.RoleAssignment.Driver {
-	case "default":
-		roleAssigner = userroles.NewDefaultRoleAssigner(
-			userroles.WithRoleService(rolesClient),
-			userroles.WithLogger(logger),
-		)
-	case "oidc":
-		roleAssigner = userroles.NewOIDCRoleAssigner(
-			userroles.WithRoleService(rolesClient),
-			userroles.WithLogger(logger),
-			userroles.WithRolesClaim(cfg.RoleAssignment.OIDCRoleMapper.RoleClaim),
-			userroles.WithRoleMapping(cfg.RoleAssignment.OIDCRoleMapper.RoleMapping),
-			userroles.WithAutoProvisonCreator(autoProvsionCreator),
-		)
-	default:
-		logger.Fatal().Msgf("Invalid role assignment driver '%s'", cfg.RoleAssignment.Driver)
-	}
-
 	storeClient := storesvc.NewStoreService("com.owncloud.api.store", grpc.DefaultClient())
 	if err != nil {
 		logger.Error().Err(err).
@@ -234,7 +203,6 @@ func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config)
 		Logger:             logger,
 		PreSignedURLConfig: cfg.PreSignedURL,
 		UserProvider:       userProvider,
-		UserRoleAssigner:   roleAssigner,
 		Store:              storeClient,
 	})
 
@@ -261,19 +229,21 @@ func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config)
 		middleware.AccountResolver(
 			middleware.Logger(logger),
 			middleware.UserProvider(userProvider),
-			middleware.UserRoleAssigner(roleAssigner),
+			middleware.TokenManagerConfig(*cfg.TokenManager),
 			middleware.UserOIDCClaim(cfg.UserOIDCClaim),
 			middleware.UserCS3Claim(cfg.UserCS3Claim),
 			middleware.AutoprovisionAccounts(cfg.AutoprovisionAccounts),
 		),
 		middleware.SelectorCookie(
 			middleware.Logger(logger),
+			middleware.UserProvider(userProvider),
 			middleware.PolicySelectorConfig(*cfg.PolicySelector),
 		),
 		middleware.Policies(logger, cfg.PoliciesMiddleware.Query),
 		// finally, trigger home creation when a user logs in
 		middleware.CreateHome(
 			middleware.Logger(logger),
+			middleware.TokenManagerConfig(*cfg.TokenManager),
 			middleware.RevaGatewayClient(revaClient),
 			middleware.RoleQuotas(cfg.RoleQuotas),
 		),
diff --git a/services/proxy/pkg/config/config.go b/services/proxy/pkg/config/config.go
index a0e5312601a..554caebcc2b 100644
--- a/services/proxy/pkg/config/config.go
+++ b/services/proxy/pkg/config/config.go
@@ -25,7 +25,6 @@ type Config struct {
 	Policies              []Policy           `yaml:"policies"`
 	OIDC                  OIDC               `yaml:"oidc"`
 	TokenManager          *TokenManager      `mask:"struct" yaml:"token_manager"`
-	RoleAssignment        RoleAssignment     `yaml:"role_assignment"`
 	PolicySelector        *PolicySelector    `yaml:"policy_selector"`
 	PreSignedURL          PreSignedURL       `yaml:"pre_signed_url"`
 	AccountBackend        string             `yaml:"account_backend" env:"PROXY_ACCOUNT_BACKEND_TYPE" desc:"Account backend the PROXY service should use. Currently only 'cs3' is possible here."`
@@ -122,18 +121,6 @@ type UserinfoCache struct {
 	TTL  int `yaml:"ttl" env:"PROXY_OIDC_USERINFO_CACHE_TTL" desc:"Max TTL in seconds for the OIDC user info cache."`
 }
 
-// RoleAssignment contains the configuration for how to assign roles to users during login
-type RoleAssignment struct {
-	Driver         string         `yaml:"driver" env:"PROXY_ROLE_ASSIGNMENT_DRIVER" desc:"The mechanism that should be used to assign roles to user upon login. Supported values: 'default' or 'oidc'. 'default' will assign the role 'user' to users which don't have a role assigned at the time they login. 'oidc' will assign the role based on the value of a claim (configured via PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM) from the users OIDC claims."`
-	OIDCRoleMapper OIDCRoleMapper `yaml:"oidc_role_mapper"`
-}
-
-// OIDCRoleMapper contains the configuration for the "oidc" role assignment driber
-type OIDCRoleMapper struct {
-	RoleClaim   string            `yaml:"role_claim" env:"PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM" desc:"The OIDC claim used to create the users role assignment."`
-	RoleMapping map[string]string `yaml:"role_mapping" desc:"A mapping of ocis role names to PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM claim values. This setting can only be configured in the configuration file and not via environment variables."`
-}
-
 // PolicySelector is the toplevel-configuration for different selectors
 type PolicySelector struct {
 	Static *StaticSelectorConf `yaml:"static"`
diff --git a/services/proxy/pkg/config/defaults/defaultconfig.go b/services/proxy/pkg/config/defaults/defaultconfig.go
index c7166fb9a07..f1316cf9125 100644
--- a/services/proxy/pkg/config/defaults/defaultconfig.go
+++ b/services/proxy/pkg/config/defaults/defaultconfig.go
@@ -52,20 +52,7 @@ func DefaultConfig() *config.Config {
 			},
 		},
 		PolicySelector: nil,
-		RoleAssignment: config.RoleAssignment{
-			Driver: "default",
-			// this default is only relevant when Driver is set to "oidc"
-			OIDCRoleMapper: config.OIDCRoleMapper{
-				RoleClaim: "roles",
-				RoleMapping: map[string]string{
-					"admin":      "ocisAdmin",
-					"spaceadmin": "ocisSpaceAdmin",
-					"user":       "ocisUser",
-					"guest":      "ocisGuest",
-				},
-			},
-		},
-		Reva: shared.DefaultRevaConfig(),
+		Reva:           shared.DefaultRevaConfig(),
 		PreSignedURL: config.PreSignedURL{
 			AllowedHTTPMethods: []string{"GET"},
 			Enabled:            true,
diff --git a/services/proxy/pkg/middleware/account_resolver.go b/services/proxy/pkg/middleware/account_resolver.go
index c8c16c9c7f7..6ccdf987d15 100644
--- a/services/proxy/pkg/middleware/account_resolver.go
+++ b/services/proxy/pkg/middleware/account_resolver.go
@@ -5,7 +5,6 @@ import (
 	"net/http"
 
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend"
-	"github.com/owncloud/ocis/v2/services/proxy/pkg/userroles"
 
 	revactx "github.com/cs3org/reva/v2/pkg/ctx"
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
@@ -25,7 +24,6 @@ func AccountResolver(optionSetters ...Option) func(next http.Handler) http.Handl
 			userProvider:          options.UserProvider,
 			userOIDCClaim:         options.UserOIDCClaim,
 			userCS3Claim:          options.UserCS3Claim,
-			userRoleAssigner:      options.UserRoleAssigner,
 			autoProvisionAccounts: options.AutoprovisionAccounts,
 		}
 	}
@@ -35,7 +33,6 @@ type accountResolver struct {
 	next                  http.Handler
 	logger                log.Logger
 	userProvider          backend.UserBackend
-	userRoleAssigner      userroles.UserRoleAssigner
 	autoProvisionAccounts bool
 	userOIDCClaim         string
 	userCS3Claim          string
@@ -65,7 +62,7 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 			return
 		}
 
-		user, token, err = m.userProvider.GetUserByClaims(req.Context(), m.userCS3Claim, value)
+		user, token, err = m.userProvider.GetUserByClaims(req.Context(), m.userCS3Claim, value, true)
 
 		if errors.Is(err, backend.ErrAccountNotFound) {
 			m.logger.Debug().Str("claim", m.userOIDCClaim).Str("value", value).Msg("User by claim not found")
@@ -79,7 +76,7 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 			if err != nil {
 				m.logger.Error().Err(err).Msg("Autoprovisioning user failed")
 			}
-			user, token, err = m.userProvider.GetUserByClaims(req.Context(), "userid", user.Id.OpaqueId)
+			user, token, err = m.userProvider.GetUserByClaims(req.Context(), "userid", user.Id.OpaqueId, true)
 			if err != nil {
 				m.logger.Error().Err(err).Str("userid", user.Id.OpaqueId).Msg("Error getting token for autoprovisioned user")
 			}
@@ -97,14 +94,6 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 			return
 		}
 
-		// resolve the user's roles
-		user, err = m.userRoleAssigner.UpdateUserRoleAssignment(ctx, user, claims)
-		if err != nil {
-			m.logger.Error().Err(err).Msg("Could not get user roles")
-			w.WriteHeader(http.StatusInternalServerError)
-			return
-		}
-
 		// add user to context for selectors
 		ctx = revactx.ContextSetUser(ctx, user)
 		req = req.WithContext(ctx)
@@ -112,7 +101,7 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 		m.logger.Debug().Interface("claims", claims).Interface("user", user).Msg("associated claims with user")
 	} else if user != nil {
 		var err error
-		_, token, err = m.userProvider.GetUserByClaims(req.Context(), "username", user.Username)
+		_, token, err = m.userProvider.GetUserByClaims(req.Context(), "username", user.Username, true)
 
 		if errors.Is(err, backend.ErrAccountDisabled) {
 			m.logger.Debug().Interface("user", user).Msg("Disabled")
diff --git a/services/proxy/pkg/middleware/options.go b/services/proxy/pkg/middleware/options.go
index 770d971ee30..c45bdd6682b 100644
--- a/services/proxy/pkg/middleware/options.go
+++ b/services/proxy/pkg/middleware/options.go
@@ -5,7 +5,6 @@ import (
 	"time"
 
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend"
-	"github.com/owncloud/ocis/v2/services/proxy/pkg/userroles"
 
 	settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
 	storesvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/store/v0"
@@ -28,10 +27,8 @@ type Options struct {
 	PolicySelector config.PolicySelector
 	// HTTPClient to use for communication with the oidcAuth provider
 	HTTPClient *http.Client
-	// UserProvider backend to use for resolving User
+	// UP
 	UserProvider backend.UserBackend
-	// UserRoleAssigner to user for assign a users default role
-	UserRoleAssigner userroles.UserRoleAssigner
 	// SettingsRoleService for the roles API in settings
 	SettingsRoleService settingssvc.RoleService
 	// OIDCProviderFunc to lazily initialize an oidc provider, must be set for the oidc_auth middleware
@@ -205,13 +202,6 @@ func UserProvider(up backend.UserBackend) Option {
 	}
 }
 
-// UserRoleAssigner sets the mechanism for assigning the default user roles
-func UserRoleAssigner(ra userroles.UserRoleAssigner) Option {
-	return func(o *Options) {
-		o.UserRoleAssigner = ra
-	}
-}
-
 // AccessTokenVerifyMethod set the mechanism for access token verification
 func AccessTokenVerifyMethod(method string) Option {
 	return func(o *Options) {
diff --git a/services/proxy/pkg/middleware/signed_url_auth.go b/services/proxy/pkg/middleware/signed_url_auth.go
index a6bc3a703e3..793f6d8adca 100644
--- a/services/proxy/pkg/middleware/signed_url_auth.go
+++ b/services/proxy/pkg/middleware/signed_url_auth.go
@@ -17,7 +17,6 @@ import (
 	storesvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/store/v0"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend"
-	"github.com/owncloud/ocis/v2/services/proxy/pkg/userroles"
 	"golang.org/x/crypto/pbkdf2"
 )
 
@@ -44,7 +43,6 @@ type SignedURLAuthenticator struct {
 	Logger             log.Logger
 	PreSignedURLConfig config.PreSignedURL
 	UserProvider       backend.UserBackend
-	UserRoleAssigner   userroles.UserRoleAssigner
 	Store              storesvc.StoreService
 }
 
@@ -194,17 +192,7 @@ func (m SignedURLAuthenticator) Authenticate(r *http.Request) (*http.Request, bo
 		return nil, false
 	}
 
-	user, _, err := m.UserProvider.GetUserByClaims(r.Context(), "username", r.URL.Query().Get(_paramOCCredential))
-	if err != nil {
-		m.Logger.Error().
-			Err(err).
-			Str("authenticator", "signed_url").
-			Str("path", r.URL.Path).
-			Msg("Could not get user by claim")
-		return nil, false
-	}
-
-	user, err = m.UserRoleAssigner.ApplyUserRole(r.Context(), user)
+	user, _, err := m.UserProvider.GetUserByClaims(r.Context(), "username", r.URL.Query().Get(_paramOCCredential), true)
 	if err != nil {
 		m.Logger.Error().
 			Err(err).
diff --git a/services/proxy/pkg/user/backend/backend.go b/services/proxy/pkg/user/backend/backend.go
index efce21d55dc..b7aded6d3a6 100644
--- a/services/proxy/pkg/user/backend/backend.go
+++ b/services/proxy/pkg/user/backend/backend.go
@@ -2,10 +2,13 @@ package backend
 
 import (
 	"context"
+	"encoding/json"
 	"errors"
 
 	gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
 	cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
+	types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
+	settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
 	"google.golang.org/grpc"
 )
 
@@ -18,16 +21,46 @@ var (
 	ErrNotSupported = errors.New("operation not supported")
 )
 
-//go:generate mockery --name=UserBackend
-
 // UserBackend allows the proxy to retrieve users from different user-backends (accounts-service, CS3)
 type UserBackend interface {
-	GetUserByClaims(ctx context.Context, claim, value string) (*cs3.User, string, error)
+	GetUserByClaims(ctx context.Context, claim, value string, withRoles bool) (*cs3.User, string, error)
 	Authenticate(ctx context.Context, username string, password string) (*cs3.User, string, error)
 	CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*cs3.User, error)
+	GetUserGroups(ctx context.Context, userID string)
 }
 
 // RevaAuthenticator helper interface to mock auth-method from reva gateway-client.
 type RevaAuthenticator interface {
 	Authenticate(ctx context.Context, in *gateway.AuthenticateRequest, opts ...grpc.CallOption) (*gateway.AuthenticateResponse, error)
 }
+
+// loadRolesIDs returns the role-ids assigned to an user
+func loadRolesIDs(ctx context.Context, opaqueUserID string, rs settingssvc.RoleService) ([]string, error) {
+	req := &settingssvc.ListRoleAssignmentsRequest{AccountUuid: opaqueUserID}
+	assignmentResponse, err := rs.ListRoleAssignments(ctx, req)
+
+	if err != nil {
+		return nil, err
+	}
+
+	roleIDs := make([]string, 0)
+
+	for _, assignment := range assignmentResponse.Assignments {
+		roleIDs = append(roleIDs, assignment.RoleId)
+	}
+
+	return roleIDs, nil
+}
+
+// encodeRoleIDs encoded the given role id's in to reva-specific format to be able to mint a token from them
+func encodeRoleIDs(roleIDs []string) (*types.OpaqueEntry, error) {
+	roleIDsJSON, err := json.Marshal(roleIDs)
+	if err != nil {
+		return nil, err
+	}
+
+	return &types.OpaqueEntry{
+		Decoder: "json",
+		Value:   roleIDsJSON,
+	}, nil
+}
diff --git a/services/proxy/pkg/user/backend/cs3.go b/services/proxy/pkg/user/backend/cs3.go
index 59ef8dbaf9a..b37cd481336 100644
--- a/services/proxy/pkg/user/backend/cs3.go
+++ b/services/proxy/pkg/user/backend/cs3.go
@@ -10,87 +10,48 @@ import (
 	gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
 	cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
 	rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
+	types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
+	"github.com/cs3org/reva/v2/pkg/auth/scope"
 	revactx "github.com/cs3org/reva/v2/pkg/ctx"
+	"github.com/cs3org/reva/v2/pkg/token"
 	libregraph "github.com/owncloud/libre-graph-api-go"
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
 	"github.com/owncloud/ocis/v2/ocis-pkg/oidc"
 	"github.com/owncloud/ocis/v2/ocis-pkg/registry"
+	settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
 	"github.com/owncloud/ocis/v2/services/graph/pkg/service/v0/errorcode"
-	"github.com/owncloud/ocis/v2/services/proxy/pkg/autoprovision"
+	settingsService "github.com/owncloud/ocis/v2/services/settings/pkg/service/v0"
+	"go-micro.dev/v4/metadata"
 	"go-micro.dev/v4/selector"
 )
 
 type cs3backend struct {
-	graphSelector selector.Selector
-	Options
-}
-
-// Option defines a single option function.
-type Option func(o *Options)
-
-// Options defines the available options for this package.
-type Options struct {
-	logger              log.Logger
+	graphSelector       selector.Selector
+	settingsRoleService settingssvc.RoleService
 	authProvider        RevaAuthenticator
-	machineAuthAPIKey   string
 	oidcISS             string
-	autoProvsionCreator autoprovision.Creator
-}
-
-// WithLogger sets the logger option
-func WithLogger(l log.Logger) Option {
-	return func(o *Options) {
-		o.logger = l
-	}
-}
-
-// WithRevaAuthenticator set the RevaAuthenticator option
-func WithRevaAuthenticator(ra RevaAuthenticator) Option {
-	return func(o *Options) {
-		o.authProvider = ra
-	}
-}
-
-// WithMachineAuthAPIKey configures the machine auth API key
-func WithMachineAuthAPIKey(ma string) Option {
-	return func(o *Options) {
-		o.machineAuthAPIKey = ma
-	}
-}
-
-// WithOIDCissuer set the OIDC issuer URL
-func WithOIDCissuer(oidcISS string) Option {
-	return func(o *Options) {
-		o.oidcISS = oidcISS
-	}
-}
-
-// WithAutoProvisonCreator configures the autoprovision creator to use
-func WithAutoProvisonCreator(c autoprovision.Creator) Option {
-	return func(o *Options) {
-		o.autoProvsionCreator = c
-	}
+	machineAuthAPIKey   string
+	tokenManager        token.Manager
+	logger              log.Logger
 }
 
 // NewCS3UserBackend creates a user-provider which fetches users from a CS3 UserBackend
-func NewCS3UserBackend(opts ...Option) UserBackend {
-	opt := Options{}
-	for _, o := range opts {
-		o(&opt)
-	}
-
+func NewCS3UserBackend(rs settingssvc.RoleService, ap RevaAuthenticator, machineAuthAPIKey string, oidcISS string, tokenManager token.Manager, logger log.Logger) UserBackend {
 	reg := registry.GetRegistry()
 	sel := selector.NewSelector(selector.Registry(reg))
-
-	b := cs3backend{
-		Options:       opt,
-		graphSelector: sel,
+	return &cs3backend{
+		graphSelector:       sel,
+		settingsRoleService: rs,
+		authProvider:        ap,
+		oidcISS:             oidcISS,
+		machineAuthAPIKey:   machineAuthAPIKey,
+		tokenManager:        tokenManager,
+		logger:              logger,
 	}
-
-	return &b
 }
 
-func (c *cs3backend) GetUserByClaims(ctx context.Context, claim, value string) (*cs3.User, string, error) {
+func (c *cs3backend) GetUserByClaims(ctx context.Context, claim, value string, withRoles bool) (*cs3.User, string, error) {
 	res, err := c.authProvider.Authenticate(ctx, &gateway.AuthenticateRequest{
 		Type:         "machine",
 		ClientId:     claim + ":" + value,
@@ -109,6 +70,53 @@ func (c *cs3backend) GetUserByClaims(ctx context.Context, claim, value string) (
 
 	user := res.User
 
+	if !withRoles {
+		return user, res.Token, nil
+	}
+
+	var roleIDs []string
+	if user.Id.Type != cs3.UserType_USER_TYPE_LIGHTWEIGHT {
+		roleIDs, err = loadRolesIDs(ctx, user.Id.OpaqueId, c.settingsRoleService)
+		if err != nil {
+			c.logger.Error().Err(err).Msgf("Could not load roles")
+			return nil, "", err
+		}
+
+		if len(roleIDs) == 0 {
+			// This user doesn't have a role assignment yet. Assign a
+			// default user role. At least until proper roles are provided. See
+			// https://github.com/owncloud/ocis/v2/issues/1825 for more context.
+			if user.Id.Type == cs3.UserType_USER_TYPE_PRIMARY {
+				c.logger.Info().Str("userid", user.Id.OpaqueId).Msg("user has no role assigned, assigning default user role")
+				ctx = metadata.Set(ctx, middleware.AccountID, user.Id.OpaqueId)
+				_, err := c.settingsRoleService.AssignRoleToUser(ctx, &settingssvc.AssignRoleToUserRequest{
+					AccountUuid: user.Id.OpaqueId,
+					RoleId:      settingsService.BundleUUIDRoleUser,
+				})
+				if err != nil {
+					c.logger.Error().Err(err).Msg("Could not add default role")
+					return nil, "", err
+				}
+				roleIDs = append(roleIDs, settingsService.BundleUUIDRoleUser)
+			}
+		}
+	}
+
+	enc, err := encodeRoleIDs(roleIDs)
+	if err != nil {
+		c.logger.Error().Err(err).Msg("Could not encode loaded roles")
+	}
+
+	if user.Opaque == nil {
+		user.Opaque = &types.Opaque{
+			Map: map[string]*types.OpaqueEntry{
+				"roles": enc,
+			},
+		}
+	} else {
+		user.Opaque.Map["roles"] = enc
+	}
+
 	return user, res.Token, nil
 }
 
@@ -135,7 +143,7 @@ func (c *cs3backend) Authenticate(ctx context.Context, username string, password
 // function will just return the existing user.
 func (c *cs3backend) CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*cs3.User, error) {
 	newctx := context.Background()
-	token, err := c.autoProvsionCreator.GetAutoProvisionAdminToken(newctx)
+	token, err := c.generateAutoProvisionAdminToken(newctx)
 	if err != nil {
 		c.logger.Error().Err(err).Msg("Error generating token for autoprovisioning user.")
 		return nil, err
@@ -155,8 +163,6 @@ func (c *cs3backend) CreateUserFromClaims(ctx context.Context, claims map[string
 	req := lgClient.UsersApi.CreateUser(newctx).User(newUser)
 
 	created, resp, err := req.Execute()
-	defer resp.Body.Close()
-
 	var reread bool
 	if err != nil {
 		if resp == nil {
@@ -180,8 +186,7 @@ func (c *cs3backend) CreateUserFromClaims(ctx context.Context, claims map[string
 	if reread {
 		c.logger.Debug().Msg("User already exist, re-reading via libregraph")
 		gureq := lgClient.UserApi.GetUser(newctx, newUser.GetOnPremisesSamAccountName())
-		created, resp, err = gureq.Execute()
-		defer resp.Body.Close()
+		created, _, err = gureq.Execute()
 		if err != nil {
 			c.logger.Error().Err(err).Msg("Error trying to re-read user from graphAPI")
 			return nil, err
@@ -193,6 +198,10 @@ func (c *cs3backend) CreateUserFromClaims(ctx context.Context, claims map[string
 	return &cs3UserCreated, nil
 }
 
+func (c cs3backend) GetUserGroups(ctx context.Context, userID string) {
+	panic("implement me")
+}
+
 func (c cs3backend) setupLibregraphClient(ctx context.Context, cs3token string) (*libregraph.APIClient, error) {
 	// Use micro registry to resolve next graph service endpoint
 	next, err := c.graphSelector.Select("com.owncloud.graph.graph")
@@ -271,3 +280,48 @@ func (c cs3backend) cs3UserFromLibregraph(ctx context.Context, lu *libregraph.Us
 	cs3user.Mail = lu.GetMail()
 	return cs3user
 }
+
+// This returns an hardcoded internal User, that is privileged to create new User via
+// the Graph API. This user is needed for autoprovisioning of users from incoming OIDC
+// claims.
+func getAutoProvisionUserCreator() (*cs3.User, error) {
+	encRoleID, err := encodeRoleIDs([]string{settingsService.BundleUUIDRoleAdmin})
+	if err != nil {
+		return nil, err
+	}
+
+	autoProvisionUserCreator := &cs3.User{
+		DisplayName: "Autoprovision User",
+		Username:    "autoprovisioner",
+		Id: &cs3.UserId{
+			Idp:      "internal",
+			OpaqueId: "autoprov-user-id00-0000-000000000000",
+		},
+		Opaque: &types.Opaque{
+			Map: map[string]*types.OpaqueEntry{
+				"roles": encRoleID,
+			},
+		},
+	}
+	return autoProvisionUserCreator, nil
+}
+
+func (c cs3backend) generateAutoProvisionAdminToken(ctx context.Context) (string, error) {
+	userCreator, err := getAutoProvisionUserCreator()
+	if err != nil {
+		return "", err
+	}
+
+	s, err := scope.AddOwnerScope(nil)
+	if err != nil {
+		c.logger.Error().Err(err).Msg("could not get owner scope")
+		return "", err
+	}
+
+	token, err := c.tokenManager.MintToken(ctx, userCreator, s)
+	if err != nil {
+		c.logger.Error().Err(err).Msg("could not mint token")
+		return "", err
+	}
+	return token, nil
+}
diff --git a/services/proxy/pkg/user/backend/mocks/UserBackend.go b/services/proxy/pkg/user/backend/mocks/UserBackend.go
deleted file mode 100644
index 76fe443c0cb..00000000000
--- a/services/proxy/pkg/user/backend/mocks/UserBackend.go
+++ /dev/null
@@ -1,113 +0,0 @@
-// Code generated by mockery v2.14.0. DO NOT EDIT.
-
-package mocks
-
-import (
-	context "context"
-
-	userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
-	mock "github.com/stretchr/testify/mock"
-)
-
-// UserBackend is an autogenerated mock type for the UserBackend type
-type UserBackend struct {
-	mock.Mock
-}
-
-// Authenticate provides a mock function with given fields: ctx, username, password
-func (_m *UserBackend) Authenticate(ctx context.Context, username string, password string) (*userv1beta1.User, string, error) {
-	ret := _m.Called(ctx, username, password)
-
-	var r0 *userv1beta1.User
-	if rf, ok := ret.Get(0).(func(context.Context, string, string) *userv1beta1.User); ok {
-		r0 = rf(ctx, username, password)
-	} else {
-		if ret.Get(0) != nil {
-			r0 = ret.Get(0).(*userv1beta1.User)
-		}
-	}
-
-	var r1 string
-	if rf, ok := ret.Get(1).(func(context.Context, string, string) string); ok {
-		r1 = rf(ctx, username, password)
-	} else {
-		r1 = ret.Get(1).(string)
-	}
-
-	var r2 error
-	if rf, ok := ret.Get(2).(func(context.Context, string, string) error); ok {
-		r2 = rf(ctx, username, password)
-	} else {
-		r2 = ret.Error(2)
-	}
-
-	return r0, r1, r2
-}
-
-// CreateUserFromClaims provides a mock function with given fields: ctx, claims
-func (_m *UserBackend) CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*userv1beta1.User, error) {
-	ret := _m.Called(ctx, claims)
-
-	var r0 *userv1beta1.User
-	if rf, ok := ret.Get(0).(func(context.Context, map[string]interface{}) *userv1beta1.User); ok {
-		r0 = rf(ctx, claims)
-	} else {
-		if ret.Get(0) != nil {
-			r0 = ret.Get(0).(*userv1beta1.User)
-		}
-	}
-
-	var r1 error
-	if rf, ok := ret.Get(1).(func(context.Context, map[string]interface{}) error); ok {
-		r1 = rf(ctx, claims)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// GetUserByClaims provides a mock function with given fields: ctx, claim, value
-func (_m *UserBackend) GetUserByClaims(ctx context.Context, claim string, value string) (*userv1beta1.User, string, error) {
-	ret := _m.Called(ctx, claim, value)
-
-	var r0 *userv1beta1.User
-	if rf, ok := ret.Get(0).(func(context.Context, string, string) *userv1beta1.User); ok {
-		r0 = rf(ctx, claim, value)
-	} else {
-		if ret.Get(0) != nil {
-			r0 = ret.Get(0).(*userv1beta1.User)
-		}
-	}
-
-	var r1 string
-	if rf, ok := ret.Get(1).(func(context.Context, string, string) string); ok {
-		r1 = rf(ctx, claim, value)
-	} else {
-		r1 = ret.Get(1).(string)
-	}
-
-	var r2 error
-	if rf, ok := ret.Get(2).(func(context.Context, string, string) error); ok {
-		r2 = rf(ctx, claim, value)
-	} else {
-		r2 = ret.Error(2)
-	}
-
-	return r0, r1, r2
-}
-
-type mockConstructorTestingTNewUserBackend interface {
-	mock.TestingT
-	Cleanup(func())
-}
-
-// NewUserBackend creates a new instance of UserBackend. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewUserBackend(t mockConstructorTestingTNewUserBackend) *UserBackend {
-	mock := &UserBackend{}
-	mock.Mock.Test(t)
-
-	t.Cleanup(func() { mock.AssertExpectations(t) })
-
-	return mock
-}
diff --git a/services/proxy/pkg/userroles/defaultrole.go b/services/proxy/pkg/userroles/defaultrole.go
deleted file mode 100644
index ac5cc6e2b2a..00000000000
--- a/services/proxy/pkg/userroles/defaultrole.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package userroles
-
-import (
-	"context"
-
-	cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
-	"github.com/cs3org/reva/v2/pkg/utils"
-	"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
-	settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
-	settingsService "github.com/owncloud/ocis/v2/services/settings/pkg/service/v0"
-	"go-micro.dev/v4/metadata"
-)
-
-type defaultRoleAssigner struct {
-	Options
-}
-
-// NewDefaultRoleAssigner returns an implemenation of the UserRoleAssigner interface
-func NewDefaultRoleAssigner(opts ...Option) UserRoleAssigner {
-	opt := Options{}
-	for _, o := range opts {
-		o(&opt)
-	}
-
-	return defaultRoleAssigner{
-		Options: opt,
-	}
-}
-
-// UpdateUserRoleAssignment assigns the role "User" to the supplied user. Unless the user
-// already has a different role assigned.
-func (d defaultRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user *cs3.User, claims map[string]interface{}) (*cs3.User, error) {
-	var roleIDs []string
-	if user.Id.Type != cs3.UserType_USER_TYPE_LIGHTWEIGHT {
-		var err error
-		roleIDs, err = loadRolesIDs(ctx, user.Id.OpaqueId, d.roleService)
-		if err != nil {
-			d.logger.Error().Err(err).Msgf("Could not load roles")
-			return nil, err
-		}
-
-		if len(roleIDs) == 0 {
-			// This user doesn't have a role assignment yet. Assign a
-			// default user role. At least until proper roles are provided. See
-			// https://github.com/owncloud/ocis/issues/1825 for more context.
-			if user.Id.Type == cs3.UserType_USER_TYPE_PRIMARY {
-				d.logger.Info().Str("userid", user.Id.OpaqueId).Msg("user has no role assigned, assigning default user role")
-				ctx = metadata.Set(ctx, middleware.AccountID, user.Id.OpaqueId)
-				_, err := d.roleService.AssignRoleToUser(ctx, &settingssvc.AssignRoleToUserRequest{
-					AccountUuid: user.Id.OpaqueId,
-					RoleId:      settingsService.BundleUUIDRoleUser,
-				})
-				if err != nil {
-					d.logger.Error().Err(err).Msg("Could not add default role")
-					return nil, err
-				}
-				roleIDs = append(roleIDs, settingsService.BundleUUIDRoleUser)
-			}
-		}
-	}
-
-	user.Opaque = utils.AppendJSONToOpaque(user.Opaque, "roles", roleIDs)
-	return user, nil
-}
-
-// ApplyUserRole it looks up the user's role in the settings service and adds it
-// user's opaque data
-func (d defaultRoleAssigner) ApplyUserRole(ctx context.Context, user *cs3.User) (*cs3.User, error) {
-	roleIDs, err := loadRolesIDs(ctx, user.Id.OpaqueId, d.roleService)
-	if err != nil {
-		d.logger.Error().Err(err).Msgf("Could not load roles")
-		return nil, err
-	}
-
-	user.Opaque = utils.AppendJSONToOpaque(user.Opaque, "roles", roleIDs)
-	return user, nil
-}
diff --git a/services/proxy/pkg/userroles/mocks/UserRoleAssigner.go b/services/proxy/pkg/userroles/mocks/UserRoleAssigner.go
deleted file mode 100644
index 39282c5b904..00000000000
--- a/services/proxy/pkg/userroles/mocks/UserRoleAssigner.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Code generated by mockery v2.14.0. DO NOT EDIT.
-
-package mocks
-
-import (
-	context "context"
-
-	mock "github.com/stretchr/testify/mock"
-
-	userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
-)
-
-// UserRoleAssigner is an autogenerated mock type for the UserRoleAssigner type
-type UserRoleAssigner struct {
-	mock.Mock
-}
-
-// ApplyUserRole provides a mock function with given fields: ctx, user
-func (_m *UserRoleAssigner) ApplyUserRole(ctx context.Context, user *userv1beta1.User) (*userv1beta1.User, error) {
-	ret := _m.Called(ctx, user)
-
-	var r0 *userv1beta1.User
-	if rf, ok := ret.Get(0).(func(context.Context, *userv1beta1.User) *userv1beta1.User); ok {
-		r0 = rf(ctx, user)
-	} else {
-		if ret.Get(0) != nil {
-			r0 = ret.Get(0).(*userv1beta1.User)
-		}
-	}
-
-	var r1 error
-	if rf, ok := ret.Get(1).(func(context.Context, *userv1beta1.User) error); ok {
-		r1 = rf(ctx, user)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-// UpdateUserRoleAssignment provides a mock function with given fields: ctx, user, claims
-func (_m *UserRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) (*userv1beta1.User, error) {
-	ret := _m.Called(ctx, user, claims)
-
-	var r0 *userv1beta1.User
-	if rf, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]interface{}) *userv1beta1.User); ok {
-		r0 = rf(ctx, user, claims)
-	} else {
-		if ret.Get(0) != nil {
-			r0 = ret.Get(0).(*userv1beta1.User)
-		}
-	}
-
-	var r1 error
-	if rf, ok := ret.Get(1).(func(context.Context, *userv1beta1.User, map[string]interface{}) error); ok {
-		r1 = rf(ctx, user, claims)
-	} else {
-		r1 = ret.Error(1)
-	}
-
-	return r0, r1
-}
-
-type mockConstructorTestingTNewUserRoleAssigner interface {
-	mock.TestingT
-	Cleanup(func())
-}
-
-// NewUserRoleAssigner creates a new instance of UserRoleAssigner. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewUserRoleAssigner(t mockConstructorTestingTNewUserRoleAssigner) *UserRoleAssigner {
-	mock := &UserRoleAssigner{}
-	mock.Mock.Test(t)
-
-	t.Cleanup(func() { mock.AssertExpectations(t) })
-
-	return mock
-}
diff --git a/services/proxy/pkg/userroles/oidcroles.go b/services/proxy/pkg/userroles/oidcroles.go
deleted file mode 100644
index 0aee52d873b..00000000000
--- a/services/proxy/pkg/userroles/oidcroles.go
+++ /dev/null
@@ -1,198 +0,0 @@
-package userroles
-
-import (
-	"context"
-	"errors"
-	"sync"
-	"time"
-
-	cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
-	revactx "github.com/cs3org/reva/v2/pkg/ctx"
-	"github.com/cs3org/reva/v2/pkg/utils"
-	"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
-	settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
-	"go-micro.dev/v4/metadata"
-)
-
-type oidcRoleAssigner struct {
-	Options
-}
-
-// NewOIDCRoleAssigner returns an implemenation of the UserRoleAssigner interface
-func NewOIDCRoleAssigner(opts ...Option) UserRoleAssigner {
-	opt := Options{}
-	for _, o := range opts {
-		o(&opt)
-	}
-
-	return oidcRoleAssigner{
-		Options: opt,
-	}
-}
-
-// UpdateUserRoleAssignment assigns the role "User" to the supplied user. Unless the user
-// already has a different role assigned.
-func (ra oidcRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user *cs3.User, claims map[string]interface{}) (*cs3.User, error) {
-	logger := ra.logger.SubloggerWithRequestID(ctx).With().Str("userid", user.GetId().GetOpaqueId()).Logger()
-	claimValueToRoleID, err := ra.oidcClaimvaluesToRoleIDs()
-	if err != nil {
-		logger.Error().Err(err).Msg("Error mapping claims to roles ids")
-		return nil, err
-	}
-
-	roleIDsFromClaim := make([]string, 0, 1)
-	claimRoles, ok := claims[ra.rolesClaim].([]interface{})
-	if !ok {
-		logger.Error().Err(err).Str("rolesClaim", ra.rolesClaim).Msg("No roles in user claims")
-		return nil, err
-	}
-	logger.Debug().Str("rolesClaim", ra.rolesClaim).Interface("rolesInClaim", claims[ra.rolesClaim]).Msg("got roles in claim")
-	for _, cri := range claimRoles {
-		cr, ok := cri.(string)
-		if !ok {
-			err := errors.New("invalid role in claims")
-			logger.Error().Err(err).Interface("claimValue", cri).Msg("Is not a valid string.")
-			return nil, err
-		}
-		id, ok := claimValueToRoleID[cr]
-		if !ok {
-			logger.Debug().Str("role", cr).Msg("No mapping for claim role. Skipped.")
-			continue
-		}
-		roleIDsFromClaim = append(roleIDsFromClaim, id)
-	}
-	logger.Debug().Interface("roleIDs", roleIDsFromClaim).Msg("Mapped claim roles to roleids")
-
-	switch len(roleIDsFromClaim) {
-	default:
-		err := errors.New("too many roles found in claims")
-		logger.Error().Err(err).Msg("Only one role per user is allowed.")
-		return nil, err
-	case 0:
-		err := errors.New("no role in claim, maps to a ocis role")
-		logger.Error().Err(err).Msg("")
-		return nil, err
-	case 1:
-		// exactly one mapping. This is right
-	}
-	assignedRoles, err := loadRolesIDs(ctx, user.GetId().GetOpaqueId(), ra.roleService)
-	if err != nil {
-		logger.Error().Err(err).Msg("Could not load roles")
-		return nil, err
-	}
-	if len(assignedRoles) > 1 {
-		err := errors.New("too many roles assigned")
-		logger.Error().Err(err).Msg("The user has too many roles assigned")
-		return nil, err
-	}
-	logger.Debug().Interface("assignedRoleIds", assignedRoles).Msg("Currently assigned roles")
-	if len(assignedRoles) == 0 || (assignedRoles[0] != roleIDsFromClaim[0]) {
-		logger.Debug().Interface("assignedRoleIds", assignedRoles).Interface("newRoleIds", roleIDsFromClaim).Msg("Updating role assignment for user")
-		newctx, err := ra.prepareAdminContext()
-		if err != nil {
-			logger.Error().Err(err).Msg("Error creating admin context")
-			return nil, err
-		}
-		if _, err = ra.roleService.AssignRoleToUser(newctx, &settingssvc.AssignRoleToUserRequest{
-			AccountUuid: user.GetId().GetOpaqueId(),
-			RoleId:      roleIDsFromClaim[0],
-		}); err != nil {
-			logger.Error().Err(err).Msg("Role assignment failed")
-			return nil, err
-		}
-	}
-
-	user.Opaque = utils.AppendJSONToOpaque(user.Opaque, "roles", roleIDsFromClaim)
-	return user, nil
-}
-
-// ApplyUserRole it looks up the user's role in the settings service and adds it
-// user's opaque data
-func (ra oidcRoleAssigner) ApplyUserRole(ctx context.Context, user *cs3.User) (*cs3.User, error) {
-	roleIDs, err := loadRolesIDs(ctx, user.Id.OpaqueId, ra.roleService)
-	if err != nil {
-		ra.logger.Error().Err(err).Msgf("Could not load roles")
-		return nil, err
-	}
-
-	user.Opaque = utils.AppendJSONToOpaque(user.Opaque, "roles", roleIDs)
-	return user, nil
-}
-
-func (ra oidcRoleAssigner) prepareAdminContext() (context.Context, error) {
-	newctx := context.Background()
-	autoProvisionUser, err := ra.autoProvsionCreator.GetAutoProvisionAdmin()
-	if err != nil {
-		return nil, err
-	}
-	token, err := ra.autoProvsionCreator.GetAutoProvisionAdminToken(newctx)
-	if err != nil {
-		ra.logger.Error().Err(err).Msg("Error generating token for provisioning role assignments.")
-		return nil, err
-	}
-	newctx = revactx.ContextSetToken(newctx, token)
-	newctx = metadata.Set(newctx, middleware.AccountID, autoProvisionUser.Id.OpaqueId)
-	newctx = metadata.Set(newctx, middleware.RoleIDs, string(autoProvisionUser.Opaque.Map["roles"].Value))
-	return newctx, nil
-}
-
-type roleClaimToIDCache struct {
-	roleClaimToID map[string]string
-	lastRead      time.Time
-	lock          sync.RWMutex
-}
-
-var roleClaimToID roleClaimToIDCache
-
-func (ra oidcRoleAssigner) oidcClaimvaluesToRoleIDs() (map[string]string, error) {
-	cacheTTL := 5 * time.Minute
-	roleClaimToID.lock.RLock()
-
-	if !roleClaimToID.lastRead.IsZero() && time.Since(roleClaimToID.lastRead) < cacheTTL {
-		defer roleClaimToID.lock.RUnlock()
-		return roleClaimToID.roleClaimToID, nil
-	}
-	ra.logger.Debug().Msg("refreshing roles ids")
-
-	// cache needs Refresh get a write lock
-	roleClaimToID.lock.RUnlock()
-	roleClaimToID.lock.Lock()
-	defer roleClaimToID.lock.Unlock()
-
-	// check again, another goroutine might have updated while we "upgraded" the lock
-	if !roleClaimToID.lastRead.IsZero() && time.Since(roleClaimToID.lastRead) < cacheTTL {
-		return roleClaimToID.roleClaimToID, nil
-	}
-
-	// Get all roles to find the role IDs.
-	// To list roles we need some elevated access to the settings service
-	// prepare a new request context for that until we have service accounts
-	ctx, err := ra.prepareAdminContext()
-	if err != nil {
-		ra.logger.Error().Err(err).Msg("Error creating admin context")
-		return nil, err
-	}
-
-	req := &settingssvc.ListBundlesRequest{}
-	res, err := ra.roleService.ListRoles(ctx, req)
-	if err != nil {
-		ra.logger.Error().Err(err).Msg("Failed to list all roles")
-		return map[string]string{}, err
-	}
-
-	newIDs := map[string]string{}
-	for _, role := range res.Bundles {
-		ra.logger.Debug().Str("role", role.Name).Str("id", role.Id).Msg("Got Role")
-		roleClaim, ok := ra.roleMapping[role.Name]
-		if !ok {
-			err := errors.New("Incomplete role mapping")
-			ra.logger.Error().Err(err).Str("role", role.Name).Msg("Role not mapped to a claim value")
-			return map[string]string{}, err
-		}
-		newIDs[roleClaim] = role.Id
-	}
-	ra.logger.Debug().Interface("roleMap", newIDs).Msg("Claim Role to role ID map")
-	roleClaimToID.roleClaimToID = newIDs
-	roleClaimToID.lastRead = time.Now()
-	return roleClaimToID.roleClaimToID, nil
-}
diff --git a/services/proxy/pkg/userroles/userroles.go b/services/proxy/pkg/userroles/userroles.go
deleted file mode 100644
index 8c2dd431fe1..00000000000
--- a/services/proxy/pkg/userroles/userroles.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package userroles
-
-import (
-	"context"
-
-	cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
-	"github.com/owncloud/ocis/v2/ocis-pkg/log"
-	settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
-	"github.com/owncloud/ocis/v2/services/proxy/pkg/autoprovision"
-)
-
-//go:generate mockery --name=UserRoleAssigner
-
-// UserRoleAssigner allows to provide different implemenation for how users get their default roles
-// assigned by the proxy during authentication
-type UserRoleAssigner interface {
-	// UpdateUserRoleAssignment is called by the account resolver middleware. It updates the user's role assignment
-	// based on the user's (OIDC) claims. It adds the user's roles to the opaque data of the cs3.User struct
-	UpdateUserRoleAssignment(ctx context.Context, user *cs3.User, claims map[string]interface{}) (*cs3.User, error)
-	// ApplyUserRole can be called by proxy middlewares, it looks up the user's roles and adds them
-	// the users "roles" key in the user's opaque data
-	ApplyUserRole(ctx context.Context, user *cs3.User) (*cs3.User, error)
-}
-
-// Options defines the available options for this package.
-type Options struct {
-	roleService         settingssvc.RoleService
-	rolesClaim          string
-	roleMapping         map[string]string
-	autoProvsionCreator autoprovision.Creator
-	logger              log.Logger
-}
-
-// Option defines a single option function.
-type Option func(o *Options)
-
-// WithLogger configure the logger
-func WithLogger(l log.Logger) Option {
-	return func(o *Options) {
-		o.logger = l
-	}
-}
-
-// WithRoleService sets the roleservice instance to use
-func WithRoleService(rs settingssvc.RoleService) Option {
-	return func(o *Options) {
-		o.roleService = rs
-	}
-}
-
-// WithRolesClaim sets the OIDC claim for looking up role names
-func WithRolesClaim(claim string) Option {
-	return func(o *Options) {
-		o.rolesClaim = claim
-	}
-}
-
-// WithRoleMapping configures the map of ocis role names to claims values
-func WithRoleMapping(roleMap map[string]string) Option {
-	return func(o *Options) {
-		o.roleMapping = roleMap
-	}
-}
-
-// WithAutoProvisonCreator configures the autoprovision creator to use
-func WithAutoProvisonCreator(c autoprovision.Creator) Option {
-	return func(o *Options) {
-		o.autoProvsionCreator = c
-	}
-}
-
-// loadRolesIDs returns the role-ids assigned to an user
-func loadRolesIDs(ctx context.Context, opaqueUserID string, rs settingssvc.RoleService) ([]string, error) {
-	req := &settingssvc.ListRoleAssignmentsRequest{AccountUuid: opaqueUserID}
-	assignmentResponse, err := rs.ListRoleAssignments(ctx, req)
-
-	if err != nil {
-		return nil, err
-	}
-
-	roleIDs := make([]string, 0)
-
-	for _, assignment := range assignmentResponse.Assignments {
-		roleIDs = append(roleIDs, assignment.RoleId)
-	}
-
-	return roleIDs, nil
-}
diff --git a/services/settings/pkg/settings/mocks/Manager.go b/services/settings/pkg/settings/mocks/Manager.go
index c5542f3ed37..ca216d97804 100644
--- a/services/settings/pkg/settings/mocks/Manager.go
+++ b/services/settings/pkg/settings/mocks/Manager.go
@@ -1,4 +1,4 @@
-// Code generated by mockery v2.14.0. DO NOT EDIT.
+// Code generated by mockery v2.10.4. DO NOT EDIT.
 
 package mocks
 
@@ -362,18 +362,3 @@ func (_m *Manager) WriteValue(value *v0.Value) (*v0.Value, error) {
 
 	return r0, r1
 }
-
-type mockConstructorTestingTNewManager interface {
-	mock.TestingT
-	Cleanup(func())
-}
-
-// NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-func NewManager(t mockConstructorTestingTNewManager) *Manager {
-	mock := &Manager{}
-	mock.Mock.Test(t)
-
-	t.Cleanup(func() { mock.AssertExpectations(t) })
-
-	return mock
-}
diff --git a/services/userlog/pkg/service/service.go b/services/userlog/pkg/service/service.go
index 2c6ee2837da..266d6403414 100644
--- a/services/userlog/pkg/service/service.go
+++ b/services/userlog/pkg/service/service.go
@@ -83,8 +83,9 @@ func (ul *UserlogService) MemorizeEvents(ch <-chan events.Event) {
 		// for each event we need to:
 		// I) find users eligible to receive the event
 		var (
-			users []string
-			err   error
+			users     []string
+			executant *user.UserId
+			err       error
 		)
 
 		switch e := event.Event.(type) {
@@ -92,22 +93,28 @@ func (ul *UserlogService) MemorizeEvents(ch <-chan events.Event) {
 			err = errors.New("unhandled event")
 		// space related // TODO: how to find spaceadmins?
 		case events.SpaceDisabled:
+			executant = e.Executant
 			users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), viewer)
 		case events.SpaceDeleted:
+			executant = e.Executant
 			for u := range e.FinalMembers {
 				users = append(users, u)
 			}
 		case events.SpaceShared:
+			executant = e.Executant
 			users, err = ul.resolveID(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID)
 		case events.SpaceUnshared:
+			executant = e.Executant
 			users, err = ul.resolveID(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID)
 		case events.SpaceMembershipExpired:
 			users, err = ul.resolveID(ul.impersonate(e.SpaceOwner), e.GranteeUserID, e.GranteeGroupID)
 
 		// share related
 		case events.ShareCreated:
+			executant = e.Executant
 			users, err = ul.resolveID(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID)
 		case events.ShareRemoved:
+			executant = e.Executant
 			users, err = ul.resolveID(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID)
 		case events.ShareExpired:
 			users, err = ul.resolveID(ul.impersonate(e.ShareOwner), e.GranteeUserID, e.GranteeGroupID)
@@ -122,6 +129,8 @@ func (ul *UserlogService) MemorizeEvents(ch <-chan events.Event) {
 		// II) filter users who want to receive the event
 		// This step is postponed for later.
 		// For now each user should get all events she is eligible to receive
+		// ...except notifications for their own actions
+		users = removeExecutant(users, executant)
 
 		// III) store the eventID for each user
 		for _, id := range users {
@@ -451,6 +460,16 @@ func listStorageSpaceRequest(spaceID string) *storageprovider.ListStorageSpacesR
 	}
 }
 
+func removeExecutant(users []string, executant *user.UserId) []string {
+	var usrs []string
+	for _, u := range users {
+		if u != executant.GetOpaqueId() {
+			usrs = append(usrs, u)
+		}
+	}
+	return usrs
+}
+
 type permissionChecker func(*storageprovider.ResourcePermissions) bool
 
 func viewer(perms *storageprovider.ResourcePermissions) bool {


Test patch:
diff --git a/services/proxy/pkg/middleware/account_resolver_test.go b/services/proxy/pkg/middleware/account_resolver_test.go
index e1b3b227d14..14a74225cb0 100644
--- a/services/proxy/pkg/middleware/account_resolver_test.go
+++ b/services/proxy/pkg/middleware/account_resolver_test.go
@@ -14,10 +14,8 @@ import (
 	"github.com/owncloud/ocis/v2/ocis-pkg/oidc"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend"
-	"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend/mocks"
-	userRoleMocks "github.com/owncloud/ocis/v2/services/proxy/pkg/userroles/mocks"
+	"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend/test"
 	"github.com/stretchr/testify/assert"
-	"github.com/test-go/testify/mock"
 )
 
 func TestTokenIsAddedWithMailClaim(t *testing.T) {
@@ -121,17 +119,15 @@ func newMockAccountResolver(userBackendResult *userv1beta1.User, userBackendErr
 		token, _ = tokenManager.MintToken(context.Background(), userBackendResult, s)
 	}
 
-	ub := mocks.UserBackend{}
-	ub.On("GetUserByClaims", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(userBackendResult, token, userBackendErr)
-	ub.On("GetUserRoles", mock.Anything, mock.Anything).Return(userBackendResult, nil)
-
-	ra := userRoleMocks.UserRoleAssigner{}
-	ra.On("UpdateUserRoleAssignment", mock.Anything, mock.Anything, mock.Anything).Return(userBackendResult, nil)
+	mock := &test.UserBackendMock{
+		GetUserByClaimsFunc: func(ctx context.Context, claim string, value string, withRoles bool) (*userv1beta1.User, string, error) {
+			return userBackendResult, token, userBackendErr
+		},
+	}
 
 	return AccountResolver(
 		Logger(log.NewLogger()),
-		UserProvider(&ub),
-		UserRoleAssigner(&ra),
+		UserProvider(mock),
 		TokenManagerConfig(config.TokenManager{JWTSecret: "secret"}),
 		UserOIDCClaim(oidcclaim),
 		UserCS3Claim(cs3claim),
diff --git a/services/proxy/pkg/middleware/basic_auth_test.go b/services/proxy/pkg/middleware/basic_auth_test.go
index 3e7660cf0dc..fcc2e6f3ce0 100644
--- a/services/proxy/pkg/middleware/basic_auth_test.go
+++ b/services/proxy/pkg/middleware/basic_auth_test.go
@@ -1,41 +1,42 @@
 package middleware
 
 import (
+	"context"
 	"net/http"
 	"net/http/httptest"
 
 	userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
 	. "github.com/onsi/ginkgo/v2"
-	"github.com/test-go/testify/mock"
 
 	. "github.com/onsi/gomega"
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
 	"github.com/owncloud/ocis/v2/ocis-pkg/oidc"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend"
-	"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend/mocks"
+	"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend/test"
 )
 
 var _ = Describe("Authenticating requests", Label("BasicAuthenticator"), func() {
 	var authenticator Authenticator
-	ub := mocks.UserBackend{}
-	ub.On("Authenticate", mock.Anything, "testuser", "testpassword").Return(
-		&userv1beta1.User{
-			Id: &userv1beta1.UserId{
-				Idp:      "IdpId",
-				OpaqueId: "OpaqueId",
-			},
-			Username: "testuser",
-			Mail:     "testuser@example.com",
-		},
-		"",
-		nil,
-	)
-	ub.On("Authenticate", mock.Anything, mock.Anything, mock.Anything).Return(nil, "", backend.ErrAccountNotFound)
-
 	BeforeEach(func() {
 		authenticator = BasicAuthenticator{
-			Logger:       log.NewLogger(),
-			UserProvider: &ub,
+			Logger: log.NewLogger(),
+			UserProvider: &test.UserBackendMock{
+				AuthenticateFunc: func(ctx context.Context, username, password string) (*userv1beta1.User, string, error) {
+					var user *userv1beta1.User
+					if username == "testuser" && password == "testpassword" {
+						user = &userv1beta1.User{
+							Id: &userv1beta1.UserId{
+								Idp:      "IdpId",
+								OpaqueId: "OpaqueId",
+							},
+							Username: "testuser",
+							Mail:     "testuser@example.com",
+						}
+						return user, "", nil
+					}
+					return nil, "", backend.ErrAccountNotFound
+				},
+			},
 		}
 	})
 
diff --git a/services/proxy/pkg/user/backend/test/backend_mock.go b/services/proxy/pkg/user/backend/test/backend_mock.go
new file mode 100644
index 00000000000..49c642a29ac
--- /dev/null
+++ b/services/proxy/pkg/user/backend/test/backend_mock.go
@@ -0,0 +1,248 @@
+// Code generated by moq; DO NOT EDIT.
+// github.com/matryer/moq
+
+package test
+
+import (
+	"context"
+	"sync"
+
+	userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
+	"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend"
+)
+
+// Ensure, that UserBackendMock does implement UserBackend.
+// If this is not the case, regenerate this file with moq.
+var _ backend.UserBackend = &UserBackendMock{}
+
+// UserBackendMock is a mock implementation of UserBackend.
+//
+//     func TestSomethingThatUsesUserBackend(t *testing.T) {
+//
+//         // make and configure a mocked UserBackend
+//         mockedUserBackend := &UserBackendMock{
+//             AuthenticateFunc: func(ctx context.Context, username string, password string) (*userv1beta1.User, error) {
+// 	               panic("mock out the Authenticate method")
+//             },
+//             CreateUserFromClaimsFunc: func(ctx context.Context, claims *oidc.StandardClaims) (*userv1beta1.User, error) {
+// 	               panic("mock out the CreateUserFromClaims method")
+//             },
+//             GetUserByClaimsFunc: func(ctx context.Context, claim string, value string, withRoles bool) (*userv1beta1.User, error) {
+// 	               panic("mock out the GetUserByClaims method")
+//             },
+//             GetUserGroupsFunc: func(ctx context.Context, userID string)  {
+// 	               panic("mock out the GetUserGroups method")
+//             },
+//         }
+//
+//         // use mockedUserBackend in code that requires UserBackend
+//         // and then make assertions.
+//
+//     }
+type UserBackendMock struct {
+	// AuthenticateFunc mocks the Authenticate method.
+	AuthenticateFunc func(ctx context.Context, username string, password string) (*userv1beta1.User, string, error)
+
+	// CreateUserFromClaimsFunc mocks the CreateUserFromClaims method.
+	CreateUserFromClaimsFunc func(ctx context.Context, claims map[string]interface{}) (*userv1beta1.User, error)
+
+	// GetUserByClaimsFunc mocks the GetUserByClaims method.
+	GetUserByClaimsFunc func(ctx context.Context, claim string, value string, withRoles bool) (*userv1beta1.User, string, error)
+
+	// GetUserGroupsFunc mocks the GetUserGroups method.
+	GetUserGroupsFunc func(ctx context.Context, userID string)
+
+	// calls tracks calls to the methods.
+	calls struct {
+		// Authenticate holds details about calls to the Authenticate method.
+		Authenticate []struct {
+			// Ctx is the ctx argument value.
+			Ctx context.Context
+			// Username is the username argument value.
+			Username string
+			// Password is the password argument value.
+			Password string
+		}
+		// CreateUserFromClaims holds details about calls to the CreateUserFromClaims method.
+		CreateUserFromClaims []struct {
+			// Ctx is the ctx argument value.
+			Ctx context.Context
+			// Claims is the claims argument value.
+			Claims map[string]interface{}
+		}
+		// GetUserByClaims holds details about calls to the GetUserByClaims method.
+		GetUserByClaims []struct {
+			// Ctx is the ctx argument value.
+			Ctx context.Context
+			// Claim is the claim argument value.
+			Claim string
+			// Value is the value argument value.
+			Value string
+			// WithRoles is the withRoles argument value.
+			WithRoles bool
+		}
+		// GetUserGroups holds details about calls to the GetUserGroups method.
+		GetUserGroups []struct {
+			// Ctx is the ctx argument value.
+			Ctx context.Context
+			// UserID is the userID argument value.
+			UserID string
+		}
+	}
+	lockAuthenticate         sync.RWMutex
+	lockCreateUserFromClaims sync.RWMutex
+	lockGetUserByClaims      sync.RWMutex
+	lockGetUserGroups        sync.RWMutex
+}
+
+// Authenticate calls AuthenticateFunc.
+func (mock *UserBackendMock) Authenticate(ctx context.Context, username string, password string) (*userv1beta1.User, string, error) {
+	if mock.AuthenticateFunc == nil {
+		panic("UserBackendMock.AuthenticateFunc: method is nil but UserBackend.Authenticate was just called")
+	}
+	callInfo := struct {
+		Ctx      context.Context
+		Username string
+		Password string
+	}{
+		Ctx:      ctx,
+		Username: username,
+		Password: password,
+	}
+	mock.lockAuthenticate.Lock()
+	mock.calls.Authenticate = append(mock.calls.Authenticate, callInfo)
+	mock.lockAuthenticate.Unlock()
+	return mock.AuthenticateFunc(ctx, username, password)
+}
+
+// AuthenticateCalls gets all the calls that were made to Authenticate.
+// Check the length with:
+//     len(mockedUserBackend.AuthenticateCalls())
+func (mock *UserBackendMock) AuthenticateCalls() []struct {
+	Ctx      context.Context
+	Username string
+	Password string
+} {
+	var calls []struct {
+		Ctx      context.Context
+		Username string
+		Password string
+	}
+	mock.lockAuthenticate.RLock()
+	calls = mock.calls.Authenticate
+	mock.lockAuthenticate.RUnlock()
+	return calls
+}
+
+// CreateUserFromClaims calls CreateUserFromClaimsFunc.
+func (mock *UserBackendMock) CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*userv1beta1.User, error) {
+	if mock.CreateUserFromClaimsFunc == nil {
+		panic("UserBackendMock.CreateUserFromClaimsFunc: method is nil but UserBackend.CreateUserFromClaims was just called")
+	}
+	callInfo := struct {
+		Ctx    context.Context
+		Claims map[string]interface{}
+	}{
+		Ctx:    ctx,
+		Claims: claims,
+	}
+	mock.lockCreateUserFromClaims.Lock()
+	mock.calls.CreateUserFromClaims = append(mock.calls.CreateUserFromClaims, callInfo)
+	mock.lockCreateUserFromClaims.Unlock()
+	return mock.CreateUserFromClaimsFunc(ctx, claims)
+}
+
+// CreateUserFromClaimsCalls gets all the calls that were made to CreateUserFromClaims.
+// Check the length with:
+//     len(mockedUserBackend.CreateUserFromClaimsCalls())
+func (mock *UserBackendMock) CreateUserFromClaimsCalls() []struct {
+	Ctx    context.Context
+	Claims map[string]interface{}
+} {
+	var calls []struct {
+		Ctx    context.Context
+		Claims map[string]interface{}
+	}
+	mock.lockCreateUserFromClaims.RLock()
+	calls = mock.calls.CreateUserFromClaims
+	mock.lockCreateUserFromClaims.RUnlock()
+	return calls
+}
+
+// GetUserByClaims calls GetUserByClaimsFunc.
+func (mock *UserBackendMock) GetUserByClaims(ctx context.Context, claim string, value string, withRoles bool) (*userv1beta1.User, string, error) {
+	if mock.GetUserByClaimsFunc == nil {
+		panic("UserBackendMock.GetUserByClaimsFunc: method is nil but UserBackend.GetUserByClaims was just called")
+	}
+	callInfo := struct {
+		Ctx       context.Context
+		Claim     string
+		Value     string
+		WithRoles bool
+	}{
+		Ctx:       ctx,
+		Claim:     claim,
+		Value:     value,
+		WithRoles: withRoles,
+	}
+	mock.lockGetUserByClaims.Lock()
+	mock.calls.GetUserByClaims = append(mock.calls.GetUserByClaims, callInfo)
+	mock.lockGetUserByClaims.Unlock()
+	return mock.GetUserByClaimsFunc(ctx, claim, value, withRoles)
+}
+
+// GetUserByClaimsCalls gets all the calls that were made to GetUserByClaims.
+// Check the length with:
+//     len(mockedUserBackend.GetUserByClaimsCalls())
+func (mock *UserBackendMock) GetUserByClaimsCalls() []struct {
+	Ctx       context.Context
+	Claim     string
+	Value     string
+	WithRoles bool
+} {
+	var calls []struct {
+		Ctx       context.Context
+		Claim     string
+		Value     string
+		WithRoles bool
+	}
+	mock.lockGetUserByClaims.RLock()
+	calls = mock.calls.GetUserByClaims
+	mock.lockGetUserByClaims.RUnlock()
+	return calls
+}
+
+// GetUserGroups calls GetUserGroupsFunc.
+func (mock *UserBackendMock) GetUserGroups(ctx context.Context, userID string) {
+	if mock.GetUserGroupsFunc == nil {
+		panic("UserBackendMock.GetUserGroupsFunc: method is nil but UserBackend.GetUserGroups was just called")
+	}
+	callInfo := struct {
+		Ctx    context.Context
+		UserID string
+	}{
+		Ctx:    ctx,
+		UserID: userID,
+	}
+	mock.lockGetUserGroups.Lock()
+	mock.calls.GetUserGroups = append(mock.calls.GetUserGroups, callInfo)
+	mock.lockGetUserGroups.Unlock()
+	mock.GetUserGroupsFunc(ctx, userID)
+}
+
+// GetUserGroupsCalls gets all the calls that were made to GetUserGroups.
+// Check the length with:
+//     len(mockedUserBackend.GetUserGroupsCalls())
+func (mock *UserBackendMock) GetUserGroupsCalls() []struct {
+	Ctx    context.Context
+	UserID string
+} {
+	var calls []struct {
+		Ctx    context.Context
+		UserID string
+	}
+	mock.lockGetUserGroups.RLock()
+	calls = mock.calls.GetUserGroups
+	mock.lockGetUserGroups.RUnlock()
+	return calls
+}
diff --git a/services/userlog/pkg/service/service_test.go b/services/userlog/pkg/service/service_test.go
index 89ce6871fa2..22a6e7831c7 100644
--- a/services/userlog/pkg/service/service_test.go
+++ b/services/userlog/pkg/service/service_test.go
@@ -73,9 +73,9 @@ var _ = Describe("UserlogService", func() {
 
 	It("it stores, returns and deletes a couple of events", func() {
 		ids := make(map[string]struct{})
-		ids[bus.Publish(events.SpaceDisabled{Executant: &user.UserId{OpaqueId: "userid"}})] = struct{}{}
-		ids[bus.Publish(events.SpaceDisabled{Executant: &user.UserId{OpaqueId: "userid"}})] = struct{}{}
-		ids[bus.Publish(events.SpaceDisabled{Executant: &user.UserId{OpaqueId: "userid"}})] = struct{}{}
+		ids[bus.Publish(events.SpaceDisabled{Executant: &user.UserId{OpaqueId: "executinguserid"}})] = struct{}{}
+		ids[bus.Publish(events.SpaceDisabled{Executant: &user.UserId{OpaqueId: "executinguserid"}})] = struct{}{}
+		ids[bus.Publish(events.SpaceDisabled{Executant: &user.UserId{OpaqueId: "executinguserid"}})] = struct{}{}
 		// ids[bus.Publish(events.SpaceMembershipExpired{SpaceOwner: &user.UserId{OpaqueId: "userid"}})] = struct{}{}
 		// ids[bus.Publish(events.ShareCreated{Executant: &user.UserId{OpaqueId: "userid"}})] = struct{}{}