diff --git a/pluto-server/pom.xml b/pluto-server/pom.xml
index 099275d17b573d74b86cd0de8dc179855a78cd1c..2c899e3df470f8b828b139db5a0dd41af2b6509d 100644
--- a/pluto-server/pom.xml
+++ b/pluto-server/pom.xml
@@ -168,6 +168,11 @@
 				</exclusion>
 			</exclusions>
 		</dependency>
+		<dependency>
+			<groupId>org.springframework.security</groupId>
+			<artifactId>spring-security-test</artifactId>
+		</dependency>
+		
 		<dependency>
 			<groupId>org.junit.jupiter</groupId>
 			<artifactId>junit-jupiter-engine</artifactId>
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/PlutoServerApplication.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/PlutoServerApplication.java
index 77094c8371175c6bc0e073ae69d44156617284db..c3e9cbd217f58f9afa146e0d9a328eeecdc56016 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/PlutoServerApplication.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/PlutoServerApplication.java
@@ -5,9 +5,12 @@ import java.util.TimeZone;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.EnableAspectJAutoProxy;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.security.authentication.AuthenticationTrustResolver;
+import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
 
 import io.mongock.runner.springboot.EnableMongock;
 
@@ -23,4 +26,9 @@ public class PlutoServerApplication {
 		TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
 		SpringApplication.run(PlutoServerApplication.class, args);
 	}
+
+	@Bean
+	public AuthenticationTrustResolver trustResolver() {
+		return new AuthenticationTrustResolverImpl();
+	}
 }
\ No newline at end of file
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextHandleInterceptor.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextHandleInterceptor.java
index 6342d627cb95e251ffc0a859d07f2b4f10779bd8..68c6072e330399106361f4097f7f501e589096bc 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextHandleInterceptor.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextHandleInterceptor.java
@@ -94,12 +94,12 @@ class CallContextHandleInterceptor implements ServerInterceptor {
 
 		CallContextUser createUser() {
 			var builder = CallContextUser.builder()
+					.userId(getFromHeaders(KEY_USER_ID, headers))
 					.userName(getFromHeaders(KEY_USER_NAME, headers))
 					.organisatorischeEinheitenIds(getCollection(KEY_ACCESS_LIMITED_ORGAID, headers));
 
 			// TODO throw exception if missing required data as soon all clients are fine
 			// with using headers for auth data.
-			getFromHeaders(KEY_USER_ID, headers).ifPresentOrElse(builder::userId, () -> LOG.warn("Missing user id in grpc header."));
 			getFromHeaders(KEY_CLIENT_NAME, headers).ifPresentOrElse(builder::clientName, () -> LOG.warn("Missing client name in grpc header."));
 
 			return builder.build();
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUser.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUser.java
index 7a37d14d040876302598bdb7596106710622ca67..6f1b4b5a090d8bdc87607e5e6a09b12f49d7f2aa 100644
--- a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUser.java
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUser.java
@@ -18,7 +18,8 @@ public class CallContextUser implements AuthenticatedPrincipal, Serializable {
 
 	private final String clientName;
 
-	private final String userId;
+	@Builder.Default
+	private final transient Optional<String> userId = Optional.empty();
 	@Builder.Default
 	private final transient Optional<String> userName = Optional.empty();
 	@Singular
diff --git a/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserService.java b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserService.java
new file mode 100644
index 0000000000000000000000000000000000000000..d6b15332f824e8ce8d614931eed5a45ae7f87753
--- /dev/null
+++ b/pluto-server/src/main/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserService.java
@@ -0,0 +1,43 @@
+package de.itvsh.ozg.pluto.common.callcontext;
+
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationTrustResolver;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CurrentUserService {
+
+	@Autowired
+	private AuthenticationTrustResolver trustResolver;
+
+	public CallContextUser getUser() {
+		var auth = getAuthentication();
+
+		if (auth instanceof CallContextAuthenticationToken) {
+			return (CallContextUser) auth.getPrincipal();
+		} else {
+			return CallContextUser.builder()
+					.clientName(auth.getName())
+					.organisatorischeEinheitenIds(
+							auth.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toUnmodifiableSet()))
+					.build();
+		}
+
+	}
+
+	public Authentication getAuthentication() {
+		return findTrustedAuthentication().orElseThrow(() -> new IllegalStateException("No authenticated User found"));
+	}
+
+	Optional<Authentication> findTrustedAuthentication() {
+		return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
+				.filter(auth -> !trustResolver.isAnonymous(auth))
+				.filter(Authentication::isAuthenticated);
+	}
+}
diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUserTestFactory.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUserTestFactory.java
index 4aeb8415b4de1310e3495b9ae2d1bfb353aff8c9..68de875e14329f85c258c0d0261a1a47d166211c 100644
--- a/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUserTestFactory.java
+++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CallContextUserTestFactory.java
@@ -13,7 +13,7 @@ public class CallContextUserTestFactory {
 	static CallContextUser.CallContextUserBuilder createBuilder() {
 		return CallContextUser.builder()
 				.clientName(CallContextTestFactory.CLIENT)
-				.userId(UserTestFactory.ID)
+				.userId(Optional.of(UserTestFactory.ID))
 				.userName(Optional.of(UserTestFactory.NAME))
 				.organisatorischeEinheitenId(UserTestFactory.ORGANISATORISCHE_EINHEITEN_ID);
 	}
diff --git a/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserServiceITCase.java b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserServiceITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..66bca90a40ff38ddf6842475528bf22c2edef3ee
--- /dev/null
+++ b/pluto-server/src/test/java/de/itvsh/ozg/pluto/common/callcontext/CurrentUserServiceITCase.java
@@ -0,0 +1,47 @@
+package de.itvsh.ozg.pluto.common.callcontext;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.test.context.support.WithAnonymousUser;
+import org.springframework.security.test.context.support.WithMockUser;
+
+import de.itvsh.kop.common.test.ITCase;
+
+@ITCase
+class CurrentUserServiceITCase {
+
+	@Autowired
+	private CurrentUserService service;
+
+	@Test
+	void shouldThrowExceptionIfUserIsMissing() {
+		assertThatThrownBy(() -> service.getUser()).isInstanceOf(IllegalStateException.class);
+	}
+
+	@Test
+	@WithAnonymousUser
+	void shouldThrowExceptionIfAnonymouse() {
+		assertThatThrownBy(() -> service.getUser()).isInstanceOf(IllegalStateException.class);
+	}
+
+	@Test
+	@WithMockUser
+	void shouldReturnUser() {
+		var user = service.getUser();
+
+		assertThat(user.getName()).isEqualTo("user");
+	}
+
+	@Test
+	void shouldReturnUserFromToken() {
+		var inUser = CallContextUserTestFactory.create();
+		SecurityContextHolder.getContext().setAuthentication(CallContextAuthenticationToken.authenticate(inUser));
+
+		var user = service.getUser();
+
+		assertThat(user).isSameAs(inUser);
+	}
+}