diff --git a/apps/backend-api-springboot3/pom.xml b/apps/backend-api-springboot3/pom.xml
index cf7d7214..d7800d5d 100644
--- a/apps/backend-api-springboot3/pom.xml
+++ b/apps/backend-api-springboot3/pom.xml
@@ -1,83 +1,88 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-starter-parent</artifactId>
-        <version>3.0.2</version>
-        <relativePath/> <!-- lookup parent from repository -->
-    </parent>
-    <groupId>com.example</groupId>
-    <artifactId>backend-api-springboot3</artifactId>
-    <version>0.0.1-SNAPSHOT</version>
-    <name>backend-api-springboot3</name>
-    <description>backend-api-springboot3</description>
-    <properties>
-        <java.version>17</java.version>
-    </properties>
-    <dependencies>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-devtools</artifactId>
-            <scope>runtime</scope>
-            <optional>true</optional>
-        </dependency>
-
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-test</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>com.c4-soft.springaddons</groupId>
-            <artifactId>spring-addons-oauth2-test</artifactId>
-            <version>6.0.12</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.springframework.boot</groupId>
-                <artifactId>spring-boot-maven-plugin</artifactId>
-            </plugin>
-        </plugins>
-    </build>
-    <repositories>
-        <repository>
-            <id>spring-milestones</id>
-            <name>Spring Milestones</name>
-            <url>https://repo.spring.io/milestone</url>
-            <snapshots>
-                <enabled>false</enabled>
-            </snapshots>
-        </repository>
-    </repositories>
-    <pluginRepositories>
-        <pluginRepository>
-            <id>spring-milestones</id>
-            <name>Spring Milestones</name>
-            <url>https://repo.spring.io/milestone</url>
-            <snapshots>
-                <enabled>false</enabled>
-            </snapshots>
-        </pluginRepository>
-    </pluginRepositories>
-
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>3.0.2</version>
+		<relativePath /> <!-- lookup parent from repository -->
+	</parent>
+	<groupId>com.example</groupId>
+	<artifactId>backend-api-springboot3</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+	<name>backend-api-springboot3</name>
+	<description>backend-api-springboot3</description>
+	<properties>
+		<java.version>17</java.version>
+		<spring-addons.version>6.0.12</spring-addons.version>
+	</properties>
+	<dependencies>
+		<dependency>
+			<groupId>com.c4-soft.springaddons</groupId>
+			<artifactId>spring-addons-webmvc-jwt-resource-server</artifactId>
+			<version>${spring-addons.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-devtools</artifactId>
+			<scope>runtime</scope>
+			<optional>true</optional>
+		</dependency>
+		<dependency>
+			<groupId>org.projectlombok</groupId>
+			<artifactId>lombok</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-test</artifactId>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.c4-soft.springaddons</groupId>
+			<artifactId>spring-addons-webmvc-jwt-test</artifactId>
+			<version>${spring-addons.version}</version>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+				<configuration>
+					<excludes>
+						<exclude>
+							<groupId>org.projectlombok</groupId>
+							<artifactId>lombok</artifactId>
+						</exclude>
+					</excludes>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+	<repositories>
+		<repository>
+			<id>spring-milestones</id>
+			<name>Spring Milestones</name>
+			<url>https://repo.spring.io/milestone</url>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+		</repository>
+	</repositories>
+	<pluginRepositories>
+		<pluginRepository>
+			<id>spring-milestones</id>
+			<name>Spring Milestones</name>
+			<url>https://repo.spring.io/milestone</url>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+		</pluginRepository>
+	</pluginRepositories>
 </project>
diff --git a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/AccessController.java b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/AccessController.java
new file mode 100644
index 00000000..1a0bbe12
--- /dev/null
+++ b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/AccessController.java
@@ -0,0 +1,31 @@
+package com.acme.backend.springboot.users.config;
+
+import java.util.function.Supplier;
+
+import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Example for generic custom access checks on request level.
+ */
+@Slf4j
+public class AccessController {
+
+	private static final AuthorizationDecision GRANTED = new AuthorizationDecision(true);
+	private static final AuthorizationDecision DENIED = new AuthorizationDecision(false);
+
+	public static AuthorizationDecision checkAccess(Supplier<Authentication> authentication, RequestAuthorizationContext requestContext) {
+
+		var auth = authentication.get();
+		if (auth == null) {
+			log.warn("Authentication provider returned null authentication");
+			return DENIED;
+		}
+		log.info("Check access for username={} path={}", auth.getName(), requestContext.getRequest().getRequestURI());
+		return auth.getAuthorities().stream().map(GrantedAuthority::getAuthority).filter("ROLE_ACCESS"::equals).count() > 0 ? GRANTED : DENIED;
+	}
+}
diff --git a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/AcmeServiceProperties.java b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/AcmeServiceProperties.java
deleted file mode 100644
index 90af5ecf..00000000
--- a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/AcmeServiceProperties.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.acme.backend.springboot.users.config;
-
-import lombok.Getter;
-import lombok.Setter;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-
-@Getter
-@Setter
-@Component
-@ConfigurationProperties(prefix = "acme")
-public class AcmeServiceProperties {
-
-    private KeycloakJwtProperties jwt = new KeycloakJwtProperties();
-
-    /**
-     * Specifies JWT client ID, issuer URI and allowed audiences
-     * for validation
-     */
-    @Getter
-    @Setter
-    public static class KeycloakJwtProperties {
-
-        private String clientId;
-
-        private String issuerUri;
-
-        private List<String> allowedAudiences;
-    }
-
-}
diff --git a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/JwtSecurityConfig.java b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/JwtSecurityConfig.java
deleted file mode 100644
index 6b5f55d7..00000000
--- a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/JwtSecurityConfig.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.acme.backend.springboot.users.config;
-
-import com.acme.backend.springboot.users.support.keycloak.KeycloakGrantedAuthoritiesConverter;
-import com.acme.backend.springboot.users.support.keycloak.KeycloakJwtAuthenticationConverter;
-import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
-import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
-import org.springframework.security.oauth2.core.OAuth2TokenValidator;
-import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
-import org.springframework.security.oauth2.jwt.Jwt;
-import org.springframework.security.oauth2.jwt.JwtDecoder;
-import org.springframework.security.oauth2.jwt.JwtIssuerValidator;
-import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
-import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Configures JWT handling (decoder and validator)
- */
-@Configuration
-class JwtSecurityConfig {
-
-    /**
-     * Configures a decoder with the specified validators (validation key fetched from JWKS endpoint)
-     *
-     * @param validators validators for the given key
-     * @param properties key properties (provides JWK location)
-     * @return the decoder bean
-     */
-    @Bean
-    JwtDecoder jwtDecoder(List<OAuth2TokenValidator<Jwt>> validators, OAuth2ResourceServerProperties properties) {
-
-        NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder //
-                .withJwkSetUri(properties.getJwt().getJwkSetUri()) //
-                .jwsAlgorithms(algs -> algs.addAll(Set.of(SignatureAlgorithm.RS256, SignatureAlgorithm.ES256))) //
-                .build();
-
-        jwtDecoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>(validators));
-
-        return jwtDecoder;
-    }
-
-    /**
-     * Configures the token validator. Specifies two additional validation constraints:
-     * <p>
-     * * Timestamp on the token is still valid
-     * * The issuer is the expected entity
-     *
-     * @param properties JWT resource specification
-     * @return token validator
-     */
-    @Bean
-    OAuth2TokenValidator<Jwt> defaultTokenValidator(OAuth2ResourceServerProperties properties) {
-
-        List<OAuth2TokenValidator<Jwt>> validators = new ArrayList<>();
-        validators.add(new JwtTimestampValidator());
-        validators.add(new JwtIssuerValidator(properties.getJwt().getIssuerUri()));
-
-        return new DelegatingOAuth2TokenValidator<>(validators);
-    }
-
-    @Bean
-    KeycloakJwtAuthenticationConverter keycloakJwtAuthenticationConverter(Converter<Jwt, Collection<GrantedAuthority>> authoritiesConverter) {
-        return new KeycloakJwtAuthenticationConverter(authoritiesConverter);
-    }
-
-    @Bean
-    Converter<Jwt, Collection<GrantedAuthority>> keycloakGrantedAuthoritiesConverter(GrantedAuthoritiesMapper authoritiesMapper, AcmeServiceProperties acmeServiceProperties) {
-        String clientId = acmeServiceProperties.getJwt().getClientId();
-        return new KeycloakGrantedAuthoritiesConverter(clientId, authoritiesMapper);
-    }
-
-}
diff --git a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/MethodSecurityConfig.java b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/MethodSecurityConfig.java
deleted file mode 100644
index 4a859ba0..00000000
--- a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/MethodSecurityConfig.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.acme.backend.springboot.users.config;
-
-import lombok.RequiredArgsConstructor;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.access.PermissionEvaluator;
-import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
-import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
-import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
-import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
-import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
-import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
-
-
-/**
- * Enables security annotations via like {@link org.springframework.security.access.prepost.PreAuthorize} and
- * {@link org.springframework.security.access.prepost.PostAuthorize} annotations per-method.
- */
-@Configuration
-@RequiredArgsConstructor
-@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
-class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
-
-    private final ApplicationContext applicationContext;
-
-    private final PermissionEvaluator permissionEvaluator;
-
-    @Override
-    protected MethodSecurityExpressionHandler createExpressionHandler() {
-
-        DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
-        expressionHandler.setApplicationContext(applicationContext);
-        expressionHandler.setPermissionEvaluator(permissionEvaluator);
-
-        return expressionHandler;
-    }
-
-    @Bean
-    GrantedAuthoritiesMapper keycloakAuthoritiesMapper() {
-
-        SimpleAuthorityMapper mapper = new SimpleAuthorityMapper();
-        mapper.setConvertToUpperCase(true);
-        return mapper;
-    }
-
-}
\ No newline at end of file
diff --git a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/WebSecurityConfig.java b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/WebSecurityConfig.java
index 5e303cf1..25b301f1 100644
--- a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/WebSecurityConfig.java
+++ b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/WebSecurityConfig.java
@@ -1,91 +1,38 @@
 package com.acme.backend.springboot.users.config;
 
