Repository: SAP/cloud-security-xsuaa-integration
Pull request #135 (2019-09-11 09:52:58)

Version 2.0
- `spring-xsuaa`removes package com.sap.xs2.security.container
- `token-client` lib supports password token grant
- removes deprecated methods/classes

related issues:
- https://github.com/SAP/cloud-security-xsuaa-integration/issues/107
- https://github.com/SAP/cloud-security-xsuaa-integration/issues/119


Patch:
diff --git a/api/pom.xml b/api/pom.xml
index e1606ad3..8643a0c6 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -4,12 +4,12 @@
 
 	<groupId>com.sap.cloud.security.xsuaa</groupId>
 	<artifactId>api</artifactId>
-	<version>1.7.0</version>
+	<version>2.0.0</version>
 
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>1.7.0</version>
+		<version>2.0.0</version>
 	</parent>
 
 	<packaging>jar</packaging>
diff --git a/pom.xml b/pom.xml
index 8e6a49b9..422a94ca 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
 
 	<groupId>com.sap.cloud.security.xsuaa</groupId>
 	<artifactId>parent</artifactId>
-	<version>1.7.0</version>
+	<version>2.0.0</version>
 	<packaging>pom</packaging>
 
 	<name>parent</name>
diff --git a/samples/sap-java-buildpack-api-usage/manifest.yml b/samples/sap-java-buildpack-api-usage/manifest.yml
index d8f9c48e..a9652a32 100644
--- a/samples/sap-java-buildpack-api-usage/manifest.yml
+++ b/samples/sap-java-buildpack-api-usage/manifest.yml
@@ -12,13 +12,15 @@ applications:
 
   host: 
   path: target/sap-java-buildpack-api-usage.war
-  buildpack: sap_java_buildpack
+  buildpacks:
+    - sap_java_buildpack
   services:
     - xsuaa-buildpack
 # Application Router as web server
 - name: approuter-sap-java-buildpack-api-usage
   path: approuter
-  buildpack: nodejs_buildpack
+  buildpacks:
+    - nodejs_buildpack
   memory: 128M
   routes:
     - route: approuter-sap-java-buildpack-api-usage-((ID)).((LANDSCAPE_APPS_DOMAIN))
diff --git a/samples/sap-java-buildpack-api-usage/pom.xml b/samples/sap-java-buildpack-api-usage/pom.xml
index 157dc28b..b384b8d9 100755
--- a/samples/sap-java-buildpack-api-usage/pom.xml
+++ b/samples/sap-java-buildpack-api-usage/pom.xml
@@ -21,7 +21,7 @@
 		<dependency>
 			<groupId>com.sap.cloud.security.xsuaa</groupId>
 			<artifactId>api</artifactId>
-			<version>1.7.0</version>
+			<version>2.0.0</version>
 			<scope>provided</scope>
 		</dependency>
 		<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
diff --git a/samples/spring-security-basic-auth/pom.xml b/samples/spring-security-basic-auth/pom.xml
index cac08426..5344446e 100644
--- a/samples/spring-security-basic-auth/pom.xml
+++ b/samples/spring-security-basic-auth/pom.xml
@@ -11,7 +11,7 @@
 	</parent>
 
 	<artifactId>spring-security-basic-auth</artifactId>
-	<version>1.7.0</version>
+	<version>2.0.0</version>
 	<name>spring-security-basic-auth</name>
 
 	<properties>
diff --git a/samples/spring-security-xsuaa-usage/manifest.yml b/samples/spring-security-xsuaa-usage/manifest.yml
index baec79d3..c4009bd3 100644
--- a/samples/spring-security-xsuaa-usage/manifest.yml
+++ b/samples/spring-security-xsuaa-usage/manifest.yml
@@ -16,7 +16,8 @@ applications:
 # Application Router as web server
 - name: approuter-spring-security-xsuaa-usage
   path: approuter
-  buildpack: nodejs_buildpack
+  buildpacks:
+    - nodejs_buildpack
   memory: 128M
   routes:
     - route: spring-security-xsuaa-usage-web-((ID)).((LANDSCAPE_APPS_DOMAIN))
diff --git a/samples/spring-security-xsuaa-usage/pom.xml b/samples/spring-security-xsuaa-usage/pom.xml
index e5bf6fad..46d43a2c 100644
--- a/samples/spring-security-xsuaa-usage/pom.xml
+++ b/samples/spring-security-xsuaa-usage/pom.xml
@@ -14,7 +14,7 @@
 
 	<groupId>com.sap.cloud.security.samples</groupId>
 	<artifactId>spring-security-xsuaa-usage</artifactId>
-	<version>1.3.0</version>
+	<version>2.0.0</version>
 	<name>spring-security-xsuaa-usage</name>
 
 	<properties>
@@ -37,7 +37,7 @@
         <dependency>
             <groupId>com.sap.cloud.security.xsuaa</groupId>
             <artifactId>xsuaa-spring-boot-starter</artifactId>
-            <version>1.7.0</version>
+            <version>2.0.0</version>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
diff --git a/samples/spring-webflux-security-xsuaa-usage/manifest.yml b/samples/spring-webflux-security-xsuaa-usage/manifest.yml
index f32b8659..6f743101 100644
--- a/samples/spring-webflux-security-xsuaa-usage/manifest.yml
+++ b/samples/spring-webflux-security-xsuaa-usage/manifest.yml
@@ -10,6 +10,8 @@ applications:
     routes:
       - route: spring-webflux-security-xsuaa-usage-((ID)).((LANDSCAPE_APPS_DOMAIN))
     path: target/spring-webflux-security-xsuaa-usage.jar
+    env:
+      JBP_CONFIG_DEBUG: '{enabled: true}'
     services:
       - xsuaa-webflux
 
diff --git a/samples/spring-webflux-security-xsuaa-usage/pom.xml b/samples/spring-webflux-security-xsuaa-usage/pom.xml
index 26ac63c4..be73a34e 100644
--- a/samples/spring-webflux-security-xsuaa-usage/pom.xml
+++ b/samples/spring-webflux-security-xsuaa-usage/pom.xml
@@ -12,7 +12,7 @@
 
     <groupId>com.sap.cloud.security.samples</groupId>
     <artifactId>spring-webflux-security-xsuaa-usage</artifactId>
-    <version>1.7.0</version>
+    <version>2.0.0</version>
     <name>spring-webflux-security-xsuaa-usage</name>
 
     <properties>
diff --git a/spring-xsuaa-it/pom.xml b/spring-xsuaa-it/pom.xml
index f41e3bb3..63c10db3 100644
--- a/spring-xsuaa-it/pom.xml
+++ b/spring-xsuaa-it/pom.xml
@@ -11,7 +11,7 @@
 	</parent>
 
 	<artifactId>spring-xsuaa-it</artifactId>
-	<version>1.7.0</version>
+	<version>2.0.0</version>
 	<name>spring-xsuaa-it</name>
 
 	<properties>
diff --git a/spring-xsuaa-it/src/main/java/com/sap/cloud/security/xsuaa/mock/MockPostProcessor.java b/spring-xsuaa-it/src/main/java/com/sap/cloud/security/xsuaa/mock/MockPostProcessor.java
index 0e76b60a..a7ccd3ec 100644
--- a/spring-xsuaa-it/src/main/java/com/sap/cloud/security/xsuaa/mock/MockPostProcessor.java
+++ b/spring-xsuaa-it/src/main/java/com/sap/cloud/security/xsuaa/mock/MockPostProcessor.java
@@ -38,25 +38,21 @@ public class MockPostProcessor implements EnvironmentPostProcessor, DisposableBe
 			if ("/otherdomain/token_keys".equals(request.getPath())) {
 				return getResponseFromFile("/mock/otherdomain_token_keys.json", HttpStatus.OK);
 			}
