diff --git a/token-checker-interface/src/main/protobuf/tokencheck.model.proto b/token-checker-interface/src/main/protobuf/tokencheck.model.proto
index 715ec6ef7f1f832abdb3ffd05cc02a4763cd13c5..a2edda6189d7b7736fe5c44ffd6d5e87abf384fb 100644
--- a/token-checker-interface/src/main/protobuf/tokencheck.model.proto
+++ b/token-checker-interface/src/main/protobuf/tokencheck.model.proto
@@ -14,7 +14,7 @@ message GrpcCheckTokenResponse {
   bool tokenValid = 1;
   oneof checkTokenResult {
     GrpcTokenAttributes tokenAttributes = 2;
-    GrpcCheckErrors checkError = 3;
+    GrpcCheckErrors checkErrors = 3;
   }
 }
 
@@ -30,7 +30,7 @@ message GrpcOtherField {
 }
 
 message GrpcCheckErrors {
-  repeated GrpcCheckError message = 1;
+  repeated GrpcCheckError checkError = 1;
 }
 
 message GrpcCheckError {
diff --git a/token-checker-server/src/main/java/de/ozgcloud/token/saml/SamlAttributeService.java b/token-checker-server/src/main/java/de/ozgcloud/token/saml/SamlAttributeService.java
index fbba32136fc96a2f983d5093833c4293723ab99a..a62ce6cb39d523e132699a09c44b6ae022eb181f 100644
--- a/token-checker-server/src/main/java/de/ozgcloud/token/saml/SamlAttributeService.java
+++ b/token-checker-server/src/main/java/de/ozgcloud/token/saml/SamlAttributeService.java
@@ -24,15 +24,15 @@
 
 package de.ozgcloud.token.saml;
 
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.Set;
 import java.util.stream.Collectors;
 
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.opensaml.core.xml.XMLObject;
 import org.opensaml.core.xml.schema.XSAny;
@@ -53,53 +53,63 @@ import org.opensaml.xmlsec.signature.support.SignatureException;
 import org.opensaml.xmlsec.signature.support.SignatureTrustEngine;
 
 import de.ozgcloud.token.TokenAttribute;
+import de.ozgcloud.token.TokenAttributes;
 import de.ozgcloud.token.TokenValidationProperties.TokenValidationProperty;
 import de.ozgcloud.token.common.errorhandling.TokenVerificationException;
+import de.ozgcloud.token.common.errorhandling.ValidationError;
 import lombok.Builder;
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 
 @Builder
 public class SamlAttributeService {
 
+	private static final String ID_AS_POSTFACH_ID_KEY = "OZG_CLOUD_POSTFACH_ID";
+
 	private final SignatureTrustEngine signatureTrustEngine;
 	private final Decrypter decrypter;
 	private final SAMLSignatureProfileValidator profileValidator;
 	private final TokenValidationProperty tokenValidationProperty;
 	private final CriteriaSet verificationCriteria;
 
-	public Set<TokenAttribute> validate(Response token) {
+	public TokenAttributes getAttributes(Response token) {
 		validateToken(token);
-		var tokenAttributes = decryptAttributes(token);
-		return buildTokenAttributes(tokenAttributes, token);
+		return buildTokenAttributes(decryptSamlAttributes(token), token);
 	}
 
 	void validateToken(Response token) {
 		if (Objects.isNull(token.getSignature())) {
 			throw new TokenVerificationException("Token signature is missing");
 		}
-		validateSignatureProfile(token.getSignature());
-		if (!validateSignature(token.getSignature())) {
-			throw new TokenVerificationException("Invalid token signature");
+		var validationErrors = new ArrayList<ValidationError>();
+		validateSignatureProfile(token.getSignature()).ifPresent(validationErrors::add);
+		validateSignature(token.getSignature()).ifPresent(validationErrors::add);
+		if (CollectionUtils.isNotEmpty(validationErrors)) {
+			throw new TokenVerificationException("Token validation failed", validationErrors);
 		}
 	}
 
-	void validateSignatureProfile(Signature signature) {
+	Optional<ValidationError> validateSignatureProfile(Signature signature) {
 		try {
 			profileValidator.validate(signature);
 		} catch (SignatureException e) {
-			throw new TokenVerificationException("Invalid signature profile", e);
+			return Optional.of(ValidationError.builder().message("Invalid signature profile: " + e.getMessage()).cause(e).build());
 		}
+		return Optional.empty();
 	}
 
-	boolean validateSignature(Signature signature) {
+	Optional<ValidationError> validateSignature(Signature signature) {
 		try {
-			return signatureTrustEngine.validate(signature, verificationCriteria);
+			var isValidSignature = signatureTrustEngine.validate(signature, verificationCriteria);
+			if (!isValidSignature) {
+				return Optional.of(ValidationError.builder().message("Invalid token signature").build());
+			}
 		} catch (SecurityException e) {
-			throw new TokenVerificationException("Error on validating signature.", e);
+			return Optional.of(ValidationError.builder().message("Error on signature validation: " + e.getMessage()).cause(e).build());
 		}
+		return Optional.empty();
 	}
 
-	public Map<String, String> decryptAttributes(Response token) {
+	Map<String, String> decryptSamlAttributes(Response token) {
 		return token.getEncryptedAssertions().stream()
 				.map(this::decryptAssertion)
 				.findFirst()
@@ -141,37 +151,30 @@ public class SamlAttributeService {
 		};
 	}
 
-	Set<TokenAttribute> buildTokenAttributes(Map<String, String> tokenAttributes, Response token) {
-		return adjustAttributes(tokenAttributes, token).entrySet().stream().map(this::buildTokenAttribute).collect(Collectors.toSet());
+	TokenAttributes buildTokenAttributes(Map<String, String> tokenAttributes, Response token) {
+		var result = TokenAttributes.builder().postfachId(getPostfachId(tokenAttributes, token)).trustLevel(getTrustLevel(tokenAttributes));
+		tokenAttributes.entrySet().stream().filter(this::isNotMappedField).map(this::buildTokenAttribute).forEach(result::otherAttribute);
+		return result.build();
 	}
 
-	Map<String, String> adjustAttributes(Map<String, String> tokenAttributes, Response token) {
-		return Collections.unmodifiableMap(adjustPostfachIdAttribute(replaceKeys(new HashMap<>(tokenAttributes)), token));
+	String getPostfachId(Map<String, String> tokenAttributes, Response token) {
+		return tokenValidationProperty.isUseIdAsPostfachId() ? token.getID() : getMappedValue(tokenAttributes, TokenAttributes.POSTFACH_ID_KEY);
 	}
 
-	Map<String, String> replaceKeys(Map<String, String> tokenAttributes) {
-		tokenValidationProperty.getMappings().forEach((key, mappedKey) -> {
-			var attrValue = tokenAttributes.remove(mappedKey);
-			if (StringUtils.isNotBlank(attrValue)) {
-				tokenAttributes.put(key, attrValue);
-			}
-		});
-		return tokenAttributes;
+	String getTrustLevel(Map<String, String> tokenAttributes) {
+		return getMappedValue(tokenAttributes, TokenAttributes.TRUST_LEVEL_KEY);
 	}
 
-	Map<String, String> adjustPostfachIdAttribute(Map<String, String> tokenAttributes, Response token) {
-		if (tokenValidationProperty.isUseIdAsPostfachId()) {
-			tokenAttributes.put(TokenAttribute.POSTFACH_ID_KEY, token.getID());
-		}
-		return tokenAttributes;
+	String getMappedValue(Map<String, String> tokenAttributes, String key) {
+		var mappedKey = tokenValidationProperty.getMappings().getOrDefault(key, key);
+		return tokenAttributes.get(mappedKey);
 	}
 
-	TokenAttribute buildTokenAttribute(Map.Entry<String, String> attribute) {
-		return TokenAttribute.builder().name(mapAttributeKey(attribute.getKey())).value(attribute.getValue()).build();
+	boolean isNotMappedField(Map.Entry<String, String> attributeEntry) {
+		return !tokenValidationProperty.getMappings().containsValue(attributeEntry.getKey());
 	}
 
-	String mapAttributeKey(String key) {
-		return tokenValidationProperty.getMappings().entrySet().stream().filter(entry -> StringUtils.equals(entry.getValue(), key))
-				.map(Map.Entry::getKey).findFirst().orElse(key);
+	TokenAttribute buildTokenAttribute(Map.Entry<String, String> attribute) {
+		return TokenAttribute.builder().name(attribute.getKey()).value(attribute.getValue()).build();
 	}
 }
diff --git a/token-checker-server/src/test/java/de/ozgcloud/token/TokenAttributesTestFactory.java b/token-checker-server/src/test/java/de/ozgcloud/token/TokenAttributesTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e4e4d2fc7c5b02f9b8d77f754fd1875c8e94277
--- /dev/null
+++ b/token-checker-server/src/test/java/de/ozgcloud/token/TokenAttributesTestFactory.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+
+package de.ozgcloud.token;
+
+import java.util.Map;
+import java.util.UUID;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+public class TokenAttributesTestFactory {
+
+	public static final String POSTFACH_ID = UUID.randomUUID().toString();
+	public static final String TRUST_LEVEL = LoremIpsum.getInstance().getWords(1);
+	public static final TokenAttribute OTHER_ATTRIBUTE = TokenAttributeTestFactory.create();
+
+	public static TokenAttributes create() {
+		return createBuilder().build();
+	}
+
+	public static TokenAttributes.TokenAttributesBuilder createBuilder() {
+		return TokenAttributes.builder()
+				.postfachId(POSTFACH_ID)
+				.trustLevel(TRUST_LEVEL)
+				.otherAttribute(OTHER_ATTRIBUTE);
+	}
+
+	public static Map<String, String> asMap() {
+		return Map.of(
+				TokenAttributes.POSTFACH_ID_KEY, POSTFACH_ID,
+				TokenAttributes.TRUST_LEVEL_KEY, TRUST_LEVEL,
+				TokenAttributeTestFactory.NAME, TokenAttributeTestFactory.VALUE
+		);
+	}
+}
diff --git a/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlAttributeServiceTest.java b/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlAttributeServiceTest.java
index 70c33fb0a31bcce22359bcd1b501bde89cd0c1a0..9d22ec18ad28b2e656d23ffbdebe25f8d62c0a07 100644
--- a/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlAttributeServiceTest.java
+++ b/token-checker-server/src/test/java/de/ozgcloud/token/saml/SamlAttributeServiceTest.java
@@ -27,12 +27,12 @@ import static org.assertj.core.api.Assertions.*;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Random;
-import java.util.Set;
+import java.util.SimpleTimeZone;
+import java.util.UUID;
 
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
@@ -57,15 +57,22 @@ import org.opensaml.saml.saml2.core.Response;
 import org.opensaml.saml.saml2.core.Statement;
 import org.opensaml.saml.saml2.encryption.Decrypter;
 import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator;
+import org.opensaml.security.SecurityException;
 import org.opensaml.xmlsec.signature.Signature;
+import org.opensaml.xmlsec.signature.support.SignatureException;
 import org.opensaml.xmlsec.signature.support.SignatureTrustEngine;
+import org.testcontainers.shaded.org.checkerframework.checker.units.qual.N;
 
 import com.thedeanda.lorem.LoremIpsum;
 
 import de.ozgcloud.token.TokenAttribute;
 import de.ozgcloud.token.TokenAttributeTestFactory;
+import de.ozgcloud.token.TokenAttributes;
+import de.ozgcloud.token.TokenAttributesTestFactory;
 import de.ozgcloud.token.TokenValidationProperties.TokenValidationProperty;
 import de.ozgcloud.token.common.errorhandling.TokenVerificationException;
+import de.ozgcloud.token.common.errorhandling.ValidationError;
+import lombok.Builder;
 import lombok.SneakyThrows;
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 
@@ -87,33 +94,34 @@ class SamlAttributeServiceTest {
 	private CriteriaSet verificationCriteria;
 
 	@Nested
-	class TestValidate {
+	class TestGetAttributes {
 
 		private static final Map<String, String> TOKEN_ATTRIBUTES_MAP = Map.of("key", "value");
-		private static final TokenAttribute TOKEN_ATTRIBUTE = TokenAttributeTestFactory.create();
 
 		@Mock
 		private Response token;
+		@Mock
+		private TokenAttributes tokenAttributes;
 
 		@BeforeEach
 		void init() {
 			doNothing().when(service).validateToken(any());
-			doReturn(TOKEN_ATTRIBUTES_MAP).when(service).decryptAttributes(any());
-			doReturn(Set.of(TOKEN_ATTRIBUTE)).when(service).buildTokenAttributes(any(), any());
+			doReturn(TOKEN_ATTRIBUTES_MAP).when(service).decryptSamlAttributes(any());
+			doReturn(tokenAttributes).when(service).buildTokenAttributes(any(), any());
 		}
 
 		@Test
 		void shouldCallValidateToken() {
 			validate();
 
-			verify(service).validate(token);
+			verify(service).getAttributes(token);
 		}
 
 		@Test
 		void shouldCallDecryptAttributes() {
 			validate();
 
-			verify(service).decryptAttributes(token);
+			verify(service).decryptSamlAttributes(token);
 		}
 
 		@Test
@@ -127,11 +135,11 @@ class SamlAttributeServiceTest {
 		void shouldReturnResult() {
 			var result = validate();
 
-			assertThat(result).containsExactly(TOKEN_ATTRIBUTE);
+			assertThat(result).isSameAs(tokenAttributes);
 		}
 
-		private Set<TokenAttribute> validate() {
-			return service.validate(token);
+		private TokenAttributes validate() {
+			return service.getAttributes(token);
 		}
 	}
 
@@ -141,6 +149,11 @@ class SamlAttributeServiceTest {
 		@Mock
 		private Response token;
 
+		@Test
+		void shouldThrowExceptionWhenMissingSignature() {
+			assertThrows(TokenVerificationException.class, TestValidateToken.this::validateToken);
+		}
+
 		@Nested
 		class TestValidateSuccessfully {
 
@@ -150,7 +163,13 @@ class SamlAttributeServiceTest {
 			@BeforeEach
 			void init() {
 				when(token.getSignature()).thenReturn(signature);
-				doReturn(true).when(service).validateSignature(any());
+				doReturn(Optional.empty()).when(service).validateSignatureProfile(any());
+				doReturn(Optional.empty()).when(service).validateSignature(any());
+			}
+
+			@Test
+			void shouldNotThrowException() {
+				assertDoesNotThrow(TestValidateToken.this::validateToken);
 			}
 
 			@Test
@@ -161,10 +180,10 @@ class SamlAttributeServiceTest {
 			}
 
 			@Test
-			void shouldValidateToken() {
+			void shouldCallValidateSignature() {
 				validateToken();
 
-				Assertions.assertDoesNotThrow(TestValidateToken.this::validateToken);
+				verify(service).validateSignature(signature);
 			}
 		}
 
@@ -173,18 +192,30 @@ class SamlAttributeServiceTest {
 
 			@Mock
 			private Signature signature;
+			@Mock
+			private ValidationError signatureProfileError;
+			@Mock
+			private ValidationError signatureError;
+
+			@BeforeEach
+			void init() {
+				when(token.getSignature()).thenReturn(signature);
+				doReturn(Optional.of(signatureProfileError)).when(service).validateSignatureProfile(any());
+				doReturn(Optional.of(signatureError)).when(service).validateSignature(any());
+			}
 
 			@Test
-			void shouldThrowWhenMissingSignature() {
-				assertThrows(TokenVerificationException.class, TestValidateToken.this::validateToken);
+			void shouldAddInvalidSignatureProfileToException() {
+				var exception = assertThrows(TokenVerificationException.class, TestValidateToken.this::validateToken);
+
+				assertThat(exception.getValidationErrors()).contains(signatureProfileError);
 			}
 
 			@Test
-			void shouldThrowWhenInvalidSignatureProfile() {
-				when(token.getSignature()).thenReturn(signature);
-				when(service.validateSignature(any())).thenReturn(false);
+			void shouldAddInvalidSignatureToException() {
+				var exception = assertThrows(TokenVerificationException.class, TestValidateToken.this::validateToken);
 
-				assertThrows(TokenVerificationException.class, TestValidateToken.this::validateToken);
+				assertThat(exception.getValidationErrors()).contains(signatureError);
 			}
 		}
 
@@ -199,12 +230,53 @@ class SamlAttributeServiceTest {
 		@Mock
 		private Signature signature;
 
-		@Test
-		@SneakyThrows
-		void shouldCallProfileValidator() {
-			service.validateSignatureProfile(signature);
+		@Nested
+		class TestSignatureProfileValide {
 
-			verify(profileValidator).validate(signature);
+			@Test
+			@SneakyThrows
+			void shouldCallProfileValidator() {
+				service.validateSignatureProfile(signature);
+
+				verify(profileValidator).validate(signature);
+			}
+
+			@Test
+			void shouldReturnEmpty() {
+				var result = service.validateSignatureProfile(signature);
+
+				assertThat(result).isEmpty();
+			}
+		}
+
+		@Nested
+		class TestInvalidSignatureProfile {
+
+			private static final String EXCEPTION_MESSAGE = LoremIpsum.getInstance().getWords(1);
+
+			private final SignatureException signatureException = new SignatureException(EXCEPTION_MESSAGE);
+
+			@BeforeEach
+			@SneakyThrows
+			void init() {
+				doThrow(signatureException).when(profileValidator).validate(any());
+			}
+
+			@Test
+			void shouldSetMessage() {
+				var result = service.validateSignatureProfile(signature);
+
+				assertThat(result).get().extracting(ValidationError::getMessage, STRING)
+						.hasSizeGreaterThan(EXCEPTION_MESSAGE.length())
+						.endsWith(EXCEPTION_MESSAGE);
+			}
+
+			@Test
+			void shouldSetCause() {
+				var result = service.validateSignatureProfile(signature);
+
+				assertThat(result).get().extracting(ValidationError::getCause).isEqualTo(signatureException);
+			}
 		}
 	}
 
@@ -221,6 +293,56 @@ class SamlAttributeServiceTest {
 
 			verify(signatureTrustEngine).validate(signature, verificationCriteria);
 		}
+
+		@Test
+		@SneakyThrows
+		void shouldReturnEmpty() {
+			doReturn(true).when(signatureTrustEngine).validate(any(), any());
+
+			var result = service.validateSignature(signature);
+
+			assertThat(result).isEmpty();
+		}
+
+		@SneakyThrows
+		@Test
+		void shouldSetMessageIfInvalid() {
+			doReturn(false).when(signatureTrustEngine).validate(any(), any());
+
+			var result = service.validateSignature(signature);
+
+			assertThat(result).get().extracting(ValidationError::getMessage, STRING).isNotEmpty();
+		}
+
+		@Nested
+		class TestOnException {
+
+			private static final String EXCEPTION_MESSAGE = LoremIpsum.getInstance().getWords(1);
+
+			private final SecurityException signatureException = new SecurityException(EXCEPTION_MESSAGE);
+
+			@BeforeEach
+			@SneakyThrows
+			void init() {
+				doThrow(signatureException).when(signatureTrustEngine).validate(any(), any());
+			}
+
+			@Test
+			void shouldSetMessage() {
+				var result = service.validateSignature(signature);
+
+				assertThat(result).get().extracting(ValidationError::getMessage, STRING)
+						.hasSizeGreaterThan(EXCEPTION_MESSAGE.length())
+						.endsWith(EXCEPTION_MESSAGE);
+			}
+
+			@Test
+			void shouldSetCause() {
+				var result = service.validateSignature(signature);
+
+				assertThat(result).get().extracting(ValidationError::getCause).isEqualTo(signatureException);
+			}
+		}
 	}
 
 	@Nested
@@ -276,7 +398,7 @@ class SamlAttributeServiceTest {
 		}
 
 		private Map<String, String> decryptAttributes() {
-			return service.decryptAttributes(token);
+			return service.decryptSamlAttributes(token);
 		}
 	}
 
@@ -429,145 +551,208 @@ class SamlAttributeServiceTest {
 	@Nested
 	class TestBuildTokenAttributes {
 
-		private static final Map.Entry<String, String> ADJUSTED_TOKEN_ATTRIBUTES_ENTRY = Map.entry("key", "value");
-		private static final Map<String, String> ADJUSTED_TOKEN_ATTRIBUTES_MAP = Map.ofEntries(ADJUSTED_TOKEN_ATTRIBUTES_ENTRY);
-		private static final TokenAttribute TOKEN_ATTRIBUTE = TokenAttributeTestFactory.create();
+		private static final Map<String, String> TOKEN_ATTRIBUTES_MAP = TokenAttributeTestFactory.asMap();
 
 		@Mock
 		private Response token;
 
 		@BeforeEach
 		void init() {
-			doReturn(ADJUSTED_TOKEN_ATTRIBUTES_MAP).when(service).adjustAttributes(any(), any());
-			doReturn(TOKEN_ATTRIBUTE).when(service).buildTokenAttribute(any());
+			doReturn(true).when(service).isNotMappedField(any());
+			doReturn(TokenAttributesTestFactory.OTHER_ATTRIBUTE).when(service).buildTokenAttribute(any());
+		}
+
+		@Test
+		void shouldCallGetPostfachId() {
+			buildTokenAttributes();
+
+			verify(service).getPostfachId(TOKEN_ATTRIBUTES_MAP, token);
+		}
+
+		@Test
+		void shouldSetPostfachId() {
+			doReturn(TokenAttributesTestFactory.POSTFACH_ID).when(service).getPostfachId(any(), any());
+
+			var result = buildTokenAttributes();
+
+			assertThat(result.getPostfachId()).isEqualTo(TokenAttributesTestFactory.POSTFACH_ID);
+		}
+
+		@Test
+		void shouldCallGetTrustLevel() {
+			buildTokenAttributes();
+
+			verify(service).getTrustLevel(TOKEN_ATTRIBUTES_MAP);
+		}
+
+		@Test
+		void shouldSetTrustLevel() {
+			doReturn(TokenAttributesTestFactory.TRUST_LEVEL).when(service).getTrustLevel(any());
+
+			var result = buildTokenAttributes();
+
+			assertThat(result.getTrustLevel()).isEqualTo(TokenAttributesTestFactory.TRUST_LEVEL);
 		}
 
 		@Test
-		void shouldCallAdjustAttribute() {
+		void shouldCallIsNotMappedField() {
 			buildTokenAttributes();
 
-			verify(service).adjustAttributes(TokenAttributeTestFactory.asMap(), token);
+			verify(service).isNotMappedField(Map.entry(TokenAttributeTestFactory.NAME, TokenAttributeTestFactory.VALUE));
 		}
 
 		@Test
 		void shouldCallBuildTokenAttribute() {
 			buildTokenAttributes();
 
-			verify(service).buildTokenAttribute(ADJUSTED_TOKEN_ATTRIBUTES_ENTRY);
+			verify(service).buildTokenAttribute(Map.entry(TokenAttributeTestFactory.NAME, TokenAttributeTestFactory.VALUE));
 		}
 
 		@Test
-		void shouldReturnTokenAttributes() {
+		void shouldSetOtherAttributes() {
 			var result = buildTokenAttributes();
 
-			assertThat(result).containsExactly(TOKEN_ATTRIBUTE);
+			assertThat(result.getOtherAttributes()).containsExactly(TokenAttributesTestFactory.OTHER_ATTRIBUTE);
 		}
 
-		private Set<TokenAttribute> buildTokenAttributes() {
-			return service.buildTokenAttributes(TokenAttributeTestFactory.asMap(), token);
+		private TokenAttributes buildTokenAttributes() {
+			return service.buildTokenAttributes(TOKEN_ATTRIBUTES_MAP, token);
 		}
 	}
 
 	@Nested
-	class TestAdjustAttributes {
-
-		private static final Map<String, String> TOKEN_ATTRIBUTES_MAP = TokenAttributeTestFactory.asMap();
-		private static final Map<String, String> ADJUSTED_TOKEN_ATTRIBUTES_MAP = Map.of("key", "value");
-		private static final Map<String, String> REPLACED_TOKEN_ATTRIBUTES_MAP = Map.of("key", "value");
+	class TestGetPostfachId {
 
 		@Mock
 		private Response token;
-		@Captor
-		private ArgumentCaptor<Map<String, String>> tokenAttributesCaptor;
 
-		@BeforeEach
-		void init() {
-			when(service.replaceKeys(any())).thenReturn(REPLACED_TOKEN_ATTRIBUTES_MAP);
-			when(service.adjustPostfachIdAttribute(any(), any())).thenReturn(ADJUSTED_TOKEN_ATTRIBUTES_MAP);
-		}
+		@Nested
+		class TestTokenId {
 
-		@Test
-		void shouldCallReplaceKeys() {
-			adjustAttributes();
+			private static final String TOKEN_ID = UUID.randomUUID().toString();
 
-			verify(service).replaceKeys(tokenAttributesCaptor.capture());
-			assertThat(tokenAttributesCaptor.getValue()).isEqualTo(TOKEN_ATTRIBUTES_MAP);
-			assertDoesNotThrow(() -> tokenAttributesCaptor.getValue().put("key", "value"));
-		}
+			@BeforeEach
+			void init() {
+				when(tokenValidationProperty.isUseIdAsPostfachId()).thenReturn(true);
+				doReturn(TOKEN_ID).when(token).getID();
+			}
 
-		@Test
-		void shouldCallAdjustPostfachIdAttributes() {
-			adjustAttributes();
+			@Test
+			void shouldCallGetTokenId() {
+				getPostfachId();
+
+				verify(service).getPostfachId(TokenAttributeTestFactory.asMap(), token);
+			}
 
-			verify(service).adjustPostfachIdAttribute(REPLACED_TOKEN_ATTRIBUTES_MAP, token);
+			@Test
+			void shouldReturnTokenId() {
+				var result = getPostfachId();
+
+				assertThat(result).contains(TOKEN_ID);
+			}
 		}
 
-		@Test
-		void shouldReturnUnmodifiableMap() {
-			var result = adjustAttributes();
+		@Nested
+		class TestTokenAttribute {
+
+			@BeforeEach
+			void init() {
+				when(tokenValidationProperty.isUseIdAsPostfachId()).thenReturn(false);
+				doReturn(TokenAttributeTestFactory.VALUE).when(service).getMappedValue(any(), any());
+			}
+
+			@Test
+			void shouldCallGetMappedValue() {
+				getPostfachId();
 
-			assertThat(result).isEqualTo(REPLACED_TOKEN_ATTRIBUTES_MAP);
-			Assertions.assertThrows(UnsupportedOperationException.class, () -> result.put("key", "value"));
+				verify(service).getMappedValue(TokenAttributeTestFactory.asMap(), TokenAttributes.POSTFACH_ID_KEY);
+			}
+
+			@Test
+			void shouldReturnMappedValue() {
+				var result = getPostfachId();
+
+				assertThat(result).contains(TokenAttributeTestFactory.VALUE);
+			}
 		}
 
-		private Map<String, String> adjustAttributes() {
-			return service.adjustAttributes(TOKEN_ATTRIBUTES_MAP, token);
+		private String getPostfachId() {
+			return service.getPostfachId(TokenAttributeTestFactory.asMap(), token);
 		}
 	}
 
 	@Nested
-	class TestReplaceKeys {
+	class TestGetTrustLevel {
 
-		private static final String MAPPING_KEY = LoremIpsum.getInstance().getWords(1);
+		@BeforeEach
+		void init() {
+			doReturn(TokenAttributeTestFactory.VALUE).when(service).getMappedValue(any(), any());
+		}
 
 		@Test
-		void shouldReplaceValue() {
-			when(tokenValidationProperty.getMappings()).thenReturn(Map.of(MAPPING_KEY, TokenAttributeTestFactory.NAME));
+		void shouldCallGetMappedValue() {
+			getTrustLevel();
 
-			var result = service.replaceKeys(TokenAttributeTestFactory.asMap());
+			verify(service).getMappedValue(TokenAttributeTestFactory.asMap(), TokenAttributes.TRUST_LEVEL_KEY);
+		}
 
-			assertThat(result).containsOnly(Map.entry(MAPPING_KEY, TokenAttributeTestFactory.VALUE));
+		@Test
+		void shouldReturnMappedValue() {
+			var result = getTrustLevel();
+
+			assertThat(result).contains(TokenAttributeTestFactory.VALUE);
 		}
 
+		private String getTrustLevel() {
+			return service.getTrustLevel(TokenAttributeTestFactory.asMap());
+		}
 	}
 
 	@Nested
-	class TestAdjustPostfachIdAttribute {
+	class TestGetMappedValue {
 
-		private static final String POSTFACH_ID = LoremIpsum.getInstance().getWords(1);
-
-		@Mock
-		private Response token;
+		private static final String MAPPED_KEY = UUID.randomUUID().toString();
 
 		@Test
-		void shouldSetPostfachId() {
-			when(tokenValidationProperty.isUseIdAsPostfachId()).thenReturn(true);
-			when(token.getID()).thenReturn(POSTFACH_ID);
+		void shouldReturnValueByMappedKey() {
+			when(tokenValidationProperty.getMappings()).thenReturn(Map.of(TokenAttributeTestFactory.NAME, MAPPED_KEY));
 
-			var result = service.adjustPostfachIdAttribute(TokenAttributeTestFactory.asMap(), token);
+			var result = service.getMappedValue(Map.of(MAPPED_KEY, TokenAttributeTestFactory.VALUE), TokenAttributeTestFactory.NAME);
 
-			assertThat(result).containsEntry(TokenAttribute.POSTFACH_ID_KEY, POSTFACH_ID);
+			assertThat(result).isEqualTo(TokenAttributeTestFactory.VALUE);
 		}
 
 		@Test
-		void shouldRewritePostfachId() {
-			when(tokenValidationProperty.isUseIdAsPostfachId()).thenReturn(true);
-			var attributeMap = new HashMap<>(Map.of(TokenAttribute.POSTFACH_ID_KEY, LoremIpsum.getInstance().getWords(1)));
-			when(token.getID()).thenReturn(POSTFACH_ID);
+		void shouldReturnValueByKey() {
+			var result = service.getMappedValue(TokenAttributeTestFactory.asMap(), TokenAttributeTestFactory.NAME);
+
+			assertThat(result).isEqualTo(TokenAttributeTestFactory.VALUE);
+		}
+	}
+
+	@Nested
+	class TestIsNotMappedField {
 
-			var result = service.adjustPostfachIdAttribute(attributeMap, token);
+		private static final String KEY = UUID.randomUUID().toString();
 
-			assertThat(result).containsEntry(TokenAttribute.POSTFACH_ID_KEY, POSTFACH_ID);
+		@Test
+		void shouldReturnTrueWhenNotMapped() {
+			var result = isNotMappedField();
+
+			assertThat(result).isTrue();
 		}
 
 		@Test
-		void shouldReturnUnchangedMap() {
-			when(tokenValidationProperty.isUseIdAsPostfachId()).thenReturn(false);
-			var attributeMap = TokenAttributeTestFactory.asMap();
+		void shouldReturnFalseWhenMapped() {
+			when(tokenValidationProperty.getMappings()).thenReturn(Map.of(KEY, TokenAttributeTestFactory.NAME));
 
-			var result = service.adjustPostfachIdAttribute(attributeMap, token);
+			var result = service.isNotMappedField(Map.entry(TokenAttributeTestFactory.NAME, TokenAttributeTestFactory.VALUE));
+
+			assertThat(result).isFalse();
+		}
 
-			assertThat(result).isEqualTo(attributeMap);
+		private boolean isNotMappedField() {
+			return service.isNotMappedField(Map.entry(TokenAttributeTestFactory.NAME, TokenAttributeTestFactory.VALUE));
 		}
 	}
 
@@ -578,7 +763,7 @@ class SamlAttributeServiceTest {
 		void shouldBuildTokenAttribute() {
 			var result = service.buildTokenAttribute(Map.entry(TokenAttributeTestFactory.NAME, TokenAttributeTestFactory.VALUE));
 
-			assertThat(result).isEqualTo(TokenAttributeTestFactory.create());
+			assertThat(result).usingRecursiveComparison().isEqualTo(TokenAttributeTestFactory.create());
 		}
 	}
 }
\ No newline at end of file