-import com.acme.backend.springboot.users.support.access.AccessController;
-import com.acme.backend.springboot.users.support.keycloak.KeycloakJwtAuthenticationConverter;
-import lombok.RequiredArgsConstructor;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configurers.CorsConfigurer;
-import org.springframework.security.config.http.SessionCreationPolicy;
-import org.springframework.security.web.SecurityFilterChain;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
 
-import java.util.List;
+import com.c4_soft.springaddons.security.oauth2.config.synchronised.ExpressionInterceptUrlRegistryPostProcessor;
 
 /**
- * Configuration applied on all web endpoints defined for this
- * application. Any configuration on specific resources is applied
- * in addition to these global rules.
+ * Configuration applied on all web endpoints defined for this application. Any configuration on specific resources is applied in addition to these global
+ * rules.
+ * <ul>
+ * <li>Stateless session (no session kept server-side)</li>
+ * <li>CORS set up</li>
+ * <li>Require the role "ACCESS" for all api paths</li>
+ * <li>JWT converted into Spring token</li>
+ * </ul>
  */
 @Configuration
-@RequiredArgsConstructor
-class WebSecurityConfig {
-
-    private final KeycloakJwtAuthenticationConverter keycloakJwtAuthenticationConverter;
-
-    /**
-     * Configures basic security handler per HTTP session.
-     * <p>
-     * <ul>
-     * <li>Stateless session (no session kept server-side)</li>
-     * <li>CORS set up</li>
-     * <li>Require the role "ACCESS" for all api paths</li>
-     * <li>JWT converted into Spring token</li>
-     * </ul>
-     *
-     * @param http security configuration
-     * @throws Exception any error
-     */
-    @Bean
-    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
-
-        http.sessionManagement(smc -> {
-            smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
-        });
-        http.cors(this::configureCors);
-        http.authorizeHttpRequests(ahrc -> {
-            // declarative route configuration
-            // .mvcMatchers("/api").hasAuthority("ROLE_ACCESS")
-            ahrc.requestMatchers("/api/**").access(AccessController::checkAccess);
-            // add additional routes
-            ahrc.anyRequest().fullyAuthenticated(); //
-        });
-        http.oauth2ResourceServer(arsc -> {
-            arsc.jwt().jwtAuthenticationConverter(keycloakJwtAuthenticationConverter);
-        });
-
-        return http.build();
-    }
-
-    @Bean
-    AccessController accessController() {
-        return new AccessController();
-    }
-
-    /**
-     * Configures CORS to allow requests from localhost:30000
-     *
-     * @param cors mutable cors configuration
-     */
-    protected void configureCors(CorsConfigurer<HttpSecurity> cors) {
-
-        UrlBasedCorsConfigurationSource defaultUrlBasedCorsConfigSource = new UrlBasedCorsConfigurationSource();
-        CorsConfiguration corsConfiguration = new CorsConfiguration().applyPermitDefaultValues();
-        corsConfiguration.addAllowedOrigin("https://apps.acme.test:4443");
-        List.of("GET", "POST", "PUT", "DELETE").forEach(corsConfiguration::addAllowedMethod);
-        defaultUrlBasedCorsConfigSource.registerCorsConfiguration("/api/**", corsConfiguration);
-
-        cors.configurationSource(req -> {
-
-            CorsConfiguration config = new CorsConfiguration();
-
-            config = config.combine(defaultUrlBasedCorsConfigSource.getCorsConfiguration(req));
-
-            // check if request Header "origin" is in white-list -> dynamically generate cors config
-
-            return config;
-        });
-    }
+@EnableMethodSecurity(securedEnabled = true, proxyTargetClass = true)
+public class WebSecurityConfig {
+
+	/**
+	 * Default security requires users to be authenticated to all routes but those listed in "permit-all" property (see yaml file)
+	 *
+	 * @return a custom authorization registry for the routes not listed in "permit-all" property
+	 */
+	@Bean
+	ExpressionInterceptUrlRegistryPostProcessor expressionInterceptUrlRegistryPostProcessor() {
+		// @formatter:off
+        return (AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) -> registry
+        		.requestMatchers("/api/**").access(AccessController::checkAccess)
+                .anyRequest().fullyAuthenticated();
+        // @formatter:on
+	}
 }