-			if (request.getPath().equals("/oauth/token")) {
+			if (request.getPath().equals("/oauth/token") && "POST".equals(request.getMethod())) {
 				String body = request.getBody().readString(StandardCharsets.UTF_8);
-				if ("basic c2ItamF2YS1oZWxsby13b3JsZDpteXNlY3JldC1iYXNpYw=="
-						.equalsIgnoreCase(request.getHeader("authorization")) && "POST".equals(request.getMethod())
-						&& body.contains("username=basic.user") && body.contains("password=basic.password")) {
-
+				if (body.contains("grant_type=password") && body.contains("username=basic.user")
+						&& body.contains("password=basic.password")) {
 					try {
 						return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
 								.setResponseCode(HttpStatus.OK.value())
-								.setBody(String.format("{\"access_token\": \"%s\"}",
+								.setBody(String.format("{\"expires_in\": 43199, \"access_token\": \"%s\"}",
 										JWTUtil.createJWT("/password.txt", "testdomain")));
 					} catch (Exception e) {
 						e.printStackTrace();
 						getResponse(RESPONSE_500, HttpStatus.INTERNAL_SERVER_ERROR);
 					}
 				}
-				if ("POST".equals(request.getMethod())
-						&& body.contains("grant_type=client_credentials")) {
-
+				if (body.contains("grant_type=client_credentials")) {
 					try {
 						return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
 								.setResponseCode(HttpStatus.OK.value()).setBody(String.format(
diff --git a/spring-xsuaa-mock/README.md b/spring-xsuaa-mock/README.md
index 7a437623..de637c7c 100644
--- a/spring-xsuaa-mock/README.md
+++ b/spring-xsuaa-mock/README.md
@@ -17,7 +17,7 @@ The default implementation offers already valid *token_keys* for JWT tokens, tha
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>spring-xsuaa-mock</artifactId>
-    <version>1.7.0</version>
+    <version>2.0.0</version>
 </dependency>
 <dependency> <!-- new with version 1.5.0 - provided with org.springframework.boot:spring-boot-starter:jar -->
     <groupId>org.springframework.boot</groupId>
diff --git a/spring-xsuaa-mock/pom.xml b/spring-xsuaa-mock/pom.xml
index a9d4b7a7..46bd4964 100644
--- a/spring-xsuaa-mock/pom.xml
+++ b/spring-xsuaa-mock/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>1.7.0</version>
+		<version>2.0.0</version>
 	</parent>
 
 	<artifactId>spring-xsuaa-mock</artifactId>
diff --git a/spring-xsuaa-starter/pom.xml b/spring-xsuaa-starter/pom.xml
index 6404e847..75170166 100644
--- a/spring-xsuaa-starter/pom.xml
+++ b/spring-xsuaa-starter/pom.xml
@@ -14,7 +14,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>1.7.0</version>
+		<version>2.0.0</version>
 	</parent>
 
 	<dependencyManagement>
@@ -30,6 +30,7 @@
 	</dependencyManagement>
 
 	<artifactId>xsuaa-spring-boot-starter</artifactId>
+	<version>2.0.0</version>
 	<name>SAP Spring Boot Xsuaa Starter</name>
 	<description>SAP Starter for integrating application with XSUAA service</description>
 	<url>https://github.com/SAP/cloud-security-xsuaa-integration</url>
diff --git a/spring-xsuaa/README.md b/spring-xsuaa/README.md
index 4836a711..217cf3ec 100644
--- a/spring-xsuaa/README.md
+++ b/spring-xsuaa/README.md
@@ -23,7 +23,7 @@ This library enhances the [spring-security](https://github.com/spring-projects/s
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>spring-xsuaa</artifactId>
-    <version>1.7.0</version>
+    <version>2.0.0</version>
 </dependency>
 <dependency> <!-- new with version 1.5.0 -->
     <groupId>org.apache.logging.log4j</groupId>
@@ -38,7 +38,7 @@ This library enhances the [spring-security](https://github.com/spring-projects/s
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>xsuaa-spring-boot-starter</artifactId>
-    <version>1.7.0</version>
+    <version>2.0.0</version>
 </dependency>
 ```
 
diff --git a/spring-xsuaa/pom.xml b/spring-xsuaa/pom.xml
index f4813ad1..f83d8e26 100644
--- a/spring-xsuaa/pom.xml
+++ b/spring-xsuaa/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>1.7.0</version>
+		<version>2.0.0</version>
 	</parent>
 
 	<artifactId>spring-xsuaa</artifactId>
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServiceConfiguration.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServiceConfiguration.java
index a35be47d..5ce8e3f4 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServiceConfiguration.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServiceConfiguration.java
@@ -23,21 +23,6 @@ public interface XsuaaServiceConfiguration {
 	 */
 	String getUaaUrl();
 
-	/**
-	 * Url to the token_keys endpoint
-	 * 
-	 * @param identityZoneId
-	 *            Identity Zone Id (subaccount id)
-	 * @param subdomain
-	 *            of the subaccount
-	 * @return token key endpoint
-	 *
-	 * @deprecated Xsuaa version 2.8.0 provides jwt token key url (jku) as part of
-	 *             the JWT. This method gets deleted with version 2.0.0.
-	 */
-	@Deprecated
-	String getTokenKeyUrl(String identityZoneId, String subdomain);
-
 	/**
 	 * XS application identifier
 	 * 
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServiceConfigurationDefault.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServiceConfigurationDefault.java
index 4e9bf332..cb36d79c 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServiceConfigurationDefault.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServiceConfigurationDefault.java
@@ -37,16 +37,6 @@ public class XsuaaServiceConfigurationDefault implements XsuaaServiceConfigurati
 		return clientId;
 	}
 
-	@Override
-	public String getTokenKeyUrl(String identityZoneId, String subdomain) {
-		// Please note this method is deprecated and will be deleted with version 2.0
-		if ("uaa".equals(identityZoneId)) {
-			return getUaaUrl() + "/token_keys";
-		} else {
-			return String.format("https://%s.%s/token_keys", subdomain, uaadomain);
-		}
-	}
-
 	@Override
 	public String getClientSecret() {
 		return clientSecret;
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServicePropertySourceFactory.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServicePropertySourceFactory.java
index 7b0c8e8e..5a07d17a 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServicePropertySourceFactory.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/XsuaaServicePropertySourceFactory.java
@@ -3,8 +3,6 @@ package com.sap.cloud.security.xsuaa;
 import java.io.IOException;
 import java.util.Properties;
 
-import com.sap.cloud.security.xsuaa.autoconfiguration.XsuaaAutoConfiguration;
-import net.minidev.json.parser.ParseException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.core.env.PropertiesPropertySource;
@@ -12,6 +10,10 @@ import org.springframework.core.env.PropertySource;
 import org.springframework.core.io.support.EncodedResource;
 import org.springframework.core.io.support.PropertySourceFactory;
 
+import com.sap.cloud.security.xsuaa.autoconfiguration.XsuaaAutoConfiguration;
+
+import net.minidev.json.parser.ParseException;
+
 /**
  * Part of Auto Configuration {@link XsuaaAutoConfiguration}
  *
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaAutoConfiguration.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaAutoConfiguration.java
index b71c6a16..940234f9 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaAutoConfiguration.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaAutoConfiguration.java
@@ -1,20 +1,22 @@
 package com.sap.cloud.security.xsuaa.autoconfiguration;
 
-import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.XsuaaServiceConfigurationDefault;
-import com.sap.cloud.security.xsuaa.XsuaaServicePropertySourceFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.annotation.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
 import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.web.client.RestOperations;
 import org.springframework.web.client.RestTemplate;
 
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfigurationDefault;
+import com.sap.cloud.security.xsuaa.XsuaaServicePropertySourceFactory;
+
 /**
  * {@link EnableAutoConfiguration Auto-configuration} for default beans used by
  * the XSUAA client library.
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaResourceServerJwkAutoConfiguration.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaResourceServerJwkAutoConfiguration.java
index e73c8c6a..97de6923 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaResourceServerJwkAutoConfiguration.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaResourceServerJwkAutoConfiguration.java
@@ -1,19 +1,24 @@
 package com.sap.cloud.security.xsuaa.autoconfiguration;
 
-import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.token.authentication.XsuaaJwtDecoderBuilder;
+import static org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.boot.autoconfigure.AutoConfigureBefore;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.*;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
 import org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.security.oauth2.jwt.JwtDecoder;
 
-import static org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.*;
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.token.authentication.XsuaaJwtDecoderBuilder;
 
 /**
  * {@link EnableAutoConfiguration Auto-configuration} that exposes a
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfiguration.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfiguration.java
index 27549f76..b1077651 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfiguration.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfiguration.java
@@ -1,8 +1,5 @@
 package com.sap.cloud.security.xsuaa.autoconfiguration;
 
-import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.client.*;
-import com.sap.cloud.security.xsuaa.tokenflows.XsuaaTokenFlows;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -14,6 +11,14 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.client.RestOperations;
 
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.client.ClientCredentials;
+import com.sap.cloud.security.xsuaa.client.OAuth2ServiceEndpointsProvider;
+import com.sap.cloud.security.xsuaa.client.OAuth2TokenService;
+import com.sap.cloud.security.xsuaa.client.XsuaaDefaultEndpoints;
+import com.sap.cloud.security.xsuaa.client.XsuaaOAuth2TokenService;
+import com.sap.cloud.security.xsuaa.tokenflows.XsuaaTokenFlows;
+
 /**
  * {@link EnableAutoConfiguration Auto-configuration} for default beans used by
  * the XSUAA client library.
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/AuthenticationInformationExtractor.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/AuthenticationInformationExtractor.java
index 4934d653..3b3689c4 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/AuthenticationInformationExtractor.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/AuthenticationInformationExtractor.java
@@ -1,13 +1,10 @@
-/**
- * 
- */
 package com.sap.cloud.security.xsuaa.extractor;
 
+import javax.servlet.http.HttpServletRequest;
+
 import java.util.List;
 import java.util.Optional;
 
-import javax.servlet.http.HttpServletRequest;
-
 public interface AuthenticationInformationExtractor {
 
 	/**
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/AuthoritiesExtractor.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/AuthoritiesExtractor.java
index 6ce5a524..ba64493d 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/AuthoritiesExtractor.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/AuthoritiesExtractor.java
@@ -2,9 +2,10 @@ package com.sap.cloud.security.xsuaa.extractor;
 
 import java.util.Collection;
 
-import com.sap.cloud.security.xsuaa.token.XsuaaToken;
 import org.springframework.security.core.GrantedAuthority;
 
+import com.sap.cloud.security.xsuaa.token.XsuaaToken;
+
 /**
  * Extracts the authorities from the Jwt token. Can use this method to map /
  * manipulate scopes, e.g. by changing their prefix, etc.
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/DefaultAuthenticationInformationExtractor.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/DefaultAuthenticationInformationExtractor.java
index 99628b74..b2e4a599 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/DefaultAuthenticationInformationExtractor.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/DefaultAuthenticationInformationExtractor.java
@@ -1,15 +1,12 @@
-/**
- * 
- */
 package com.sap.cloud.security.xsuaa.extractor;
 
+import javax.servlet.http.HttpServletRequest;
+
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 
-import javax.servlet.http.HttpServletRequest;
-
 /**
  * Default Implementation
  *
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/DefaultAuthoritiesExtractor.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/DefaultAuthoritiesExtractor.java
index ab1d26ea..10091a70 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/DefaultAuthoritiesExtractor.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/DefaultAuthoritiesExtractor.java
@@ -5,13 +5,14 @@ import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 
-import com.sap.cloud.security.xsuaa.token.TokenClaims;
-import com.sap.cloud.security.xsuaa.token.XsuaaToken;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
 
+import com.sap.cloud.security.xsuaa.token.TokenClaims;
+import com.sap.cloud.security.xsuaa.token.XsuaaToken;
+
 public class DefaultAuthoritiesExtractor extends JwtAuthenticationConverter implements AuthoritiesExtractor {
 
 	public Collection<GrantedAuthority> getAuthorities(XsuaaToken jwt) {
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/LocalAuthoritiesExtractor.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/LocalAuthoritiesExtractor.java
index 276b4fcd..e8a6f937 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/LocalAuthoritiesExtractor.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/LocalAuthoritiesExtractor.java
@@ -5,10 +5,11 @@ import java.util.Collections;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import com.sap.cloud.security.xsuaa.token.XsuaaToken;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 
+import com.sap.cloud.security.xsuaa.token.XsuaaToken;
+
 public class LocalAuthoritiesExtractor implements AuthoritiesExtractor {
 
 	protected String appId;
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/TokenBroker.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/TokenBroker.java
index eba0f7d1..60f263fc 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/TokenBroker.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/TokenBroker.java
@@ -1,9 +1,17 @@
 package com.sap.cloud.security.xsuaa.extractor;
 
+import java.net.URI;
+import java.util.Map;
+
+import com.sap.cloud.security.xsuaa.client.ClientCredentials;
+
 /**
  *
- *
+ * @deprecated in favor of
+ *             {@link com.sap.cloud.security.xsuaa.client.OAuth2TokenService}
+ *             API. Will be removed with version 3.0.0.
  */
+@Deprecated
 public interface TokenBroker {
 
 	/**
@@ -18,7 +26,10 @@ public interface TokenBroker {
 	 * @return String
 	 * @throws TokenBrokerException
 	 *             TokenBrokerException
+	 * @deprecated in favor of
+	 *             {@link com.sap.cloud.security.xsuaa.client.OAuth2TokenService#retrieveAccessTokenViaClientCredentialsGrant(URI, ClientCredentials, String, Map)}
 	 */
+	@Deprecated
 	public String getAccessTokenFromClientCredentials(String tokenURL, String clientId, String clientSecret)
 			throws TokenBrokerException;
 
@@ -38,6 +49,8 @@ public interface TokenBroker {
 	 * @return String
 	 * @throws TokenBrokerException
 	 *             TokenBrokerException
+	 * @deprecated in favor of
+	 *             {@link com.sap.cloud.security.xsuaa.client.OAuth2TokenService#retrieveAccessTokenViaPasswordGrant(URI, ClientCredentials, String, String, String, Map)}
 	 */
 	public String getAccessTokenFromPasswordCredentials(String tokenURL, String clientId, String clientSecret,
 			String username, String password) throws TokenBrokerException;
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/TokenBrokerResolver.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/TokenBrokerResolver.java
index 69330d9a..a39c4e52 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/TokenBrokerResolver.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/TokenBrokerResolver.java
@@ -1,5 +1,7 @@
 package com.sap.cloud.security.xsuaa.extractor;
 
+import javax.servlet.http.HttpServletRequest;
+
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -8,15 +10,16 @@ import java.util.Enumeration;
 import java.util.List;
 import java.util.Optional;
 
-import javax.servlet.http.HttpServletRequest;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.cache.Cache;
+import org.springframework.lang.Nullable;
 import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
 import org.springframework.util.StringUtils;
 
 import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.client.ClientCredentials;
+import com.sap.cloud.security.xsuaa.client.OAuth2TokenService;
 
 /**
  * Analyse authentication header and obtain token from UAA
@@ -40,8 +43,6 @@ public class TokenBrokerResolver implements BearerTokenResolver {
 
 	private Cache tokenCache;
 	private TokenBroker tokenBroker;
-	private String uaaUrl;
-	private String uaaDomain;
 	private AuthenticationInformationExtractor authenticationConfig;
 
 	/**
@@ -53,31 +54,53 @@ public class TokenBrokerResolver implements BearerTokenResolver {
 	 *            Token-Broker for accessing the UAA
 	 * @param authenticationConfig
 	 *            configured AuthenticationMethodConfiguration
+	 * @deprecated in favor of
+	 *             {@link #TokenBrokerResolver(XsuaaServiceConfiguration, Cache, OAuth2TokenService, AuthenticationInformationExtractor)}
 	 */
-
+	@Deprecated
 	public TokenBrokerResolver(XsuaaServiceConfiguration configuration, Cache tokenCache, TokenBroker tokenBroker,
 			AuthenticationInformationExtractor authenticationConfig) {
 		this.configuration = configuration;
 		this.tokenCache = tokenCache;
 		this.tokenBroker = tokenBroker;
-		this.uaaUrl = configuration.getUaaUrl();
-		this.uaaDomain = configuration.getUaaDomain();
 		this.authenticationConfig = authenticationConfig;
 	}
 
+	/**
+	 * @param configuration
+	 *            - Configuration properties from environment.
+	 * @param tokenCache
+	 *            - the Token-Cache.
+	 * @param tokenService
+	 *            - the {@link OAuth2TokenService} used to execute the final
+	 *            request.
+	 * @param authenticationConfig
+	 *            - configured AuthenticationMethodConfiguration.
+	 */
+	public TokenBrokerResolver(XsuaaServiceConfiguration configuration, Cache tokenCache,
+			OAuth2TokenService tokenService,
+			AuthenticationInformationExtractor authenticationConfig) {
+		this.configuration = configuration;
+		this.tokenCache = tokenCache;
+		this.tokenBroker = new UaaTokenBroker(tokenService);
+		this.authenticationConfig = authenticationConfig;
+	}
+
+	/**
+	 * @param configuration
+	 *            Configuration properties from environment
+	 * @param tokenCache
+	 *            Token-Cache
+	 * @param authenticationMethods
+	 *            list of supported authentication methods.
+	 *            Choose either {@link AuthenticationMethod#BASIC} or {@link AuthenticationMethod#CLIENT_CREDENTIALS}.
+	 */
 	public TokenBrokerResolver(XsuaaServiceConfiguration configuration, Cache tokenCache,
 			AuthenticationMethod... authenticationMethods) {
 		this(configuration, tokenCache, new UaaTokenBroker(),
 				new DefaultAuthenticationInformationExtractor(authenticationMethods));
 	}
 
-	private void checkTypes(List<AuthenticationMethod> authenticationMethods) {
-		if (authenticationMethods.contains(AuthenticationMethod.BASIC)
-				&& authenticationMethods.contains(AuthenticationMethod.CLIENT_CREDENTIALS)) {
-			throw new IllegalArgumentException("Use either CLIENT_CREDENTIALS or BASIC");
-		}
-	}
-
 	@Override
 	public String resolve(HttpServletRequest request) {
 		try {
@@ -93,14 +116,7 @@ public class TokenBrokerResolver implements BearerTokenResolver {
 
 		checkTypes(authenticationMethods);
 
-		Optional<String> subdomainResult = authenticationConfig.getSubdomain(request);
-		String oauthTokenUrl;
-		if (subdomainResult.isPresent()) {
-			oauthTokenUrl = TokenUrlUtils.getMultiTenancyUrl(OAUTH_TOKEN_PATH, uaaUrl, uaaDomain,
-					subdomainResult.get());
-		} else {
-			oauthTokenUrl = TokenUrlUtils.getOauthTokenUrl(OAUTH_TOKEN_PATH, uaaUrl, uaaDomain);
-		}
+		String oauthTokenUrl = getOAuthTokenUrl(request);
 
 		for (AuthenticationMethod credentialType : authenticationMethods) {
 			Enumeration<String> headers = request.getHeaders(AUTHORIZATION_HEADER);
@@ -112,55 +128,68 @@ public class TokenBrokerResolver implements BearerTokenResolver {
 		return null;
 	}
 
+	private void checkTypes(List<AuthenticationMethod> authenticationMethods) {
+		if (authenticationMethods.contains(AuthenticationMethod.BASIC)
+				&& authenticationMethods.contains(AuthenticationMethod.CLIENT_CREDENTIALS)) {
+			throw new IllegalArgumentException("Use either CLIENT_CREDENTIALS or BASIC");
+		}
+	}
+
+	private String getOAuthTokenUrl(HttpServletRequest request) {
+		String uaaUrl = configuration.getUaaUrl();
+		String uaaDomain = configuration.getUaaDomain();
+
+		Optional<String> subdomainResult = authenticationConfig.getSubdomain(request);
+
+		String oauthTokenUrl;
+		if (subdomainResult.isPresent()) {
+			oauthTokenUrl = TokenUrlUtils.getMultiTenancyUrl(OAUTH_TOKEN_PATH, uaaUrl, uaaDomain,
+					subdomainResult.get());
+		} else {
+			oauthTokenUrl = TokenUrlUtils.getOauthTokenUrl(OAUTH_TOKEN_PATH, uaaUrl, uaaDomain);
+		}
+
+		return oauthTokenUrl;
+	}
+
 	private String getBrokerToken(AuthenticationMethod credentialType, Enumeration<String> headers,
 			String oauthTokenUrl) throws TokenBrokerException {
+		ClientCredentials clientCredentials = new ClientCredentials(configuration.getClientId(), configuration.getClientSecret());
 		while (headers.hasMoreElements()) {
 			String header = headers.nextElement();
 			switch (credentialType) {
 			case OAUTH2:
-				return extractCredential(BEARER_TYPE, header);
+				return extractAuthorizationHeader(BEARER_TYPE, header);
 			case BASIC:
-				String clientId = configuration.getClientId();
-				String clientSecret = configuration.getClientSecret();
-				if (clientId == null) {
-					throw new TokenBrokerException("Missing clientId");
-				}
-				if (clientSecret == null) {
-					throw new TokenBrokerException("Missing client secret");
-				}
-				String basicCredential = extractCredential(BASIC_CREDENTIAL, header);
-				if (basicCredential != null) {
-					final String[] credentialDetails = obtainCredentialDetails(basicCredential);
-					if (credentialDetails.length == 2) {
-						String cacheKey = createSecureHash(oauthTokenUrl, clientId, clientSecret, credentialDetails[0],
-								credentialDetails[1]);
-						String storedToken = tokenCache.get(cacheKey, String.class);
-						if (storedToken == null) {
-							String token = tokenBroker.getAccessTokenFromPasswordCredentials(oauthTokenUrl, clientId,
-									clientSecret, credentialDetails[0], credentialDetails[1]);
-							tokenCache.put(cacheKey, token);
-							return token;
-						} else {
-							return storedToken;
-						}
+				String basicAuthHeader = extractAuthorizationHeader(BASIC_CREDENTIAL, header);
+				ClientCredentials userCredentialsFromHeader = getCredentialsFromBasicAuthorizationHeader(basicAuthHeader);
+				if (userCredentialsFromHeader != null) {
+					String cacheKey = createSecureHash(oauthTokenUrl, clientCredentials.toString(), userCredentialsFromHeader.toString());
+					String cachedToken = tokenCache.get(cacheKey, String.class);
+					if (cachedToken != null) {
+						return cachedToken;
+					} else {
+						String token = tokenBroker.getAccessTokenFromPasswordCredentials(oauthTokenUrl, clientCredentials.getId(),
+								clientCredentials.getSecret(), userCredentialsFromHeader.getId(), userCredentialsFromHeader.getSecret());
+						tokenCache.put(cacheKey, token);
+						return token;
 					}
 				}
 				break;
 			case CLIENT_CREDENTIALS:
-				String clientCredential = extractCredential(BASIC_CREDENTIAL, header);
-				if (clientCredential != null) {
-					final String[] credentialDetails = obtainCredentialDetails(clientCredential);
-					if (credentialDetails.length == 2) {
-						String cacheKey = createSecureHash(oauthTokenUrl, credentialDetails[0], credentialDetails[1]);
-						String storedToken = tokenCache.get(cacheKey, String.class);
-						if (storedToken == null) {
-							String token = tokenBroker.getAccessTokenFromClientCredentials(oauthTokenUrl,
-									credentialDetails[0], credentialDetails[1]);
-							tokenCache.put(cacheKey, token);
-							return token;
-						} else {
-							return storedToken;
-						}
+				String clientCredentialsAuthHeader = extractAuthorizationHeader(BASIC_CREDENTIAL, header);
+				ClientCredentials clientCredentialsFromHeader = getCredentialsFromBasicAuthorizationHeader(clientCredentialsAuthHeader);
+				if (clientCredentialsFromHeader != null) {
+					String cacheKey = createSecureHash(oauthTokenUrl, clientCredentialsFromHeader.toString());
+					String cachedToken = tokenCache.get(cacheKey, String.class);
+					if (cachedToken != null) {
+						return cachedToken;
+					} else {
+						String token = tokenBroker
+								.getAccessTokenFromClientCredentials(oauthTokenUrl, clientCredentialsFromHeader.getId(),
+										clientCredentialsFromHeader.getSecret());
+						tokenCache.put(cacheKey, token);
+						return token;
 					}
 				}
 				break;
@@ -171,14 +200,20 @@ public class TokenBrokerResolver implements BearerTokenResolver {
 		return null;
 	}
 
-	private String[] obtainCredentialDetails(String basicCredential) {
-		byte[] decodedBytes = Base64.getDecoder().decode(basicCredential.getBytes(StandardCharsets.UTF_8));
+	@Nullable
+	private ClientCredentials getCredentialsFromBasicAuthorizationHeader(@Nullable String basicAuthHeader) {
+		if(basicAuthHeader == null) {
+			return null;
+		}
+		byte[] decodedBytes = Base64.getDecoder().decode(basicAuthHeader.getBytes(StandardCharsets.UTF_8));
 		final String pair = new String(decodedBytes, StandardCharsets.UTF_8);
 		if (pair.contains(":")) {
 			final String[] credentialDetails = pair.split(":", 2);
-			return credentialDetails;
+			if(credentialDetails.length == 2) {
+				return new ClientCredentials(credentialDetails[0], credentialDetails[1]);
+			}
 		}
-		return new String[0];
+		return null;
 	}
 
 	private String createSecureHash(String... keys) {
@@ -195,7 +230,7 @@ public class TokenBrokerResolver implements BearerTokenResolver {
 		}
 	}
 
-	private String extractCredential(String credentialName, String httpHeader) {
+	private String extractAuthorizationHeader(String credentialName, String httpHeader) {
 		if ((httpHeader.toLowerCase().startsWith(credentialName.toLowerCase()))) {
 			String authorizationHeaderValue = httpHeader.substring(credentialName.length()).trim();
 			int index = authorizationHeaderValue.indexOf(',');
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/TokenUrlUtils.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/TokenUrlUtils.java
index 87692bc1..e56c6a40 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/TokenUrlUtils.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/TokenUrlUtils.java
@@ -1,18 +1,12 @@
-/**
- * 
- */
 package com.sap.cloud.security.xsuaa.extractor;
 
-import static org.springframework.util.StringUtils.isEmpty;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Objects;
+import java.net.URI;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.springframework.util.Assert;
 
-public final class TokenUrlUtils {
+final class TokenUrlUtils {
 
 	private final static Log logger = LogFactory.getLog(TokenUrlUtils.class);
 
@@ -22,78 +16,60 @@ public final class TokenUrlUtils {
 	/**
 	 * Retrieves the URL for the token request
 	 * <p>
-	 * 
+	 *
 	 * @param endpoint
 	 *            endpoint
 	 * @param uaaUrl
-	 *            UAA-URL from VCAP-Services
+	 *            UAA-URL from Xsuaa Service binding
 	 * @param uaaDomain
-	 *            UAA-Domain from VCAP-Services
+	 *            UAA-Domain from Xsuaa Service binding
 	 * @param uaaSubDomain
 	 *            UAA-Subdomain in case of Multi tenancy
-	 * 
+	 *
 	 * @return token request URL
 	 */
-
-	public static String getMultiTenancyUrl(final String endpoint, final String uaaUrl, final String uaaDomain,
+	static String getMultiTenancyUrl(final String endpoint, final String uaaUrl, final String uaaDomain,
 			final String uaaSubDomain) {
-		Objects.requireNonNull(uaaUrl, "URL must not be null");
-		Objects.requireNonNull(uaaDomain, "Domain must not be null");
-		Objects.requireNonNull(endpoint, "Endpoint must not be null");
+		Assert.notNull(endpoint, "Endpoint must not be null");
+		Assert.notNull(uaaUrl, "UAA URL must not be null");
+		Assert.notNull(uaaDomain, "UAA Domain must not be null");
+		Assert.notNull(uaaSubDomain, "UAA Subdomain must not be null");
 
-		if (uaaSubDomain == null) {
-			return uaaUrl + endpoint;
-		}
 		return TokenUrlUtils.getUrl(endpoint, uaaUrl, uaaDomain, uaaSubDomain);
 	}
 
-	public static String getOauthTokenUrl(final String endpoint, final String uaaUrl, final String uaaDomain) {
-		return TokenUrlUtils.getMultiTenancyUrl(endpoint, uaaUrl, uaaDomain, null);
+	/**
+	 * Retrieves the URL for the token request
+	 * <p>
+	 *
+	 * @param endpoint
+	 *            endpoint
+	 * @param uaaUrl
+	 *            UAA-URL from Xsuaa Service binding
+	 * @param uaaDomain
+	 *            UAA-URL from Xsuaa Service binding
+	 *
+	 * @return token request URL
+	 */
+	static String getOauthTokenUrl(final String endpoint, final String uaaUrl, final String uaaDomain) {
+		Assert.notNull(endpoint, "Endpoint must not be null");
+		Assert.notNull(uaaUrl, "UAA URL must not be null");
+		Assert.notNull(uaaDomain, "UAA Domain must not be null");
+		return uaaUrl + endpoint;
 	}
 
 	private static String getUrl(final String endpoint, final String uaaUrl, final String uaaDomain,
 			String tenantSubDomain) {
 
-		Objects.requireNonNull(uaaUrl, "UAA-URL must not be null");
-		Objects.requireNonNull(uaaDomain, "Domain must not be null");
-		Objects.requireNonNull(tenantSubDomain, "SubDomain must not be null");
-		Objects.requireNonNull(endpoint, "Endpoint must not be null");
-
 		String tenantUaaDomain = tenantSubDomain + "." + uaaDomain;
 
-		URL url;
-		try {
-			url = new URL(uaaUrl);
-		} catch (MalformedURLException e) {
-			throw new RuntimeException("Cannot create valid URL from given UAA-Url " + uaaUrl);
-		}
-		String protocol = url.getProtocol();
+		URI uri = URI.create(uaaUrl);
+
+		String protocol = uri.getScheme();
 
 		String tenantTokenUrl = String.format("%s://%s", protocol, tenantUaaDomain + endpoint);
 		logger.debug("Created tenant token URL " + tenantTokenUrl);
 		return tenantTokenUrl;
 	}
 
-	public static String getHost(String path) {
-		URL url;
-		try {
-			url = new URL(path);
-		} catch (MalformedURLException e) {
-			throw new RuntimeException("Cannot create valid URL from given Url " + path);
-		}
-		return url.getHost();
-	}
-
-	public static boolean isUrl(String url) {
-		if (isEmpty(url)) {
-			return false;
-		}
-		try {
-			new URL(url);
-			return true;
-		} catch (MalformedURLException e) {
-			return false;
-		}
-	}
-
 }
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/UaaTokenBroker.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/UaaTokenBroker.java
index ac3aa2ee..0b4828c9 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/UaaTokenBroker.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/extractor/UaaTokenBroker.java
@@ -1,71 +1,49 @@
 package com.sap.cloud.security.xsuaa.extractor;
 
-import java.util.Base64;
-import java.util.Map;
+import java.net.URI;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Component;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.client.HttpClientErrorException;
-import org.springframework.web.client.HttpServerErrorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.web.client.RestTemplate;
 
-@Component
-public class UaaTokenBroker implements TokenBroker {
+import com.sap.cloud.security.xsuaa.client.ClientCredentials;
+import com.sap.cloud.security.xsuaa.client.OAuth2ServiceException;
+import com.sap.cloud.security.xsuaa.client.OAuth2TokenService;
+import com.sap.cloud.security.xsuaa.client.XsuaaOAuth2TokenService;
 
-	private final static Log logger = LogFactory.getLog(UaaTokenBroker.class);
+/**
+ * @deprecated in favor of {@link #UaaTokenBroker(OAuth2TokenService)}. We are going to delete that in 3.0.0.
+ */
+class UaaTokenBroker implements TokenBroker {
+
+	private final static Logger logger = LoggerFactory.getLogger(UaaTokenBroker.class);
 
 	private final RestTemplate restTemplate;
+	private OAuth2TokenService oAuth2TokenService;
 
 	public UaaTokenBroker(RestTemplate restTemplate) {
-		super();
 		this.restTemplate = restTemplate;
+		this.oAuth2TokenService = new XsuaaOAuth2TokenService(restTemplate);
 	}
 
 	public UaaTokenBroker() {
 		this(new RestTemplate());
 	}
 
+	UaaTokenBroker(OAuth2TokenService tokenService) {
+		this.restTemplate = new RestTemplate();
+		oAuth2TokenService = tokenService;
+	}
+
 	@Override
-	@Cacheable(cacheManager = "xsuaa.tokenbroker")
 	public String getAccessTokenFromClientCredentials(String tokenURL, String clientId, String clientSecret)
 			throws TokenBrokerException {
-
 		try {
-			HttpHeaders headers = new HttpHeaders();
-			String credentials = clientId + ":" + clientSecret;
-			String base64Creds = Base64.getEncoder().encodeToString(credentials.getBytes());
-			headers.add("ACCEPT", "application/json");
-			headers.add("AUTHORIZATION", "Basic " + base64Creds);
-
-			MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();
-
-			body.add("grant_type", "client_credentials");
-			body.add("response_type", "token");
-			body.add("client_id", clientId);
-
-			// Note the body object as first parameter!
-			HttpEntity<?> httpEntity = new HttpEntity<Object>(body, headers);
-
-			@SuppressWarnings("rawtypes")
-			ResponseEntity<Map> exchange = restTemplate.exchange(tokenURL, HttpMethod.POST, httpEntity, Map.class);
-
-			return (String) exchange.getBody().get("access_token");
-		} catch (HttpClientErrorException ex) {
-			logger.warn("Cannot obtain Token from given client credentials");
-			throw new TokenBrokerException(
-					"Error obtaining access token:" + ex.getStatusText() + " " + ex.getResponseBodyAsString());
-		} catch (HttpServerErrorException ex) {
-			logger.warn("Cannot obtain Token from given client credentials");
-			throw new TokenBrokerException("Error obtaining access token from server:" + ex.getStatusText() + " "
-					+ ex.getResponseBodyAsString());
+			return oAuth2TokenService.retrieveAccessTokenViaClientCredentialsGrant(
+					URI.create(tokenURL), new ClientCredentials(clientId, clientSecret), null, null).getAccessToken();
+		} catch (OAuth2ServiceException ex) {
+			logger.warn("Cannot obtain Client Credentials Access Token for clientId {}.", clientId);
+			throw new TokenBrokerException("Cannot obtain Client Credentials Access Token from given clientId.", ex);
 		}
 	}
 
@@ -73,36 +51,11 @@ public class UaaTokenBroker implements TokenBroker {
 	public String getAccessTokenFromPasswordCredentials(String tokenURL, String clientId, String clientSecret,
 			String username, String password) throws TokenBrokerException {
 		try {
-			HttpHeaders headers = new HttpHeaders();
-			String credentials = clientId + ":" + clientSecret;
-			String base64Creds = Base64.getEncoder().encodeToString(credentials.getBytes());
-			headers.add("ACCEPT", "application/json");
-			headers.add("AUTHORIZATION", "Basic " + base64Creds);
-
-			MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();
-
-			body.add("grant_type", "password");
-			body.add("response_type", "token");
-			body.add("client_id", clientId);
-			body.add("username", username);
-			body.add("password", password);
-
-			// Note the body object as first parameter!
-			HttpEntity<?> httpEntity = new HttpEntity<Object>(body, headers);
-
-			@SuppressWarnings("rawtypes")
-			ResponseEntity<Map> exchange = restTemplate.exchange(tokenURL, HttpMethod.POST, httpEntity, Map.class);
-
-			return (String) exchange.getBody().get("access_token");
-
-		} catch (HttpClientErrorException ex) {
-			logger.warn("Cannot obtain Token from given password credentials");
-			throw new TokenBrokerException(
-					"Error obtaining access token:" + ex.getStatusText() + " " + ex.getResponseBodyAsString());
-		} catch (HttpServerErrorException ex) {
-			logger.warn("Cannot obtain Token from given password credentials");
-			throw new TokenBrokerException("Error obtaining access token from server:" + ex.getStatusText() + " "
-					+ ex.getResponseBodyAsString());
+			return oAuth2TokenService.retrieveAccessTokenViaPasswordGrant(
+					URI.create(tokenURL), new ClientCredentials(clientId, clientSecret), username, password, null, null).getAccessToken();
+		} catch (OAuth2ServiceException ex) {
+			logger.warn("Cannot obtain Token from given user / password.");
+			throw new TokenBrokerException("Cannot obtain Token from given user / password.", ex);
 		}
 	}
 
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/ReactiveSecurityContext.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/ReactiveSecurityContext.java
index b7d8f625..ac099138 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/ReactiveSecurityContext.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/ReactiveSecurityContext.java
@@ -7,11 +7,16 @@ import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.ReactiveSecurityContextHolder;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.oauth2.jwt.Jwt;
+
+import com.sap.cloud.security.xsuaa.jwt.Base64JwtDecoder;
+
 import reactor.core.publisher.Mono;
 
 public class ReactiveSecurityContext {
 	private static Logger logger = LoggerFactory.getLogger(ReactiveSecurityContext.class);
 
+	private ReactiveSecurityContext() {}
+
 	/**
 	 * Obtain the Token object from the Spring Reactive SecurityContext
 	 *
@@ -25,7 +30,7 @@ public class ReactiveSecurityContext {
 				.map(SecurityContext::getAuthentication)
 				.map(Authentication::getCredentials)
 				.map(credentials -> new XsuaaToken((Jwt) credentials))
-				.doOnSuccess(token -> logger.info("Got Jwt token: " + token.toString()))
+				.doOnSuccess(token -> logger.info("Got Jwt token: {}", token.toString()))
 				.doOnError(throwable -> logger.error("ERROR to getToken", throwable));
 	}
 }
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/ReactiveTokenAuthenticationConverter.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/ReactiveTokenAuthenticationConverter.java
index 02766c45..d40a65fa 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/ReactiveTokenAuthenticationConverter.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/ReactiveTokenAuthenticationConverter.java
@@ -1,10 +1,12 @@
 package com.sap.cloud.security.xsuaa.token;
 
-import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.extractor.LocalAuthoritiesExtractor;
 import org.springframework.core.convert.converter.Converter;
 import org.springframework.security.authentication.AbstractAuthenticationToken;
 import org.springframework.security.oauth2.jwt.Jwt;
+
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.extractor.LocalAuthoritiesExtractor;
+
 import reactor.core.publisher.Mono;
 
 /**
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/SpringSecurityContext.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/SpringSecurityContext.java
index f4b4932c..c205d847 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/SpringSecurityContext.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/SpringSecurityContext.java
@@ -1,7 +1,5 @@
 package com.sap.cloud.security.xsuaa.token;
 
-import com.sap.cloud.security.xsuaa.extractor.AuthoritiesExtractor;
-import com.sap.cloud.security.xsuaa.token.authentication.XsuaaJwtDecoder;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -9,6 +7,9 @@ import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.security.oauth2.jwt.JwtDecoder;
 import org.springframework.util.Assert;
 
+import com.sap.cloud.security.xsuaa.extractor.AuthoritiesExtractor;
+import com.sap.cloud.security.xsuaa.token.authentication.XsuaaJwtDecoder;
+
 public class SpringSecurityContext {
 
 	/**
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/Token.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/Token.java
index 24a5da5a..dd7361c1 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/Token.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/Token.java
@@ -1,35 +1,15 @@
 package com.sap.cloud.security.xsuaa.token;
 
-import com.sap.xsa.security.container.XSTokenRequest;
+import java.util.Collection;
+import java.util.Date;
+
 import org.springframework.lang.Nullable;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.userdetails.UserDetails;
 
-import java.net.URISyntaxException;
-import java.util.Collection;
-import java.util.Date;
-
 public interface Token extends UserDetails {
-	/**
-	 * @deprecated use instead @link{TokenClaims.CLAIM_XS_USER_ATTRIBUTES}
-	 * @since 2.0.0
-	 */
-	@Deprecated
-	String CLAIM_XS_USER_ATTRIBUTES = "xs.user.attributes";
-	/**
-	 * @deprecated use instead @link{TokenClaims.CLAIM_SCOPES}
-	 * @since 2.0.0
-	 */
-	@Deprecated
-	String CLAIM_SCOPES = "scope";
-	/**
-	 * @deprecated use instead @link{TokenClaims.CLAIM_CLIENT_ID}
-	 * @since 2.0.0
-	 */
-	@Deprecated
-	String CLIENT_ID = "cid";
 
-	String GRANTTYPE_CLIENTCREDENTIAL = "client_credentials";
+	static final String GRANTTYPE_CLIENTCREDENTIAL = "client_credentials";
 
 	/**
 	 * Returns the subaccount identifier, which can be used as tenant GUID.
@@ -164,22 +144,6 @@ public interface Token extends UserDetails {
 	 */
 	String getAppToken();
 
-	/**
-	 * Exchange a token into a token from another service instance
-	 * <p>
-	 *
-	 * @deprecated in favor of the @link{XsuaaTokenFlows} API.
-	 * @since 2.0.0
-	 *
-	 * @param tokenRequest
-	 *            request data
-	 * @return requested token
-	 * @throws URISyntaxException
-	 *             in case of wron URLs
-	 */
-	@Deprecated
-	String requestToken(XSTokenRequest tokenRequest) throws URISyntaxException;
-
 	/**
 	 * Returns list of scopes with appId prefix, e.g. "&lt;my-app!t123&gt;.Display".
 	 *
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/TokenAuthenticationConverter.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/TokenAuthenticationConverter.java
index c48a0a8d..b69763ba 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/TokenAuthenticationConverter.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/TokenAuthenticationConverter.java
@@ -1,14 +1,15 @@
 package com.sap.cloud.security.xsuaa.token;
 
-import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.extractor.AuthoritiesExtractor;
-import com.sap.cloud.security.xsuaa.extractor.DefaultAuthoritiesExtractor;
-import com.sap.cloud.security.xsuaa.extractor.LocalAuthoritiesExtractor;
 import org.springframework.core.convert.converter.Converter;
 import org.springframework.security.authentication.AbstractAuthenticationToken;
 import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.util.Assert;
 
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.extractor.AuthoritiesExtractor;
+import com.sap.cloud.security.xsuaa.extractor.DefaultAuthoritiesExtractor;
+import com.sap.cloud.security.xsuaa.extractor.LocalAuthoritiesExtractor;
+
 /**
  * An authentication converter that extracts authorization related information
  * from the Jwt token. For example the{@link LocalAuthoritiesExtractor} can
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/XsuaaToken.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/XsuaaToken.java
index 86f62bc3..fffcc8ca 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/XsuaaToken.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/XsuaaToken.java
@@ -16,25 +16,13 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
-import com.sap.cloud.security.xsuaa.client.ClientCredentials;
-import com.sap.cloud.security.xsuaa.client.OAuth2TokenService;
-import com.sap.cloud.security.xsuaa.client.XsuaaDefaultEndpoints;
-import com.sap.cloud.security.xsuaa.client.XsuaaOAuth2TokenService;
-import com.sap.cloud.security.xsuaa.tokenflows.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.lang.Nullable;
 import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.oauth2.core.ClaimAccessor;
 import org.springframework.security.oauth2.jwt.Jwt;
-import org.springframework.security.oauth2.jwt.JwtClaimAccessor;
 import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
 import org.springframework.util.Assert;
-import org.springframework.web.client.RestOperations;
-import org.springframework.web.client.RestTemplate;
-
-import com.sap.xs2.security.container.XSTokenRequestImpl;
-import com.sap.xsa.security.container.XSTokenRequest;
 
 import net.minidev.json.JSONArray;
 
@@ -59,7 +47,6 @@ public class XsuaaToken extends Jwt implements Token {
 	static final String CLAIM_EXTERNAL_CONTEXT = "ext_ctx";
 
 	private Collection<GrantedAuthority> authorities = Collections.emptyList();
-	private XsuaaTokenFlows xsuaaTokenFlows = null;
 
 	/**
 	 * @param jwt
@@ -227,38 +214,6 @@ public class XsuaaToken extends Jwt implements Token {
 		return getTokenValue();
 	}
 
-	@Override
-	public String requestToken(XSTokenRequest tokenRequest) {
-		Assert.notNull(tokenRequest, "TokenRequest argument is required");
-		Assert.isTrue(tokenRequest.isValid(), "TokenRequest is not valid");
-
-		RestOperations restOperations = new RestTemplate();
-
-		if (tokenRequest instanceof XSTokenRequestImpl
-				&& ((XSTokenRequestImpl) tokenRequest).getRestTemplate() != null) {
-			restOperations = ((XSTokenRequestImpl) tokenRequest).getRestTemplate();
-		}
-
-		String baseUrl = tokenRequest.getTokenEndpoint().toString().replace(tokenRequest.getTokenEndpoint().getPath(),
-				"");
-
-		// initialize token flows api
-		OAuth2TokenService oAuth2TokenService = new XsuaaOAuth2TokenService(restOperations);
-		xsuaaTokenFlows = new XsuaaTokenFlows(oAuth2TokenService, new XsuaaDefaultEndpoints(baseUrl),
-				new ClientCredentials(
-						tokenRequest.getClientId(), tokenRequest.getClientSecret()));
-
-		switch (tokenRequest.getType()) {
-		case XSTokenRequest.TYPE_USER_TOKEN:
-			return performUserTokenFlow(tokenRequest);
-		case XSTokenRequest.TYPE_CLIENT_CREDENTIALS_TOKEN:
-			return performClientCredentialsFlow(tokenRequest);
-		default:
-			throw new UnsupportedOperationException(
-					"Found unsupported XSTokenRequest type. The only supported types are XSTokenRequest.TYPE_USER_TOKEN and XSTokenRequest.TYPE_CLIENT_CREDENTIALS_TOKEN.");
-		}
-	}
-
 	@Override
 	public Collection<String> getScopes() {
 		List<String> scopesList = getClaimAsStringList(TokenClaims.CLAIM_SCOPES);
@@ -276,18 +231,6 @@ public class XsuaaToken extends Jwt implements Token {
 		return containsClaim(claim);
 	}
 
-	/**
-	 * For custom access to the claims of the authentication token.
-	 *
-	 * @return this
-	 * @deprecated with version 1.5 as XsuaaToken inherits from {@link Jwt} which
-	 *             implements {@link JwtClaimAccessor}
-	 */
-	@Deprecated
-	ClaimAccessor getClaimAccessor() {
-		return this;
-	}
-
 	void setAuthorities(Collection<GrantedAuthority> authorities) {
 		Assert.notNull(authorities, "authorities are required");
 		this.authorities = authorities;
@@ -324,40 +267,4 @@ public class XsuaaToken extends Jwt implements Token {
 		return attributeValues;
 	}
 
-	private String performClientCredentialsFlow(XSTokenRequest tokenRequest) {
-		String ccfToken;
-		try {
-			ccfToken = xsuaaTokenFlows.clientCredentialsTokenFlow()
-					.subdomain(this.getSubdomain())
-					.attributes(tokenRequest.getAdditionalAuthorizationAttributes())
-					.execute().getAccessToken();
-		} catch (TokenFlowException e) {
-			throw new RuntimeException("Error performing Client Credentials Flow. See exception cause.", e);
-		}
-
-		logger.info("Got the Client Credentials Flow Token: {}", ccfToken);
-
-		return ccfToken;
-	}
-
-	private String performUserTokenFlow(XSTokenRequest tokenRequest) {
-		String userToken;
-		try {
-			userToken = xsuaaTokenFlows.userTokenFlow()
-					.subdomain(this.getSubdomain())
-					.token(this.getTokenValue())
-					.attributes(tokenRequest.getAdditionalAuthorizationAttributes())
-					.execute().getAccessToken();
-		} catch (TokenFlowException e) {
-			throw new RuntimeException("Error performing User Token Flow. See exception cause.", e);
-		}
-
-		logger.info("Got the exchanged token for 3rd party service (clientId: {}) : {}", tokenRequest.getClientId(),
-				userToken);
-		logger.info("You can now call the 3rd party service passing the exchanged token value: {}. ",
-				userToken);
-
-		return userToken;
-	}
-
 }
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/XsuaaTokenExchanger.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/XsuaaTokenExchanger.java
deleted file mode 100644
index 786b9ef8..00000000
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/XsuaaTokenExchanger.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/**
- * Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved.
- * This file is licensed under the Apache Software License,
- * v. 2 except as noted otherwise in the LICENSE file
- * https://github.com/SAP/cloud-security-xsuaa-integration/blob/master/LICENSE
- */
-package com.sap.cloud.security.xsuaa.token;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Base64;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.util.Assert;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import com.sap.xs2.security.container.UserInfoException;
-import com.sap.xsa.security.container.XSTokenRequest;
-
-import net.minidev.json.JSONObject;
-
-/**
- * @deprecated in favor of XsuaaTokenFlows API.
- */
-@Deprecated
-public class XsuaaTokenExchanger {
-	Token token;
-	RestTemplate restTemplate;
-
-	XsuaaTokenExchanger(RestTemplate restTemplate, Token token) {
-		Assert.notNull(token, "token is required");
-		this.token = token;
-		this.restTemplate = restTemplate != null ? restTemplate : new RestTemplate();
-	}
-
-	/**
-	 * Exchange a token into a token from another service instance
-	 *
-	 * @param tokenRequest
-	 *            request data
-	 * @throws URISyntaxException
-	 *             in case of inconsistent urls
-	 * @throws UserInfoException
-	 *             in case of token exchange errors
-	 * @return requested token
-	 */
-	public String requestToken(XSTokenRequest tokenRequest) throws UserInfoException, URISyntaxException {
-		Assert.isTrue(tokenRequest.isValid(), "Invalid grant type or missing parameters for requested grant type.");
-		// build authorities string for additional authorization attributes
-		String authorities = null;
-		if (tokenRequest.getAdditionalAuthorizationAttributes() != null) {
-			Map<String, Object> azAttrMap = new HashMap<>();
-			azAttrMap.put("az_attr", tokenRequest.getAdditionalAuthorizationAttributes());
-			StringBuilder azStringBuilder = new StringBuilder();
-			try {
-				JSONObject.writeJSON(azAttrMap, azStringBuilder);
-			} catch (IOException e) {
-				throw new UserInfoException("Error creating json representation", e);
-			}
-			authorities = azStringBuilder.toString();
-		}
-		// check whether token endpoint has the correct subdomain, if not replace it
-		// with the subdomain of the token
-		String tokenSubdomain = token.getSubdomain();
-		String tokenRequestSubdomain = getSubdomain(tokenRequest.getTokenEndpoint().toString());
-		if (tokenSubdomain != null && tokenRequestSubdomain != null && !tokenSubdomain.equals(tokenRequestSubdomain)) {
-			tokenRequest.setTokenEndpoint(replaceSubdomain(tokenRequest.getTokenEndpoint(), tokenSubdomain));
-		}
-		// request the token based on the type
-		switch (tokenRequest.getType()) {
-		case XSTokenRequest.TYPE_USER_TOKEN:
-			return requestTokenNamedUser(tokenRequest.getClientId(), tokenRequest.getClientSecret(),
-					tokenRequest.getTokenEndpoint().toString(), authorities);
-		case XSTokenRequest.TYPE_CLIENT_CREDENTIALS_TOKEN:
-			return requestTokenTechnicalUser(tokenRequest, authorities);
-		default:
-			throw new UserInfoException("Invalid grant type.");
-		}
-	}
-
-	/**
-	 * Replace the subdomain in the given uri with the given subdomain
-	 * 
-	 * @param uri
-	 *            uri
-	 * @param subdomain
-	 *            subdomain
-	 * @return subdomain
-	 */
-	protected URI replaceSubdomain(URI uri, String subdomain) {
-		if (uri == null || subdomain == null || !uri.getHost().contains(".")) {
-			return null;
-		}
-		UriComponentsBuilder builder = UriComponentsBuilder.newInstance().scheme(uri.getScheme())
-				.host(subdomain + uri.getHost().substring(uri.getHost().indexOf("."))).port(uri.getPort())
-				.path(uri.getPath());
-		return uri.resolve(builder.build().toString());
-	}
-
-	private String requestTokenTechnicalUser(XSTokenRequest tokenRequest, String authorities) throws UserInfoException {
-		// note: consistency checks (clientid, clientsecret and url) have already been
-		// executed
-		// build uri for client credentials flow
-		UriComponentsBuilder builder = UriComponentsBuilder.fromUri(tokenRequest.getTokenEndpoint())
-				.queryParam("grant_type", "client_credentials");
-		if (authorities != null) {
-			builder.queryParam("authorities", authorities);
-		}
-		// build http headers
-		HttpHeaders headers = new HttpHeaders();
-		headers.add(HttpHeaders.ACCEPT, "application/json");
-		String credentials = tokenRequest.getClientId() + ":" + tokenRequest.getClientSecret();
-		String base64Creds = Base64.getEncoder().encodeToString(credentials.getBytes());
-		headers.add(HttpHeaders.AUTHORIZATION, "Basic " + base64Creds);
-		HttpEntity<Map> entity = new HttpEntity<Map>(headers);
-		// request the token
-		ResponseEntity<Map> responseEntity = restTemplate.postForEntity(builder.build().encode().toUri(), entity,
-				Map.class);
-		if (responseEntity.getStatusCode() == HttpStatus.UNAUTHORIZED) {
-			throw new UserInfoException(
-					"Call to /oauth/token was not successful (grant_type: client_credentials). Client credentials invalid");
-		}
-		if (responseEntity.getStatusCode() != HttpStatus.OK) {
-			throw new UserInfoException(
-					"Call to /oauth/token was not successful (grant_type: client_credentials). HTTP status code: "
-							+ responseEntity.getStatusCode());
-		}
-		return responseEntity.getBody().get("access_token").toString();
-	}
-
-	private String requestTokenNamedUser(String serviceClientId, String serviceClientSecret, String serviceUaaUrl,
-			String authorities) throws UserInfoException {
-		// consistency checks
-		if (serviceClientId == null || serviceClientSecret == null) {
-			throw new UserInfoException("Invalid service credentials: Missing clientid/clientsecret.");
-		}
-		if (serviceUaaUrl == null) {
-			throw new UserInfoException("Invalid service credentials: Missing url.");
-		}
-		if (!checkScope("uaa.user")) {
-			throw new UserInfoException("JWT token does not include scope 'uaa.user'.");
-		}
-		// build uri for user token flow
-		UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(serviceUaaUrl)
-				.queryParam("grant_type", "user_token").queryParam("response_type", "token")
-				.queryParam("client_id", serviceClientId);
-		if (authorities != null) {
-			builder.queryParam("authorities", authorities);
-		}
-		// build http headers
-		HttpHeaders headers = new HttpHeaders();
-		headers.add(HttpHeaders.ACCEPT, "application/json");
-		headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + token.getAppToken());
-		HttpEntity<Map> entity = new HttpEntity<Map>(headers);
-		// request the token
-		ResponseEntity<Map> responseEntity = restTemplate.postForEntity(builder.build().encode().toUri(), entity,
-				Map.class);
-		if (responseEntity.getStatusCode() == HttpStatus.UNAUTHORIZED) {
-			throw new UserInfoException(
-					"Call to /oauth/token was not successful (grant_type: user_token). Bearer token invalid, requesting client does not have grant_type=user_token or no scopes were granted.");
-
-		}
-		if (responseEntity.getStatusCode() != HttpStatus.OK) {
-			throw new UserInfoException(
-					"Call to /oauth/token was not successful (grant_type: user_token). HTTP status code: "
-							+ responseEntity.getStatusCode());
-
-		}
-		// build uri for refresh token flow
-		builder = UriComponentsBuilder.fromHttpUrl(serviceUaaUrl).queryParam("grant_type", "refresh_token")
-				.queryParam("refresh_token", responseEntity.getBody().get("refresh_token").toString());
-		// build http headers
-		headers.clear();
-		String credentials = serviceClientId + ":" + serviceClientSecret;
-		String base64Creds = Base64.getEncoder().encodeToString(credentials.getBytes());
-		headers.add(HttpHeaders.ACCEPT, "application/json");
-		headers.add(HttpHeaders.AUTHORIZATION, "Basic " + base64Creds);
-		entity = new HttpEntity<Map>(headers);
-		// request the token
-		responseEntity = restTemplate.postForEntity(builder.build().encode().toUri(), entity, Map.class);
-		if (responseEntity.getStatusCode() == HttpStatus.UNAUTHORIZED) {
-			throw new UserInfoException(
-					"Call to /oauth/token was not successful (grant_type: refresh_token). Client credentials invalid");
-		}
-		if (responseEntity.getStatusCode() != HttpStatus.OK) {
-			throw new UserInfoException(
-					"Call to /oauth/token was not successful (grant_type: refresh_token). HTTP status code: "
-							+ responseEntity.getStatusCode());
-		}
-		return responseEntity.getBody().get("access_token").toString();
-	}
-
-	/**
-	 * Get the subdomain (host) from the given url
-	 *
-	 * @param url
-	 *            url of given endpoint
-	 * @return subdomain
-	 */
-	protected String getSubdomain(String url) {
-		String host = null;
-		try {
-			host = new URI(url).getHost();
-		} catch (URISyntaxException e) {
-			return null;
-		}
-		if (host == null || !host.contains(".")) {
-			return null;
-		}
-		return host.split("\\.")[0];
-	}
-
-	protected boolean checkScope(String scope) {
-		List<String> scopes = ((XsuaaToken) token).getClaimAsStringList(TokenClaims.CLAIM_SCOPES);
-		return scopes.contains(scope);
-	}
-
-}
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/ReactiveXsuaaJwtDecoder.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/ReactiveXsuaaJwtDecoder.java
index 5d78feb1..b836ed69 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/ReactiveXsuaaJwtDecoder.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/ReactiveXsuaaJwtDecoder.java
@@ -1,14 +1,20 @@
 package com.sap.cloud.security.xsuaa.token.authentication;
 
+import static com.sap.cloud.security.xsuaa.token.TokenClaims.CLAIM_JKU;
+import static com.sap.cloud.security.xsuaa.token.TokenClaims.CLAIM_KID;
+
 import java.text.ParseException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
 import org.springframework.security.oauth2.core.OAuth2TokenValidator;
 import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.security.oauth2.jwt.JwtException;
-import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
 import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder;
 import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
 
@@ -18,15 +24,14 @@ import com.nimbusds.jwt.JWT;
 import com.nimbusds.jwt.JWTParser;
 import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
 
-import net.minidev.json.JSONObject;
 import reactor.core.publisher.Mono;
 
 public class ReactiveXsuaaJwtDecoder implements ReactiveJwtDecoder {
 
 	Cache<String, ReactiveJwtDecoder> cache;
-	private final XsuaaServiceConfiguration xsuaaServiceConfiguration;
 	private List<OAuth2TokenValidator<Jwt>> tokenValidators = new ArrayList<>();
 	private Collection<PostValidationAction> postValidationActions;
+	private TokenInfoExtractor tokenInfoExtractor;
 
 	private static final String EXT_ATTR = "ext_attr";
 	private static final String ZDN = "zdn";
@@ -39,7 +44,23 @@ public class ReactiveXsuaaJwtDecoder implements ReactiveJwtDecoder {
 			OAuth2TokenValidator<Jwt> tokenValidators, Collection<PostValidationAction> postValidationActions) {
 		cache = Caffeine.newBuilder().expireAfterWrite(cacheValidityInSeconds, TimeUnit.SECONDS).maximumSize(cacheSize)
 				.build();
-		this.xsuaaServiceConfiguration = xsuaaServiceConfiguration;
+
+		this.tokenInfoExtractor = new TokenInfoExtractor() {
+			@Override
+			public String getJku(JWT jwt) {
+				return (String) jwt.getHeader().toJSONObject().getOrDefault(CLAIM_JKU, null);
+			}
+
+			@Override
+			public String getKid(JWT jwt) {
+				return (String) jwt.getHeader().toJSONObject().getOrDefault(CLAIM_KID, null);
+			}
+
+			@Override
+			public String getUaaDomain(JWT jwt) {
+				return xsuaaServiceConfiguration.getUaaDomain();
+			}
+		};
 
 		this.tokenValidators.addAll(Arrays.asList(tokenValidators));
 		this.postValidationActions = postValidationActions != null ? postValidationActions : Collections.EMPTY_LIST;
@@ -54,29 +75,14 @@ public class ReactiveXsuaaJwtDecoder implements ReactiveJwtDecoder {
 				throw new JwtException("Error initializing JWT decoder:" + e.getMessage());
 			}
 		}).map(jwtToken -> {
-			try {
-				String subdomain = this.getSubdomain(jwtToken);
-				String zoneId = jwtToken.getJWTClaimsSet().getStringClaim(ZID);
-				return cache.get(subdomain, k -> this.getDecoder(zoneId, subdomain));
-			} catch (ParseException e) {
-				throw new JwtException("Error initializing JWT decoder:" + e.getMessage());
-			}
+			String cacheKey = tokenInfoExtractor.getJku(jwtToken) + tokenInfoExtractor.getKid(jwtToken);
+			return cache.get(cacheKey, k -> this.getDecoder(tokenInfoExtractor.getJku(jwtToken)));
 		}).flatMap(decoder -> decoder.decode(token))
 				.doOnSuccess(jwt -> postValidationActions.forEach(act -> act.perform(jwt)));
 	}
 
-	protected String getSubdomain(JWT jwt) throws ParseException {
-		String subdomain = "";
-		JSONObject extAttr = jwt.getJWTClaimsSet().getJSONObjectClaim(EXT_ATTR);
-		if (extAttr != null && extAttr.getAsString(ZDN) != null) {
-			subdomain = extAttr.getAsString(ZDN);
-		}
-		return subdomain;
-	}
-
-	private ReactiveJwtDecoder getDecoder(String zid, String subdomain) {
-		String url = xsuaaServiceConfiguration.getTokenKeyUrl(zid, subdomain);
-		NimbusReactiveJwtDecoder decoder = new NimbusReactiveJwtDecoder(url);
+	private ReactiveJwtDecoder getDecoder(String jku) {
+		NimbusReactiveJwtDecoder decoder = new NimbusReactiveJwtDecoder(jku);
 		decoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>(tokenValidators));
 		return decoder;
 	}
diff --git a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoderBuilder.java b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoderBuilder.java
index 2eb555e8..8cec2b52 100644
--- a/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoderBuilder.java
+++ b/spring-xsuaa/src/main/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaJwtDecoderBuilder.java
@@ -3,14 +3,14 @@ package com.sap.cloud.security.xsuaa.token.authentication;
 import java.util.Arrays;
 import java.util.Collection;
 
-import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
 import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
 import org.springframework.security.oauth2.core.OAuth2TokenValidator;
 import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.security.oauth2.jwt.JwtDecoder;
+import org.springframework.security.oauth2.jwt.JwtValidators;
 import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
 
-import org.springframework.security.oauth2.jwt.JwtValidators;
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
 
 public class XsuaaJwtDecoderBuilder {
 
diff --git a/spring-xsuaa/src/main/java/com/sap/xs2/security/container/SecurityContext.java b/spring-xsuaa/src/main/java/com/sap/xs2/security/container/SecurityContext.java
deleted file mode 100644
index 5ce120b1..00000000
--- a/spring-xsuaa/src/main/java/com/sap/xs2/security/container/SecurityContext.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package com.sap.xs2.security.container;
-
-import com.sap.cloud.security.xsuaa.extractor.AuthoritiesExtractor;
-import com.sap.cloud.security.xsuaa.extractor.LocalAuthoritiesExtractor;
-import com.sap.cloud.security.xsuaa.token.SpringSecurityContext;
-import com.sap.cloud.security.xsuaa.token.Token;
-import com.sap.cloud.security.xsuaa.token.TokenAuthenticationConverter;
-import org.springframework.security.access.AccessDeniedException;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.oauth2.jwt.Jwt;
-import org.springframework.security.oauth2.jwt.JwtDecoder;
-
-/**
- * As part of this Spring xsuaa library, we need to get rid of
- * {@code com.sap.xs2.security.container} package. It will be removed with
- * version {@code 2.0.0}
- *
- * @deprecated use {@link SpringSecurityContext} class instead. Will be removed
- *             with version 2.0.
- */
-@Deprecated
-public class SecurityContext {
-	/**
-	 * Obtain the UserInfo object from the Spring Security Context
-	 *
-	 * @return UserInfo object
-	 * @throws UserInfoException
-	 *             in case of error
-	 * @deprecated use {@link #getToken()} instead.
-	 */
-	static public UserInfo getUserInfo() throws UserInfoException {
-		if (SecurityContextHolder.getContext().getAuthentication() != null) {
-			if (SecurityContextHolder.getContext().getAuthentication().getPrincipal() instanceof UserInfo) {
-				return (UserInfo) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
-			} else {
-				throw new UserInfoException("Unexpected principal type");
-			}
-		} else {
-			throw new UserInfoException("Not authenticated");
-		}
-	}
-
-	/**
-	 * Obtain the Token object from the Spring Security Context
-	 *
-	 * @return Token object
-	 * @throws AccessDeniedException
-	 *             in case there is no token, user is not authenticated
-	 *             <p>
-	 *             Note: This method is introduced with xsuaa spring client lib.
-	 * @deprecated method is moved to {@link SpringSecurityContext#getToken()}
-	 */
-	static public Token getToken() {
-		return SpringSecurityContext.getToken();
-	}
-
-	/**
-	 * Initializes the Spring Security Context and extracts the authorities.
-	 *
-	 * @param appId
-	 *            the application id e.g. myXsAppname!t123
-	 * @param token
-	 *            the jwt token
-	 * @param extractLocalScopesOnly
-	 *            true when {@link Token#getAuthorities()} should only extract local
-	 *            scopes. Local scopes means that non-application specific scopes
-	 *            are filtered out and scopes are returned without appId prefix,
-	 *            e.g. "Display".
-	 * @deprecated use method
-	 *             {@link SpringSecurityContext#init(String, JwtDecoder, AuthoritiesExtractor)}
-	 *             instead
-	 */
-	static public void init(String appId, Jwt token, boolean extractLocalScopesOnly) {
-		TokenAuthenticationConverter authenticationConverter = new TokenAuthenticationConverter(
-				new LocalAuthoritiesExtractor(appId));
-		Authentication authentication = authenticationConverter.convert(token);
-
-		SecurityContextHolder.createEmptyContext();
-		SecurityContextHolder.getContext().setAuthentication(authentication);
-	}
-
-	/**
-	 * Cleans up the Spring Security Context and release thread locals for Garbage
-	 * Collector to avoid memory leaks resources.
-	 *
-	 * @deprecated method is moved to {@link SpringSecurityContext#clear()}
-	 */
-	static public void clear() {
-		SpringSecurityContext.clear();
-	}
-}
\ No newline at end of file
diff --git a/spring-xsuaa/src/main/java/com/sap/xs2/security/container/UserInfo.java b/spring-xsuaa/src/main/java/com/sap/xs2/security/container/UserInfo.java
deleted file mode 100644
index 7e63c825..00000000
--- a/spring-xsuaa/src/main/java/com/sap/xs2/security/container/UserInfo.java
+++ /dev/null
@@ -1,657 +0,0 @@
-package com.sap.xs2.security.container;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.*;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.oauth2.jwt.Jwt;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import com.sap.xsa.security.container.XSTokenRequest;
-import com.sap.xsa.security.container.XSUserInfo;
-
-import net.minidev.json.JSONArray;
-import net.minidev.json.JSONObject;
-
-/**
- * Class providing access to common user related attributes extracted from the
- * JWT token.
- * 
- * @deprecated will be removed with version 2.0
- */
-@Deprecated
-public class UserInfo implements XSUserInfo {
-
-	private static final String USER_NAME = "user_name";
-	private static final String GIVEN_NAME = "given_name";
-	private static final String FAMILY_NAME = "family_name";
-	private static final String EMAIL = "email";
-	private static final String CID = "cid";
-	private static final String ORIGIN = "origin";
-	private static final String GRANT_TYPE = "grant_type";
-	private static final String ADDITIONAL_AZ_ATTR = "az_attr";
-	private static final String ZONE_ID = "zid";
-	private static final String EXTERNAL_ATTR = "ext_attr";
-	private static final String XS_SYSTEM_ATTRIBUTES = "xs.system.attributes";
-	private static final String HDB_NAMEDUSER_SAML = "hdb.nameduser.saml";
-	private static final String SERVICEINSTANCEID = "serviceinstanceid";
-	private static final String ZDN = "zdn";
-	private static final String SYSTEM = "SYSTEM";
-	private static final String HDB = "HDB";
-	public static final String XS_USER_ATTRIBUTES = "xs.user.attributes";
-	public static final String SCOPE = "scope";
-	public static final String GRANTTYPE_CLIENTCREDENTIAL = "client_credentials";
-	public static final String GRANTTYPE_SAML2BEARER = "urn:ietf:params:oauth:grant-type:saml2-bearer";
-	public static final String GRANTTYPE_PASSWORD = "password"; // NOSONAR
-	public static final String GRANTTYPE_AUTHCODE = "authorization_code";
-	public static final String GRANTTYPE_USERTOKEN = "user_token";
-	public static final String EXTERNAL_CONTEXT = "ext_ctx";
-
-	protected final Log logger = LogFactory.getLog(getClass());
-
-	private String xsappname = null;
-	private boolean foreignMode = false;
-	private Jwt jwt;
-
-	/**
-	 * @param jwt
-	 *            token
-	 * @param xsappname
-	 *            app name
-	 */
-	protected UserInfo(Jwt jwt, String xsappname) {
-		this.xsappname = xsappname;
-		this.jwt = jwt;
-	}
-
-	/**
-	 * Get the logon name (attribute logon_name)
-	 *
-	 * @return user name
-	 * @throws UserInfoException
-	 *             if method is not supported for this grant type
-	 */
-	@Override
-	public String getLogonName() throws UserInfoException {
-		if (getGrantType().equals(GRANTTYPE_CLIENTCREDENTIAL)) {
-			throw new UserInfoException(
-					"Method getLogonName is not supported for grant type " + GRANTTYPE_CLIENTCREDENTIAL);
-		}
-		return getJsonValueInternal(USER_NAME);
-	}
-
-	/**
-	 * Get the given name (attribute given_name)
-	 *
-	 * @return name
-	 * @throws UserInfoException
-	 *             if method is not supported for this grant type
-	 */
-	@Override
-	public String getGivenName() throws UserInfoException {
-		if (getGrantType().equals(GRANTTYPE_CLIENTCREDENTIAL)) {
-			throw new UserInfoException(
-					"Method getGivenName is not supported for grant type " + GRANTTYPE_CLIENTCREDENTIAL);
-		}
-		return getExternalAttributeWithFallback(GIVEN_NAME);
-	}
-
-	/**
-	 * Get the family name (attribute family_name)
-	 *
-	 * @return family name
-	 * @throws UserInfoException
-	 *             if method is not supported for this grant type
-	 */
-	@Override
-	public String getFamilyName() throws UserInfoException {
-		if (getGrantType().equals(GRANTTYPE_CLIENTCREDENTIAL)) {
-			throw new UserInfoException(
-					"Method getFamilyName is not supported for grant type " + GRANTTYPE_CLIENTCREDENTIAL);
-		}
-		return getExternalAttributeWithFallback(FAMILY_NAME);
-	}
-
-	/**
-	 * Get the uaa identity zone from the token
-	 *
-	 * @return identity zone
-	 * @throws UserInfoException
-	 *             attribute not found
-	 */
-	public String getIdentityZone() throws UserInfoException {
-		return getJsonValueInternal(ZONE_ID);
-	}
-
-	/**
-	 * Get the subdomain from the token
-	 *
-	 * @return subdomain
-	 * @throws UserInfoException
-	 *             attribute cannot be found or read
-	 */
-	@Override
-	public String getSubdomain() throws UserInfoException {
-		try {
-			return getExternalAttribute(ZDN);
-		} catch (Exception e) {
-			return null;
-		}
-	}
-
-	/**
-	 * Get the client id from the token
-	 *
-	 * @return client id
-	 * @throws UserInfoException
-	 *             attribute cannot be found or read
-	 */
-	@Override
-	public String getClientId() throws UserInfoException {
-		return getJsonValueInternal(CID);
-	}
-
-	/**
-	 * Get the expriation date of the access token
-	 *
-	 * @return expiration date
-	 * @throws UserInfoException
-	 *             attribute cannot be found or read
-	 */
-	public Date getExpirationDate() throws UserInfoException {
-		return Date.from(jwt.getExpiresAt());
-	}
-
-	private String getJsonValueInternal(String attribute) throws UserInfoException {
-		String data = jwt.getClaimAsString(attribute);
-		if (data == null)
-			throw new UserInfoException("Invalid user attribute " + attribute);
-		return data;
-	}
-
-	/**
-	 * Method to extract raw data from the JWT token
-	 *
-	 * @param attribute
-	 *            attribute name
-	 * @return attribute value
-	 * @throws UserInfoException
-	 *             attribute cannot be found or read
-	 */
-	@Deprecated
-	public String getJsonValue(String attribute) throws UserInfoException {
-		return getJsonValueInternal(attribute);
-	}
-
-	/**
-	 * Get email address property
-	 *
-	 * @return email address
-	 * @throws UserInfoException
-	 *             method is not supported for this grant typ
-	 */
-	@Override
-	public String getEmail() throws UserInfoException {
-		if (getGrantType().equals(GRANTTYPE_CLIENTCREDENTIAL)) {
-			throw new UserInfoException(
-					"Method getEmail is not supported for grant type " + GRANTTYPE_CLIENTCREDENTIAL);
-		}
-		return getJsonValueInternal(EMAIL);
-	}
-
-	/**
-	 * Get a token for personalizing the connection to the HANA database
-	 *
-	 * @return token
-	 * @throws UserInfoException
-	 *             attribute cannot be found or read
-	 */
-	@Deprecated
-	@Override
-	public String getDBToken() throws UserInfoException {
-		return getHdbToken();
-	}
-
-	/**
-	 * Get a token for personalizing the connection to the HANA database
-	 *
-	 * @return token
-	 * @throws UserInfoException
-	 *             attribute cannot be found or read
-	 */
-	@Override
-	public String getHdbToken() throws UserInfoException {
-		return getToken(SYSTEM, HDB);
-	}
-
-	/**
-	 * Get the application token, e.g. for token forwarding to another app
-	 *
-	 * @return token
-	 */
-	@Override
-	public String getAppToken() {
-		return jwt.getTokenValue();
-	}
-
-	/**
-	 * Get a token, e.g. for forwarding to other resource servers
-	 *
-	 * @param namespace
-	 *            token namespace
-	 * @param name
-	 *            attribute name
-	 * @return token
-	 * @throws UserInfoException
-	 *             attribute cannot be found or read
-	 */
-	@Deprecated
-	@Override
-	public String getToken(String namespace, String name) throws UserInfoException {
-		if (!(getGrantType().equals(GRANTTYPE_CLIENTCREDENTIAL)) && hasAttributes() && isInForeignMode()) {
-			throw new UserInfoException("The Spring Security Context has been initialized with an access token of a\n"
-					+ "foreign OAuth Client Id and/or Identity Zone. Furthermore, the\n"
-					+ "access token contains attributes. Due to the fact that we want to\n"
-					+ "restrict attribute access to the application that provided the \n"
-					+ "attributes, the getToken function does not return a valid token");
-		}
-		if (!namespace.equals(SYSTEM)) {
-			throw new UserInfoException("Invalid namespace " + namespace);
-		}
-		if (name.equals(HDB)) {
-			String token = null;
-			if (this.jwt.getClaimAsMap(EXTERNAL_CONTEXT) != null)
-				token = ((net.minidev.json.JSONObject) this.jwt.getClaimAsMap(EXTERNAL_CONTEXT))
-						.getAsString(HDB_NAMEDUSER_SAML);
-			else
-				token = getJsonValueInternal(HDB_NAMEDUSER_SAML);
-
-			return token;
-		} else if (name.equals("JobScheduler")) {
-			return jwt.getTokenValue();
-		} else {
-			throw new UserInfoException("Invalid name " + name + " for namespace " + namespace);
-		}
-	}
-
-	/**
-	 * Get a user attribute from the JWT token
-	 *
-	 * @return attribute values
-	 * @throws UserInfoException
-	 *             attribute cannot be found or read
-	 */
-	@Override
-	public String[] getAttribute(String attributeName) throws UserInfoException {
-		if (getGrantType().equals(GRANTTYPE_CLIENTCREDENTIAL)) {
-			throw new UserInfoException(
-					"Method getAttribute is not supported for grant type " + GRANTTYPE_CLIENTCREDENTIAL);
-		}
-		return getMultiValueAttributeFromExtObject(attributeName, XS_USER_ATTRIBUTES);
-	}
-
-	/**
-	 * Check if the JWT token contains attributes
-	 *
-	 * @return true: attribute exists
-	 * @throws UserInfoException
-	 *             attribute cannot be found or read
-	 */
-	@Override
-	public boolean hasAttributes() throws UserInfoException {
-		if (getGrantType().equals(GRANTTYPE_CLIENTCREDENTIAL)) {
-			throw new UserInfoException(
-					"Method hasAttributes is not supported for grant type " + GRANTTYPE_CLIENTCREDENTIAL);
-		}
-
-		Map<String, Object> attributeData;
-		if (this.jwt.containsClaim(EXTERNAL_CONTEXT)) {
-			attributeData = (Map<String, Object>) this.jwt.getClaimAsMap(EXTERNAL_CONTEXT).get(XS_USER_ATTRIBUTES);
-		} else {
-			attributeData = this.jwt.getClaimAsMap(XS_USER_ATTRIBUTES);
-		}
-		if (attributeData == null) {
-			return false;
-		} else {
-			for (String attributeName : attributeData.keySet())
-				if (((JSONArray) attributeData.get(attributeName)).size() > 0) {
-					return true;
-				}
-		}
-		return false;
-	}
-
-	/**
-	 * Get a system attribute from the JWT token
-	 *
-	 * @param attributeName
-	 *            attribute name
-	 * @return attribute values
-	 * @throws UserInfoException
-	 *             attribute cannot be found or read
-	 */
-	@Override
-	public String[] getSystemAttribute(String attributeName) throws UserInfoException {
-		return getMultiValueAttributeFromExtObject(attributeName, XS_SYSTEM_ATTRIBUTES);
-	}
-
-	/**
-	 * Check if a scope {@code <xsappname>.<local scope name>} is granted to a user
-	 *
-	 * @param scope
-	 *            scope name
-	 * @return true: has scope
-	 * @throws UserInfoException
-	 *             attribute cannot be found or read
-	 */
-	@Override
-	public boolean checkScope(String scope) throws UserInfoException {
-		List<String> scopes = jwt.getClaimAsStringList(SCOPE);
-		return scopes.contains(scope);
-	}
-
-	/**
-	 * Check if a local scope is granted to a user
-	 *
-	 * @param scope
-	 *            scope name
-	 * @return true: has scope
-	 * @throws UserInfoException
-	 *             attribute cannot be found or read
-	 */
-	@Override
-	public boolean checkLocalScope(String scope) throws UserInfoException {
-		if (xsappname == null) {
-			throw new UserInfoException(
-					"Property xsappname not found in VCAP_SERVICES, must be declared in xs-security.json");
-		}
-		return checkScope(xsappname + "." + scope);
-	}
-
-	// for unit test
-	protected void setXSAppname(String xsappname) {
-		this.xsappname = xsappname;
-	}
-
-	// for unit test
-	protected void setForeignMode(boolean foreignMode) {
-		this.foreignMode = foreignMode;
-	}
-
-	@Override
-	public String getAdditionalAuthAttribute(String attributeName) throws UserInfoException {
-		return getAttributeFromObject(attributeName, ADDITIONAL_AZ_ATTR);
-	}
-
-	@Override
-	public String getCloneServiceInstanceId() throws UserInfoException {
-		return getExternalAttribute(SERVICEINSTANCEID);
-	}
-
-	@Override
-	public String getGrantType() throws UserInfoException {
-		return getJsonValueInternal(GRANT_TYPE);
-	}
-
-	@Override
-	public boolean isInForeignMode() throws UserInfoException {
-		return foreignMode;
-	}
-
-	private String getExternalAttribute(String attributeName) throws UserInfoException {
-		return getAttributeFromObject(attributeName, EXTERNAL_ATTR);
-	}
-
-	private String getExternalAttributeWithFallback(String attributeName) throws UserInfoException {
-		try {
-			return getExternalAttribute(attributeName);
-		} catch (UserInfoException e) {
-			return getJsonValueInternal(attributeName);
-		}
-	}
-
-	private String getAttributeFromObject(String attributeName, String objectName) throws UserInfoException {
-		Map<String, Object> dataMap = jwt.getClaimAsMap(objectName);
-		if (dataMap == null) {
-			throw new UserInfoException("Invalid value of " + objectName);
-		}
-		String data = (String) jwt.getClaimAsMap(objectName).get(attributeName);
-		if (data == null)
-			throw new UserInfoException("Invalid value of " + objectName);
-		return data;
-	}
-
-	private String[] getMultiValueAttributeFromExtObject(String attributeName, String objectName)
-			throws UserInfoException {
-		String[] attributeValues = null;
-		if (jwt.containsClaim(EXTERNAL_CONTEXT)) {
-			JSONObject jsonExtern = (JSONObject) jwt.getClaimAsMap(EXTERNAL_CONTEXT);
-			JSONObject jsonObject = (JSONObject) jsonExtern.get(objectName);
-			JSONArray jsonArray = (JSONArray) jsonObject.get(attributeName);
-			int length = jsonArray.size();
-			attributeValues = new String[length];
-			for (int i = 0; i < length; i++) {
-				attributeValues[i] = (String) jsonArray.get(i);
-			}
-		} else {
-			return getMultiValueAttributeFromObject(attributeName, objectName);
-		}
-
-		return attributeValues;
-	}
-
-	private String[] getMultiValueAttributeFromObject(String attributeName, String objectName)
-			throws UserInfoException {
-		String[] attributeValues = new String[0];
-		Map<String, Object> jsonObject = jwt.getClaimAsMap(objectName);
-		if (jsonObject == null) {
-			throw new UserInfoException("Invalid value of " + objectName);
-		}
-		JSONArray jsonArray = (JSONArray) jsonObject.get(attributeName);
-		if (jsonArray != null) {
-			int length = jsonArray.size();
-			attributeValues = new String[length];
-			for (int i = 0; i < length; i++) {
-				attributeValues[i] = (String) jsonArray.get(i);
-			}
-		} else {
-			throw new UserInfoException("Invalid value of " + objectName);
-		}
-		return attributeValues;
-	}
-
-	@Override
-	public String getSubaccountId() throws UserInfoException {
-		return getIdentityZone();
-	}
-
-	@Override
-	public String getOrigin() throws UserInfoException {
-		if (getGrantType().equals(GRANTTYPE_CLIENTCREDENTIAL)) {
-			throw new UserInfoException(
-					"Method getOrigin is not supported for grant type " + GRANTTYPE_CLIENTCREDENTIAL);
-		}
-		return getJsonValueInternal(ORIGIN);
-	}
-
-	@Override
-	public String requestToken(XSTokenRequest tokenRequest) throws UserInfoException {
-		if (!tokenRequest.isValid()) {
-			throw new UserInfoException("Invalid grant type or missing parameters for requested grant type.");
-		}
-		// build authorities string for additional authorization attributes
-		String authorities = null;
-		if (tokenRequest.getAdditionalAuthorizationAttributes() != null) {
-			Map<String, Object> azAttrMap = new HashMap<>();
-			azAttrMap.put("az_attr", tokenRequest.getAdditionalAuthorizationAttributes());
-			StringBuilder azStringBuilder = new StringBuilder();
-			try {
-				JSONObject.writeJSON(azAttrMap, azStringBuilder);
-			} catch (IOException e) {
-				throw new UserInfoException("Error creating json representation", e);
-			}
-			authorities = azStringBuilder.toString();
-		}
-		// check whether token endpoint has the correct subdomain, if not replace it
-		// with the subdomain of the token
-		String tokenSubdomain = getSubdomain();
-		String tokenRequestSubdomain = getSubdomain(tokenRequest.getTokenEndpoint().toString());
-		if (tokenSubdomain != null && tokenRequestSubdomain != null && !tokenSubdomain.equals(tokenRequestSubdomain)) {
-			tokenRequest.setTokenEndpoint(replaceSubdomain(tokenRequest.getTokenEndpoint(), tokenSubdomain));
-		}
-		// request the token based on the type
-		switch (tokenRequest.getType()) {
-		case XSTokenRequest.TYPE_USER_TOKEN:
-			return requestTokenNamedUser(tokenRequest.getClientId(), tokenRequest.getClientSecret(),
-					tokenRequest.getTokenEndpoint().toString(), authorities);
-		case XSTokenRequest.TYPE_CLIENT_CREDENTIALS_TOKEN:
-			return requestTokenTechnicalUser(tokenRequest, authorities);
-		default:
-			throw new UserInfoException("Invalid grant type.");
-		}
-	}
-
-	private String requestTokenTechnicalUser(XSTokenRequest tokenRequest, String authorities) throws UserInfoException {
-		// note: consistency checks (clientid, clientsecret and url) have already been
-		// executed
-		// build uri for client credentials flow
-		UriComponentsBuilder builder = UriComponentsBuilder.fromUri(tokenRequest.getTokenEndpoint())
-				.queryParam("grant_type", "client_credentials");
-		if (authorities != null) {
-			builder.queryParam("authorities", authorities);
-		}
-		// build http headers
-		HttpHeaders headers = new HttpHeaders();
-		headers.add(HttpHeaders.ACCEPT, "application/json");
-		String credentials = tokenRequest.getClientId() + ":" + tokenRequest.getClientSecret();
-		String base64Creds = Base64.getEncoder().encodeToString(credentials.getBytes());
-		headers.add(HttpHeaders.AUTHORIZATION, "Basic " + base64Creds);
-		HttpEntity<Map> entity = new HttpEntity<Map>(headers);
-		// request the token
-		RestTemplate rt = new RestTemplate();
-		ResponseEntity<Map> responseEntity = rt.postForEntity(builder.build().encode().toUri(), entity, Map.class);
-		if (responseEntity.getStatusCode() == HttpStatus.UNAUTHORIZED) {
-			throw new UserInfoException(
-					"Call to /oauth/token was not successful (grant_type: client_credentials). Client credentials invalid");
-		}
-		if (responseEntity.getStatusCode() != HttpStatus.OK) {
-			throw new UserInfoException(
-					"Call to /oauth/token was not successful (grant_type: client_credentials). HTTP status code: "
-							+ responseEntity.getStatusCode());
-		}
-		return responseEntity.getBody().get("access_token").toString();
-	}
-
-	private String requestTokenNamedUser(String serviceClientId, String serviceClientSecret, String serviceUaaUrl,
-			String authorities) throws UserInfoException {
-		// consistency checks
-		if (serviceClientId == null || serviceClientSecret == null) {
-			throw new UserInfoException("Invalid service credentials: Missing clientid/clientsecret.");
-		}
-		if (serviceUaaUrl == null) {
-			throw new UserInfoException("Invalid service credentials: Missing url.");
-		}
-		if (!checkScope("uaa.user")) {
-			throw new UserInfoException("JWT token does not include scope 'uaa.user'.");
-		}
-		// build uri for user token flow
-		UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(serviceUaaUrl)
-				.queryParam("grant_type", "user_token").queryParam("response_type", "token")
-				.queryParam("client_id", serviceClientId);
-		if (authorities != null) {
-			builder.queryParam("authorities", authorities);
-		}
-		// build http headers
-		HttpHeaders headers = new HttpHeaders();
-		headers.add(HttpHeaders.ACCEPT, "application/json");
-		headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + this.jwt.getTokenValue());
-		HttpEntity<Map> entity = new HttpEntity<Map>(headers);
-		// request the token
-		RestTemplate rt = new RestTemplate();
-		ResponseEntity<Map> responseEntity = rt.postForEntity(builder.build().encode().toUri(), entity, Map.class);
-		if (responseEntity.getStatusCode() == HttpStatus.UNAUTHORIZED) {
-			throw new UserInfoException(
-					"Call to /oauth/token was not successful (grant_type: user_token). Bearer token invalid, requesting client does not have grant_type=user_token or no scopes were granted.");
-
-		}
-		if (responseEntity.getStatusCode() != HttpStatus.OK) {
-			throw new UserInfoException(
-					"Call to /oauth/token was not successful (grant_type: user_token). HTTP status code: "
-							+ responseEntity.getStatusCode());
-
-		}
-		// build uri for refresh token flow
-		builder = UriComponentsBuilder.fromHttpUrl(serviceUaaUrl).queryParam("grant_type", "refresh_token")
-				.queryParam("refresh_token", responseEntity.getBody().get("refresh_token").toString());
-		// build http headers
-		headers.clear();
-		String credentials = serviceClientId + ":" + serviceClientSecret;
-		String base64Creds = Base64.getEncoder().encodeToString(credentials.getBytes());
-		headers.add(HttpHeaders.ACCEPT, "application/json");
-		headers.add(HttpHeaders.AUTHORIZATION, "Basic " + base64Creds);
-		entity = new HttpEntity<Map>(headers);
-		// request the token
-		responseEntity = rt.postForEntity(builder.build().encode().toUri(), entity, Map.class);
-		if (responseEntity.getStatusCode() == HttpStatus.UNAUTHORIZED) {
-			throw new UserInfoException(
-					"Call to /oauth/token was not successful (grant_type: refresh_token). Client credentials invalid");
-		}
-		if (responseEntity.getStatusCode() != HttpStatus.OK) {
-			throw new UserInfoException(
-					"Call to /oauth/token was not successful (grant_type: refresh_token). HTTP status code: "
-							+ responseEntity.getStatusCode());
-		}
-		return responseEntity.getBody().get("access_token").toString();
-	}
-
-	@Deprecated
-	public String requestTokenForClient(String serviceClientId, String serviceClientSecret, String serviceUaaUrl)
-			throws UserInfoException {
-		String url = serviceUaaUrl != null ? serviceUaaUrl + "/oauth/token" : null;
-		return requestTokenNamedUser(serviceClientId, serviceClientSecret, url, null);
-	}
-
-	/**
-	 * Get the subdomain from the given url
-	 *
-	 * @return
-	 * @throws UserInfoException
-	 */
-	private String getSubdomain(String url) {
-		String host = null;
-		try {
-			host = new URI(url).getHost();
-		} catch (URISyntaxException e) {
-			return null;
-		}
-		if (host == null || !host.contains(".")) {
-			return null;
-		}
-		return host.split("\\.")[0];
-	}
-
-	/**
-	 * Replace the subdomain in the given uri with the given subdomain
-	 *
-	 * @return
-	 * @throws UserInfoException
-	 */
-	private URI replaceSubdomain(URI uri, String subdomain) {
-		if (uri == null || subdomain == null || !uri.getHost().contains(".")) {
-			return null;
-		}
-		UriComponentsBuilder builder = UriComponentsBuilder.newInstance().scheme(uri.getScheme())
-				.host(subdomain + uri.getHost().substring(uri.getHost().indexOf("."))).port(uri.getPort())
-				.path(uri.getPath());
-		return uri.resolve(builder.build().toString());
-	}
-
-}
diff --git a/spring-xsuaa/src/main/java/com/sap/xs2/security/container/UserInfoException.java b/spring-xsuaa/src/main/java/com/sap/xs2/security/container/UserInfoException.java
deleted file mode 100644
index 66d13bbb..00000000
--- a/spring-xsuaa/src/main/java/com/sap/xs2/security/container/UserInfoException.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.sap.xs2.security.container;
-
-import com.sap.xsa.security.container.XSUserInfoException;
-
-/**
- * @deprecated will be removed with version 2.0
- */
-@Deprecated
-public class UserInfoException extends XSUserInfoException {
-
-	private static final long serialVersionUID = 1L;
-
-	public UserInfoException(String message) {
-		super(message);
-	}
-
-	public UserInfoException(String message, Throwable reason) {
-		super(message, reason);
-	}
-
-}
\ No newline at end of file
diff --git a/spring-xsuaa/src/main/java/com/sap/xs2/security/container/XSTokenRequestImpl.java b/spring-xsuaa/src/main/java/com/sap/xs2/security/container/XSTokenRequestImpl.java
deleted file mode 100644
index 6ca2ea05..00000000
--- a/spring-xsuaa/src/main/java/com/sap/xs2/security/container/XSTokenRequestImpl.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/**
- * Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved.
- * This file is licensed under the Apache Software License,
- * v. 2 except as noted otherwise in the LICENSE file
- * https://github.com/SAP/cloud-security-xsuaa-integration/blob/master/LICENSE
- */
-package com.sap.xs2.security.container;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-import com.sap.xsa.security.container.XSTokenRequest;
-import org.springframework.web.client.RestTemplate;
-
-/**
- * @deprecated in favor of XsuaaTokenFlows API. Will be removed with version
- *             2.0.
- */
-@Deprecated
-public class XSTokenRequestImpl implements XSTokenRequest {
-
-	@Deprecated
-	public static final int TYPE_USER_TOKEN = 0;
-	@Deprecated
-	public static final int TYPE_CLIENT_CREDENTIALS_TOKEN = 1;
-
-	private URI tokenEndpoint;
-
-	private int type;
-	private String clientId;
-	private String clientSecret;
-	private RestTemplate restTemplate;
-
-	private Map<String, String> additionalAuthorizationAttributes;
-
-	/**
-	 * Constructs a token request
-	 * 
-	 * @param uaabaseUrl
-	 *            - uaa base url
-	 * @throws URISyntaxException
-	 *             when uaabaseUrl could not be parsed as URI
-	 */
-	public XSTokenRequestImpl(String uaabaseUrl) throws URISyntaxException {
-		URI uaaBaseURI = URI.create(uaabaseUrl);
-		this.tokenEndpoint = new URI(uaabaseUrl + "/oauth/token");
-	}
-
-	/**
-	 * Returns true if this object contains enough information to retrieve a token
-	 * 
-	 * @return true if this object contains enough information to retrieve a token
-	 */
-	public boolean isValid() {
-		return !this.hasAnyNullValues(Arrays.asList(this.tokenEndpoint, this.clientId, this.clientSecret));
-	}
-
-	/**
-	 * Returns the client ID, if set, that will be used to authenticate the client
-	 * 
-	 * @return the client ID if set
-	 */
-	public String getClientId() {
-		return this.clientId;
-	}
-
-	/**
-	 * Sets the client ID to be used for authentication during the token request
-	 * 
-	 * @param clientId
-	 *            a string, no more than 255 characters identifying a valid client
-	 *            on the UAA
-	 * @return this mutable object
-	 */
-	public XSTokenRequest setClientId(String clientId) {
-		this.clientId = clientId;
-		return this;
-	}
-
-	/**
-	 * Returns the client secret, if set, that will be used to authenticate the
-	 * client
-	 * 
-	 * @return the client secret if set
-	 */
-	public String getClientSecret() {
-		return this.clientSecret;
-	}
-
-	/**
-	 * Sets the client secret to be used for authentication during the token request
-	 * 
-	 * @param clientSecret
-	 *            a string representing the password for a valid client on the UAA
-	 * @return this mutable object
-	 */
-	public XSTokenRequest setClientSecret(String clientSecret) {
-		this.clientSecret = clientSecret;
-		return this;
-	}
-
-	/**
-	 * Returns the list of requested additional authorization attributes, or null if
-	 * no additional authorization attributes have been requested.
-	 * 
-	 * @return the list of requested additional authorization attributes, or null if
-	 *         no additional authorization attributes have been requested.
-	 */
-	public Map<String, String> getAdditionalAuthorizationAttributes() {
-		return additionalAuthorizationAttributes;
-	}
-
-	/**
-	 * Sets the requested additional authorization attributes list for this token
-	 * request. Use this if you would like to add additional authorization
-	 * attributes to the access token
-	 * 
-	 * @param additionalAuthorizationAttributes
-	 *            a set of strings representing requested additional authorization
-	 *            attributes
-	 * @return this mutable object
-	 */
-	public XSTokenRequest setAdditionalAuthorizationAttributes(Map<String, String> additionalAuthorizationAttributes) {
-		this.additionalAuthorizationAttributes = (additionalAuthorizationAttributes == null) ? null
-				: new HashMap<>(additionalAuthorizationAttributes);
-		return this;
-	}
-
-	/**
-	 * Returns the type of the requested token
-	 * 
-	 * @return the type of the requested token
-	 */
-	public int getType() {
-		return this.type;
-	}
-
-	/**
-	 * Set the requested token type
-	 * 
-	 * @param type
-	 *            an integer representing the grant type
-	 * @return this mutable object
-	 */
-	public XSTokenRequest setType(int type) {
-		this.type = type;
-		return this;
-	}
-
-	/**
-	 * @return the token endpoint URI, for example
-	 *         http://localhost:8080/uaa/oauth/token
-	 */
-	public URI getTokenEndpoint() {
-		return this.tokenEndpoint;
-	}
-
-	/**
-	 * Set the token endpoint URI
-	 * 
-	 * @param tokenEndpoint
-	 *            an URI representing the token endpoint of the UAA
-	 * @return this mutable object
-	 */
-	public XSTokenRequest setTokenEndpoint(URI tokenEndpoint) {
-		this.tokenEndpoint = tokenEndpoint;
-		return this;
-	}
-
-	/**
-	 * Returns true if the list or any item in the list is null
-	 * 
-	 * @param objects
-	 *            a list of items to be evaluated for null references
-	 * @return true if the list or any item in the list is null
-	 */
-	private boolean hasAnyNullValues(List<Object> objects) {
-		if (Objects.isNull(objects)) {
-			return true;
-		}
-		return objects.stream().filter(o -> Objects.isNull(o)).count() > 0;
-	}
-
-	/**
-	 * Allows to overwrite the default RestTemplate
-	 * 
-	 * @param restTemplate
-	 *            the custom restTemplate
-	 */
-	public void setRestTemplate(RestTemplate restTemplate) {
-		this.restTemplate = restTemplate;
-	}
-
-	/**
-	 * Returns the custom RestTemplate
-	 *
-	 * @return the custom restTemplate or null
-	 */
-	public RestTemplate getRestTemplate() {
-		return restTemplate;
-	}
-}
diff --git a/token-client/README.md b/token-client/README.md
index db83fb10..54153d64 100644
--- a/token-client/README.md
+++ b/token-client/README.md
@@ -2,7 +2,7 @@
 
 ## Motivation
 
-This library serves as slim client for some XSUAA `/oauth/token` token endpoints as specified [here](https://docs.cloudfoundry.org/api/uaa/version/4.30.0/index.html#token). 
+This library serves as slim client for some XSUAA `/oauth/token` token endpoints as specified [here](https://docs.cloudfoundry.org/api/uaa/version/74.1.0/index.html#token). 
 Furthermore it introduces a new API to support the following token flows:
 
 * **User Token Flow**.  
@@ -25,7 +25,7 @@ A Refresh Token ([RFC 6749, section 1.5](https://tools.ietf.org/html/rfc6749#sec
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>token-client</artifactId>
-    <version>1.7.0</version>
+    <version>2.0.0</version>
 </dependency>
 ```
 ## Configuration for Spring Boot Applications
@@ -36,7 +36,7 @@ In context of a Spring Boot application you may like to leverage auto-configurat
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>xsuaa-spring-boot-starter</artifactId>
-    <version>1.7.0</version>
+    <version>2.0.0</version>
 </dependency>
 ```
 
diff --git a/token-client/pom.xml b/token-client/pom.xml
index 714532a6..5d61c1a6 100644
--- a/token-client/pom.xml
+++ b/token-client/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>1.7.0</version>
+		<version>2.0.0</version>
 	</parent>
 
 	<artifactId>token-client</artifactId>
@@ -36,11 +36,6 @@
 			<artifactId>json</artifactId>
 			<version>20190722</version>
 		</dependency>
-		<dependency>
-			<groupId>org.springframework.security</groupId>
-			<artifactId>spring-security-jwt</artifactId>
-			<version>1.0.9.RELEASE</version>
-		</dependency>
 		<dependency>
 			<groupId>com.google.code.findbugs</groupId>
 			<artifactId>jsr305</artifactId>
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/Assertions.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/Assertions.java
index b3b29efd..5ee3224d 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/Assertions.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/Assertions.java
@@ -1,6 +1,9 @@
 package com.sap.cloud.security.xsuaa;
 
 public class Assertions {
+
+	private Assertions() {}
+
 	public static void assertNotNull(Object object, String message) {
 		if (object == null) {
 			throw new IllegalArgumentException(message);
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/ClientCredentials.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/ClientCredentials.java
index c9708387..ea2049af 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/ClientCredentials.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/ClientCredentials.java
@@ -1,7 +1,5 @@
 package com.sap.cloud.security.xsuaa.client;
 
-import com.sap.cloud.security.xsuaa.Assertions;
-
 import javax.annotation.Nonnull;
 import java.util.Objects;
 
@@ -50,4 +48,10 @@ public class ClientCredentials {
 	public int hashCode() {
 		return Objects.hash(clientSecret, clientId);
 	}
+
+	@Override
+	public String toString() {
+		return String.format("%s:%s", clientId, clientSecret);
+	}
+
 }
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenService.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenService.java
index 00c8421e..242e8e84 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenService.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenService.java
@@ -23,7 +23,6 @@ public interface OAuth2TokenService {
 	 *            supplying a subdomain (tenant).
 	 * @param optionalParameters
 	 *            optional request parameters, can be null.
-	 *
 	 * @return the OAuth2AccessToken.
 	 * @throws OAuth2ServiceException
 	 *             in case of an error during the http request.
@@ -50,7 +49,6 @@ public interface OAuth2TokenService {
 	 *            supplying a subdomain (tenant).
 	 * @param optionalParameters
 	 *            optional request parameters, can be null.
-	 *
 	 * @return the OAuth2AccessToken.
 	 * @throws OAuth2ServiceException
 	 *             in case of an error during the http request.
@@ -82,4 +80,28 @@ public interface OAuth2TokenService {
 	 */
 	OAuth2TokenResponse retrieveAccessTokenViaRefreshToken(URI tokenEndpointUri, ClientCredentials clientCredentials,
 			String refreshToken, @Nullable String subdomain) throws OAuth2ServiceException;
+
+	/**
+	 * @param tokenEndpointUri
+	 *            the token endpoint URI.
+	 * @param clientCredentials
+	 *            the client id and secret of the OAuth client, the recipient of the
+	 *            token.
+	 * @param username
+	 *            the username for the user trying to get a token
+	 * @param password
+	 *            the password for the user trying to get a token
+	 * @param subdomain
+	 *            optionally indicates what Identity Zone this request goes to by
+	 *            supplying a subdomain (tenant).
+	 * @param optionalParameters
+	 *            optional request parameters, can be null.
+	 * @return the OAuth2AccessToken
+	 * @throws OAuth2ServiceException
+	 *             in case of an error during the http request.
+	 */
+	OAuth2TokenResponse retrieveAccessTokenViaPasswordGrant(URI tokenEndpointUri, ClientCredentials clientCredentials,
+			String username, String password, @Nullable String subdomain,
+			@Nullable Map<String, String> optionalParameters) throws OAuth2ServiceException;
+
 }
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenServiceConstants.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenServiceConstants.java
index 3fcd5bd4..bf41a3f0 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenServiceConstants.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/OAuth2TokenServiceConstants.java
@@ -11,11 +11,15 @@ public class OAuth2TokenServiceConstants {
 	public static final String REFRESH_TOKEN = "refresh_token";
 	public static final String CLIENT_ID = "client_id";
 	public static final String CLIENT_SECRET = "client_secret";
+	public static final String USERNAME = "username";
+	public static final String PASSWORD = "password";
 
 	public static final String GRANT_TYPE = "grant_type";
 	public static final String GRANT_TYPE_USER_TOKEN = "user_token";
 	public static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token";
 	public static final String GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials";
+	public static final String GRANT_TYPE_PASSWORD = "password";
+
 	public static final String TOKEN_TYPE_OPAQUE = "opaque";
 
 	public static final String PARAMETER_CLIENT_ID = "client_id";
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenService.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenService.java
index c3ec8537..71df29ed 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenService.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenService.java
@@ -1,21 +1,5 @@
 package com.sap.cloud.security.xsuaa.client;
 
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.ACCESS_TOKEN;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.CLIENT_ID;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.CLIENT_SECRET;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.EXPIRES_IN;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.GRANT_TYPE;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.GRANT_TYPE_CLIENT_CREDENTIALS;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.GRANT_TYPE_REFRESH_TOKEN;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.GRANT_TYPE_USER_TOKEN;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.PARAMETER_CLIENT_ID;
-import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.REFRESH_TOKEN;
-
-import java.net.URI;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.http.HttpEntity;
@@ -29,10 +13,18 @@ import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
 import org.springframework.util.StringUtils;
 import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.RestOperations;
 import org.springframework.web.util.UriBuilder;
 import org.springframework.web.util.UriComponentsBuilder;
 
+import java.net.URI;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.*;
+
 public class XsuaaOAuth2TokenService implements OAuth2TokenService {
 
 	private final RestOperations restOperations;
@@ -54,8 +46,7 @@ public class XsuaaOAuth2TokenService implements OAuth2TokenService {
 		// build parameters
 		Map<String, String> parameters = new HashMap<>();
 		parameters.put(GRANT_TYPE, GRANT_TYPE_CLIENT_CREDENTIALS);
-		parameters.put(CLIENT_ID, clientCredentials.getId());
-		parameters.put(CLIENT_SECRET, clientCredentials.getSecret());
+		addClientCredentialsToParameters(clientCredentials, parameters);
 		if (optionalParameters != null) {
 			optionalParameters.forEach(parameters::putIfAbsent);
 		}
@@ -101,8 +92,7 @@ public class XsuaaOAuth2TokenService implements OAuth2TokenService {
 		Map<String, String> parameters = new HashMap<>();
 		parameters.put(GRANT_TYPE, GRANT_TYPE_REFRESH_TOKEN);
 		parameters.put(REFRESH_TOKEN, refreshToken);
-		parameters.put(CLIENT_ID, clientCredentials.getId());
-		parameters.put(CLIENT_SECRET, clientCredentials.getSecret());
+		addClientCredentialsToParameters(clientCredentials, parameters);
 
 		// build header
 		HttpHeaders headers = createHeadersWithoutAuthorization();
@@ -110,6 +100,31 @@ public class XsuaaOAuth2TokenService implements OAuth2TokenService {
 		return requestAccessToken(replaceSubdomain(tokenEndpointUri, subdomain), headers, copyIntoForm(parameters));
 	}
 
+	@Override
+	public OAuth2TokenResponse retrieveAccessTokenViaPasswordGrant(@NonNull URI tokenEndpoint,
+			@NonNull ClientCredentials clientCredentials, @NonNull String username, @NonNull String password,
+			@Nullable String subdomain, @Nullable Map<String, String> optionalParameters)
+			throws OAuth2ServiceException {
+		Assert.notNull(tokenEndpoint, "tokenEndpoint is required");
+		Assert.notNull(clientCredentials, "clientCredentials are required");
+		Assert.notNull(username, "username is required");
+		Assert.notNull(password, "password is required");
+
+		Map<String, String> parameters = new HashMap<>();
+		parameters.put(GRANT_TYPE, GRANT_TYPE_PASSWORD);
+		parameters.put(USERNAME, username);
+		parameters.put(PASSWORD, password);
+		addClientCredentialsToParameters(clientCredentials, parameters);
+
+		if (optionalParameters != null) {
+			optionalParameters.forEach(parameters::putIfAbsent);
+		}
+
+		HttpHeaders headers = createHeadersWithoutAuthorization();
+
+		return requestAccessToken(replaceSubdomain(tokenEndpoint, subdomain), headers, copyIntoForm(parameters));
+	}
+
 	/**
 	 * Utility method that replaces the subdomain of the URI with the given
 	 * subdomain.
@@ -148,14 +163,14 @@ public class XsuaaOAuth2TokenService implements OAuth2TokenService {
 		try {
 			responseEntity = restOperations.postForEntity(requestUri, requestEntity, Map.class);
 		} catch (HttpClientErrorException ex) {
-			if (!ex.getStatusCode().is2xxSuccessful()) {
-				throw new OAuth2ServiceException(String.format(
-						"Error retrieving JWT token. Received status code %s. Call to XSUAA was not successful: %s",
-						ex.getStatusCode(), ex.getCause()));
-			}
-			throw new OAuth2ServiceException(String.format(
-					"Error retrieving JWT token. Call to XSUAA was not successful: %s",
-					ex.getMessage()));
+			String warningMsg = String.format("Error retrieving JWT token. Received status code %s. Call to XSUAA was not successful: %s",
+					ex.getStatusCode(), ex.getResponseBodyAsString());
+			throw new OAuth2ServiceException(warningMsg);
+		} catch (HttpServerErrorException ex) {
+			String warningMsg = String.format("Server error while obtaining access token from XSUAA (%s): %s",
+					ex.getStatusCode(), ex.getResponseBodyAsString());
+			logger.error(warningMsg, ex);
+			throw new OAuth2ServiceException(warningMsg);
 		}
 
 		@SuppressWarnings("unchecked")
@@ -170,7 +185,7 @@ public class XsuaaOAuth2TokenService implements OAuth2TokenService {
 
 	/**
 	 * Creates a copy of the given map or an new empty map of type MultiValueMap.
-	 * 
+	 *
 	 * @return a new @link{MultiValueMap} that contains all entries of the optional
 	 *         map.
 	 */
@@ -208,6 +223,12 @@ public class XsuaaOAuth2TokenService implements OAuth2TokenService {
 		return headers;
 	}
 
+	private void addClientCredentialsToParameters(ClientCredentials clientCredentials,
+			Map<String, String> parameters) {
+		parameters.put(CLIENT_ID, clientCredentials.getId());
+		parameters.put(CLIENT_SECRET, clientCredentials.getSecret());
+	}
+
 	/** common utilities **/
 
 	/**
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/UserTokenFlow.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/UserTokenFlow.java
index 59a4fa66..85ebe425 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/UserTokenFlow.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/UserTokenFlow.java
@@ -1,7 +1,6 @@
 package com.sap.cloud.security.xsuaa.tokenflows;
 
 import static com.sap.cloud.security.xsuaa.tokenflows.XsuaaTokenFlowsUtils.buildAuthorities;
-import org.springframework.security.jwt.JwtHelper;
 
 import java.util.HashMap;
 import java.util.Iterator;
@@ -17,6 +16,7 @@ import com.sap.cloud.security.xsuaa.client.OAuth2TokenResponse;
 import com.sap.cloud.security.xsuaa.client.OAuth2ServiceEndpointsProvider;
 import com.sap.cloud.security.xsuaa.client.OAuth2ServiceException;
 import com.sap.cloud.security.xsuaa.client.OAuth2TokenService;
+import com.sap.cloud.security.xsuaa.jwt.Base64JwtDecoder;
 import com.sap.xsa.security.container.XSTokenRequest;
 
 /**
@@ -215,7 +215,7 @@ public class UserTokenFlow {
 	 * @return {@code true} if the scope is contained, {@code false} otherwise.
 	 */
 	private boolean hasScope(String token, String scope) {
-		String claims = JwtHelper.decode(token).getClaims();
+		String claims = new Base64JwtDecoder().decode(token).getPayload();
 		try {
 			JSONObject rootObject = new JSONObject(claims);
 			JSONArray scopesArray = rootObject.getJSONArray(SCOPE_CLAIM);
diff --git a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlowRequest.java b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlowRequest.java
index e3d7a4e6..34398057 100644
--- a/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlowRequest.java
+++ b/token-client/src/main/java/com/sap/cloud/security/xsuaa/tokenflows/XsuaaTokenFlowRequest.java
@@ -21,6 +21,7 @@ class XsuaaTokenFlowRequest implements XSTokenRequest {
 	private String subdomain;
 	private String clientSecret;
 	private Map<String, String> additionalAuthorizationAttributes;
+	private static final String UNSUPPORTED_INTF_METHOD_INFO = "This XSTokenRequest method is no longer needed in context of new XsuaaTokenFlows API.";
 
 	/**
 	 * Creates a new token exchange request.
@@ -80,24 +81,27 @@ class XsuaaTokenFlowRequest implements XSTokenRequest {
 	 * @deprecated in favor of @link{XsuaaTokenFlows} API
 	 */
 	@Override
+	@Deprecated
 	public XSTokenRequest setType(int type) {
-		throw new AssertionError("This method is no longer needed in context of new XsuaaTokenFlows API.");
+		throw new AssertionError(UNSUPPORTED_INTF_METHOD_INFO);
 	}
 
 	/**
 	 * @deprecated in favor of @link{XsuaaTokenFlows} API
 	 */
 	@Override
+	@Deprecated
 	public int getType() {
-		throw new AssertionError("This method is no longer needed in context of new XsuaaTokenFlows API.");
+		throw new AssertionError(UNSUPPORTED_INTF_METHOD_INFO);
 	}
 
 	/**
 	 * @deprecated in favor of @link{{@link #setSubdomain} )}}
 	 */
 	@Override
+	@Deprecated
 	public XSTokenRequest setTokenEndpoint(URI tokenUri) {
-		throw new AssertionError("This method is no longer needed in context of new XsuaaTokenFlows API.");
+		throw new AssertionError(UNSUPPORTED_INTF_METHOD_INFO);
 	}
 
 	/**


Test patch:
diff --git a/samples/spring-security-basic-auth/src/main/java/sample/spring/xsuaa/TestController.java b/samples/spring-security-basic-auth/src/main/java/sample/spring/xsuaa/TestController.java
index 4b35b9d7..ccdc1d3c 100644
--- a/samples/spring-security-basic-auth/src/main/java/sample/spring/xsuaa/TestController.java
+++ b/samples/spring-security-basic-auth/src/main/java/sample/spring/xsuaa/TestController.java
@@ -29,7 +29,7 @@ public class TestController {
 
 	@GetMapping("/hello-token")
 	public Map<String, String> message(@AuthenticationPrincipal Token token) {
-		Map<String, String> result = new HashMap<>();
+		Map<String, String> result = new HashMap();
 		result.put("grant type", token.getGrantType());
 		result.put("client id", token.getClientId());
 		result.put("subaccount id", token.getSubaccountId());
diff --git a/samples/spring-security-xsuaa-usage/src/main/java/sample/spring/xsuaa/TestController.java b/samples/spring-security-xsuaa-usage/src/main/java/sample/spring/xsuaa/TestController.java
index 347704a5..ab443d91 100644
--- a/samples/spring-security-xsuaa-usage/src/main/java/sample/spring/xsuaa/TestController.java
+++ b/samples/spring-security-xsuaa-usage/src/main/java/sample/spring/xsuaa/TestController.java
@@ -126,7 +126,7 @@ public class TestController {
         OAuth2TokenResponse clientCredentialsTokenResponse = tokenFlows.clientCredentialsTokenFlow().execute();
         logger.info("Got the Client Credentials Token: {}", clientCredentialsTokenResponse.getAccessToken());
 
-        return "The client-credentials token (encoded) can be found in the logs 'cf logs spring-security-xsuaa-usage --recent'";
+        return clientCredentialsTokenResponse.getDecodedAccessToken().getPayload();
     }
 
     /**
@@ -156,7 +156,9 @@ public class TestController {
         logger.info("Got the exchanged token for 3rd party service: {}", userTokenResponse);
         logger.info("You can now call the 3rd party service passing the exchanged token value: {}. ", userTokenResponse);
 
-        return "The refresh-token: " + userTokenResponse.getRefreshToken() + ". The access-token (encoded) can be found in the logs 'cf logs spring-security-xsuaa-usage --recent'";
+        return "<p>The access-token (decoded):</p><p>" + userTokenResponse.getDecodedAccessToken().getPayload()
+                + "</p><p>The refresh-token: </p><p>" + userTokenResponse.getRefreshToken()
+                + "</p><p>The access-token (encoded) can be found in the logs 'cf logs spring-security-xsuaa-usage --recent'</p>";
     }
 
     /**
@@ -176,7 +178,7 @@ public class TestController {
         logger.info("Got the access token for the refresh token: {}", refreshTokenResponse.getAccessToken());
         logger.info("You could now inject this into Spring's SecurityContext, using: SpringSecurityContext.init(...).");
 
-        return "The exchanged access token (encoded) can be found in the logs 'cf logs spring-security-xsuaa-usage --recent'";
+        return refreshTokenResponse.getDecodedAccessToken().getPayload();
     }
 
 }
diff --git a/samples/spring-webflux-security-xsuaa-usage/src/main/java/sample/spring/webflux/xsuaa/TestController.java b/samples/spring-webflux-security-xsuaa-usage/src/main/java/sample/spring/webflux/xsuaa/TestController.java
index d5942bc5..7ba455b5 100644
--- a/samples/spring-webflux-security-xsuaa-usage/src/main/java/sample/spring/webflux/xsuaa/TestController.java
+++ b/samples/spring-webflux-security-xsuaa-usage/src/main/java/sample/spring/webflux/xsuaa/TestController.java
@@ -1,5 +1,6 @@
 package sample.spring.webflux.xsuaa;
 
+import com.sap.cloud.security.xsuaa.jwt.Base64JwtDecoder;
 import com.sap.cloud.security.xsuaa.token.ReactiveSecurityContext;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
@@ -18,6 +19,6 @@ public class TestController {
 		return ReactiveSecurityContext.getToken()
 				.doOnError(throwable -> Mono.just(unAuthenticated))
 				.map(token -> ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN)
-						.body("Authorities: " + token.getAuthorities()));
+						.body(new Base64JwtDecoder().decode(token.getAppToken()).getPayload()));
 	}
 }
diff --git a/samples/spring-webflux-security-xsuaa-usage/src/test/java/sample/spring/webflux/xsuaa/TestControllerTest.java b/samples/spring-webflux-security-xsuaa-usage/src/test/java/sample/spring/webflux/xsuaa/TestControllerTest.java
index 9b97895c..057e33ab 100644
--- a/samples/spring-webflux-security-xsuaa-usage/src/test/java/sample/spring/webflux/xsuaa/TestControllerTest.java
+++ b/samples/spring-webflux-security-xsuaa-usage/src/test/java/sample/spring/webflux/xsuaa/TestControllerTest.java
@@ -14,6 +14,7 @@ import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.test.web.reactive.server.WebTestClient;
 import org.springframework.util.Assert;
 
+import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.startsWith;
 
 @RunWith(SpringRunner.class)
@@ -42,7 +43,7 @@ public class TestControllerTest {
 
 		webClient.method(HttpMethod.GET).uri("/v1/sayHello").contentType(MediaType.APPLICATION_JSON_UTF8)
 				.header(HttpHeaders.AUTHORIZATION, jwtGenerator.getTokenForAuthorizationHeader()).exchange()
-				.expectStatus().is2xxSuccessful().expectBody(String.class).value(startsWith("Authorities:"));
+				.expectStatus().is2xxSuccessful().expectBody(String.class).value(containsString(",\"scope\":[\"xsapplication!t895.Read\"],"));
 	}
 
 	private String getGlobalScope(String localScope) {
diff --git a/spring-xsuaa-it/src/main/java/testservice/api/basic/TestController.java b/spring-xsuaa-it/src/main/java/testservice/api/basic/TestController.java
index b7967499..b788ffb4 100644
--- a/spring-xsuaa-it/src/main/java/testservice/api/basic/TestController.java
+++ b/spring-xsuaa-it/src/main/java/testservice/api/basic/TestController.java
@@ -20,7 +20,6 @@ import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.core.IsCollectionContaining.hasItem;
 import static org.junit.Assert.assertThat;
 
-import java.net.URISyntaxException;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
@@ -33,11 +32,17 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
 
 import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.client.ClientCredentials;
+import com.sap.cloud.security.xsuaa.client.OAuth2TokenResponse;
+import com.sap.cloud.security.xsuaa.client.XsuaaDefaultEndpoints;
+import com.sap.cloud.security.xsuaa.client.XsuaaOAuth2TokenService;
 import com.sap.cloud.security.xsuaa.token.Token;
-import com.sap.xs2.security.container.XSTokenRequestImpl;
-import com.sap.xsa.security.container.XSTokenRequest;
+import com.sap.cloud.security.xsuaa.tokenflows.ClientCredentialsTokenFlow;
+import com.sap.cloud.security.xsuaa.tokenflows.TokenFlowException;
+import com.sap.cloud.security.xsuaa.tokenflows.XsuaaTokenFlows;
 
 @RestController
 @Profile({ "test.api.basic" })
@@ -66,14 +71,17 @@ public class TestController {
 	}
 
 	@GetMapping("/requesttoken")
-	public String requestToken(@AuthenticationPrincipal Token token) throws URISyntaxException {
-		XSTokenRequestImpl tokenRequest = new XSTokenRequestImpl(serviceConfiguration.getUaaUrl());
-		tokenRequest.setClientId("c1").setClientSecret("s1").setType(XSTokenRequest.TYPE_CLIENT_CREDENTIALS_TOKEN);
+	public String requestToken(@AuthenticationPrincipal Token token) throws TokenFlowException {
 		Map<String, String> azMape = new HashMap();
 		azMape.put("a", "b");
 		azMape.put("c", "d");
-		tokenRequest.setAdditionalAuthorizationAttributes(azMape);
-		String newToken = token.requestToken(tokenRequest);
-		return newToken;
+
+		XsuaaTokenFlows tokenFlows = new XsuaaTokenFlows(new XsuaaOAuth2TokenService(new RestTemplate()),
+				new XsuaaDefaultEndpoints(serviceConfiguration.getUaaUrl()), new ClientCredentials("c1", "s1"));
+		ClientCredentialsTokenFlow ccTokenFlow = tokenFlows.clientCredentialsTokenFlow().attributes(azMape)
+				.subdomain(token.getSubdomain());
+
+		OAuth2TokenResponse newToken = ccTokenFlow.execute();
+		return newToken.getAccessToken();
 	}
 }
diff --git a/spring-xsuaa-it/src/main/java/testservice/api/nohttp/MyEventHandler.java b/spring-xsuaa-it/src/main/java/testservice/api/nohttp/MyEventHandler.java
index 7b8eb336..886908b3 100644
--- a/spring-xsuaa-it/src/main/java/testservice/api/nohttp/MyEventHandler.java
+++ b/spring-xsuaa-it/src/main/java/testservice/api/nohttp/MyEventHandler.java
@@ -10,13 +10,11 @@ import org.springframework.context.annotation.Profile;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.security.oauth2.jwt.JwtDecoder;
 import org.springframework.stereotype.Service;
 
 import com.sap.cloud.security.xsuaa.extractor.LocalAuthoritiesExtractor;
 import com.sap.cloud.security.xsuaa.token.SpringSecurityContext;
-import com.sap.xs2.security.container.SecurityContext;
 
 @Service
 @Profile({ "test.api.nohttp" })
@@ -29,19 +27,6 @@ public class MyEventHandler {
 	@Autowired
 	JwtDecoder jwtDecoder;
 
-	@Deprecated
-	public void onEvent_deprecated(String myEncodedJwtToken) {
-		if (myEncodedJwtToken != null) {
-			Jwt jwtToken = jwtDecoder.decode(myEncodedJwtToken);
-			SecurityContext.init(appId, jwtToken, true);
-		}
-		try {
-			handleEvent();
-		} finally {
-			SpringSecurityContext.clear();
-		}
-	}
-
 	public void onEvent(String myEncodedJwtToken) {
 		if (myEncodedJwtToken != null) {
 			SpringSecurityContext.init(myEncodedJwtToken, jwtDecoder, new LocalAuthoritiesExtractor(appId));
diff --git a/spring-xsuaa-it/src/main/java/testservice/api/v1/TestController.java b/spring-xsuaa-it/src/main/java/testservice/api/v1/TestController.java
index 270cb9e4..0da7b100 100644
--- a/spring-xsuaa-it/src/main/java/testservice/api/v1/TestController.java
+++ b/spring-xsuaa-it/src/main/java/testservice/api/v1/TestController.java
@@ -1,9 +1,10 @@
 package testservice.api.v1;
 
-import static org.hamcrest.CoreMatchers.*;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
 import static org.junit.Assert.assertThat;
 
-import java.net.URISyntaxException;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
@@ -28,8 +29,6 @@ import com.sap.cloud.security.xsuaa.token.Token;
 import com.sap.cloud.security.xsuaa.tokenflows.ClientCredentialsTokenFlow;
 import com.sap.cloud.security.xsuaa.tokenflows.TokenFlowException;
 import com.sap.cloud.security.xsuaa.tokenflows.XsuaaTokenFlows;
-import com.sap.xs2.security.container.XSTokenRequestImpl;
-import com.sap.xsa.security.container.XSTokenRequest;
 
 @RestController
 @Profile({ "test.api.v1" })
@@ -81,19 +80,6 @@ public class TestController {
 		assertThat(authorities, not(hasItem(new SimpleGrantedAuthority("Other"))));
 	}
 
-	@GetMapping("/requesttoken")
-	@Deprecated
-	public String requestToken(@AuthenticationPrincipal Token token) throws URISyntaxException {
-		XSTokenRequestImpl tokenRequest = new XSTokenRequestImpl(serviceConfiguration.getUaaUrl());
-		tokenRequest.setClientId("c1").setClientSecret("s1").setType(XSTokenRequest.TYPE_CLIENT_CREDENTIALS_TOKEN);
-		Map<String, String> azMape = new HashMap();
-		azMape.put("a", "b");
-		azMape.put("c", "d");
-		tokenRequest.setAdditionalAuthorizationAttributes(azMape);
-		String newToken = token.requestToken(tokenRequest);
-		return newToken;
-	}
-
 	@GetMapping("/clientCredentialsToken")
 	public String requestClientCredentialsToken(@AuthenticationPrincipal Token token) throws TokenFlowException {
 		Map<String, String> azMape = new HashMap();
diff --git a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/extractor/BasicCredentialExtractorTest.java b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/extractor/BasicCredentialExtractorTest.java
index 5ef04843..b1564f2c 100644
--- a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/extractor/BasicCredentialExtractorTest.java
+++ b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/extractor/BasicCredentialExtractorTest.java
@@ -21,6 +21,8 @@ import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.test.context.support.AnnotationConfigContextLoader;
 
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+
 @RunWith(SpringRunner.class)
 @ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = { XsuaaServiceConfigurationDummy.class,
 		TokenBrokerTestConfiguration.class })
@@ -72,7 +74,7 @@ public class BasicCredentialExtractorTest {
 				authenticationMethods(AuthenticationMethod.CLIENT_CREDENTIALS));
 		request.addHeader("Authorization",
 				"basic " + Base64.getEncoder().encodeToString("client1234:secret1234".getBytes()));
-		request.addHeader("X-Identity-Zone-Subdomain", "true");
+		request.addHeader("X-Identity-Zone-Subdomain", "x-idz-subdomain");
 		request.setScheme("http");
 		request.setServerName("t1.cloudfoundry");
 		String token = extractor.resolve(request);
@@ -134,7 +136,7 @@ public class BasicCredentialExtractorTest {
 		assertThat(token).isEqualTo("token_pwd");
 	}
 
-	private XsuaaServiceConfigurationDummy getXsuaaServiceConfiguration() {
+	private XsuaaServiceConfiguration getXsuaaServiceConfiguration() {
 		XsuaaServiceConfigurationDummy cfg = new XsuaaServiceConfigurationDummy();
 		cfg.appId = "a1!123";
 		cfg.clientId = "myclient!t1";
diff --git a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/extractor/XsuaaServiceConfigurationDummy.java b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/extractor/XsuaaServiceConfigurationDummy.java
index 82f84c49..d4dc72ba 100644
--- a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/extractor/XsuaaServiceConfigurationDummy.java
+++ b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/extractor/XsuaaServiceConfigurationDummy.java
@@ -25,11 +25,6 @@ public class XsuaaServiceConfigurationDummy implements XsuaaServiceConfiguration
 		return uaaUrl;
 	}
 
-	@Override
-	public String getTokenKeyUrl(String identityZoneId, String subdomain) {
-		return null;
-	}
-
 	@Override
 	public String getAppId() {
 		return appId;
diff --git a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaServiceConfigurationTest.java b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaServiceConfigurationTest.java
index 2ec502b8..a4c732b6 100644
--- a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaServiceConfigurationTest.java
+++ b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaServiceConfigurationTest.java
@@ -30,11 +30,6 @@ public class XsuaaServiceConfigurationTest {
 		Assert.assertEquals("https://auth.com", exampleBean.serviceConfiguration.getUaaUrl());
 		Assert.assertEquals("xs2.usertoken", exampleBean.serviceConfiguration.getClientId());
 		Assert.assertEquals("secret", exampleBean.serviceConfiguration.getClientSecret());
-		Assert.assertEquals("https://auth.com/token_keys",
-				exampleBean.serviceConfiguration.getTokenKeyUrl("uaa", null));
-		Assert.assertEquals("https://myhost.auth.com/token_keys",
-				exampleBean.serviceConfiguration.getTokenKeyUrl("zone", "myhost"));
-		Assert.assertEquals("java-hello-world", exampleBean.serviceConfiguration.getAppId());
 		Assert.assertEquals("auth.com", exampleBean.serviceConfiguration.getUaaDomain());
 	}
 
diff --git a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaTokenValidationTest.java b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaTokenValidationTest.java
index d4497226..65df56f7 100644
--- a/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaTokenValidationTest.java
+++ b/spring-xsuaa-it/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaTokenValidationTest.java
@@ -54,16 +54,6 @@ public class XsuaaTokenValidationTest {
 	}
 
 	@Test
-	@Deprecated
-	public void test_requesttoken() throws Exception {
-		this.mvc.perform(
-				get("/requesttoken").with(bearerToken(JWTUtil.createJWT("/saml.txt", "uaa", "legacy-token-key"))))
-				.andExpect(status().isOk()).andExpect(
-						content().string(containsString(".ewogICJqdGkiOiAiOGU3YjNiMDAtNzc1MS00YjQ2LTliMWEtNWE0NmEyY")));
-	}
-
-	@Test
-	@Deprecated
 	public void test_clientcredentialstoken() throws Exception {
 		this.mvc.perform(
 				get("/clientCredentialsToken")
diff --git a/spring-xsuaa-test/README.md b/spring-xsuaa-test/README.md
index fb4a3614..c90505c7 100644
--- a/spring-xsuaa-test/README.md
+++ b/spring-xsuaa-test/README.md
@@ -27,7 +27,7 @@ This includes for example a `JwtGenerator` that generates JSON Web Tokens (JWT)
 <dependency>
     <groupId>com.sap.cloud.security.xsuaa</groupId>
     <artifactId>spring-xsuaa-test</artifactId>
-    <version>1.7.0</version>
+    <version>2.0.0</version>
     <scope>test</scope>
 </dependency>
 
diff --git a/spring-xsuaa-test/pom.xml b/spring-xsuaa-test/pom.xml
index 46fefea9..eff5d19b 100644
--- a/spring-xsuaa-test/pom.xml
+++ b/spring-xsuaa-test/pom.xml
@@ -7,7 +7,7 @@
 	<parent>
 		<groupId>com.sap.cloud.security.xsuaa</groupId>
 		<artifactId>parent</artifactId>
-		<version>1.7.0</version>
+		<version>2.0.0</version>
 	</parent>
 
 	<artifactId>spring-xsuaa-test</artifactId>
diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/DummyXsuaaServiceConfiguration.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/DummyXsuaaServiceConfiguration.java
index c46412b6..9051bdb0 100644
--- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/DummyXsuaaServiceConfiguration.java
+++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/DummyXsuaaServiceConfiguration.java
@@ -29,11 +29,6 @@ public class DummyXsuaaServiceConfiguration implements XsuaaServiceConfiguration
 		return "https://subdomain.authentication.eu10.hana.ondemand.com";
 	}
 
-	@Override
-	public String getTokenKeyUrl(String identityZoneId, String subdomain) {
-		return null;
-	}
-
 	@Override
 	public String getAppId() {
 		return appId;
diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaAutoConfigurationTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaAutoConfigurationTest.java
index 2aae5de1..7a4e9e06 100644
--- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaAutoConfigurationTest.java
+++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaAutoConfigurationTest.java
@@ -1,8 +1,11 @@
 package com.sap.cloud.security.xsuaa.autoconfiguration;
 
-import com.sap.cloud.security.xsuaa.DummyXsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.XsuaaServiceConfigurationDefault;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -19,9 +22,9 @@ import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.web.client.RestOperations;
 import org.springframework.web.client.RestTemplate;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.assertThat;
+import com.sap.cloud.security.xsuaa.DummyXsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfigurationDefault;
 
 @RunWith(SpringRunner.class)
 @SpringBootTest(classes = { XsuaaAutoConfiguration.class, DummyXsuaaServiceConfiguration.class })
diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaResourceServerJwkAutoConfigurationTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaResourceServerJwkAutoConfigurationTest.java
index f0b11c8e..be7f2906 100644
--- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaResourceServerJwkAutoConfigurationTest.java
+++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaResourceServerJwkAutoConfigurationTest.java
@@ -6,7 +6,6 @@ import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.nullValue;
 import static org.junit.Assert.assertThat;
 
-import com.sap.cloud.security.xsuaa.token.authentication.XsuaaJwtDecoder;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -24,6 +23,8 @@ import org.springframework.security.oauth2.jwt.JwtDecoder;
 import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
 import org.springframework.test.context.junit4.SpringRunner;
 
+import com.sap.cloud.security.xsuaa.token.authentication.XsuaaJwtDecoder;
+
 @RunWith(SpringRunner.class)
 @SpringBootTest(classes = { XsuaaResourceServerJwkAutoConfiguration.class, XsuaaAutoConfiguration.class })
 public class XsuaaResourceServerJwkAutoConfigurationTest {
diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfigurationTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfigurationTest.java
index 7f757305..15374a9d 100644
--- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfigurationTest.java
+++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/autoconfiguration/XsuaaTokenFlowAutoConfigurationTest.java
@@ -1,11 +1,7 @@
 package com.sap.cloud.security.xsuaa.autoconfiguration;
 
-import com.sap.cloud.security.xsuaa.DummyXsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.client.ClientCredentials;
-import com.sap.cloud.security.xsuaa.client.XsuaaDefaultEndpoints;
-import com.sap.cloud.security.xsuaa.client.XsuaaOAuth2TokenService;
-import com.sap.cloud.security.xsuaa.tokenflows.XsuaaTokenFlows;
+import static org.assertj.core.api.Assertions.assertThat;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -19,7 +15,12 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.web.client.RestOperations;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import com.sap.cloud.security.xsuaa.DummyXsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.client.ClientCredentials;
+import com.sap.cloud.security.xsuaa.client.XsuaaDefaultEndpoints;
+import com.sap.cloud.security.xsuaa.client.XsuaaOAuth2TokenService;
+import com.sap.cloud.security.xsuaa.tokenflows.XsuaaTokenFlows;
 
 @RunWith(SpringRunner.class)
 @SpringBootTest(classes = { XsuaaAutoConfiguration.class, XsuaaTokenFlowAutoConfiguration.class,
diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/ReactiveSecurityContextTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/ReactiveSecurityContextTest.java
index 2fae87dd..19c3d08b 100644
--- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/ReactiveSecurityContextTest.java
+++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/ReactiveSecurityContextTest.java
@@ -1,6 +1,5 @@
 package com.sap.cloud.security.xsuaa.token;
 
-import com.sap.cloud.security.xsuaa.test.JwtGenerator;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.springframework.security.access.AccessDeniedException;
@@ -8,6 +7,9 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.core.context.ReactiveSecurityContextHolder;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextImpl;
+
+import com.sap.cloud.security.xsuaa.test.JwtGenerator;
+
 import reactor.core.publisher.Mono;
 import reactor.test.StepVerifier;
 
diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/SpringSecurityContextTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/SpringSecurityContextTest.java
index af6019fd..32c8f97a 100644
--- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/SpringSecurityContextTest.java
+++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/SpringSecurityContextTest.java
@@ -1,8 +1,13 @@
 package com.sap.cloud.security.xsuaa.token;
 
-import com.sap.cloud.security.xsuaa.extractor.DefaultAuthoritiesExtractor;
-import com.sap.cloud.security.xsuaa.test.JwtGenerator;
-import com.sap.cloud.security.xsuaa.token.authentication.XsuaaJwtDecoder;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
@@ -11,13 +16,9 @@ import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.security.oauth2.jwt.JwtDecoder;
 import org.springframework.security.oauth2.jwt.JwtException;
 
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.when;
+import com.sap.cloud.security.xsuaa.extractor.DefaultAuthoritiesExtractor;
+import com.sap.cloud.security.xsuaa.test.JwtGenerator;
+import com.sap.cloud.security.xsuaa.token.authentication.XsuaaJwtDecoder;
 
 public class SpringSecurityContextTest {
 
diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/TokenAuthenticationConverterTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/TokenAuthenticationConverterTest.java
index 9998b87a..eb000333 100644
--- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/TokenAuthenticationConverterTest.java
+++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/TokenAuthenticationConverterTest.java
@@ -9,9 +9,6 @@ import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
 
-import com.sap.cloud.security.xsuaa.extractor.AuthoritiesExtractor;
-import com.sap.cloud.security.xsuaa.extractor.DefaultAuthoritiesExtractor;
-import com.sap.cloud.security.xsuaa.test.JwtGenerator;
 import org.junit.Before;
 import org.junit.Test;
 import org.springframework.security.authentication.AbstractAuthenticationToken;
@@ -19,6 +16,10 @@ import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.oauth2.jwt.Jwt;
 
+import com.sap.cloud.security.xsuaa.extractor.AuthoritiesExtractor;
+import com.sap.cloud.security.xsuaa.extractor.DefaultAuthoritiesExtractor;
+import com.sap.cloud.security.xsuaa.test.JwtGenerator;
+
 public class TokenAuthenticationConverterTest {
 	private String xsAppName = "my-app-name!400";
 	private TokenAuthenticationConverter tokenConverterDefault;
diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaTokenTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaTokenTest.java
index a57a5f70..30710f2e 100644
--- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaTokenTest.java
+++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/XsuaaTokenTest.java
@@ -1,36 +1,31 @@
 package com.sap.cloud.security.xsuaa.token;
 
-import static org.hamcrest.CoreMatchers.*;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.CoreMatchers.startsWith;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
 
 import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.time.Instant;
-import java.util.*;
-
-import com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.Mockito;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.oauth2.jwt.Jwt;
-import org.springframework.web.client.RestTemplate;
 
 import com.nimbusds.jwt.JWTClaimsSet;
 import com.sap.cloud.security.xsuaa.test.JwtGenerator;
-import com.sap.xs2.security.container.XSTokenRequestImpl;
-import com.sap.xsa.security.container.XSTokenRequest;
 
 public class XsuaaTokenTest {
 
@@ -250,70 +245,6 @@ public class XsuaaTokenTest {
 		assertThat(token.getAppToken(), startsWith("eyJhbGciOiJSUzI1NiIsInR5"));
 	}
 
-	@Test
-	@Deprecated
-	public void requestClientCredentialsToken() throws URISyntaxException {
-		// prepare response
-		Map<String, Object> ccToken = new HashMap<>();
-		Jwt mockJwt = buildMockJwt();
-		ccToken.put(OAuth2TokenServiceConstants.ACCESS_TOKEN, mockJwt.getTokenValue());
-		ccToken.put(OAuth2TokenServiceConstants.EXPIRES_IN, 43199);
-
-		// mock rest call
-		// http://myuaa.com/oauth/token?grant_type=client_credentials&authorities=%7B%22az_attr%22:%7B%22a%22:%22b%22,%22c%22:%22d%22%7D%7D
-		RestTemplate mockRestTemplate = Mockito.mock(RestTemplate.class);
-		ResponseEntity<Map> response = new ResponseEntity<>(ccToken, HttpStatus.OK);
-		Mockito.when(mockRestTemplate.postForEntity(any(URI.class), any(HttpEntity.class), eq(Map.class)))
-				.thenReturn(response);
-
-		token = createToken(claimsSetBuilder);
-
-		String mockServerUrl = "http://myuaa.com";
-		XSTokenRequestImpl tokenRequest = new XSTokenRequestImpl(mockServerUrl);
-		tokenRequest.setRestTemplate(mockRestTemplate);
-		tokenRequest.setClientId("c1").setClientSecret("s1").setType(XSTokenRequest.TYPE_CLIENT_CREDENTIALS_TOKEN);
-
-		Map<String, String> azMape = new HashMap<>();
-		azMape.put("a", "b");
-		azMape.put("c", "d");
-		tokenRequest.setAdditionalAuthorizationAttributes(azMape);
-
-		assertThat(token.requestToken(tokenRequest), is("mock.jwt.value"));
-	}
-
-	@Test
-	@Deprecated
-	public void requestUserToken() throws URISyntaxException {
-		// prepare response
-		Map<String, Object> userToken = new HashMap<>();
-		Jwt mockJwt = buildMockJwt();
-		userToken.put(OAuth2TokenServiceConstants.ACCESS_TOKEN, mockJwt.getTokenValue());
-		userToken.put(OAuth2TokenServiceConstants.EXPIRES_IN, 43199);
-		userToken.put(OAuth2TokenServiceConstants.REFRESH_TOKEN, "a07356ec2e5449329ab6dd6728623bda");
-
-		// mock rest call
-		// http://myuaa.com/oauth/token?grant_type=client_credentials&authorities=%7B%22az_attr%22:%7B%22a%22:%22b%22,%22c%22:%22d%22%7D%7D
-		RestTemplate mockRestTemplate = Mockito.mock(RestTemplate.class);
-		ResponseEntity<Map> response = new ResponseEntity<>(userToken, HttpStatus.OK);
-		Mockito.when(mockRestTemplate.postForEntity(any(URI.class), any(HttpEntity.class), eq(Map.class)))
-				.thenReturn(response);
-
-		claimsSetBuilder.claim(TokenClaims.CLAIM_SCOPES, new String[] { "uaa.user" });
-		token = createToken(claimsSetBuilder);
-
-		String mockServerUrl = "http://myuaa.com";
-		XSTokenRequestImpl tokenRequest = new XSTokenRequestImpl(mockServerUrl);
-		tokenRequest.setRestTemplate(mockRestTemplate);
-		tokenRequest.setClientId("c1").setClientSecret("s1").setType(XSTokenRequest.TYPE_USER_TOKEN);
-
-		Map<String, String> azMape = new HashMap<>();
-		azMape.put("a", "b");
-		azMape.put("c", "d");
-		tokenRequest.setAdditionalAuthorizationAttributes(azMape);
-
-		assertThat(token.requestToken(tokenRequest), is("mock.jwt.value"));
-	}
-
 	private Jwt buildMockJwt() {
 		Map<String, Object> jwtHeaders = new HashMap<String, Object>();
 		jwtHeaders.put("dummyHeader", "dummyHeaderValue");
diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaAudienceValidatorForCloneTokenTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaAudienceValidatorForCloneTokenTest.java
index 8b1654ec..5fbf8503 100644
--- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaAudienceValidatorForCloneTokenTest.java
+++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaAudienceValidatorForCloneTokenTest.java
@@ -6,11 +6,6 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
-import com.nimbusds.jwt.JWTClaimsSet;
-import com.sap.cloud.security.xsuaa.DummyXsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.test.JwtGenerator;
-import com.sap.cloud.security.xsuaa.token.TokenClaims;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -18,6 +13,12 @@ import org.springframework.security.oauth2.core.OAuth2Error;
 import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
 import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
 
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.sap.cloud.security.xsuaa.DummyXsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.test.JwtGenerator;
+import com.sap.cloud.security.xsuaa.token.TokenClaims;
+
 public class XsuaaAudienceValidatorForCloneTokenTest {
 
 	private JWTClaimsSet.Builder claimsBuilder;
diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaAudienceValidatorTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaAudienceValidatorTest.java
index e7b918a3..0cddf0a8 100644
--- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaAudienceValidatorTest.java
+++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaAudienceValidatorTest.java
@@ -8,11 +8,6 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
-import com.nimbusds.jwt.JWTClaimsSet;
-import com.sap.cloud.security.xsuaa.DummyXsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
-import com.sap.cloud.security.xsuaa.test.JwtGenerator;
-import com.sap.cloud.security.xsuaa.token.TokenClaims;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -21,6 +16,12 @@ import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
 import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
 import org.springframework.security.oauth2.jwt.Jwt;
 
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.sap.cloud.security.xsuaa.DummyXsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration;
+import com.sap.cloud.security.xsuaa.test.JwtGenerator;
+import com.sap.cloud.security.xsuaa.token.TokenClaims;
+
 public class XsuaaAudienceValidatorTest {
 
 	private Jwt tokenWithAudience;
diff --git a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestClientCredentials.java b/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestClientCredentials.java
deleted file mode 100644
index 8b559bf9..00000000
--- a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestClientCredentials.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.sap.xs2.security.container;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.sap.xsa.security.container.XSUserInfoException;
-
-public class UserInfoTestClientCredentials {
-
-	private UserInfo infoCc = null;
-	private UserInfo infoCcNoAttr = null;
-
-	@Before
-	public void setup() throws Exception {
-		infoCc = UserInfoTestUtil.createFromJwtFile("/token_cc.txt", "java-hello-world");
-		infoCcNoAttr = UserInfoTestUtil.createFromJwtFile("/token_cc_noattr.txt", "java-hello-world");
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void getLogonNameCc() throws XSUserInfoException {
-		infoCc.getLogonName();
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void getEmailCc() throws XSUserInfoException {
-		infoCc.getEmail();
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void getGivenNameCc() throws XSUserInfoException {
-		infoCc.getGivenName();
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void getFamilyNameCc() throws XSUserInfoException {
-		infoCc.getFamilyName();
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void getOriginCc() throws XSUserInfoException {
-		Assert.assertNull(infoCc.getOrigin()); // not in samlUserInfo
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void getAttributeCc() throws XSUserInfoException {
-		infoCc.getAttribute("cost center");
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void getAttributeCcNotExisting() throws XSUserInfoException {
-		infoCcNoAttr.getAttribute("cost center");
-	}
-
-	@Test(expected = XSUserInfoException.class)
-	public void hasAttributesCc() throws XSUserInfoException {
-		infoCc.hasAttributes();
-	}
-
-	@Test
-	public void getTokenCc() throws XSUserInfoException {
-		Assert.assertNotNull("Token must not be null", infoCc.getHdbToken());
-		Assert.assertTrue(!infoCc.getHdbToken().isEmpty());
-		Assert.assertTrue(infoCc.getHdbToken().equals(infoCc.getToken("SYSTEM", "HDB")));
-		Assert.assertTrue(!infoCc.getAppToken().isEmpty());
-		Assert.assertTrue(infoCc.getAppToken().equals(infoCc.getToken("SYSTEM", "JobScheduler")));
-	}
-}
diff --git a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestEndUser.java b/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestEndUser.java
deleted file mode 100644
index 5367b1e8..00000000
--- a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestEndUser.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.sap.xs2.security.container;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.sap.xsa.security.container.XSUserInfoException;
-
-public class UserInfoTestEndUser {
-
-	private UserInfo correctEnduserInfo = null;
-	private UserInfo correctEnduserInfoWithUaaUser = null;
-
-	@Before
-	public void setup() throws Exception {
-		correctEnduserInfo = UserInfoTestUtil.createFromJwtFile("/correctEndUserToken.txt", "java-hello-world");
-		correctEnduserInfoWithUaaUser = UserInfoTestUtil.createFromJwtFile("/correctEndUserTokenUaaUser.txt",
-				"java-hello-world");
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void requestTokenForClientTestNoUaaUserScope() throws XSUserInfoException {
-		correctEnduserInfo.requestTokenForClient("foo", "bar", "foobar");
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void requestTokenForClientTestInvalidClientId() throws XSUserInfoException {
-		correctEnduserInfoWithUaaUser.requestTokenForClient(null, "foo", "bar");
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void requestTokenForClientTestInvalidClientSecret() throws XSUserInfoException {
-		correctEnduserInfoWithUaaUser.requestTokenForClient("foo", null, "bar");
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void requestTokenForClientTestInvalidUaaUrl() throws XSUserInfoException {
-		correctEnduserInfoWithUaaUser.requestTokenForClient("foo", "bar", null);
-	}
-}
diff --git a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestSAML.java b/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestSAML.java
deleted file mode 100644
index c7417bb5..00000000
--- a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestSAML.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.sap.xs2.security.container;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-public class UserInfoTestSAML {
-
-	UserInfo samlUserInfo = null;
-
-	@Before
-	public void setup() throws Exception {
-		samlUserInfo = UserInfoTestUtil.createFromTemplate("/saml.txt", "java-hello-world");
-	}
-
-	@Test
-	public void testSAMLToken() throws Exception {
-		// attributes - old style
-		Assert.assertEquals(2, samlUserInfo.getAttribute("cost-center").length);
-		Assert.assertEquals("0815", samlUserInfo.getAttribute("cost-center")[0]);
-		Assert.assertEquals("4711", samlUserInfo.getAttribute("cost-center")[1]);
-		Assert.assertEquals(1, samlUserInfo.getAttribute("country").length);
-		Assert.assertEquals("Germany", samlUserInfo.getAttribute("country")[0]);
-
-		// scopes
-		Assert.assertEquals(true, samlUserInfo.checkLocalScope("Display"));
-		Assert.assertEquals(true, samlUserInfo.checkLocalScope("Create"));
-		Assert.assertEquals(true, samlUserInfo.checkLocalScope("Delete"));
-		Assert.assertEquals(false, samlUserInfo.checkLocalScope("Other"));
-		// client id
-		Assert.assertEquals("sb-java-hello-world", samlUserInfo.getClientId());
-		// grant type
-		Assert.assertEquals("authorization_code", samlUserInfo.getGrantType());
-
-		// logon name
-		Assert.assertEquals("Mustermann", samlUserInfo.getLogonName());
-		// email
-		Assert.assertEquals("max@example.com", samlUserInfo.getEmail());
-		// zone
-		Assert.assertEquals("11-22-33", samlUserInfo.getIdentityZone());
-		Assert.assertEquals("11-22-33", samlUserInfo.getSubaccountId());
-		// embedded SAML
-		Assert.assertNotNull(samlUserInfo.getHdbToken());
-		// ext attr
-		Assert.assertEquals("domain\\group1", samlUserInfo.getAdditionalAuthAttribute("external_group"));
-		Assert.assertEquals("abcd1234", samlUserInfo.getAdditionalAuthAttribute("external_id"));
-		// subdomain
-		Assert.assertEquals("testsubdomain", samlUserInfo.getSubdomain());
-		// service instance id
-		Assert.assertEquals("abcd1234", samlUserInfo.getCloneServiceInstanceId());
-		// groups
-		Assert.assertEquals(1, samlUserInfo.getSystemAttribute("xs.saml.groups").length);
-		Assert.assertEquals("g1", samlUserInfo.getSystemAttribute("xs.saml.groups")[0]);
-		// role collections
-		Assert.assertEquals(1, samlUserInfo.getSystemAttribute("xs.rolecollections").length);
-		Assert.assertEquals("rc1", samlUserInfo.getSystemAttribute("xs.rolecollections")[0]);
-	}
-}
diff --git a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestUser.java b/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestUser.java
deleted file mode 100644
index c5819ae6..00000000
--- a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestUser.java
+++ /dev/null
@@ -1,186 +0,0 @@
-package com.sap.xs2.security.container;
-
-import java.util.Calendar;
-import java.util.TimeZone;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import com.sap.xsa.security.container.XSUserInfoException;
-
-import net.minidev.json.parser.ParseException;
-
-public class UserInfoTestUser {
-
-	private UserInfo infoUser = null;
-	private UserInfo infoUserNoAttr = null;
-
-	@Before
-	public void setup() throws Exception {
-		infoUser = UserInfoTestUtil.createFromJwtFile("/token_user.txt", "java-hello-world");
-		infoUserNoAttr = UserInfoTestUtil.createFromJwtFile("/token_user_noattr.txt", "java-hello-world");
-	}
-
-	@Test
-	public void testSAMLToken() throws Exception {
-
-		UserInfo token = UserInfoTestUtil.createFromTemplate("/saml.txt", "java-hello-world");
-		// attributes - old style
-		Assert.assertEquals(2, token.getAttribute("cost-center").length);
-		Assert.assertEquals("0815", token.getAttribute("cost-center")[0]);
-		Assert.assertEquals("4711", token.getAttribute("cost-center")[1]);
-		Assert.assertEquals(1, token.getAttribute("country").length);
-		Assert.assertEquals("Germany", token.getAttribute("country")[0]);
-
-		// scopes
-		Assert.assertEquals(true, token.checkLocalScope("Display"));
-		Assert.assertEquals(true, token.checkLocalScope("Create"));
-		Assert.assertEquals(true, token.checkLocalScope("Delete"));
-		Assert.assertEquals(false, token.checkLocalScope("Other"));
-		// client id
-		Assert.assertEquals("sb-java-hello-world", token.getClientId());
-		// grant type
-		Assert.assertEquals("authorization_code", token.getGrantType());
-
-		// logon name
-		Assert.assertEquals("Mustermann", token.getLogonName());
-		// email
-		Assert.assertEquals("max@example.com", token.getEmail());
-		// zone
-		Assert.assertEquals("11-22-33", token.getIdentityZone());
-		Assert.assertEquals("11-22-33", token.getSubaccountId());
-		// embedded SAML
-		Assert.assertNotNull(token.getHdbToken());
-		// ext attr
-		Assert.assertEquals("domain\\group1", token.getAdditionalAuthAttribute("external_group"));
-		Assert.assertEquals("abcd1234", token.getAdditionalAuthAttribute("external_id"));
-		// subdomain
-		Assert.assertEquals("testsubdomain", token.getSubdomain());
-		// service instance id
-		Assert.assertEquals("abcd1234", token.getCloneServiceInstanceId());
-		// groups
-		Assert.assertEquals(1, token.getSystemAttribute("xs.saml.groups").length);
-		Assert.assertEquals("g1", token.getSystemAttribute("xs.saml.groups")[0]);
-		// role collections
-		Assert.assertEquals(1, token.getSystemAttribute("xs.rolecollections").length);
-		Assert.assertEquals("rc1", token.getSystemAttribute("xs.rolecollections")[0]);
-	}
-
-	@Test
-	public void getLogonName() throws XSUserInfoException {
-		Assert.assertEquals("WOLFGANG", infoUser.getLogonName());
-	}
-
-	@Test
-	public void getEmail() throws XSUserInfoException {
-		Assert.assertEquals("WOLFGANG@unknown", infoUser.getEmail());
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void getGivenName() throws XSUserInfoException {
-		infoUser.getGivenName(); // not in samlUserInfo
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void getFamilyName() throws XSUserInfoException {
-		infoUser.getFamilyName(); // not in samlUserInfo
-	}
-
-	@Test
-	public void getOrigin() throws XSUserInfoException {
-		Assert.assertEquals("useridp", infoUser.getOrigin());
-	}
-
-	@Ignore
-	@Test
-	public void getJwtAlg() throws XSUserInfoException {
-		// Assert.assertEquals(1, infoUser.getJwtAlgId());
-	}
-
-	@Test
-	public void getIdentityZone() throws UserInfoException {
-		Assert.assertEquals("uaa", infoUser.getIdentityZone());
-		Assert.assertEquals("uaa", infoUser.getSubaccountId());
-	}
-
-	@Test
-	public void getClientId() throws UserInfoException {
-		Assert.assertEquals("sb-java-hello-world", infoUser.getClientId());
-	}
-
-	@Test
-	public void getExpirationDate() throws UserInfoException {
-		// Expected date: Tue Sep 22 22:55:22 CEST 2015
-		Calendar calendar = Calendar.getInstance();
-		calendar.setTime(infoUser.getExpirationDate());
-		calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
-		Assert.assertEquals("Year", 2015, calendar.get(Calendar.YEAR));
-		Assert.assertEquals("Month", Calendar.SEPTEMBER, calendar.get(Calendar.MONTH));
-		Assert.assertEquals("Day", 22, calendar.get(Calendar.DAY_OF_MONTH));
-		Assert.assertEquals("Hours", 20, calendar.get(Calendar.HOUR_OF_DAY));
-		Assert.assertEquals("Minutes", 55, calendar.get(Calendar.MINUTE));
-		Assert.assertEquals("Seconds", 22, calendar.get(Calendar.SECOND));
-	}
-
-	@Test
-	public void checkScope() throws UserInfoException {
-		Assert.assertEquals(false, infoUser.checkScope("cloud_controller.read"));
-		Assert.assertEquals(true, infoUser.checkScope("java-hello-world.Display"));
-	}
-
-	@Test
-	public void checkLocalScopeXsappname() throws UserInfoException {
-		infoUser.setXSAppname("cloud_controller");
-		Assert.assertEquals(false, infoUser.checkLocalScope("read"));
-		infoUser.setXSAppname("java-hello-world");
-		Assert.assertEquals(true, infoUser.checkLocalScope("Display"));
-	}
-
-	@Test
-	public void getAttribute() throws XSUserInfoException {
-		String[] cost_center = infoUser.getAttribute("cost center");
-		Assert.assertEquals(2, cost_center.length);
-		Assert.assertEquals("0815", cost_center[0]);
-		Assert.assertEquals("4711", cost_center[1]);
-		String[] country = infoUser.getAttribute("country");
-		Assert.assertEquals(1, country.length);
-		Assert.assertEquals("Germany", country[0]);
-	}
-
-	@Test
-	public void testServiceInstanceId() throws XSUserInfoException {
-		Assert.assertEquals("abcd1234", infoUser.getCloneServiceInstanceId());
-	}
-
-	@Test
-	public void testAdditionalAuthAttr() throws XSUserInfoException {
-		Assert.assertEquals("abcd1234", infoUser.getAdditionalAuthAttribute("external_id"));
-	}
-
-	@Test
-	public void getToken() throws XSUserInfoException {
-		Assert.assertNotNull("Token must not be null", infoUser.getHdbToken());
-		Assert.assertTrue(!infoUser.getHdbToken().isEmpty());
-		Assert.assertTrue(infoUser.getHdbToken().equals(infoUser.getToken("SYSTEM", "HDB")));
-		Assert.assertTrue(!infoUser.getAppToken().isEmpty());
-		Assert.assertTrue(infoUser.getAppToken().equals(infoUser.getToken("SYSTEM", "JobScheduler")));
-	}
-
-	@Test(expected = UserInfoException.class)
-	public void getAttributeNotExisting() throws XSUserInfoException {
-		infoUserNoAttr.getAttribute("cost center");
-	}
-
-	@Test(expected = XSUserInfoException.class)
-	public void testFailServiceInstanceIdNoId() throws XSUserInfoException {
-		Assert.assertEquals("abcd1234", infoUserNoAttr.getCloneServiceInstanceId());
-	}
-
-	@Test(expected = XSUserInfoException.class)
-	public void testFailAdditionalAuthAttrNoAttr() throws XSUserInfoException {
-		Assert.assertEquals("abcd1234", infoUserNoAttr.getAdditionalAuthAttribute("external_id"));
-	}
-
-}
diff --git a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestUtil.java b/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestUtil.java
deleted file mode 100644
index 4bb3fed1..00000000
--- a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestUtil.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.sap.xs2.security.container;
-
-import java.io.IOException;
-import java.nio.charset.Charset;
-
-import org.apache.commons.io.IOUtils;
-import org.springframework.security.oauth2.jwt.Jwt;
-
-import com.sap.cloud.security.xsuaa.test.JwtGenerator;
-
-public class UserInfoTestUtil {
-
-	public static UserInfo createFromTemplate(String pathToTemplate, String appName) throws IOException {
-		Jwt jwt = new JwtGenerator().createFromTemplate(pathToTemplate);
-		return new UserInfo(jwt, appName);
-	}
-
-	public static UserInfo createFromJwtFile(String pathToJwt, String appName) throws IOException {
-		String token = IOUtils.resourceToString(pathToJwt, Charset.forName("UTF-8"));
-		Jwt jwt = JwtGenerator.convertTokenToOAuthJwt(token);
-		return new UserInfo(jwt, appName);
-	}
-}
\ No newline at end of file
diff --git a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/XSTokenRequestImplTest.java b/spring-xsuaa/src/test/java/com/sap/xs2/security/container/XSTokenRequestImplTest.java
deleted file mode 100644
index 3999ca73..00000000
--- a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/XSTokenRequestImplTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.sap.xs2.security.container;
-
-import static org.junit.Assert.*;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.HashMap;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.sap.xsa.security.container.XSTokenRequest;
-
-public class XSTokenRequestImplTest {
-
-	private XSTokenRequest request;
-
-	@Before
-	public void setUp() throws Exception {
-		request = new XSTokenRequestImpl("http://localhost:8080/uaa/oauth/samlUserInfo");
-	}
-
-	@Test
-	public void test_setTokenEndpoint() throws URISyntaxException {
-		URI tokenEndpoint = new URI("http://localhost:8080/uaa/oauth/samlUserInfo");
-		request.setTokenEndpoint(tokenEndpoint);
-		assertEquals(request.getTokenEndpoint().toString(), "http://localhost:8080/uaa/oauth/samlUserInfo");
-	}
-
-	@Test(expected = URISyntaxException.class)
-	public void test_setTokenEndpoint_fails_UriSyntax() throws URISyntaxException {
-		URI tokenEndpoint = new URI("PC_DEV2::localhost:8080/uaa/oauth/samlUserInfo");
-		request.setTokenEndpoint(tokenEndpoint);
-	}
-
-	@Test
-	public void test_is_user_token_grant_valid() throws Exception {
-		assertFalse(request.isValid());
-		assertFalse(request.setType(XSTokenRequest.TYPE_USER_TOKEN).isValid());
-		assertFalse(request.setClientId("client_id").isValid());
-		assertTrue(request.setClientSecret("client_secret").isValid());
-	}
-
-	@Test
-	public void test_is_client_credentials_grant_valid() throws Exception {
-		assertFalse(request.isValid());
-		assertFalse(request.setType(XSTokenRequest.TYPE_CLIENT_CREDENTIALS_TOKEN).isValid());
-		assertFalse(request.setClientId("client_id").isValid());
-		assertTrue(request.setClientSecret("client_secret").isValid());
-	}
-
-	@Test
-	public void test_additional_authorization_attributes() throws Exception {
-		HashMap<String, String> map = new HashMap<>();
-		map.put("foo", "bar");
-		map.put("key", "value");
-		request.setAdditionalAuthorizationAttributes(map);
-		assertEquals("bar", request.getAdditionalAuthorizationAttributes().get("foo"));
-		assertEquals("value", request.getAdditionalAuthorizationAttributes().get("key"));
-		assertFalse(request.getAdditionalAuthorizationAttributes().containsKey("hugo"));
-	}
-
-	@Test
-	public void test_additional_authorization_attributes_null() throws Exception {
-		request.setAdditionalAuthorizationAttributes(null);
-		assertNull(request.getAdditionalAuthorizationAttributes());
-		HashMap<String, String> map = new HashMap<>();
-		request.setAdditionalAuthorizationAttributes(map);
-		assertNull(request.getAdditionalAuthorizationAttributes().get(null));
-		assertNotNull(request.getAdditionalAuthorizationAttributes());
-		/*
-		 * assertEquals("bar",
-		 * request.getAdditionalAuthorizationAttributes().get("foo"));
-		 * assertEquals("value",
-		 * request.getAdditionalAuthorizationAttributes().get("key"));
-		 * assertFalse(request.getAdditionalAuthorizationAttributes().containsKey("hugo"
-		 * ));
-		 */
-	}
-}
diff --git a/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/ClientCredentialsTest.java b/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/ClientCredentialsTest.java
index 8bdd7963..36dd8189 100644
--- a/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/ClientCredentialsTest.java
+++ b/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/ClientCredentialsTest.java
@@ -1,7 +1,9 @@
 package com.sap.cloud.security.xsuaa.client;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.ArgumentMatchers.isNotNull;
 
 import org.junit.Test;
 
@@ -9,16 +11,29 @@ public class ClientCredentialsTest {
 	ClientCredentials cut = new ClientCredentials("clientId", "clientSecret");
 
 	@Test
-	public void clientCredentials_equals() {
+	public void equals() {
 		assertThat(cut.equals(cut), is(true));
 		assertThat(cut.equals(new ClientCredentials("clientId", "clientSecret")), is(true));
 	}
 
 	@Test
-	public void clientCredentials_notequals() {
+	public void not_equals() {
 		assertThat(cut.equals(new ClientCredentials("clientId2", "clientSecret")), is(false));
 		assertThat(cut.equals(new ClientCredentials("clientId", "clientSecret2")), is(false));
 		assertThat(cut.equals(null), is(false));
 		assertThat(cut.equals(new Object()), is(false));
 	}
+
+	@Test
+	public void hashCoded() {
+		int cutHashCode = cut.hashCode();
+		assertThat(cutHashCode, is(not(0)));
+		assertThat(cutHashCode, is(new ClientCredentials("clientId", "clientSecret").hashCode()));
+		assertThat(cutHashCode, is(not(new ClientCredentials("clientId2", "clientSecret").hashCode())));
+	}
+
+	@Test
+	public void stringify() {
+		assertThat(cut.toString(), is("clientId:clientSecret"));
+	}
 }
diff --git a/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenServicePasswordTest.java b/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenServicePasswordTest.java
new file mode 100644
index 00000000..6f20770c
--- /dev/null
+++ b/token-client/src/test/java/com/sap/cloud/security/xsuaa/client/XsuaaOAuth2TokenServicePasswordTest.java
@@ -0,0 +1,197 @@
+package com.sap.cloud.security.xsuaa.client;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.http.*;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.RestOperations;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.sap.cloud.security.xsuaa.client.OAuth2TokenServiceConstants.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class XsuaaOAuth2TokenServicePasswordTest {
+
+	private OAuth2TokenService cut;
+
+	private String clientSecret = "test321";
+	private String clientId = "theClientId";
+	private String password = "test123";
+	private String username = "bob";
+	private String subdomain = "subdomain";
+	private ClientCredentials clientCredentials = new ClientCredentials(clientId, clientSecret);
+	private URI tokenEndpoint = URI.create("https://subdomain.myauth.server.com/oauth/token");
+	private Map<String, String> optionalParameters;
+	private Map<String, String> response;
+
+	@Mock
+	private RestOperations mockRestOperations;
+
+	@Before
+	public void setup() {
+		response = new HashMap();
+		response.putIfAbsent(ACCESS_TOKEN, "f529.dd6e30.d454677322aaabb0");
+		response.putIfAbsent(EXPIRES_IN, "43199");
+		when(mockRestOperations.postForEntity(any(), any(), any()))
+				.thenReturn(ResponseEntity.status(200).body(response));
+		optionalParameters = new HashMap<>();
+		cut = new XsuaaOAuth2TokenService(mockRestOperations);
+	}
+
+	@Test(expected = OAuth2ServiceException.class)
+	public void retrieveToken_httpStatusUnauthorized_throwsException() throws OAuth2ServiceException {
+		throwExceptionOnPost(HttpStatus.UNAUTHORIZED);
+
+		cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, clientCredentials,
+				username, password, null, null);
+	}
+
+	@Test(expected = OAuth2ServiceException.class)
+	public void retrieveToken_httpStatusNotOk_throwsException() throws OAuth2ServiceException {
+		throwExceptionOnPost(HttpStatus.BAD_REQUEST);
+
+		cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, clientCredentials,
+				username, password, null, null);
+	}
+
+	@Test
+	public void retrieveToken_requiredParametersMissing_throwsException() {
+		assertThatThrownBy(() -> cut.retrieveAccessTokenViaPasswordGrant(null, clientCredentials,
+				username, password, subdomain, optionalParameters)).isInstanceOf(IllegalArgumentException.class);
+		assertThatThrownBy(() -> cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, null,
+				username, password, subdomain, optionalParameters)).isInstanceOf(IllegalArgumentException.class);
+		assertThatThrownBy(() -> cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, clientCredentials,
+				null, password, subdomain, optionalParameters)).isInstanceOf(IllegalArgumentException.class);
+		assertThatThrownBy(() -> cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, clientCredentials,
+				username, null, subdomain, optionalParameters)).isInstanceOf(IllegalArgumentException.class);
+	}
+
+	@Test
+	public void retrieveToken_callsTokenEndpoint() throws OAuth2ServiceException {
+		cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, clientCredentials,
+				username, password, null, null);
+
+		Mockito.verify(mockRestOperations, times(1))
+				.postForEntity(eq(tokenEndpoint), any(), any());
+	}
+
+	@Test
+	public void retrieveToken_setsCorrectGrantType() throws OAuth2ServiceException {
+		cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, clientCredentials,
+				username, password, null, null);
+
+		ArgumentCaptor<HttpEntity<MultiValueMap<String, String>>> requestEntityCaptor = captureRequestEntity();
+
+		String actualGrantType = valueOfParameter(GRANT_TYPE, requestEntityCaptor);
+		assertThat(actualGrantType).isEqualTo(GRANT_TYPE_PASSWORD);
+	}
+
+	@Test
+	public void retrieveToken_setsUsername() throws OAuth2ServiceException {
+		cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, clientCredentials,
+				username, password, null, null);
+
+		ArgumentCaptor<HttpEntity<MultiValueMap<String, String>>> requestEntityCaptor = captureRequestEntity();
+
+		assertThat(valueOfParameter(USERNAME, requestEntityCaptor)).isEqualTo(username);
+	}
+
+	@Test
+	public void retrieveToken_setsPassword() throws OAuth2ServiceException {
+		cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, clientCredentials,
+				username, password, null, null);
+
+		ArgumentCaptor<HttpEntity<MultiValueMap<String, String>>> requestEntityCaptor = captureRequestEntity();
+
+		assertThat(valueOfParameter(PASSWORD, requestEntityCaptor)).isEqualTo(password);
+	}
+
+	@Test
+	public void retrieveToken_setsClientCredentials() throws OAuth2ServiceException {
+		cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, clientCredentials,
+				username, password, null, null);
+
+		ArgumentCaptor<HttpEntity<MultiValueMap<String, String>>> requestEntityCaptor = captureRequestEntity();
+
+		assertThat(valueOfParameter(CLIENT_ID, requestEntityCaptor)).isEqualTo(clientCredentials.getId());
+		assertThat(valueOfParameter(CLIENT_SECRET, requestEntityCaptor)).isEqualTo(clientCredentials.getSecret());
+	}
+
+	@Test
+	public void retrieveToken_setsOptionalParameters() throws OAuth2ServiceException {
+		String tokenFormatParameterKey = "token_format";
+		String tokenFormat = "opaque";
+		String loginHintParameterKey = "login_hint";
+		String loginHint = "origin";
+
+		optionalParameters.put(tokenFormatParameterKey, tokenFormat);
+		optionalParameters.put(loginHintParameterKey, loginHint);
+
+		cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, clientCredentials,
+				username, password, null, optionalParameters);
+
+		ArgumentCaptor<HttpEntity<MultiValueMap<String, String>>> requestEntityCaptor = captureRequestEntity();
+		assertThat(valueOfParameter(tokenFormatParameterKey, requestEntityCaptor)).isEqualTo(tokenFormat);
+		assertThat(valueOfParameter(loginHintParameterKey, requestEntityCaptor)).isEqualTo(loginHint);
+	}
+
+	@Test
+	public void retrieveToken_setsCorrectHeaders() throws OAuth2ServiceException {
+		cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, clientCredentials,
+				username, password, null, optionalParameters);
+
+		ArgumentCaptor<HttpEntity<MultiValueMap<String, String>>> requestEntityCaptor = captureRequestEntity();
+		HttpHeaders headers = requestEntityCaptor.getValue().getHeaders();
+
+		assertThat(headers.getAccept()).containsExactly(MediaType.APPLICATION_JSON);
+		assertThat(headers.getContentType()).isEqualTo(MediaType.APPLICATION_FORM_URLENCODED);
+	}
+
+	@Test
+	public void retrieveToken() throws OAuth2ServiceException {
+		OAuth2TokenResponse actualResponse = cut.retrieveAccessTokenViaPasswordGrant(tokenEndpoint, clientCredentials,
+				username, password, null, null);
+
+		assertThat(actualResponse.getAccessToken()).isEqualTo(response.get(ACCESS_TOKEN));
+
+		assertThat(actualResponse.getExpiredAtDate()).isNotNull();
+	}
+
+	private ArgumentCaptor<HttpEntity<MultiValueMap<String, String>>> captureRequestEntity() {
+		ArgumentCaptor<HttpEntity<MultiValueMap<String, String>>> requestEntityCaptor = ArgumentCaptor
+				.forClass(HttpEntity.class);
+		Mockito.verify(mockRestOperations, times(1))
+				.postForEntity(
+						eq(tokenEndpoint),
+						requestEntityCaptor.capture(),
+						eq(Map.class));
+		return requestEntityCaptor;
+	}
+
+	private String valueOfParameter(
+			String parameterKey, ArgumentCaptor<HttpEntity<MultiValueMap<String, String>>> requestEntityCaptor) {
+		MultiValueMap<String, String> body = requestEntityCaptor.getValue().getBody();
+		return body.getFirst(parameterKey);
+	}
+
+	private void throwExceptionOnPost(HttpStatus unauthorized) {
+		when(mockRestOperations.postForEntity(any(), any(), any()))
+				.thenThrow(new HttpClientErrorException(unauthorized));
+	}
+
+}
\ No newline at end of file