Repository: owncloud/ocis
Pull request #7110 (2023-08-23 12:21:05)

Add missing tracing references to multiple services.
This adds missing tracing references to a lot of services.

Note: There's also a quite specific workaround for enabling tracing in ocdav.


Patch:
diff --git a/.drone.env b/.drone.env
index 48286524f8f..9ca94b0524a 100644
--- a/.drone.env
+++ b/.drone.env
@@ -1,3 +1,3 @@
 # The test runner source for UI tests
-WEB_COMMITID=779be73d9cfa3b91535044d7a191282d7c3c2578
+WEB_COMMITID=a26f7920d4ef8bf57488b18e451525d16e246e9e
 WEB_BRANCH=stable-7.1
diff --git a/.drone.star b/.drone.star
index d36bf4ac18a..951690839d1 100644
--- a/.drone.star
+++ b/.drone.star
@@ -1130,7 +1130,7 @@ def e2eTests(ctx):
             "tikaNeeded": True,
         },
         "suite2": {
-            "path": "tests/e2e/cucumber/features/smoke/*/*[!.oc10].feature",
+            "path": "tests/e2e/cucumber/features/smoke/*[!app-provider]/*[!.oc10].feature",
             "tikaNeeded": False,
         },
     }
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9fb6e89d96f..74affc63ae1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ The following sections list the changes for unreleased.
 * Enhancement - Add static secret to gn endpoints: [#6946](https://github.com/owncloud/ocis/pull/6946)
 * Enhancement - Nats named connections: [#6979](https://github.com/owncloud/ocis/pull/6979)
 * Enhancement - Remove deprecated environment variables: [#7099](https://github.com/owncloud/ocis/pull/7099)
+* Enhancement - Update web to v7.1.0: [#7107](https://github.com/owncloud/ocis/pull/7107)
 
 ## Details
 
@@ -81,6 +82,105 @@ The following sections list the changes for unreleased.
    removal for 4.0.0
 
    https://github.com/owncloud/ocis/pull/7099
+
+* Enhancement - Update web to v7.1.0: [#7107](https://github.com/owncloud/ocis/pull/7107)
+
+   Tags: web
+
+   We updated ownCloud Web to v7.1.0. Please refer to the changelog (linked) for details on the web
+   release.
+
+   ## Summary * Bugfix [owncloud/web#9078](https://github.com/owncloud/web/pull/9078):
+   Favorites list update on removal * Bugfix
+   [owncloud/web#9213](https://github.com/owncloud/web/pull/9213): Space creation does
+   not block reoccurring event * Bugfix
+   [owncloud/web#9247](https://github.com/owncloud/web/issues/9247): Uploading to
+   folders that contain special characters * Bugfix
+   [owncloud/web#9259](https://github.com/owncloud/web/issues/9259): Relative user
+   quota display limited to two decimals * Bugfix
+   [owncloud/web#9261](https://github.com/owncloud/web/issues/9261): Remember
+   location after token invalidation * Bugfix
+   [owncloud/web#9299](https://github.com/owncloud/web/pull/9299): Authenticated
+   public links breaking uploads * Bugfix
+   [owncloud/web#9315](https://github.com/owncloud/web/issues/9315): Switch columns
+   displayed on small screens in "Shared with me" view * Bugfix
+   [owncloud/web#9351](https://github.com/owncloud/web/pull/9351): Media controls
+   overflow on mobile screens * Bugfix
+   [owncloud/web#9389](https://github.com/owncloud/web/pull/9389): Space editors see
+   empty trashbin and delete actions in space trashbin * Bugfix
+   [owncloud/web#9461](https://github.com/owncloud/web/issues/9461): Merging folders *
+   Enhancement [owncloud/web#7967](https://github.com/owncloud/web/pull/7967): Add
+   hasPriority property for editors per extension * Enhancement
+   [owncloud/web#8422](https://github.com/owncloud/web/issues/8422): Improve
+   extension app topbar * Enhancement
+   [owncloud/web#8445](https://github.com/owncloud/web/issues/8445): Open
+   individually shared file in dedicated view * Enhancement
+   [owncloud/web#8599](https://github.com/owncloud/web/issues/8599): Shrink table
+   columns * Enhancement
+   [owncloud/web#8921](https://github.com/owncloud/web/pull/8921): Add whitespace
+   context-menu * Enhancement
+   [owncloud/web#8983](https://github.com/owncloud/web/pull/8983): Deny share access *
+   Enhancement [owncloud/web#8984](https://github.com/owncloud/web/pull/8984): Long
+   breadcrumb strategy * Enhancement
+   [owncloud/web#9044](https://github.com/owncloud/web/pull/9044): Search tag filter *
+   Enhancement [owncloud/web#9046](https://github.com/owncloud/web/pull/9046): Single
+   file link open with default app * Enhancement
+   [owncloud/web#9052](https://github.com/owncloud/web/pull/9052): Drag & drop on parent
+   folder * Enhancement
+   [owncloud/web#9055](https://github.com/owncloud/web/pull/9055): Respect archiver
+   limits * Enhancement
+   [owncloud/web#9056](https://github.com/owncloud/web/issues/9056): Enable download
+   (archive) on spaces * Enhancement
+   [owncloud/web#9059](https://github.com/owncloud/web/pull/9059): Search full-text
+   filter * Enhancement
+   [owncloud/web#9077](https://github.com/owncloud/web/pull/9077): Advanced search
+   button * Enhancement
+   [owncloud/web#9077](https://github.com/owncloud/web/pull/9077): Search breadcrumb *
+   Enhancement [owncloud/web#9088](https://github.com/owncloud/web/pull/9088): Use app
+   icons for files * Enhancement
+   [owncloud/web#9140](https://github.com/owncloud/web/pull/9140): Upload file on paste
+   * Enhancement [owncloud/web#9151](https://github.com/owncloud/web/issues/9151):
+   Cloud import * Enhancement
+   [owncloud/web#9174](https://github.com/owncloud/web/issues/9174): Privacy
+   statement in account menu * Enhancement
+   [owncloud/web#9178](https://github.com/owncloud/web/pull/9178): Add login button to
+   top bar * Enhancement
+   [owncloud/web#9195](https://github.com/owncloud/web/pull/9195): Project spaces list
+   viewmode * Enhancement
+   [owncloud/web#9199](https://github.com/owncloud/web/pull/9199): Add pagination
+   options to admin settings * Enhancement
+   [owncloud/web#9200](https://github.com/owncloud/web/pull/9200): Add batch actions to
+   search result list * Enhancement
+   [owncloud/web#9216](https://github.com/owncloud/web/issues/9216): Restyle possible
+   sharees * Enhancement
+   [owncloud/web#9226](https://github.com/owncloud/web/pull/9226): Streamline URL
+   query names * Enhancement
+   [owncloud/web#9263](https://github.com/owncloud/web/pull/9263): Access denied page
+   update message * Enhancement
+   [owncloud/web#9280](https://github.com/owncloud/web/issues/9280): Hover tooltips in
+   topbar * Enhancement
+   [owncloud/web#9294](https://github.com/owncloud/web/pull/9294): Search list add
+   highlighted file content * Enhancement
+   [owncloud/web#9299](https://github.com/owncloud/web/pull/9299): Resolve pulic links
+   to their actual location * Enhancement
+   [owncloud/web#9304](https://github.com/owncloud/web/pull/9304): Add search location
+   filter * Enhancement
+   [owncloud/web#9344](https://github.com/owncloud/web/pull/9344): Ambiguation for URL
+   view mode params * Enhancement
+   [owncloud/web#9346](https://github.com/owncloud/web/pull/9346): Batch actions
+   redesign * Enhancement
+   [owncloud/web#9348](https://github.com/owncloud/web/pull/9348): Tag comma
+   separation on client side * Enhancement
+   [owncloud/web#9377](https://github.com/owncloud/web/issues/9377): User
+   notification for blocked pop-ups and redirects * Enhancement
+   [owncloud/web#9386](https://github.com/owncloud/web/pull/9386): Allow local storage
+   for auth token * Enhancement
+   [owncloud/web#9394](https://github.com/owncloud/web/pull/9394): Button styling *
+   Enhancement [owncloud/web#9436](https://github.com/owncloud/web/pull/9436): Add
+   error log to upload dialog
+
+   https://github.com/owncloud/ocis/pull/7107
+   https://github.com/owncloud/web/releases/tag/v7.1.0
 # Changelog for [3.1.0] (2023-08-02)
 
 The following sections list the changes for 3.1.0.
diff --git a/changelog/unreleased/update-web-7.1.0.md b/changelog/unreleased/update-web-7.1.0.md
new file mode 100644
index 00000000000..75f78ee732f
--- /dev/null
+++ b/changelog/unreleased/update-web-7.1.0.md
@@ -0,0 +1,57 @@
+Enhancement: Update web to v7.1.0
+
+Tags: web
+
+We updated ownCloud Web to v7.1.0. Please refer to the changelog (linked) for details on the web release.
+
+## Summary
+* Bugfix [owncloud/web#9078](https://github.com/owncloud/web/pull/9078): Favorites list update on removal
+* Bugfix [owncloud/web#9213](https://github.com/owncloud/web/pull/9213): Space creation does not block reoccurring event
+* Bugfix [owncloud/web#9247](https://github.com/owncloud/web/issues/9247): Uploading to folders that contain special characters
+* Bugfix [owncloud/web#9259](https://github.com/owncloud/web/issues/9259): Relative user quota display limited to two decimals
+* Bugfix [owncloud/web#9261](https://github.com/owncloud/web/issues/9261): Remember location after token invalidation
+* Bugfix [owncloud/web#9299](https://github.com/owncloud/web/pull/9299): Authenticated public links breaking uploads
+* Bugfix [owncloud/web#9315](https://github.com/owncloud/web/issues/9315): Switch columns displayed on small screens in "Shared with me" view
+* Bugfix [owncloud/web#9351](https://github.com/owncloud/web/pull/9351): Media controls overflow on mobile screens
+* Bugfix [owncloud/web#9389](https://github.com/owncloud/web/pull/9389): Space editors see empty trashbin and delete actions in space trashbin
+* Bugfix [owncloud/web#9461](https://github.com/owncloud/web/issues/9461): Merging folders
+* Enhancement [owncloud/web#7967](https://github.com/owncloud/web/pull/7967): Add hasPriority property for editors per extension
+* Enhancement [owncloud/web#8422](https://github.com/owncloud/web/issues/8422): Improve extension app topbar
+* Enhancement [owncloud/web#8445](https://github.com/owncloud/web/issues/8445): Open individually shared file in dedicated view
+* Enhancement [owncloud/web#8599](https://github.com/owncloud/web/issues/8599): Shrink table columns
+* Enhancement [owncloud/web#8921](https://github.com/owncloud/web/pull/8921): Add whitespace context-menu
+* Enhancement [owncloud/web#8983](https://github.com/owncloud/web/pull/8983): Deny share access
+* Enhancement [owncloud/web#8984](https://github.com/owncloud/web/pull/8984): Long breadcrumb strategy
+* Enhancement [owncloud/web#9044](https://github.com/owncloud/web/pull/9044): Search tag filter
+* Enhancement [owncloud/web#9046](https://github.com/owncloud/web/pull/9046): Single file link open with default app
+* Enhancement [owncloud/web#9052](https://github.com/owncloud/web/pull/9052): Drag & drop on parent folder
+* Enhancement [owncloud/web#9055](https://github.com/owncloud/web/pull/9055): Respect archiver limits
+* Enhancement [owncloud/web#9056](https://github.com/owncloud/web/issues/9056): Enable download (archive) on spaces
+* Enhancement [owncloud/web#9059](https://github.com/owncloud/web/pull/9059): Search full-text filter
+* Enhancement [owncloud/web#9077](https://github.com/owncloud/web/pull/9077): Advanced search button
+* Enhancement [owncloud/web#9077](https://github.com/owncloud/web/pull/9077): Search breadcrumb
+* Enhancement [owncloud/web#9088](https://github.com/owncloud/web/pull/9088): Use app icons for files
+* Enhancement [owncloud/web#9140](https://github.com/owncloud/web/pull/9140): Upload file on paste
+* Enhancement [owncloud/web#9151](https://github.com/owncloud/web/issues/9151): Cloud import
+* Enhancement [owncloud/web#9174](https://github.com/owncloud/web/issues/9174): Privacy statement in account menu
+* Enhancement [owncloud/web#9178](https://github.com/owncloud/web/pull/9178): Add login button to top bar
+* Enhancement [owncloud/web#9195](https://github.com/owncloud/web/pull/9195): Project spaces list viewmode
+* Enhancement [owncloud/web#9199](https://github.com/owncloud/web/pull/9199): Add pagination options to admin settings
+* Enhancement [owncloud/web#9200](https://github.com/owncloud/web/pull/9200): Add batch actions to search result list
+* Enhancement [owncloud/web#9216](https://github.com/owncloud/web/issues/9216): Restyle possible sharees
+* Enhancement [owncloud/web#9226](https://github.com/owncloud/web/pull/9226): Streamline URL query names
+* Enhancement [owncloud/web#9263](https://github.com/owncloud/web/pull/9263): Access denied page update message
+* Enhancement [owncloud/web#9280](https://github.com/owncloud/web/issues/9280): Hover tooltips in topbar
+* Enhancement [owncloud/web#9294](https://github.com/owncloud/web/pull/9294): Search list add highlighted file content
+* Enhancement [owncloud/web#9299](https://github.com/owncloud/web/pull/9299): Resolve pulic links to their actual location
+* Enhancement [owncloud/web#9304](https://github.com/owncloud/web/pull/9304): Add search location filter
+* Enhancement [owncloud/web#9344](https://github.com/owncloud/web/pull/9344): Ambiguation for URL view mode params
+* Enhancement [owncloud/web#9346](https://github.com/owncloud/web/pull/9346): Batch actions redesign
+* Enhancement [owncloud/web#9348](https://github.com/owncloud/web/pull/9348): Tag comma separation on client side
+* Enhancement [owncloud/web#9377](https://github.com/owncloud/web/issues/9377): User notification for blocked pop-ups and redirects
+* Enhancement [owncloud/web#9386](https://github.com/owncloud/web/pull/9386): Allow local storage for auth token
+* Enhancement [owncloud/web#9394](https://github.com/owncloud/web/pull/9394): Button styling
+* Enhancement [owncloud/web#9436](https://github.com/owncloud/web/pull/9436): Add error log to upload dialog
+
+https://github.com/owncloud/ocis/pull/7107
+https://github.com/owncloud/web/releases/tag/v7.1.0
diff --git a/ocis-pkg/oidc/client.go b/ocis-pkg/oidc/client.go
index f4fab46ee67..f3bacb40e80 100644
--- a/ocis-pkg/oidc/client.go
+++ b/ocis-pkg/oidc/client.go
@@ -27,7 +27,7 @@ import (
 // OIDCClient used to mock the oidc client during tests
 type OIDCClient interface {
 	UserInfo(ctx context.Context, ts oauth2.TokenSource) (*UserInfo, error)
-	VerifyAccessToken(ctx context.Context, token string) (RegClaimsWithSID, []string, error)
+	VerifyAccessToken(ctx context.Context, token string) (RegClaimsWithSID, jwt.MapClaims, error)
 	VerifyLogoutToken(ctx context.Context, token string) (*LogoutToken, error)
 }
 
@@ -271,27 +271,26 @@ func (c *oidcClient) UserInfo(ctx context.Context, tokenSource oauth2.TokenSourc
 	}, nil
 }
 
-func (c *oidcClient) VerifyAccessToken(ctx context.Context, token string) (RegClaimsWithSID, []string, error) {
-	var mapClaims []string
+func (c *oidcClient) VerifyAccessToken(ctx context.Context, token string) (RegClaimsWithSID, jwt.MapClaims, error) {
 	if err := c.lookupWellKnownOpenidConfiguration(ctx); err != nil {
-		return RegClaimsWithSID{}, mapClaims, err
+		return RegClaimsWithSID{}, jwt.MapClaims{}, err
 	}
 	switch c.accessTokenVerifyMethod {
 	case config.AccessTokenVerificationJWT:
 		return c.verifyAccessTokenJWT(token)
 	case config.AccessTokenVerificationNone:
 		c.Logger.Debug().Msg("Access Token verification disabled")
-		return RegClaimsWithSID{}, mapClaims, nil
+		return RegClaimsWithSID{}, jwt.MapClaims{}, nil
 	default:
 		c.Logger.Error().Str("access_token_verify_method", c.accessTokenVerifyMethod).Msg("Unknown Access Token verification setting")
-		return RegClaimsWithSID{}, mapClaims, errors.New("unknown Access Token Verification method")
+		return RegClaimsWithSID{}, jwt.MapClaims{}, errors.New("unknown Access Token Verification method")
 	}
 }
 
 // verifyAccessTokenJWT tries to parse and verify the access token as a JWT.
-func (c *oidcClient) verifyAccessTokenJWT(token string) (RegClaimsWithSID, []string, error) {
+func (c *oidcClient) verifyAccessTokenJWT(token string) (RegClaimsWithSID, jwt.MapClaims, error) {
 	var claims RegClaimsWithSID
-	var mapClaims []string
+	mapClaims := jwt.MapClaims{}
 	jwks := c.getKeyfunc()
 	if jwks == nil {
 		return claims, mapClaims, errors.New("error initializing jwks keyfunc")
@@ -301,7 +300,7 @@ func (c *oidcClient) verifyAccessTokenJWT(token string) (RegClaimsWithSID, []str
 	if err != nil {
 		return claims, mapClaims, err
 	}
-	_, mapClaims, err = new(jwt.Parser).ParseUnverified(token, jwt.MapClaims{})
+	_, _, err = new(jwt.Parser).ParseUnverified(token, mapClaims)
 	// TODO: decode mapClaims to sth readable
 	c.Logger.Debug().Interface("access token", &claims).Msg("parsed access token")
 	if err != nil {
diff --git a/services/eventhistory/pkg/server/grpc/server.go b/services/eventhistory/pkg/server/grpc/server.go
index 033eb1dc289..d54a97cfce8 100644
--- a/services/eventhistory/pkg/server/grpc/server.go
+++ b/services/eventhistory/pkg/server/grpc/server.go
@@ -26,6 +26,7 @@ func NewService(opts ...Option) grpc.Service {
 		grpc.Context(options.Context),
 		grpc.Flags(options.Flags...),
 		grpc.Version(version.GetString()),
+		grpc.TraceProvider(options.TraceProvider),
 	)
 	if err != nil {
 		options.Logger.Fatal().Err(err).Msg("Error creating event history service")
diff --git a/services/graph/pkg/server/http/server.go b/services/graph/pkg/server/http/server.go
index ddf860356b0..027599665fc 100644
--- a/services/graph/pkg/server/http/server.go
+++ b/services/graph/pkg/server/http/server.go
@@ -95,7 +95,13 @@ func Server(opts ...Option) (http.Service, error) {
 				account.JWTSecret(options.Config.TokenManager.JWTSecret),
 			))
 		roleService = settingssvc.NewRoleService("com.owncloud.api.settings", grpcClient)
-		gatewaySelector, err = pool.GatewaySelector(options.Config.Reva.Address, append(options.Config.Reva.GetRevaOptions(), pool.WithRegistry(registry.GetRegistry()))...)
+		gatewaySelector, err = pool.GatewaySelector(
+			options.Config.Reva.Address,
+			append(
+				options.Config.Reva.GetRevaOptions(),
+				pool.WithRegistry(registry.GetRegistry()),
+				pool.WithTracerProvider(options.TraceProvider),
+			)...)
 		if err != nil {
 			return http.Service{}, errors.Wrap(err, "could not initialize gateway selector")
 		}
diff --git a/services/graph/pkg/service/v0/service.go b/services/graph/pkg/service/v0/service.go
index 98a397847b0..e47c562e821 100644
--- a/services/graph/pkg/service/v0/service.go
+++ b/services/graph/pkg/service/v0/service.go
@@ -320,7 +320,11 @@ func setIdentityBackends(options Options, svc *Graph) error {
 		case "cs3":
 			gatewaySelector, err := pool.GatewaySelector(
 				options.Config.Reva.Address,
-				append(options.Config.Reva.GetRevaOptions(), pool.WithRegistry(registry.GetRegistry()))...,
+				append(
+					options.Config.Reva.GetRevaOptions(),
+					pool.WithRegistry(registry.GetRegistry()),
+					pool.WithTracerProvider(options.TraceProvider),
+				)...,
 			)
 			if err != nil {
 				return err
diff --git a/services/ocdav/pkg/command/server.go b/services/ocdav/pkg/command/server.go
index edd27c1d40e..a5a8d178c41 100644
--- a/services/ocdav/pkg/command/server.go
+++ b/services/ocdav/pkg/command/server.go
@@ -83,6 +83,7 @@ func Server(cfg *config.Config) *cli.Command {
 					// ocdav.TLSConfig() // tls config for the http server
 					ocdav.MetricsEnabled(true),
 					ocdav.MetricsNamespace("ocis"),
+					ocdav.Tracing("Adding these strings is a workaround for ->", "https://github.com/cs3org/reva/issues/4131"),
 					ocdav.WithTraceProvider(tracingProvider),
 				}
 
diff --git a/services/proxy/pkg/command/server.go b/services/proxy/pkg/command/server.go
index be565f7fc14..3a5f0c8eaa1 100644
--- a/services/proxy/pkg/command/server.go
+++ b/services/proxy/pkg/command/server.go
@@ -272,7 +272,13 @@ func (h *StaticRouteHandler) backchannelLogout(w http.ResponseWriter, r *http.Re
 func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config, userInfoCache microstore.Store, traceProvider trace.TracerProvider) alice.Chain {
 	rolesClient := settingssvc.NewRoleService("com.owncloud.api.settings", cfg.GrpcClient)
 	policiesProviderClient := policiessvc.NewPoliciesProviderService("com.owncloud.api.policies", cfg.GrpcClient)
-	gatewaySelector, err := pool.GatewaySelector(cfg.Reva.Address, append(cfg.Reva.GetRevaOptions(), pool.WithRegistry(registry.GetRegistry()))...)
+	gatewaySelector, err := pool.GatewaySelector(
+		cfg.Reva.Address,
+		append(
+			cfg.Reva.GetRevaOptions(),
+			pool.WithRegistry(registry.GetRegistry()),
+			pool.WithTracerProvider(traceProvider),
+		)...)
 	if err != nil {
 		logger.Fatal().Err(err).Msg("Failed to get gateway selector")
 	}
@@ -402,6 +408,7 @@ func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config,
 			middleware.Logger(logger),
 			middleware.UserProvider(userProvider),
 			middleware.UserRoleAssigner(roleAssigner),
+			middleware.SkipUserInfo(cfg.OIDC.SkipUserInfo),
 			middleware.UserOIDCClaim(cfg.UserOIDCClaim),
 			middleware.UserCS3Claim(cfg.UserCS3Claim),
 			middleware.AutoprovisionAccounts(cfg.AutoprovisionAccounts),
diff --git a/services/proxy/pkg/config/config.go b/services/proxy/pkg/config/config.go
index fecd18ca018..7b541961d21 100644
--- a/services/proxy/pkg/config/config.go
+++ b/services/proxy/pkg/config/config.go
@@ -107,6 +107,7 @@ type OIDC struct {
 	Issuer                  string `yaml:"issuer" env:"OCIS_URL;OCIS_OIDC_ISSUER;PROXY_OIDC_ISSUER" desc:"URL of the OIDC issuer. It defaults to URL of the builtin IDP."`
 	Insecure                bool   `yaml:"insecure" env:"OCIS_INSECURE;PROXY_OIDC_INSECURE" desc:"Disable TLS certificate validation for connections to the IDP. Note that this is not recommended for production environments."`
 	AccessTokenVerifyMethod string `yaml:"access_token_verify_method" env:"PROXY_OIDC_ACCESS_TOKEN_VERIFY_METHOD" desc:"Sets how OIDC access tokens should be verified. Possible values are 'none' and 'jwt'. When using 'none', no special validation apart from using it for accessing the IPD's userinfo endpoint will be done. When using 'jwt', it tries to parse the access token as a jwt token and verifies the signature using the keys published on the IDP's 'jwks_uri'."`
+	SkipUserInfo            bool   `yaml:"skip_user_info" env:"PROXY_OIDC_SKIP_USER_INFO" desc:"Do not look up user claims at the userinfo endpoint and directly read them from the access token. Incompatible with 'PROXY_OIDC_ACCESS_TOKEN_VERIFY_METHOD=none'."`
 	UserinfoCache           *Cache `yaml:"user_info_cache"`
 	JWKS                    JWKS   `yaml:"jwks"`
 	RewriteWellKnown        bool   `yaml:"rewrite_well_known" env:"PROXY_OIDC_REWRITE_WELLKNOWN" desc:"Enables rewriting the /.well-known/openid-configuration to the configured OIDC issuer. Needed by the Desktop Client, Android Client and iOS Client to discover the OIDC provider."`
diff --git a/services/proxy/pkg/config/defaults/defaultconfig.go b/services/proxy/pkg/config/defaults/defaultconfig.go
index 68741399432..e8a93e0de52 100644
--- a/services/proxy/pkg/config/defaults/defaultconfig.go
+++ b/services/proxy/pkg/config/defaults/defaultconfig.go
@@ -41,6 +41,7 @@ func DefaultConfig() *config.Config {
 			Issuer: "https://localhost:9200",
 
 			AccessTokenVerifyMethod: config.AccessTokenVerificationJWT,
+			SkipUserInfo:            false,
 			UserinfoCache: &config.Cache{
 				Store:    "memory",
 				Database: "ocis",
@@ -61,10 +62,10 @@ func DefaultConfig() *config.Config {
 			OIDCRoleMapper: config.OIDCRoleMapper{
 				RoleClaim: "roles",
 				RolesMap: []config.RoleMapping{
-					config.RoleMapping{RoleName: "admin", ClaimValue: "ocisAdmin"},
-					config.RoleMapping{RoleName: "spaceadmin", ClaimValue: "ocisSpaceAdmin"},
-					config.RoleMapping{RoleName: "user", ClaimValue: "ocisUser"},
-					config.RoleMapping{RoleName: "guest", ClaimValue: "ocisGuest"},
+					{RoleName: "admin", ClaimValue: "ocisAdmin"},
+					{RoleName: "spaceadmin", ClaimValue: "ocisSpaceAdmin"},
+					{RoleName: "user", ClaimValue: "ocisUser"},
+					{RoleName: "guest", ClaimValue: "ocisGuest"},
 				},
 			},
 		},
diff --git a/services/proxy/pkg/config/parser/parse.go b/services/proxy/pkg/config/parser/parse.go
index 877f95ee9fe..59553b42eaf 100644
--- a/services/proxy/pkg/config/parser/parse.go
+++ b/services/proxy/pkg/config/parser/parse.go
@@ -50,6 +50,12 @@ func Validate(cfg *config.Config) error {
 			config.AccessTokenVerificationJWT, config.AccessTokenVerificationNone,
 		)
 	}
+	if cfg.OIDC.AccessTokenVerifyMethod == "none" && cfg.OIDC.SkipUserInfo {
+		return fmt.Errorf(
+			"Incompatible value '%t' for 'skip_user_info' in service %s. Must be false when 'access_token_verify_method' is 'none'.",
+			cfg.OIDC.SkipUserInfo, cfg.Service.Name,
+		)
+	}
 
 	return nil
 }
diff --git a/services/proxy/pkg/middleware/account_resolver.go b/services/proxy/pkg/middleware/account_resolver.go
index 3847f02e7d2..0a9079091ce 100644
--- a/services/proxy/pkg/middleware/account_resolver.go
+++ b/services/proxy/pkg/middleware/account_resolver.go
@@ -2,7 +2,9 @@ package middleware
 
 import (
 	"errors"
+	"fmt"
 	"net/http"
+	"strings"
 
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/user/backend"
 	"github.com/owncloud/ocis/v2/services/proxy/pkg/userroles"
@@ -41,6 +43,54 @@ type accountResolver struct {
 	userCS3Claim          string
 }
 
+// from https://codereview.stackexchange.com/a/280193
+func splitWithEscaping(s string, separator string, escapeString string) []string {
+	a := strings.Split(s, separator)
+
+	for i := len(a) - 2; i >= 0; i-- {
+		if strings.HasSuffix(a[i], escapeString) {
+			a[i] = a[i][:len(a[i])-len(escapeString)] + separator + a[i+1]
+			a = append(a[:i+1], a[i+2:]...)
+		}
+	}
+	return a
+}
+
+func readUserIDClaim(path string, claims map[string]interface{}) (string, error) {
+	// happy path
+	value, _ := claims[path].(string)
+	if value != "" {
+		return value, nil
+	}
+
+	// try splitting path at .
+	segments := splitWithEscaping(path, ".", "\\")
+	subclaims := claims
+	lastSegment := len(segments) - 1
+	for i := range segments {
+		if i < lastSegment {
+			if castedClaims, ok := subclaims[segments[i]].(map[string]interface{}); ok {
+				subclaims = castedClaims
+			} else if castedClaims, ok := subclaims[segments[i]].(map[interface{}]interface{}); ok {
+				subclaims = make(map[string]interface{}, len(castedClaims))
+				for k, v := range castedClaims {
+					if s, ok := k.(string); ok {
+						subclaims[s] = v
+					} else {
+						return "", fmt.Errorf("could not walk claims path, key '%v' is not a string", k)
+					}
+				}
+			}
+		} else {
+			if value, _ = subclaims[segments[i]].(string); value != "" {
+				return value, nil
+			}
+		}
+	}
+
+	return value, fmt.Errorf("claim path '%s' not set or empty", path)
+}
+
 // TODO do not use the context to store values: https://medium.com/@cep21/how-to-correctly-use-context-context-in-go-1-7-8f2c0fafdf39
 func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 	ctx := req.Context()
@@ -55,13 +105,10 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 	}
 
 	if user == nil && claims != nil {
-
-		var err error
-		var value string
-		var ok bool
-		if value, ok = claims[m.userOIDCClaim].(string); !ok || value == "" {
-			m.logger.Error().Str("claim", m.userOIDCClaim).Interface("claims", claims).Msg("claim not set or empty")
-			w.WriteHeader(http.StatusInternalServerError) // admin needs to make the idp send the right claim
+		value, err := readUserIDClaim(m.userOIDCClaim, claims)
+		if err != nil {
+			m.logger.Error().Err(err).Msg("could not read user id claim")
+			w.WriteHeader(http.StatusInternalServerError)
 			return
 		}
 
diff --git a/services/proxy/pkg/middleware/oidc_auth.go b/services/proxy/pkg/middleware/oidc_auth.go
index 15d0257a1d8..8250f834cb0 100644
--- a/services/proxy/pkg/middleware/oidc_auth.go
+++ b/services/proxy/pkg/middleware/oidc_auth.go
@@ -3,7 +3,6 @@ package middleware
 import (
 	"context"
 	"encoding/base64"
-	"fmt"
 	"net/http"
 	"strings"
 	"time"
@@ -35,6 +34,7 @@ func NewOIDCAuthenticator(opts ...Option) *OIDCAuthenticator {
 		OIDCIss:                 options.OIDCIss,
 		oidcClient:              options.OIDCClient,
 		AccessTokenVerifyMethod: options.AccessTokenVerifyMethod,
+		skipUserInfo:            options.SkipUserInfo,
 	}
 }
 
@@ -47,6 +47,7 @@ type OIDCAuthenticator struct {
 	DefaultTokenCacheTTL    time.Duration
 	oidcClient              oidc.OIDCClient
 	AccessTokenVerifyMethod string
+	skipUserInfo            bool
 }
 
 func (m *OIDCAuthenticator) getClaims(token string, req *http.Request) (map[string]interface{}, error) {
@@ -62,36 +63,38 @@ func (m *OIDCAuthenticator) getClaims(token string, req *http.Request) (map[stri
 		m.Logger.Error().Err(err).Msg("could not read from userinfo cache")
 	}
 	if len(record) > 0 {
-		if err = msgpack.Unmarshal(record[0].Value, &claims); err == nil {
+		if err = msgpack.UnmarshalAsMap(record[0].Value, &claims); err == nil {
 			m.Logger.Debug().Interface("claims", claims).Msg("cache hit for userinfo")
 			return claims, nil
 		}
 		m.Logger.Error().Err(err).Msg("could not unmarshal userinfo")
 	}
 
-	aClaims, _, err := m.oidcClient.VerifyAccessToken(req.Context(), token)
+	aClaims, claims, err := m.oidcClient.VerifyAccessToken(req.Context(), token)
 	if err != nil {
 		return nil, errors.Wrap(err, "failed to verify access token")
 	}
 
-	oauth2Token := &oauth2.Token{
-		AccessToken: token,
-	}
+	if !m.skipUserInfo {
+		oauth2Token := &oauth2.Token{
+			AccessToken: token,
+		}
 
-	userInfo, err := m.oidcClient.UserInfo(
-		context.WithValue(req.Context(), oauth2.HTTPClient, m.HTTPClient),
-		oauth2.StaticTokenSource(oauth2Token),
-	)
-	if err != nil {
-		return nil, errors.Wrap(err, "failed to get userinfo")
-	}
-	if err := userInfo.Claims(&claims); err != nil {
-		return nil, errors.Wrap(err, "failed to unmarshal userinfo claims")
+		userInfo, err := m.oidcClient.UserInfo(
+			context.WithValue(req.Context(), oauth2.HTTPClient, m.HTTPClient),
+			oauth2.StaticTokenSource(oauth2Token),
+		)
+		if err != nil {
+			return nil, errors.Wrap(err, "failed to get userinfo")
+		}
+		if err := userInfo.Claims(&claims); err != nil {
+			return nil, errors.Wrap(err, "failed to unmarshal userinfo claims")
+		}
 	}
 
 	expiration := m.extractExpiration(aClaims)
 	go func() {
-		if d, err := msgpack.Marshal(claims); err != nil {
+		if d, err := msgpack.MarshalAsMap(claims); err != nil {
 			m.Logger.Error().Err(err).Msg("failed to marshal claims for userinfo cache")
 		} else {
 			err = m.userInfoCache.Write(&store.Record{
@@ -106,7 +109,7 @@ func (m *OIDCAuthenticator) getClaims(token string, req *http.Request) (map[stri
 			if sid := aClaims.SessionID; sid != "" {
 				// reuse user cache for session id lookup
 				err = m.userInfoCache.Write(&store.Record{
-					Key:    fmt.Sprintf("%s", sid),
+					Key:    sid,
 					Value:  []byte(encodedHash),
 					Expiry: time.Until(expiration),
 				})
diff --git a/services/proxy/pkg/middleware/options.go b/services/proxy/pkg/middleware/options.go
index a86b7874e52..2392c21b95f 100644
--- a/services/proxy/pkg/middleware/options.go
+++ b/services/proxy/pkg/middleware/options.go
@@ -75,6 +75,8 @@ type Options struct {
 	RoleQuotas map[string]uint64
 	// TraceProvider sets the tracing provider.
 	TraceProvider trace.TracerProvider
+	// SkipUserInfo prevents the oidc middleware from querying the userinfo endpoint and read any claims directly from the access token instead
+	SkipUserInfo bool
 }
 
 // newOptions initializes the available default options.
@@ -248,3 +250,10 @@ func TraceProvider(tp trace.TracerProvider) Option {
 		o.TraceProvider = tp
 	}
 }
+
+// SkipUserInfo sets the skipUserInfo flag.
+func SkipUserInfo(val bool) Option {
+	return func(o *Options) {
+		o.SkipUserInfo = val
+	}
+}
diff --git a/services/search/pkg/server/grpc/server.go b/services/search/pkg/server/grpc/server.go
index c193da94f05..4b686cb4b36 100644
--- a/services/search/pkg/server/grpc/server.go
+++ b/services/search/pkg/server/grpc/server.go
@@ -36,6 +36,7 @@ func Server(opts ...Option) (grpc.Service, func(), error) {
 		svc.Config(options.Config),
 		svc.Logger(options.Logger),
 		svc.JWTSecret(options.JWTSecret),
+		svc.TracerProvider(options.TraceProvider),
 	)
 	if err != nil {
 		options.Logger.Error().
diff --git a/services/search/pkg/service/grpc/v0/option.go b/services/search/pkg/service/grpc/v0/option.go
index 72014b8e452..f2ed223b651 100644
--- a/services/search/pkg/service/grpc/v0/option.go
+++ b/services/search/pkg/service/grpc/v0/option.go
@@ -3,6 +3,7 @@ package service
 import (
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
 	"github.com/owncloud/ocis/v2/services/search/pkg/config"
+	"go.opentelemetry.io/otel/trace"
 )
 
 // Option defines a single option function.
@@ -10,9 +11,10 @@ type Option func(o *Options)
 
 // Options defines the available options for this package.
 type Options struct {
-	Logger    log.Logger
-	Config    *config.Config
-	JWTSecret string
+	Logger         log.Logger
+	Config         *config.Config
+	JWTSecret      string
+	TracerProvider trace.TracerProvider
 }
 
 func newOptions(opts ...Option) Options {
@@ -45,3 +47,10 @@ func JWTSecret(val string) Option {
 		o.JWTSecret = val
 	}
 }
+
+// TracerProvider provides a function to set the TracerProvider option
+func TracerProvider(val trace.TracerProvider) Option {
+	return func(o *Options) {
+		o.TracerProvider = val
+	}
+}
diff --git a/services/search/pkg/service/grpc/v0/service.go b/services/search/pkg/service/grpc/v0/service.go
index a3e4cda1dae..eea98596843 100644
--- a/services/search/pkg/service/grpc/v0/service.go
+++ b/services/search/pkg/service/grpc/v0/service.go
@@ -53,7 +53,7 @@ func NewHandler(opts ...Option) (searchsvc.SearchProviderHandler, func(), error)
 	}
 
 	// initialize gateway
-	selector, err := pool.GatewaySelector(cfg.Reva.Address, pool.WithRegistry(registry.GetRegistry()))
+	selector, err := pool.GatewaySelector(cfg.Reva.Address, pool.WithRegistry(registry.GetRegistry()), pool.WithTracerProvider(options.TracerProvider))
 	if err != nil {
 		logger.Fatal().Err(err).Msg("could not get reva gateway selector")
 		return nil, teardown, err
diff --git a/services/storage-users/pkg/command/server.go b/services/storage-users/pkg/command/server.go
index 4f544ce1218..e6acbd6f47f 100644
--- a/services/storage-users/pkg/command/server.go
+++ b/services/storage-users/pkg/command/server.go
@@ -94,7 +94,7 @@ func Server(cfg *config.Config) *cli.Command {
 					logger.Fatal().Err(err).Msg("can't connect to nats")
 				}
 
-				selector, err := pool.GatewaySelector(cfg.Reva.Address, pool.WithRegistry(registry.GetRegistry()))
+				selector, err := pool.GatewaySelector(cfg.Reva.Address, pool.WithRegistry(registry.GetRegistry()), pool.WithTracerProvider(traceProvider))
 				if err != nil {
 					return err
 				}
diff --git a/services/store/pkg/command/server.go b/services/store/pkg/command/server.go
index f02765a6b52..3d766034799 100644
--- a/services/store/pkg/command/server.go
+++ b/services/store/pkg/command/server.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
 	ogrpc "github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
+	"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
 	"github.com/owncloud/ocis/v2/services/store/pkg/config"
 	"github.com/owncloud/ocis/v2/services/store/pkg/config/parser"
@@ -15,7 +16,6 @@ import (
 	"github.com/owncloud/ocis/v2/services/store/pkg/metrics"
 	"github.com/owncloud/ocis/v2/services/store/pkg/server/debug"
 	"github.com/owncloud/ocis/v2/services/store/pkg/server/grpc"
-	"github.com/owncloud/ocis/v2/services/store/pkg/tracing"
 	"github.com/urfave/cli/v2"
 )
 
@@ -30,12 +30,15 @@ func Server(cfg *config.Config) *cli.Command {
 		},
 		Action: func(c *cli.Context) error {
 			logger := logging.Configure(cfg.Service.Name, cfg.Log)
-			err := tracing.Configure(cfg)
+			traceProvider, err := tracing.GetServiceTraceProvider(cfg.Tracing, cfg.Service.Name)
+			if err != nil {
+				return err
+			}
 			if err != nil {
 				return err
 			}
 			cfg.GrpcClient, err = ogrpc.NewClient(
-				ogrpc.GetClientOptions(cfg.GRPCClientTLS)...,
+				append(ogrpc.GetClientOptions(cfg.GRPCClientTLS), ogrpc.WithTraceProvider(traceProvider))...,
 			)
 			if err != nil {
 				return err
@@ -62,6 +65,7 @@ func Server(cfg *config.Config) *cli.Command {
 					grpc.Context(ctx),
 					grpc.Config(cfg),
 					grpc.Metrics(metrics),
+					grpc.TraceProvider(traceProvider),
 				)
 
 				gr.Add(server.Run, func(err error) {
diff --git a/services/store/pkg/config/tracing.go b/services/store/pkg/config/tracing.go
index 28f7bd3277b..c0319f3af49 100644
--- a/services/store/pkg/config/tracing.go
+++ b/services/store/pkg/config/tracing.go
@@ -1,5 +1,7 @@
 package config
 
+import "github.com/owncloud/ocis/v2/ocis-pkg/tracing"
+
 // Tracing defines the available tracing configuration.
 type Tracing struct {
 	Enabled   bool   `yaml:"enabled" env:"OCIS_TRACING_ENABLED;STORE_TRACING_ENABLED" desc:"Activates tracing."`
@@ -7,3 +9,13 @@ type Tracing struct {
 	Endpoint  string `yaml:"endpoint" env:"OCIS_TRACING_ENDPOINT;STORE_TRACING_ENDPOINT" desc:"The endpoint of the tracing agent."`
 	Collector string `yaml:"collector" env:"OCIS_TRACING_COLLECTOR;STORE_TRACING_COLLECTOR" desc:"The HTTP endpoint for sending spans directly to a collector, i.e. http://jaeger-collector:14268/api/traces. Only used if the tracing endpoint is unset."`
 }
+
+// Convert Tracing to the tracing package's Config struct.
+func (t Tracing) Convert() tracing.Config {
+	return tracing.Config{
+		Enabled:   t.Enabled,
+		Type:      t.Type,
+		Endpoint:  t.Endpoint,
+		Collector: t.Collector,
+	}
+}
diff --git a/services/store/pkg/server/grpc/option.go b/services/store/pkg/server/grpc/option.go
index dc8e168437c..4c72f473c1a 100644
--- a/services/store/pkg/server/grpc/option.go
+++ b/services/store/pkg/server/grpc/option.go
@@ -7,6 +7,7 @@ import (
 	"github.com/owncloud/ocis/v2/services/store/pkg/config"
 	"github.com/owncloud/ocis/v2/services/store/pkg/metrics"
 	"github.com/urfave/cli/v2"
+	"go.opentelemetry.io/otel/trace"
 )
 
 // Option defines a single option function.
@@ -14,12 +15,13 @@ type Option func(o *Options)
 
 // Options defines the available options for this package.
 type Options struct {
-	Name    string
-	Logger  log.Logger
-	Context context.Context
-	Config  *config.Config
-	Metrics *metrics.Metrics
-	Flags   []cli.Flag
+	Name          string
+	Logger        log.Logger
+	Context       context.Context
+	Config        *config.Config
+	Metrics       *metrics.Metrics
+	Flags         []cli.Flag
+	TraceProvider trace.TracerProvider
 }
 
 // newOptions initializes the available default options.
@@ -74,3 +76,14 @@ func Flags(val []cli.Flag) Option {
 		o.Flags = append(o.Flags, val...)
 	}
 }
+
+// TraceProvider provides a function to configure the trace provider
+func TraceProvider(traceProvider trace.TracerProvider) Option {
+	return func(o *Options) {
+		if traceProvider != nil {
+			o.TraceProvider = traceProvider
+		} else {
+			o.TraceProvider = trace.NewNoopTracerProvider()
+		}
+	}
+}
diff --git a/services/store/pkg/server/grpc/server.go b/services/store/pkg/server/grpc/server.go
index 8e9c037fca4..3826eb694c8 100644
--- a/services/store/pkg/server/grpc/server.go
+++ b/services/store/pkg/server/grpc/server.go
@@ -25,6 +25,7 @@ func Server(opts ...Option) grpc.Service {
 		grpc.Address(options.Config.GRPC.Addr),
 		grpc.Logger(options.Logger),
 		grpc.Flags(options.Flags...),
+		grpc.TraceProvider(options.TraceProvider),
 	)
 	if err != nil {
 		options.Logger.Fatal().Err(err).Msg("Error creating store service")
diff --git a/services/store/pkg/tracing/tracing.go b/services/store/pkg/tracing/tracing.go
deleted file mode 100644
index 6e6e7052617..00000000000
--- a/services/store/pkg/tracing/tracing.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package tracing
-
-import (
-	pkgtrace "github.com/owncloud/ocis/v2/ocis-pkg/tracing"
-	"github.com/owncloud/ocis/v2/services/store/pkg/config"
-	"go.opentelemetry.io/otel/trace"
-)
-
-var (
-	// TraceProvider is the global trace provider for the store service.
-	TraceProvider = trace.NewNoopTracerProvider()
-)
-
-func Configure(cfg *config.Config) error {
-	var err error
-	if cfg.Tracing.Enabled {
-		if TraceProvider, err = pkgtrace.GetTraceProvider(cfg.Tracing.Endpoint, cfg.Tracing.Collector, cfg.Service.Name, cfg.Tracing.Type); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
diff --git a/services/thumbnails/pkg/command/server.go b/services/thumbnails/pkg/command/server.go
index 6e32f7fbe13..a18b49e3b2c 100644
--- a/services/thumbnails/pkg/command/server.go
+++ b/services/thumbnails/pkg/command/server.go
@@ -95,6 +95,7 @@ func Server(cfg *config.Config) *cli.Command {
 				http.Config(cfg),
 				http.Metrics(metrics),
 				http.Namespace(cfg.HTTP.Namespace),
+				http.TraceProvider(traceProvider),
 			)
 			if err != nil {
 				logger.Info().
diff --git a/services/thumbnails/pkg/server/grpc/server.go b/services/thumbnails/pkg/server/grpc/server.go
index 270cd994cdb..39f099e14cf 100644
--- a/services/thumbnails/pkg/server/grpc/server.go
+++ b/services/thumbnails/pkg/server/grpc/server.go
@@ -49,6 +49,7 @@ func NewService(opts ...Option) grpc.Service {
 		pool.WithTLSCACert(options.Config.GRPCClientTLS.CACert),
 		pool.WithTLSMode(tm),
 		pool.WithRegistry(registry.GetRegistry()),
+		pool.WithTracerProvider(options.TraceProvider),
 	)
 	if err != nil {
 		options.Logger.Error().Err(err).Msg("could not get gateway selector")
diff --git a/services/thumbnails/pkg/server/http/option.go b/services/thumbnails/pkg/server/http/option.go
index 6cb7020ee56..b77014b1591 100644
--- a/services/thumbnails/pkg/server/http/option.go
+++ b/services/thumbnails/pkg/server/http/option.go
@@ -7,6 +7,7 @@ import (
 	"github.com/owncloud/ocis/v2/services/thumbnails/pkg/config"
 	"github.com/owncloud/ocis/v2/services/thumbnails/pkg/metrics"
 	"github.com/urfave/cli/v2"
+	"go.opentelemetry.io/otel/trace"
 )
 
 // Option defines a single option function.
@@ -14,12 +15,13 @@ type Option func(o *Options)
 
 // Options defines the available options for this package.
 type Options struct {
-	Namespace string
-	Logger    log.Logger
-	Context   context.Context
-	Config    *config.Config
-	Metrics   *metrics.Metrics
-	Flags     []cli.Flag
+	Namespace     string
+	Logger        log.Logger
+	Context       context.Context
+	Config        *config.Config
+	Metrics       *metrics.Metrics
+	Flags         []cli.Flag
+	TraceProvider trace.TracerProvider
 }
 
 // newOptions initializes the available default options.
@@ -67,3 +69,14 @@ func Namespace(val string) Option {
 		o.Namespace = val
 	}
 }
+
+// TraceProvider provides a function to configure the trace provider
+func TraceProvider(traceProvider trace.TracerProvider) Option {
+	return func(o *Options) {
+		if traceProvider != nil {
+			o.TraceProvider = traceProvider
+		} else {
+			o.TraceProvider = trace.NewNoopTracerProvider()
+		}
+	}
+}
diff --git a/services/thumbnails/pkg/server/http/server.go b/services/thumbnails/pkg/server/http/server.go
index 4401ac681c8..7dfa8adb14b 100644
--- a/services/thumbnails/pkg/server/http/server.go
+++ b/services/thumbnails/pkg/server/http/server.go
@@ -24,6 +24,7 @@ func Server(opts ...Option) (http.Service, error) {
 		http.Namespace(options.Config.HTTP.Namespace),
 		http.Address(options.Config.HTTP.Addr),
 		http.Context(options.Context),
+		http.TraceProvider(options.TraceProvider),
 	)
 	if err != nil {
 		options.Logger.Error().
@@ -56,7 +57,6 @@ func Server(opts ...Option) (http.Service, error) {
 	{
 		handle = svc.NewInstrument(handle, options.Metrics)
 		handle = svc.NewLogging(handle, options.Logger)
-		handle = svc.NewTracing(handle)
 	}
 
 	if err := micro.RegisterHandler(service.Server(), handle); err != nil {
diff --git a/services/thumbnails/pkg/service/http/v0/option.go b/services/thumbnails/pkg/service/http/v0/option.go
index 13f2f52a7f8..aa630843ec4 100644
--- a/services/thumbnails/pkg/service/http/v0/option.go
+++ b/services/thumbnails/pkg/service/http/v0/option.go
@@ -6,6 +6,7 @@ import (
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
 	"github.com/owncloud/ocis/v2/services/thumbnails/pkg/config"
 	"github.com/owncloud/ocis/v2/services/thumbnails/pkg/thumbnail/storage"
+	"go.opentelemetry.io/otel/trace"
 )
 
 // Option defines a single option function.
@@ -17,6 +18,7 @@ type Options struct {
 	Config           *config.Config
 	Middleware       []func(http.Handler) http.Handler
 	ThumbnailStorage storage.Storage
+	TraceProvider    trace.TracerProvider
 }
 
 // newOptions initializes the available default options.
@@ -57,3 +59,14 @@ func ThumbnailStorage(storage storage.Storage) Option {
 		o.ThumbnailStorage = storage
 	}
 }
+
+// TraceProvider provides a function to configure the trace provider
+func TraceProvider(traceProvider trace.TracerProvider) Option {
+	return func(o *Options) {
+		if traceProvider != nil {
+			o.TraceProvider = traceProvider
+		} else {
+			o.TraceProvider = trace.NewNoopTracerProvider()
+		}
+	}
+}
diff --git a/services/thumbnails/pkg/service/http/v0/service.go b/services/thumbnails/pkg/service/http/v0/service.go
index 1fe63be6e85..8e36a3727da 100644
--- a/services/thumbnails/pkg/service/http/v0/service.go
+++ b/services/thumbnails/pkg/service/http/v0/service.go
@@ -8,8 +8,10 @@ import (
 
 	"github.com/go-chi/chi/v5"
 	"github.com/golang-jwt/jwt/v4"
+	"github.com/riandyrn/otelchi"
 
 	"github.com/owncloud/ocis/v2/ocis-pkg/log"
+	"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
 	"github.com/owncloud/ocis/v2/services/thumbnails/pkg/config"
 	tjwt "github.com/owncloud/ocis/v2/services/thumbnails/pkg/service/jwt"
 	"github.com/owncloud/ocis/v2/services/thumbnails/pkg/thumbnail"
@@ -34,6 +36,15 @@ func NewService(opts ...Option) Service {
 	m := chi.NewMux()
 	m.Use(options.Middleware...)
 
+	m.Use(
+		otelchi.Middleware(
+			"thumbnails",
+			otelchi.WithChiRoutes(m),
+			otelchi.WithTracerProvider(options.TraceProvider),
+			otelchi.WithPropagators(tracing.GetPropagator()),
+		),
+	)
+
 	logger := options.Logger
 	resolutions, err := thumbnail.ParseResolutions(options.Config.Thumbnail.Resolutions)
 	if err != nil {
diff --git a/services/thumbnails/pkg/service/http/v0/tracing.go b/services/thumbnails/pkg/service/http/v0/tracing.go
deleted file mode 100644
index 94acf496a1b..00000000000
--- a/services/thumbnails/pkg/service/http/v0/tracing.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package svc
-
-import (
-	"net/http"
-
-	"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
-)
-
-// NewTracing returns a service that instruments traces.
-func NewTracing(next Service) Service {
-	return tracing{
-		next: next,
-	}
-}
-
-type tracing struct {
-	next Service
-}
-
-// ServeHTTP implements the Service interface.
-func (t tracing) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	middleware.TraceContext(t.next).ServeHTTP(w, r)
-}
-
-// GetThumbnail implements the Service interface.
-func (t tracing) GetThumbnail(w http.ResponseWriter, r *http.Request) {
-	t.next.GetThumbnail(w, r)
-}
diff --git a/services/userlog/pkg/server/http/server.go b/services/userlog/pkg/server/http/server.go
index bb051ffbc89..6c628608900 100644
--- a/services/userlog/pkg/server/http/server.go
+++ b/services/userlog/pkg/server/http/server.go
@@ -35,6 +35,7 @@ func Server(opts ...Option) (http.Service, error) {
 		http.Address(options.Config.HTTP.Addr),
 		http.Context(options.Context),
 		http.Flags(options.Flags...),
+		http.TraceProvider(options.TracerProvider),
 	)
 	if err != nil {
 		options.Logger.Error().
diff --git a/services/web/Makefile b/services/web/Makefile
index 2b613ded099..e5d7459a4cd 100644
--- a/services/web/Makefile
+++ b/services/web/Makefile
@@ -1,6 +1,6 @@
 SHELL := bash
 NAME := web
-WEB_ASSETS_VERSION = v7.1.0-rc.5
+WEB_ASSETS_VERSION = v7.1.0
 
 include ../../.make/recursion.mk
 
diff --git a/services/web/pkg/server/http/server.go b/services/web/pkg/server/http/server.go
index 1815e5461dd..80145b8d5d8 100644
--- a/services/web/pkg/server/http/server.go
+++ b/services/web/pkg/server/http/server.go
@@ -37,7 +37,11 @@ func Server(opts ...Option) (http.Service, error) {
 		return http.Service{}, fmt.Errorf("could not initialize http service: %w", err)
 	}
 
-	gatewaySelector, err := pool.GatewaySelector(options.Config.GatewayAddress, pool.WithRegistry(registry.GetRegistry()))
+	gatewaySelector, err := pool.GatewaySelector(
+		options.Config.GatewayAddress,
+		pool.WithRegistry(registry.GetRegistry()),
+		pool.WithTracerProvider(options.TraceProvider),
+	)
 	if err != nil {
 		return http.Service{}, err
 	}
@@ -67,6 +71,7 @@ func Server(opts ...Option) (http.Service, error) {
 				cors.AllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
 			),
 		),
+		svc.TraceProvider(options.TraceProvider),
 	)
 
 	{
diff --git a/services/webdav/pkg/server/http/server.go b/services/webdav/pkg/server/http/server.go
index 77c27435315..acb36a05701 100644
--- a/services/webdav/pkg/server/http/server.go
+++ b/services/webdav/pkg/server/http/server.go
@@ -57,6 +57,7 @@ func Server(opts ...Option) (http.Service, error) {
 				options.Logger,
 			),
 		),
+		svc.TraceProvider(options.TraceProvider),
 	)
 	if err != nil {
 		return http.Service{}, err
diff --git a/services/webdav/pkg/service/v0/service.go b/services/webdav/pkg/service/v0/service.go
index 73e91dee380..56f4e2513e2 100644
--- a/services/webdav/pkg/service/v0/service.go
+++ b/services/webdav/pkg/service/v0/service.go
@@ -78,6 +78,7 @@ func NewService(opts ...Option) (Service, error) {
 		pool.WithTLSCACert(conf.GRPCClientTLS.CACert),
 		pool.WithTLSMode(tm),
 		pool.WithRegistry(registry.GetRegistry()),
+		pool.WithTracerProvider(options.TraceProvider),
 	)
 	if err != nil {
 		return nil, err
diff --git a/services/webfinger/pkg/command/server.go b/services/webfinger/pkg/command/server.go
index 7560b5436e2..7874e8ff082 100644
--- a/services/webfinger/pkg/command/server.go
+++ b/services/webfinger/pkg/command/server.go
@@ -75,6 +75,7 @@ func Server(cfg *config.Config) *cli.Command {
 					http.Context(ctx),
 					http.Config(cfg),
 					http.Service(svc),
+					http.TraceProvider(traceProvider),
 				)
 
 				if err != nil {
diff --git a/services/webfinger/pkg/server/http/option.go b/services/webfinger/pkg/server/http/option.go
index 28ebd40d6e2..df5d6635b2d 100644
--- a/services/webfinger/pkg/server/http/option.go
+++ b/services/webfinger/pkg/server/http/option.go
@@ -7,6 +7,7 @@ import (
 	"github.com/owncloud/ocis/v2/services/webfinger/pkg/config"
 	svc "github.com/owncloud/ocis/v2/services/webfinger/pkg/service/v0"
 	"github.com/urfave/cli/v2"
+	"go.opentelemetry.io/otel/trace"
 )
 
 // Option defines a single option function.
@@ -14,13 +15,14 @@ type Option func(o *Options)
 
 // Options defines the available options for this package.
 type Options struct {
-	Name      string
-	Namespace string
-	Logger    log.Logger
-	Context   context.Context
-	Config    *config.Config
-	Flags     []cli.Flag
-	Service   svc.Service
+	Name          string
+	Namespace     string
+	Logger        log.Logger
+	Context       context.Context
+	Config        *config.Config
+	Flags         []cli.Flag
+	Service       svc.Service
+	TraceProvider trace.TracerProvider
 }
 
 // newOptions initializes the available default options.
@@ -82,3 +84,14 @@ func Service(val svc.Service) Option {
 		o.Service = val
 	}
 }
+
+// TraceProvider provides a function to configure the trace provider
+func TraceProvider(traceProvider trace.TracerProvider) Option {
+	return func(o *Options) {
+		if traceProvider != nil {
+			o.TraceProvider = traceProvider
+		} else {
+			o.TraceProvider = trace.NewNoopTracerProvider()
+		}
+	}
+}
diff --git a/services/webfinger/pkg/server/http/server.go b/services/webfinger/pkg/server/http/server.go
index 9f9aece3f54..7fe7d1740bf 100644
--- a/services/webfinger/pkg/server/http/server.go
+++ b/services/webfinger/pkg/server/http/server.go
@@ -12,10 +12,12 @@ import (
 	"github.com/owncloud/ocis/v2/ocis-pkg/cors"
 	"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
 	ohttp "github.com/owncloud/ocis/v2/ocis-pkg/service/http"
+	"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
 	"github.com/owncloud/ocis/v2/ocis-pkg/version"
 	serviceErrors "github.com/owncloud/ocis/v2/services/webfinger/pkg/service/v0"
 	svc "github.com/owncloud/ocis/v2/services/webfinger/pkg/service/v0"
 	"github.com/pkg/errors"
+	"github.com/riandyrn/otelchi"
 	"go-micro.dev/v4"
 )
 
@@ -62,6 +64,15 @@ func Server(opts ...Option) (ohttp.Service, error) {
 		version.String,
 	))
 
+	mux.Use(
+		otelchi.Middleware(
+			options.Name,
+			otelchi.WithChiRoutes(mux),
+			otelchi.WithTracerProvider(options.TraceProvider),
+			otelchi.WithPropagators(tracing.GetPropagator()),
+		),
+	)
+
 	var oidcHTTPClient = &http.Client{
 		Transport: &http.Transport{
 			TLSClientConfig: &tls.Config{


Test patch:
diff --git a/services/proxy/pkg/middleware/account_resolver_test.go b/services/proxy/pkg/middleware/account_resolver_test.go
index 3d80dfc441d..32af9351964 100644
--- a/services/proxy/pkg/middleware/account_resolver_test.go
+++ b/services/proxy/pkg/middleware/account_resolver_test.go
@@ -57,6 +57,68 @@ func TestTokenIsAddedWithUsernameClaim(t *testing.T) {
 	assert.Contains(t, token, "eyJ")
 }
 
+func TestTokenIsAddedWithDotUsernamePathClaim(t *testing.T) {
+	sut := newMockAccountResolver(&userv1beta1.User{
+		Id:   &userv1beta1.UserId{Idp: "https://idx.example.com", OpaqueId: "123"},
+		Mail: "foo@example.com",
+	}, nil, "li.un", "username")
+
+	// This is how lico adds the username to the access token
+	req, rw := mockRequest(map[string]interface{}{
+		oidc.Iss: "https://idx.example.com",
+		"li": map[string]interface{}{
+			"un": "foo",
+		},
+	})
+
+	sut.ServeHTTP(rw, req)
+
+	token := req.Header.Get(revactx.TokenHeader)
+	assert.NotEmpty(t, token)
+
+	assert.Contains(t, token, "eyJ")
+}
+
+func TestTokenIsAddedWithDotEscapedUsernameClaim(t *testing.T) {
+	sut := newMockAccountResolver(&userv1beta1.User{
+		Id:   &userv1beta1.UserId{Idp: "https://idx.example.com", OpaqueId: "123"},
+		Mail: "foo@example.com",
+	}, nil, "li\\.un", "username")
+
+	// This tests the . escaping of the readUserIDClaim
+	req, rw := mockRequest(map[string]interface{}{
+		oidc.Iss: "https://idx.example.com",
+		"li.un":  "foo",
+	})
+
+	sut.ServeHTTP(rw, req)
+
+	token := req.Header.Get(revactx.TokenHeader)
+	assert.NotEmpty(t, token)
+
+	assert.Contains(t, token, "eyJ")
+}
+
+func TestTokenIsAddedWithDottedUsernameClaimFallback(t *testing.T) {
+	sut := newMockAccountResolver(&userv1beta1.User{
+		Id:   &userv1beta1.UserId{Idp: "https://idx.example.com", OpaqueId: "123"},
+		Mail: "foo@example.com",
+	}, nil, "li.un", "username")
+
+	// This tests the . escaping fallback of the readUserIDClaim
+	req, rw := mockRequest(map[string]interface{}{
+		oidc.Iss: "https://idx.example.com",
+		"li.un":  "foo",
+	})
+
+	sut.ServeHTTP(rw, req)
+
+	token := req.Header.Get(revactx.TokenHeader)
+	assert.NotEmpty(t, token)
+
+	assert.Contains(t, token, "eyJ")
+}
+
 func TestNSkipOnNoClaims(t *testing.T) {
 	sut := newMockAccountResolver(nil, backend.ErrAccountDisabled, oidc.Email, "mail")
 	req, rw := mockRequest(nil)
@@ -133,6 +195,7 @@ func newMockAccountResolver(userBackendResult *userv1beta1.User, userBackendErr
 		UserProvider(&ub),
 		UserRoleAssigner(&ra),
 		TokenManagerConfig(config.TokenManager{JWTSecret: "secret"}),
+		SkipUserInfo(false),
 		UserOIDCClaim(oidcclaim),
 		UserCS3Claim(cs3claim),
 		AutoprovisionAccounts(false),
diff --git a/tests/acceptance/expected-failures-webUI-on-OCIS-storage.md b/tests/acceptance/expected-failures-webUI-on-OCIS-storage.md
index 6b7273598dc..e5f640cd16c 100644
--- a/tests/acceptance/expected-failures-webUI-on-OCIS-storage.md
+++ b/tests/acceptance/expected-failures-webUI-on-OCIS-storage.md
@@ -111,9 +111,6 @@ Other free text and Markdown formatting can be used elsewhere in the document if
 -   [webUISharingExternal/federationSharing.feature:38](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUISharingExternal/federationSharing.feature#L38)
 -   [webUISharingExternal/federationSharing.feature:166](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUISharingExternal/federationSharing.feature#L166)
 
-### [web config update is not properly reflected after the ocis start](https://github.com/owncloud/ocis/issues/2944)
--   [webUIFiles/breadcrumb.feature:50](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIFiles/breadcrumb.feature#L50)
-
 ### [empty subfolder inside a folder to be uploaded is not created on the server](https://github.com/owncloud/web/issues/6348)
 -   [webUIUpload/upload.feature:43](https://github.com/owncloud/web/blob/master/tests/acceptance/features/webUIUpload/upload.feature#L43)