\ No newline at end of file
diff --git a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/access/AccessController.java b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/access/AccessController.java
deleted file mode 100644
index 03f15cda..00000000
--- a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/access/AccessController.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.acme.backend.springboot.users.support.access;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.security.authorization.AuthorizationDecision;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
-
-import java.util.function.Supplier;
-
-/**
- * Example for generic custom access checks on request level.
- */
-@Slf4j
-public class AccessController {
-
-    private static final AuthorizationDecision GRANTED = new AuthorizationDecision(true);
-    private static final AuthorizationDecision DENIED = new AuthorizationDecision(false);
-
-    public static AuthorizationDecision checkAccess(Supplier<Authentication> authentication, RequestAuthorizationContext requestContext) {
-
-        var auth = authentication.get();
-        log.info("Check access for username={} path={}", auth.getName(), requestContext.getRequest().getRequestURI());
-
-        return GRANTED;
-    }
-}
diff --git a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakAudienceValidator.java b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakAudienceValidator.java
deleted file mode 100644
index c57420cc..00000000
--- a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakAudienceValidator.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.acme.backend.springboot.users.support.keycloak;
-
-import lombok.RequiredArgsConstructor;
-import org.springframework.security.oauth2.core.OAuth2Error;
-import org.springframework.security.oauth2.core.OAuth2TokenValidator;
-import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
-import org.springframework.security.oauth2.jwt.Jwt;
-import org.springframework.stereotype.Component;
-
-/**
- * Example class for custom audience (aud) or authorized party (azp) claim validations.
- */
-@Component
-@RequiredArgsConstructor
-class KeycloakAudienceValidator implements OAuth2TokenValidator<Jwt> {
-
-    private final OAuth2Error ERROR_INVALID_AUDIENCE = new OAuth2Error("invalid_token", "Invalid audience", null);
-
-    @Override
-    public OAuth2TokenValidatorResult validate(Jwt jwt) {
-
-//        String authorizedParty = jwt.getClaimAsString("azp");
-//
-//        if (!keycloakDataServiceProperties.getJwt().getAllowedAudiences().contains(authorizedParty)) {
-//            return OAuth2TokenValidatorResult.failure(ERROR_INVALID_AUDIENCE);
-//        }
-
-        return OAuth2TokenValidatorResult.success();
-    }
-}
diff --git a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakGrantedAuthoritiesConverter.java b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakGrantedAuthoritiesConverter.java
deleted file mode 100644
index 80a7f569..00000000
--- a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakGrantedAuthoritiesConverter.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.acme.backend.springboot.users.support.keycloak;
-
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
-import org.springframework.security.oauth2.jwt.Jwt;
-import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
-import org.springframework.util.CollectionUtils;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Allows to extract granted authorities from a given JWT. The authorities
- * are determined by combining the realm (overarching) and client (application-specific)
- * roles, and normalizing them (configure them to the default format).
- */
-public class KeycloakGrantedAuthoritiesConverter implements Converter<Jwt, Collection<GrantedAuthority>> {
-
-    private static final Converter<Jwt, Collection<GrantedAuthority>> JWT_SCOPE_GRANTED_AUTHORITIES_CONVERTER = new JwtGrantedAuthoritiesConverter();
-
-    private final String clientId;
-
-    private final GrantedAuthoritiesMapper authoritiesMapper;
-
-    public KeycloakGrantedAuthoritiesConverter(String clientId, GrantedAuthoritiesMapper authoritiesMapper) {
-        this.clientId = clientId;
-        this.authoritiesMapper = authoritiesMapper;
-    }
-
-    @Override
-    public Collection<GrantedAuthority> convert(Jwt jwt) {
-
-        Collection<GrantedAuthority> authorities = mapKeycloakRolesToAuthorities( //
-                getRealmRolesFrom(jwt), //
-                getClientRolesFrom(jwt, clientId) //
-        );
-
-        Collection<GrantedAuthority> scopeAuthorities = JWT_SCOPE_GRANTED_AUTHORITIES_CONVERTER.convert(jwt);
-        if(!CollectionUtils.isEmpty(scopeAuthorities)) {
-            authorities.addAll(scopeAuthorities);
-        }
-
-        return authorities;
-    }
-
-    protected Collection<GrantedAuthority> mapKeycloakRolesToAuthorities(Set<String> realmRoles, Set<String> clientRoles) {
-
-        List<GrantedAuthority> combinedAuthorities = new ArrayList<>();
-
-        combinedAuthorities.addAll(authoritiesMapper.mapAuthorities(realmRoles.stream() //
-                .map(SimpleGrantedAuthority::new) //
-                .collect(Collectors.toList())));
-
-        combinedAuthorities.addAll(authoritiesMapper.mapAuthorities(clientRoles.stream() //
-                .map(SimpleGrantedAuthority::new) //
-                .collect(Collectors.toList())));
-
-        return combinedAuthorities;
-    }
-
-    protected Set<String> getRealmRolesFrom(Jwt jwt) {
-
-        Map<String, Object> realmAccess = jwt.getClaimAsMap("realm_access");
-
-        if (CollectionUtils.isEmpty(realmAccess)) {
-            return Collections.emptySet();
-        }
-
-        @SuppressWarnings("unchecked")
-        Collection<String> realmRoles = (Collection<String>) realmAccess.get("roles");
-        if (CollectionUtils.isEmpty(realmRoles)) {
-            return Collections.emptySet();
-        }
-
-        return realmRoles.stream().map(this::normalizeRole).collect(Collectors.toSet());
-    }
-
-    protected Set<String> getClientRolesFrom(Jwt jwt, String clientId) {
-
-        Map<String, Object> resourceAccess = jwt.getClaimAsMap("resource_access");
-
-        if (CollectionUtils.isEmpty(resourceAccess)) {
-            return Collections.emptySet();
-        }
-
-        @SuppressWarnings("unchecked")
-        Map<String, List<String>> clientAccess = (Map<String, List<String>>) resourceAccess.get(clientId);
-        if (CollectionUtils.isEmpty(clientAccess)) {
-            return Collections.emptySet();
-        }
-
-        List<String> clientRoles = clientAccess.get("roles");
-        if (CollectionUtils.isEmpty(clientRoles)) {
-            return Collections.emptySet();
-        }
-
-        return clientRoles.stream().map(this::normalizeRole).collect(Collectors.toSet());
-    }
-
-    private String normalizeRole(String role) {
-        return role.replace('-', '_');
-    }
-}
diff --git a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakJwtAuthenticationConverter.java b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakJwtAuthenticationConverter.java
deleted file mode 100644
index 04e305bc..00000000
--- a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakJwtAuthenticationConverter.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.acme.backend.springboot.users.support.keycloak;
-
-import lombok.RequiredArgsConstructor;
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.security.authentication.AbstractAuthenticationToken;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.oauth2.jwt.Jwt;
-import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
-
-import java.util.Collection;
-
-/**
- * Converts a JWT into a Spring authentication token (by extracting
- * the username and roles from the claims of the token, delegating
- * to the {@link KeycloakGrantedAuthoritiesConverter})
- */
-@RequiredArgsConstructor
-public class KeycloakJwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken> {
-
-    private Converter<Jwt, Collection<GrantedAuthority>> grantedAuthoritiesConverter;
-
-    public KeycloakJwtAuthenticationConverter(Converter<Jwt, Collection<GrantedAuthority>> grantedAuthoritiesConverter) {
-        this.grantedAuthoritiesConverter = grantedAuthoritiesConverter;
-    }
-
-    @Override
-    public JwtAuthenticationToken convert(Jwt jwt) {
-
-        Collection<GrantedAuthority> authorities = grantedAuthoritiesConverter.convert(jwt);
-        String username = getUsernameFrom(jwt);
-
-        return new JwtAuthenticationToken(jwt, authorities, username);
-    }
-
-    protected String getUsernameFrom(Jwt jwt) {
-
-        if (jwt.hasClaim("preferred_username")) {
-            return jwt.getClaimAsString("preferred_username");
-        }
-
-        return jwt.getSubject();
-    }
-}
diff --git a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/permissions/DefaultPermissionEvaluator.java b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/permissions/DefaultPermissionEvaluator.java
deleted file mode 100644
index bff146b5..00000000
--- a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/permissions/DefaultPermissionEvaluator.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.acme.backend.springboot.users.support.permissions;
-
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.security.access.PermissionEvaluator;
-import org.springframework.security.core.Authentication;
-import org.springframework.stereotype.Component;
-
-import java.io.Serializable;
-
-/**
- * Custom {@link PermissionEvaluator} for method level permission checks.
- *
- * @see com.acme.backend.springboot.users.config.MethodSecurityConfig
- */
-@Slf4j
-@Component
-@RequiredArgsConstructor
-class DefaultPermissionEvaluator implements PermissionEvaluator {
-
-    @Override
-    public boolean hasPermission(Authentication auth, Object targetDomainObject, Object permission) {
-        log.info("check permission user={} target={} permission={}", auth.getName(), targetDomainObject, permission);
-
-        // TODO implement sophisticated permission check here
-        return true;
-    }
-
-    @Override
-    public boolean hasPermission(Authentication auth, Serializable targetId, String targetType, Object permission) {
-        DomainObjectReference dor = new DomainObjectReference(targetType, targetId.toString());
-        return hasPermission(auth, dor, permission);
-    }
-}
diff --git a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/permissions/DomainObjectReference.java b/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/permissions/DomainObjectReference.java
deleted file mode 100644
index 33207f15..00000000
--- a/apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/permissions/DomainObjectReference.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.acme.backend.springboot.users.support.permissions;
-
-import lombok.Data;
-
-/**
- * Defines a single domain object by a type and name to look up
- */
-@Data
-public class DomainObjectReference {
-
-    private final String type;
-
-    private final String id;
-}
diff --git a/apps/backend-api-springboot3/src/main/resources/application.yml b/apps/backend-api-springboot3/src/main/resources/application.yml
index 3092f247..3fc681cc 100644
--- a/apps/backend-api-springboot3/src/main/resources/application.yml
+++ b/apps/backend-api-springboot3/src/main/resources/application.yml
@@ -9,19 +9,29 @@ spring:
     oauth2:
       resourceserver:
         jwt:
-          issuer-uri: ${acme.jwt.issuerUri}
-          jwk-set-uri: ${acme.jwt.issuerUri}/protocol/openid-connect/certs
-# Use mock-service jwks-endpoint to obtain public key for testing
-#          jwk-set-uri: http://localhost:9999/jwks
+          audiences:
+          - https://localhost:${server.port}
 
-acme:
-  jwt:
-    issuerUri: https://id.acme.test:8443/auth/realms/acme-internal
+com:
+  c4-soft:
+    springaddons:
+      security:
+        issuers:
+          - location: https://localhost:8443/auth/realms/acme-internal
+            authorities:
+              claims:
+                - realm_access.roles
+                - resource_access.spring-addons-confidential.roles
+              caze: UPPER
+              prefix: ROLE_
+        cors:
+        - path: "/api/**"
+          allowed-origins: "https://localhost:4443"
+        permit-all: 
 
 server:
   port: 4623
   ssl:
     enabled: true
     key-store: ../../config/stage/dev/tls/acme.test+1.p12
-    key-store-password: changeit
-    key-store-type: PKCS12
\ No newline at end of file
+    key-store-password: changeit
\ No newline at end of file
diff --git a/apps/backend-api-springboot3/src/test/java/com/acme/backend/springboot/users/BackendApiSpringboot3AppTests.java b/apps/backend-api-springboot3/src/test/java/com/acme/backend/springboot/users/BackendApiSpringboot3AppTests.java
index 2cdd42de..d041dac0 100644
--- a/apps/backend-api-springboot3/src/test/java/com/acme/backend/springboot/users/BackendApiSpringboot3AppTests.java
+++ b/apps/backend-api-springboot3/src/test/java/com/acme/backend/springboot/users/BackendApiSpringboot3AppTests.java
@@ -3,7 +3,10 @@
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
 
+import com.c4_soft.springaddons.security.oauth2.test.webmvc.jwt.AutoConfigureAddonsWebSecurity;
+
 @SpringBootTest
+@AutoConfigureAddonsWebSecurity
 class BackendApiSpringboot3AppTests {
 
 	@Test
diff --git a/apps/backend-api-springboot3/src/test/java/com/acme/backend/springboot/users/web/UsersControllerTest.java b/apps/backend-api-springboot3/src/test/java/com/acme/backend/springboot/users/web/UsersControllerTest.java
index df418944..cad9a83b 100644
--- a/apps/backend-api-springboot3/src/test/java/com/acme/backend/springboot/users/web/UsersControllerTest.java
+++ b/apps/backend-api-springboot3/src/test/java/com/acme/backend/springboot/users/web/UsersControllerTest.java
@@ -8,36 +8,41 @@
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.context.annotation.Import;
 import org.springframework.test.web.servlet.MockMvc;
 
+import com.acme.backend.springboot.users.config.WebSecurityConfig;
 import com.c4_soft.springaddons.security.oauth2.test.annotations.OpenIdClaims;
 import com.c4_soft.springaddons.security.oauth2.test.annotations.WithMockJwtAuth;
+import com.c4_soft.springaddons.security.oauth2.test.webmvc.jwt.AutoConfigureAddonsWebSecurity;
 
 @WebMvcTest(controllers = UsersController.class)
+@AutoConfigureAddonsWebSecurity
+@Import(WebSecurityConfig.class)
 class UsersControllerTest {
 	@Autowired
 	MockMvc api;
 
 	@Test
-	void givenRequestIsAnonymous_whengetUsersMe_thenUnauthorized() throws Exception {
-		api.perform(get("/api/users/me")).andExpectAll(status().isUnauthorized());
+	void givenRequestIsAnonymous_whenGetUsersMe_thenUnauthorized() throws Exception {
+		api.perform(get("/api/users/me").secure(true)).andExpectAll(status().isUnauthorized());
 	}
 
 	@Test
 	@WithMockJwtAuth(claims = @OpenIdClaims(sub = "Tonton Pirate"))
-	void givenUserIsNotGrantedWithAccess_whengetUsersMe_thenForbidden() throws Exception {
+	void givenUserIsNotGrantedWithAccess_whenGetUsersMe_thenForbidden() throws Exception {
 		// @formatter:off
-        api.perform(get("/api/users/me"))
+        api.perform(get("/api/users/me").secure(true))
             // should be forbidden as user does is not granted with "ROLE_ACCESS"
-            .andExpect(status().isOk());
+            .andExpect(status().isForbidden());
         // @formatter:on
 	}
 
 	@Test
 	@WithMockJwtAuth(authorities = { "ROLE_ACCESS" }, claims = @OpenIdClaims(sub = "Tonton Pirate"))
-	void givenUserIsGrantedWithAccess_whengetUsersMe_thenOk() throws Exception {
+	void givenUserIsGrantedWithAccess_whenGetUsersMe_thenOk() throws Exception {
 		// @formatter:off
-        api.perform(get("/api/users/me"))
+        api.perform(get("/api/users/me").secure(true))
             .andExpect(status().isOk())
             .andExpect(jsonPath("$.message", is("Hello Tonton Pirate")));
         // @formatter:on