diff --git a/caching/pom.xml b/caching/pom.xml
index 24c76dc116501467ebe55038cc4e40be50c6ecb1..fdf98454b376a68b8a85541de02f6ab917d1d9df 100644
--- a/caching/pom.xml
+++ b/caching/pom.xml
@@ -9,7 +9,7 @@
     <parent>
         <groupId>org.eclipsefoundation</groupId>
         <artifactId>quarkus-commons</artifactId>
-        <version>1.0.3-SNAPSHOT</version>
+        <version>1.1.0</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <properties>
@@ -45,7 +45,7 @@
         <!-- Required for serialization -->
         <dependency>
             <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-resteasy-jackson</artifactId>
+            <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
         </dependency>
         <!-- Adds logging bindings for more natural logging -->
         <dependency>
@@ -81,7 +81,7 @@
 
         <dependency>
             <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-resteasy-qute</artifactId>
+            <artifactId>quarkus-resteasy-reactive-qute</artifactId>
         </dependency>
         <!-- Test dependencies -->
         <dependency>
@@ -137,4 +137,4 @@
             </plugin>
         </plugins>
     </build>
-</project>
\ No newline at end of file
+</project>
diff --git a/caching/src/main/java/org/eclipsefoundation/caching/model/ParameterizedCacheKey.java b/caching/src/main/java/org/eclipsefoundation/caching/model/ParameterizedCacheKey.java
index a8e1dd51a1d401221bbda940dd2e17348efd3488..be9b8a09e6017e3ac7f054227ca2809e4c1e1714 100644
--- a/caching/src/main/java/org/eclipsefoundation/caching/model/ParameterizedCacheKey.java
+++ b/caching/src/main/java/org/eclipsefoundation/caching/model/ParameterizedCacheKey.java
@@ -12,13 +12,13 @@
 package org.eclipsefoundation.caching.model;
 
 import org.eclipsefoundation.utils.helper.ParameterHelper;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
 import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
 import com.google.auto.value.AutoValue;
 
 import io.quarkus.arc.Arc;
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 
 /**
@@ -35,7 +35,7 @@ public abstract class ParameterizedCacheKey {
     public abstract MultivaluedMap<String, String> getParams();
 
     public static Builder builder() {
-        return new AutoValue_ParameterizedCacheKey.Builder().setParams(new MultivaluedMapImpl<>());
+        return new AutoValue_ParameterizedCacheKey.Builder().setParams(new MultivaluedHashMap<>());
     }
 
     @Override
diff --git a/caching/src/main/java/org/eclipsefoundation/caching/service/impl/QuarkusCachingService.java b/caching/src/main/java/org/eclipsefoundation/caching/service/impl/QuarkusCachingService.java
index 881216b6d37cc341d479e93a6cc06c71e31b4e8d..f1d3d156e7cd0a645c42763607fb261a4ba2bd47 100644
--- a/caching/src/main/java/org/eclipsefoundation/caching/service/impl/QuarkusCachingService.java
+++ b/caching/src/main/java/org/eclipsefoundation/caching/service/impl/QuarkusCachingService.java
@@ -29,7 +29,6 @@ import org.eclipsefoundation.caching.namespaces.CachingPropertyNames;
 import org.eclipsefoundation.caching.service.CachingService;
 import org.eclipsefoundation.http.model.RequestWrapper;
 import org.eclipsefoundation.http.namespace.DefaultUrlParameterNames;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,6 +42,7 @@ import io.quarkus.cache.CacheName;
 import io.quarkus.cache.CacheResult;
 import io.quarkus.cache.CaffeineCache;
 import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 
 /**
@@ -84,7 +84,7 @@ public class QuarkusCachingService implements CachingService {
             throw new IllegalStateException("Cached paginated data can only be used in the context of a request");
         }
         // copy the map to not mutate the passed reference when adding the pagination parameter
-        MultivaluedMap<String, String> paramMap = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> paramMap = new MultivaluedHashMap<>();
         if (params == null) {
             paramMap
                     .add(DefaultUrlParameterNames.PAGE_PARAMETER_NAME,
@@ -202,7 +202,7 @@ public class QuarkusCachingService implements CachingService {
      * @return the copied map, or an empty map if null
      */
     private MultivaluedMap<String, String> cloneMap(MultivaluedMap<String, String> paramMap) {
-        MultivaluedMap<String, String> out = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> out = new MultivaluedHashMap<>();
         if (paramMap != null) {
             paramMap.entrySet().forEach(e -> out.addAll(e.getKey(), e.getValue()));
         }
diff --git a/caching/src/test/java/org/eclipsefoundation/caching/service/impl/DefaultQuarkusCachingServiceTest.java b/caching/src/test/java/org/eclipsefoundation/caching/service/impl/DefaultQuarkusCachingServiceTest.java
index 265dc08d1e1af162ab5f6c047b3ef8c34b4ac70d..c22b63bb0b9da9340881fd37993af26f112b823f 100644
--- a/caching/src/test/java/org/eclipsefoundation/caching/service/impl/DefaultQuarkusCachingServiceTest.java
+++ b/caching/src/test/java/org/eclipsefoundation/caching/service/impl/DefaultQuarkusCachingServiceTest.java
@@ -17,7 +17,6 @@ import java.util.UUID;
 import org.eclipsefoundation.caching.model.CacheWrapper;
 import org.eclipsefoundation.caching.model.ParameterizedCacheKey;
 import org.eclipsefoundation.caching.service.CachingService;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -26,6 +25,7 @@ import io.quarkus.cache.CacheName;
 import io.quarkus.cache.CaffeineCache;
 import io.quarkus.test.junit.QuarkusTest;
 import jakarta.inject.Inject;
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 
 /**
@@ -62,7 +62,7 @@ class DefaultQuarkusCachingServiceTest {
         // check that we have no match for ID before proceeding
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
         // do the lookup
-        CacheWrapper<String> value = svc.get(id, new MultivaluedMapImpl<>(), String.class, () -> "sample");
+        CacheWrapper<String> value = svc.get(id, new MultivaluedHashMap<>(), String.class, () -> "sample");
 
         Assertions
                 .assertTrue(lookupCacheKeyUsingMainCache(id, Optional.empty()),
@@ -83,7 +83,7 @@ class DefaultQuarkusCachingServiceTest {
                         "Expected random UUID key to have no TTL key, but found value");
 
         // do the lookup that should generate a TTL cache entry
-        svc.get(id, new MultivaluedMapImpl<>(), String.class, () -> cacheValue);
+        svc.get(id, new MultivaluedHashMap<>(), String.class, () -> cacheValue);
 
         Assertions
                 .assertTrue(lookupCacheKeyUsingRawCache(id, Optional.empty(), ttlCache),
@@ -96,7 +96,7 @@ class DefaultQuarkusCachingServiceTest {
         String id = UUID.randomUUID().toString();
         String cacheValue = "sample";
         // create empty map to be used in comparisons
-        MultivaluedMap<String, String> emptyMap = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> emptyMap = new MultivaluedHashMap<>();
 
         // check that we have no match for ID before proceeding
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
@@ -116,10 +116,10 @@ class DefaultQuarkusCachingServiceTest {
         // generate a random key
         String id = UUID.randomUUID().toString();
         // create empty map to be used in comparisons
-        MultivaluedMap<String, String> emptyMap = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> emptyMap = new MultivaluedHashMap<>();
 
         // create a param map to use in creating distinct keys
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add(PARAMETER_NAME, "sample_value");
 
         // check that we have no match for ID before proceeding
@@ -144,7 +144,7 @@ class DefaultQuarkusCachingServiceTest {
         // generate a random key
         String id = UUID.randomUUID().toString();
         // create empty map to be used in comparisons
-        MultivaluedMap<String, String> emptyMap = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> emptyMap = new MultivaluedHashMap<>();
 
         // check that we have no match for ID before proceeding
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
@@ -172,7 +172,7 @@ class DefaultQuarkusCachingServiceTest {
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
 
         // value should be null as there was an error
-        CacheWrapper<String> value = svc.get(id, new MultivaluedMapImpl<>(), String.class, () -> { throw new RuntimeException("Kaboom"); });
+        CacheWrapper<String> value = svc.get(id, new MultivaluedHashMap<>(), String.class, () -> { throw new RuntimeException("Kaboom"); });
         Assertions.assertTrue(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to have a value, but was empty");
         Assertions.assertTrue(value.getData().isEmpty(), "Cache value should have been missing but was present");
         Assertions.assertEquals(RuntimeException.class, value.getErrorType().get(), "The exception type caught in the wrapper should be the same as thrown");
@@ -186,7 +186,7 @@ class DefaultQuarkusCachingServiceTest {
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
 
         // value should be null as there was an error
-        CacheWrapper<String> value = svc.get(id, new MultivaluedMapImpl<>(), String.class, () -> { throw new RuntimeException("Kaboom"); });
+        CacheWrapper<String> value = svc.get(id, new MultivaluedHashMap<>(), String.class, () -> { throw new RuntimeException("Kaboom"); });
         Assertions.assertTrue(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to have a value, but was empty");
         Assertions.assertTrue(value.getData().isEmpty(), "Cache value should have been missing but was present");
         Assertions.assertEquals(RuntimeException.class, value.getErrorType().get(), "The exception type caught in the wrapper should be the same as thrown");
@@ -200,7 +200,7 @@ class DefaultQuarkusCachingServiceTest {
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
 
         // value should be empty as null gets interpreted as an empty optional
-        CacheWrapper<String> value = svc.get(id, new MultivaluedMapImpl<>(), String.class, () -> null);
+        CacheWrapper<String> value = svc.get(id, new MultivaluedHashMap<>(), String.class, () -> null);
 
         Assertions.assertTrue(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to have a value, but was empty");
         Assertions.assertTrue(value.getData().isEmpty(), "Cache value should have been missing but was present");
@@ -215,7 +215,7 @@ class DefaultQuarkusCachingServiceTest {
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
 
         // value should be null as there was an error
-        CacheWrapper<String> value = svc.get(id, new MultivaluedMapImpl<>(), String.class, () -> null);
+        CacheWrapper<String> value = svc.get(id, new MultivaluedHashMap<>(), String.class, () -> null);
         Assertions.assertTrue(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to have a value, but was empty");
         Assertions.assertTrue(value.getData().isEmpty(), "Cache value should have been missing but was present");
         Assertions.assertTrue(value.getErrorType().isEmpty(), "There should be no exception caught in this case");
@@ -234,7 +234,7 @@ class DefaultQuarkusCachingServiceTest {
                 .assertFalse(svc.getCacheKeys().stream().anyMatch(k -> k.getId().equals(id)),
                         "Expected random UUID key to be empty, but found key");
         // run the op to populate the cache value
-        svc.get(id, new MultivaluedMapImpl<>(), String.class, () -> "sample");
+        svc.get(id, new MultivaluedHashMap<>(), String.class, () -> "sample");
 
         // check that the cache value can be seen in the cache key set
         Assertions
@@ -265,7 +265,7 @@ class DefaultQuarkusCachingServiceTest {
         // generate a random key
         String id = UUID.randomUUID().toString();
         // create empty map for initial post
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         // check that we have no match for ID before proceeding
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
         // request + put the data in cache and check it's there
@@ -275,7 +275,7 @@ class DefaultQuarkusCachingServiceTest {
                         "Expected new cache value to have a key present in cache key set with empty map");
 
         // update the map and create another entry
-        params = new MultivaluedMapImpl<>();
+        params = new MultivaluedHashMap<>();
         params.add(SECOND_PARAMETER_NAME, id);
         Assertions
                 .assertFalse(lookupCacheKeyUsingMainCache(id, Optional.of(params)),
@@ -303,7 +303,7 @@ class DefaultQuarkusCachingServiceTest {
         // generate a random key
         String id = UUID.randomUUID().toString();
         // create empty map for initial post
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         // check that we have no match for ID before proceeding
         Assertions
                 .assertFalse(lookupCacheKeyUsingRawCache(id, Optional.of(params), Optional.of(String.class), cache),
@@ -345,7 +345,7 @@ class DefaultQuarkusCachingServiceTest {
         // generate a random key
         String id = UUID.randomUUID().toString();
         // create empty map to be used in comparisons
-        MultivaluedMap<String, String> emptyMap = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> emptyMap = new MultivaluedHashMap<>();
 
         // check that we have no match for ID before proceeding
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
@@ -369,7 +369,7 @@ class DefaultQuarkusCachingServiceTest {
         // generate a random key
         String id = UUID.randomUUID().toString();
         // create empty map to be used in comparisons
-        MultivaluedMap<String, String> emptyMap = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> emptyMap = new MultivaluedHashMap<>();
 
         // check that we have no match for ID before proceeding
         Assertions
@@ -405,7 +405,7 @@ class DefaultQuarkusCachingServiceTest {
                 .builder()
                 .setId("other-key-not-present")
                 .setClazz(Integer.class)
-                .setParams(new MultivaluedMapImpl<>())
+                .setParams(new MultivaluedHashMap<>())
                 .build();
 
         // attempt to remove the non-existent cache key
@@ -417,7 +417,7 @@ class DefaultQuarkusCachingServiceTest {
         // generate a random key
         String id = UUID.randomUUID().toString();
         // create empty map to be used in comparisons
-        MultivaluedMap<String, String> emptyMap = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> emptyMap = new MultivaluedHashMap<>();
 
         // check that we have no match for ID before proceeding
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
@@ -448,7 +448,7 @@ class DefaultQuarkusCachingServiceTest {
         // generate a random key
         String id = UUID.randomUUID().toString();
         // create empty map to be used in comparisons
-        MultivaluedMap<String, String> emptyMap = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> emptyMap = new MultivaluedHashMap<>();
 
         // check that we have no match for ID before proceeding
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
@@ -474,10 +474,10 @@ class DefaultQuarkusCachingServiceTest {
         // generate a random key
         String id = UUID.randomUUID().toString();
         // create empty map to be used in comparisons
-        MultivaluedMap<String, String> emptyMap = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> emptyMap = new MultivaluedHashMap<>();
 
         // create a param map to use in creating distinct keys
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add(PARAMETER_NAME, "sample_value");
 
         // check that we have no match for ID before proceeding
@@ -508,7 +508,7 @@ class DefaultQuarkusCachingServiceTest {
         // generate a random key
         String id = UUID.randomUUID().toString();
         // create empty map to be used in comparisons
-        MultivaluedMap<String, String> emptyMap = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> emptyMap = new MultivaluedHashMap<>();
 
         // check that we have no match for ID before proceeding
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
@@ -531,7 +531,7 @@ class DefaultQuarkusCachingServiceTest {
         Assertions.assertFalse(lookupCacheKeyUsingMainCache(id, Optional.empty()), "Expected random UUID key to be empty, but found value");
 
         // keep map separate to reduce assertion to have 1 actual call
-        MultivaluedMap<String, String> emptyMap = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> emptyMap = new MultivaluedHashMap<>();
         Assertions
                 .assertThrows(RuntimeException.class, () -> svc.getExpiration(id, emptyMap, String.class),
                         "Expected missing cache key to throw exception when there is no TTL present");
diff --git a/core/pom.xml b/core/pom.xml
index 9031d2b2ce1a7ab6c9b08b0362487b62d32e261e..97621a5a8d20eba3e03f0f74cb0e4273a2bbd623 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -9,7 +9,7 @@
     <parent>
         <groupId>org.eclipsefoundation</groupId>
         <artifactId>quarkus-commons</artifactId>
-        <version>1.0.3-SNAPSHOT</version>
+        <version>1.1.0</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <properties>
diff --git a/core/src/main/java/org/eclipsefoundation/core/model/StandardPaginationResolver.java b/core/src/main/java/org/eclipsefoundation/core/model/StandardPaginationResolver.java
index de3c523da0865aca9cecd25a515a10fc0b50c4aa..01427235815c167853308acf56e9305879b315a1 100644
--- a/core/src/main/java/org/eclipsefoundation/core/model/StandardPaginationResolver.java
+++ b/core/src/main/java/org/eclipsefoundation/core/model/StandardPaginationResolver.java
@@ -21,7 +21,7 @@ import org.eclipsefoundation.core.service.PaginationHeaderService.PaginationReso
 import org.eclipsefoundation.http.config.PaginationConfig;
 import org.eclipsefoundation.http.model.RequestWrapper;
 import org.eclipsefoundation.http.response.PaginatedResultsFilter;
-import org.jboss.resteasy.specimpl.MultivaluedTreeMap;
+import org.jboss.resteasy.reactive.common.util.MultivaluedTreeMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/core/src/main/java/org/eclipsefoundation/core/response/CachedResponseFilter.java b/core/src/main/java/org/eclipsefoundation/core/response/CachedResponseFilter.java
index aa82aab0bd0dc2ec95e67f893d88e7b32f5c69fb..be269255758f44126347996c270279930290b749 100644
--- a/core/src/main/java/org/eclipsefoundation/core/response/CachedResponseFilter.java
+++ b/core/src/main/java/org/eclipsefoundation/core/response/CachedResponseFilter.java
@@ -16,17 +16,16 @@ import java.io.IOException;
 import org.eclipsefoundation.core.service.PaginationHeaderService;
 import org.eclipsefoundation.http.model.RequestWrapper;
 import org.eclipsefoundation.utils.helper.TransformationHelper;
+import org.jboss.resteasy.reactive.server.ServerResponseFilter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import io.vertx.core.http.HttpMethod;
-import jakarta.annotation.Priority;
 import jakarta.inject.Inject;
 import jakarta.ws.rs.container.ContainerRequestContext;
 import jakarta.ws.rs.container.ContainerResponseContext;
 import jakarta.ws.rs.container.ContainerResponseFilter;
 import jakarta.ws.rs.core.Response.Status;
-import jakarta.ws.rs.ext.Provider;
 
 /**
  * Either applies recorded actions to the response or to record the response if nothing has been recorded yet. Priority
@@ -35,8 +34,6 @@ import jakarta.ws.rs.ext.Provider;
  *
  * @author Martin Lowe
  */
-@Provider
-@Priority(50)
 public class CachedResponseFilter implements ContainerResponseFilter {
     private static final Logger LOGGER = LoggerFactory.getLogger(CachedResponseFilter.class);
 
@@ -45,7 +42,7 @@ public class CachedResponseFilter implements ContainerResponseFilter {
     @Inject
     RequestWrapper wrap;
 
-    @Override
+	@ServerResponseFilter(priority = 5050)
     public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
         if (LOGGER.isTraceEnabled()) {
             LOGGER.trace("Checking request {}", TransformationHelper.formatLog(wrap.getEndpoint()));
diff --git a/core/src/main/java/org/eclipsefoundation/core/service/APIMiddleware.java b/core/src/main/java/org/eclipsefoundation/core/service/APIMiddleware.java
index 7501c3bea0c6ce6fd0bc94b8556510ed17aedf30..2918c4f3f8420d9cb0a672c2f5f7cb3f346c68e3 100644
--- a/core/src/main/java/org/eclipsefoundation/core/service/APIMiddleware.java
+++ b/core/src/main/java/org/eclipsefoundation/core/service/APIMiddleware.java
@@ -12,7 +12,6 @@
 package org.eclipsefoundation.core.service;
 
 import java.util.List;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Function;
 
@@ -29,9 +28,9 @@ public interface APIMiddleware {
     <T> List<T> paginationPassThrough(Function<BaseAPIParameters, Response> supplier, RequestWrapper request, Class<T> type);
 
     /**
-     * Returns the full list of data for the given API call, using a function that accepts the page number to iterate over
-     * the pages of data. The Link header is scraped off of the first request and is used to determine how many calls need
-     * to be made to get the full data set.
+     * Returns the full list of data for the given API call, using a function that accepts the page number to iterate over the pages of
+     * data. The Link header is scraped off of the first request and is used to determine how many calls need to be made to get the full
+     * data set.
      * 
      * @param <T> the type of data that is retrieved
      * @param supplier function that accepts a page number and makes an API call for the given page.
@@ -41,47 +40,18 @@ public interface APIMiddleware {
     <T> List<T> getAll(Function<BaseAPIParameters, Response> supplier, Class<T> type);
 
     public static class BaseAPIParameters {
-        private Integer page;
-        private Integer limit;
-        private RequestWrapper requestWrapper;
-
-        public BaseAPIParameters() {
-        }
-
-        public BaseAPIParameters(@Nullable Integer page, @Nullable Integer limit, @Nullable RequestWrapper requestWrapper) {
-            this.limit = limit;
-            this.page = page;
-            this.requestWrapper = requestWrapper;
-        }
-
-        /**
-         * @return the page
-         */
         @Nullable
         @QueryParam("page")
-        public Integer getPage() {
-            return page;
-        }
-
-        /**
-         * @return the limit
-         */
+        public Integer page;
         @Nullable
         @QueryParam("pagesize")
-        public Integer getLimit() {
-            return limit;
-        }
-
-        /**
-         * @return the requestWrapper
-         */
-        @Nullable
-        public RequestWrapper getRequestWrapper() {
-            return requestWrapper;
-        }
+        public Integer limit;
+        public final RequestWrapper requestWrapper;
 
-        public static Builder builder() {
-            return new Builder();
+        public BaseAPIParameters(Integer page, Integer limit, RequestWrapper requestWrapper) {
+            this.page = page;
+            this.limit = limit;
+            this.requestWrapper = requestWrapper;
         }
 
         public static BaseAPIParameters buildFromWrapper(RequestWrapper request) {
@@ -91,68 +61,12 @@ public interface APIMiddleware {
             if (page.isPresent() && StringUtils.isNumeric(page.get())) {
                 pageActual = Integer.valueOf(page.get());
             }
-            return BaseAPIParameters.builder().setPage(pageActual).setLimit(request.getPageSize()).setRequestWrapper(request).build();
+            return new BaseAPIParameters(pageActual, request.getPageSize(), request);
         }
 
         @Override
         public String toString() {
-            return "BaseAPIParameters{" + "page=" + page + ", " + "limit=" + limit + "}";
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(limit, page, requestWrapper);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (obj == null) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            BaseAPIParameters other = (BaseAPIParameters) obj;
-            return Objects.equals(limit, other.limit) && Objects.equals(page, other.page)
-                    && Objects.equals(requestWrapper, other.requestWrapper);
-        }
-
-        public static class Builder {
-            private Integer page;
-            private Integer limit;
-            private RequestWrapper requestWrapper;
-
-            /**
-             * @param page the page to set
-             */
-            public Builder setPage(@Nullable Integer page) {
-                this.page = page;
-                return this;
-            }
-
-            /**
-             * @param limit the limit to set
-             */
-            @QueryParam("pagesize")
-            public Builder setLimit(@Nullable Integer limit) {
-                this.limit = limit;
-                return this;
-            }
-
-            /**
-             * @param requestWrapper the requestWrapper to set
-             */
-            public Builder setRequestWrapper(@Nullable RequestWrapper requestWrapper) {
-                this.requestWrapper = requestWrapper;
-                return this;
-            }
-
-            public BaseAPIParameters build() {
-                return new BaseAPIParameters(page, limit, requestWrapper);
-            }
+            return "BaseAPIParameters [page=" + page + ", limit=" + limit + "]";
         }
     }
 }
\ No newline at end of file
diff --git a/core/src/main/java/org/eclipsefoundation/core/service/impl/DefaultAPIMiddleware.java b/core/src/main/java/org/eclipsefoundation/core/service/impl/DefaultAPIMiddleware.java
index 6332f7c09492b4ced98997c389cfd6b767a199e4..da3c6c1d507386cdee80ea44a39b21a84589eb9d 100644
--- a/core/src/main/java/org/eclipsefoundation/core/service/impl/DefaultAPIMiddleware.java
+++ b/core/src/main/java/org/eclipsefoundation/core/service/impl/DefaultAPIMiddleware.java
@@ -29,8 +29,7 @@ import org.eclipsefoundation.core.service.APIMiddleware;
 import org.eclipsefoundation.http.model.RequestWrapper;
 import org.eclipsefoundation.http.response.PaginatedResultsFilter;
 import org.eclipsefoundation.utils.helper.ParameterHelper;
-import org.jboss.resteasy.specimpl.MultivaluedTreeMap;
-import org.jboss.resteasy.spi.LinkHeader;
+import org.jboss.resteasy.reactive.common.util.MultivaluedTreeMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,6 +40,7 @@ import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
 import jakarta.ws.rs.ServerErrorException;
 import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.Link;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.Response.Status;
@@ -141,9 +141,9 @@ public class DefaultAPIMiddleware implements APIMiddleware {
      */
     private Response doCall(Function<BaseAPIParameters, Response> supplier, int count) {
         try {
-            return supplier.apply(BaseAPIParameters.builder().setPage(count).build());
+            return supplier.apply(new BaseAPIParameters(count, null, null));
         } catch (WebApplicationException e) {
-            LOGGER.error("Error retrieving a paginated request with params: {}", BaseAPIParameters.builder().setPage(count).build());
+            LOGGER.error("Error retrieving a paginated request with params: {}", new BaseAPIParameters(count, null, null));
             // continue throwing after logging details about the problematic request
             throw e;
         }
@@ -174,16 +174,14 @@ public class DefaultAPIMiddleware implements APIMiddleware {
     }
 
     private int getLastPageIndex(Response r) {
-        List<Object> links = r.getHeaders().get("Link");
-        // convert it to retrieve the index of the last page
-        if (links != null && !links.isEmpty()) {
-            LinkHeader h = LinkHeader.valueOf(links.get(0).toString());
-            // check what the last page link has as its 'page' param val
-            URI lastLink = h.getLinkByRelationship("last").getUri();
-            MultivaluedMap<String, String> params = ParameterHelper.parseQueryString(lastLink.getQuery());
-            if (params.keySet().contains("page")) {
-                return Integer.parseInt(params.getFirst("page"));
-            }
+        Link lastPageLink = r.getLink("last");
+        if (lastPageLink == null) {
+            return 0;
+        }
+        // check what the last page link has as its 'page' param val
+        MultivaluedMap<String, String> params = ParameterHelper.parseQueryString(lastPageLink.getUri().getQuery());
+        if (params.keySet().contains("page")) {
+            return Integer.parseInt(params.getFirst("page"));
         }
         return 0;
     }
diff --git a/core/src/test/java/org/eclipsefoundation/core/model/StandardPaginationResolverTest.java b/core/src/test/java/org/eclipsefoundation/core/model/StandardPaginationResolverTest.java
index 3795bddf235fa2eb358d0863f5e006f08016ee3b..33466a1e89f2c84de97bc3e3a5801b6c854553e2 100644
--- a/core/src/test/java/org/eclipsefoundation/core/model/StandardPaginationResolverTest.java
+++ b/core/src/test/java/org/eclipsefoundation/core/model/StandardPaginationResolverTest.java
@@ -18,8 +18,8 @@ import java.util.UUID;
 import org.apache.commons.lang3.StringUtils;
 import org.eclipsefoundation.http.model.FlatRequestWrapper;
 import org.eclipsefoundation.http.response.PaginatedResultsFilter;
-import org.jboss.resteasy.specimpl.MultivaluedTreeMap;
-import org.jboss.resteasy.util.CaseInsensitiveMap;
+import org.jboss.resteasy.reactive.common.util.CaseInsensitiveMap;
+import org.jboss.resteasy.reactive.common.util.MultivaluedTreeMap;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
diff --git a/core/src/test/java/org/eclipsefoundation/core/response/CachedResponseFilterTest.java b/core/src/test/java/org/eclipsefoundation/core/response/CachedResponseFilterTest.java
index 74e74180ea1c134b35edacbb07d7f24f2815db95..c9f1200f95963823e31895735c8a904253732dbb 100644
--- a/core/src/test/java/org/eclipsefoundation/core/response/CachedResponseFilterTest.java
+++ b/core/src/test/java/org/eclipsefoundation/core/response/CachedResponseFilterTest.java
@@ -4,14 +4,15 @@ import static io.restassured.RestAssured.given;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 import java.util.UUID;
 
 import org.eclipsefoundation.core.test.resources.TestResource;
 import org.eclipsefoundation.http.response.PaginatedResultsFilter;
-import org.jboss.resteasy.spi.LinkHeader;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
+import io.quarkus.logging.Log;
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.response.Response;
 import jakarta.ws.rs.core.Link;
@@ -23,21 +24,29 @@ public class CachedResponseFilterTest {
     void filter_success_headerCachingAppliesBeforeFilter() {
         String uniqueKey = UUID.randomUUID().toString();
         Map<String, String> expectedHeaders = new HashMap<>();
-        expectedHeaders.put(PaginatedResultsFilter.MAX_RESULTS_SIZE_HEADER, TestResource.PAGINATION_HEADER_RESULT_SIZE);
-        expectedHeaders.put(PaginatedResultsFilter.MAX_PAGE_SIZE_HEADER, TestResource.PAGINATION_HEADER_PAGE_SIZE_DEFAULT);
+        expectedHeaders.put(PaginatedResultsFilter.MAX_RESULTS_SIZE_HEADER,
+                TestResource.PAGINATION_HEADER_RESULT_SIZE);
+        expectedHeaders.put(PaginatedResultsFilter.MAX_PAGE_SIZE_HEADER,
+                TestResource.PAGINATION_HEADER_PAGE_SIZE_DEFAULT);
         // endpoint has stored pagination header sources
         Response vr = given().header("result-size", 120).get("test/pagination/cached/" + uniqueKey);
-        LinkHeader expectedValue = LinkHeader.valueOf(vr.header("Link"));
-        Link expectedLastRel = expectedValue.getLinkByRelationship("last");
+        Log.error(vr.headers().getValues("Link"));
+        Optional<Link> expectedLastRel = vr.headers().getValues("Link").stream().map(l -> Link.valueOf(l))
+                .filter(l -> "last".equals(l.getRel())).findFirst();
 
-        // response that should have the cached results which would apply to the link header
+        // response that should have the cached results which would apply to the link
+        // header
         Response cachedResponse = given().get("test/pagination/cached/" + uniqueKey);
-
-        LinkHeader value = LinkHeader.valueOf(cachedResponse.header("Link"));
-        Link lastRel = value.getLinkByRelationship("last");
-        // check that our last link is the same as in the initial request which had the headers set 
-        Assertions.assertEquals(expectedLastRel, lastRel);
+        Optional<Link> actualLastRel = cachedResponse.headers().getValues("Link").stream().map(l -> Link.valueOf(l))
+                .filter(l -> "last".equals(l.getRel())).findFirst();
+
+        // check that our last link is the same as in the initial request which had the
+        // headers set
+        Assertions.assertTrue(expectedLastRel.isPresent());
+        Assertions.assertTrue(actualLastRel.isPresent());
+        Assertions.assertEquals(expectedLastRel.get(), actualLastRel.get());
         // check that the intended value of 12 is used for the resultant query string
-        Assertions.assertEquals("page=12", lastRel.getUri().getQuery(), "Expected 12 pages (10 items per page)");
+        Assertions.assertEquals("page=12", actualLastRel.get().getUri().getQuery(),
+                "Expected 12 pages (10 items per page)");
     }
 }
diff --git a/core/src/test/java/org/eclipsefoundation/core/service/impl/DefaultAPIMiddlewareTest.java b/core/src/test/java/org/eclipsefoundation/core/service/impl/DefaultAPIMiddlewareTest.java
index 4082ca2848912a818225a63e754f58ac73726d3c..8c75f327746399cfe0c5091c4a958ff383fb899b 100644
--- a/core/src/test/java/org/eclipsefoundation/core/service/impl/DefaultAPIMiddlewareTest.java
+++ b/core/src/test/java/org/eclipsefoundation/core/service/impl/DefaultAPIMiddlewareTest.java
@@ -14,6 +14,7 @@ package org.eclipsefoundation.core.service.impl;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.net.URI;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -26,7 +27,6 @@ import org.eclipsefoundation.core.service.PaginationHeaderService;
 import org.eclipsefoundation.core.test.models.TestModel;
 import org.eclipsefoundation.http.model.FlatRequestWrapper;
 import org.eclipsefoundation.http.response.PaginatedResultsFilter;
-import org.jboss.resteasy.spi.LinkHeader;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -39,6 +39,7 @@ import io.quarkus.test.junit.QuarkusTest;
 import io.quarkus.test.junit.mockito.InjectSpy;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
+import jakarta.ws.rs.core.Link;
 import jakarta.ws.rs.core.Response;
 
 @QuarkusTest
@@ -70,7 +71,8 @@ class DefaultAPIMiddlewareTest {
     @Test
     void getAll_success_GZIPContent() {
         List<TestModel> out = middleware
-                .getAll(params -> Response.ok(new ByteArrayInputStream(getListAsByteArray())).header("Content-Encoding", "GZIP").build(),
+                .getAll(params -> Response.ok(new ByteArrayInputStream(getListAsByteArray()))
+                        .header("Content-Encoding", "GZIP").build(),
                         TestModel.class);
 
         Assertions.assertEquals(2, out.size(), "Expected 2 objects in the return");
@@ -79,7 +81,8 @@ class DefaultAPIMiddlewareTest {
     @Test
     void getAll_success_GZIPContent_objectBase() {
         List<TestModel> out = middleware
-                .getAll(params -> Response.ok(new ByteArrayInputStream(getObjectAsByteArray())).header("Content-Encoding", "GZIP").build(),
+                .getAll(params -> Response.ok(new ByteArrayInputStream(getObjectAsByteArray()))
+                        .header("Content-Encoding", "GZIP").build(),
                         TestModel.class);
 
         Assertions.assertEquals(1, out.size(), "Expected a single object in the returned list");
@@ -93,7 +96,8 @@ class DefaultAPIMiddlewareTest {
 
         // test raw headers on response
         Assertions.assertEquals(10, Integer.parseInt(wrap.getHeader(PaginatedResultsFilter.MAX_PAGE_SIZE_HEADER)));
-        Assertions.assertEquals(getMaxResultsSize(pages), Integer.parseInt(wrap.getHeader(PaginatedResultsFilter.MAX_RESULTS_SIZE_HEADER)));
+        Assertions.assertEquals(getMaxResultsSize(pages),
+                Integer.parseInt(wrap.getHeader(PaginatedResultsFilter.MAX_RESULTS_SIZE_HEADER)));
     }
 
     @Test
@@ -105,7 +109,8 @@ class DefaultAPIMiddlewareTest {
         // retrieve the pagination data for current request and test it
         Map<String, String> results = headerService.resolveHeadersForRequest(wrap);
         Assertions.assertEquals(10, Integer.parseInt(results.get(PaginatedResultsFilter.MAX_PAGE_SIZE_HEADER)));
-        Assertions.assertEquals(getMaxResultsSize(pages), Integer.parseInt(results.get(PaginatedResultsFilter.MAX_RESULTS_SIZE_HEADER)));
+        Assertions.assertEquals(getMaxResultsSize(pages),
+                Integer.parseInt(results.get(PaginatedResultsFilter.MAX_RESULTS_SIZE_HEADER)));
     }
 
     public static int getMaxResultsSize(int pageCount) {
@@ -146,29 +151,32 @@ class DefaultAPIMiddlewareTest {
             // get current page safely
             Integer currentPage = 1;
             // null check the designated page in request
-            Integer designatedPage = base.getPage();
+            Integer designatedPage = base.page;
             if (designatedPage != null) {
                 currentPage = designatedPage;
             }
             // generate link headers
-            LinkHeader linkHeader = new LinkHeader();
-            linkHeader
-                    .addLink("this page of results", "self", String.format("https://sample.com/api?%spage=%d", leadingParams, currentPage),
-                            "");
-            linkHeader.addLink("first page of results", "first", String.format("https://sample.com/api?%spage=%d", leadingParams, 1), "");
-            linkHeader
-                    .addLink("last page of results", "last", String.format("https://sample.com/api?%spage=%d", leadingParams, pageCount),
-                            "");
+
+            List<Link> links = new ArrayList<>();
+            // add first + last page link headers
+            links.add(Link.fromUri(String.format("https://sample.com/api?%spage=%d", leadingParams, 1)).rel("first")
+                    .title("first page of results").build());
+            links.add(Link.fromUri(String.format("https://sample.com/api?%spage=%d", leadingParams, currentPage))
+                    .rel("self").title("this page of results").build());
+            links.add(Link.fromUri(String.format("https://sample.com/api?%spage=%d", leadingParams, pageCount))
+                    .rel("last").title("last page of results").build());
+
             if (currentPage < pageCount) {
-                linkHeader
-                        .addLink("next page of results", "next",
-                                String.format("https://sample.com/api?%spage=%d", leadingParams, currentPage + 1), "");
+                links.add(
+                        Link.fromUri(String.format("https://sample.com/api?%spage=%d", leadingParams, currentPage + 1))
+                                .rel("next").title("next page of results").build());
             }
 
-            // return basic return with link headers to test, w/ consistent fake data set size
+            // return basic return with link headers to test, w/ consistent fake data set
+            // size
             return Response
                     .ok(Collections.emptyList())
-                    .header("Link", linkHeader)
+                    .links(links.toArray(new Link[]{}))
                     .header(PaginatedResultsFilter.MAX_RESULTS_SIZE_HEADER, getMaxResultsSize(pageCount))
                     .header(PaginatedResultsFilter.MAX_PAGE_SIZE_HEADER, 10)
                     .build();
diff --git a/core/src/test/java/org/eclipsefoundation/core/service/impl/DefaultPaginationHeaderServiceTest.java b/core/src/test/java/org/eclipsefoundation/core/service/impl/DefaultPaginationHeaderServiceTest.java
index f87d22f3e58488a25a5ebecbabb91284b4924e00..36750d6340122be7cd09b7ffea88f35604020dc7 100644
--- a/core/src/test/java/org/eclipsefoundation/core/service/impl/DefaultPaginationHeaderServiceTest.java
+++ b/core/src/test/java/org/eclipsefoundation/core/service/impl/DefaultPaginationHeaderServiceTest.java
@@ -21,7 +21,7 @@ import org.eclipsefoundation.core.test.models.TestModel;
 import org.eclipsefoundation.http.model.FlatRequestWrapper;
 import org.eclipsefoundation.http.namespace.DefaultUrlParameterNames;
 import org.eclipsefoundation.http.response.PaginatedResultsFilter;
-import org.jboss.resteasy.specimpl.MultivaluedTreeMap;
+import org.jboss.resteasy.reactive.common.util.MultivaluedTreeMap;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
diff --git a/core/src/test/java/org/eclipsefoundation/core/test/models/SecondaryTestModel.java b/core/src/test/java/org/eclipsefoundation/core/test/models/SecondaryTestModel.java
index afaf21fe5efbb9aeb9bc12ebb815494a4882fcd5..6d0fe20ce149e0f4aa62a2b10918c19258602788 100644
--- a/core/src/test/java/org/eclipsefoundation/core/test/models/SecondaryTestModel.java
+++ b/core/src/test/java/org/eclipsefoundation/core/test/models/SecondaryTestModel.java
@@ -22,6 +22,8 @@ import com.google.auto.value.AutoValue;
 @AutoValue
 @JsonDeserialize(builder = AutoValue_SecondaryTestModel.Builder.class)
 public abstract class SecondaryTestModel implements Serializable {
+    private static final long serialVersionUID = 1L;
+
     @Nullable
     public abstract String getName();
 
diff --git a/core/src/test/java/org/eclipsefoundation/core/test/models/TestModel.java b/core/src/test/java/org/eclipsefoundation/core/test/models/TestModel.java
index d567091b7ea397a481912baef4da95daac966c93..163519eb09599648dfd3b88cc7587dab2503cb0b 100644
--- a/core/src/test/java/org/eclipsefoundation/core/test/models/TestModel.java
+++ b/core/src/test/java/org/eclipsefoundation/core/test/models/TestModel.java
@@ -22,6 +22,8 @@ import com.google.auto.value.AutoValue;
 @AutoValue
 @JsonDeserialize(builder = AutoValue_TestModel.Builder.class)
 public abstract class TestModel implements Serializable {
+    private static final long serialVersionUID = 1L;
+
     @Nullable
     public abstract String getName();
 
diff --git a/efservices/pom.xml b/efservices/pom.xml
index 51e0c5f9b5a1ce4493e0cc0c6ad8c70d3e974f70..f0e7ee438815f144ff423b2845c7898baa77faa5 100644
--- a/efservices/pom.xml
+++ b/efservices/pom.xml
@@ -8,7 +8,7 @@
   <parent>
     <groupId>org.eclipsefoundation</groupId>
     <artifactId>quarkus-commons</artifactId>
-    <version>1.0.3-SNAPSHOT</version>
+    <version>1.1.0</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <properties>
@@ -22,8 +22,9 @@
     </dependency>
     <dependency>
       <groupId>io.quarkus</groupId>
-      <artifactId>quarkus-rest-client</artifactId>
+      <artifactId>quarkus-rest-client-reactive</artifactId>
     </dependency>
+    
     <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
     <dependency>
       <groupId>org.apache.commons</groupId>
@@ -61,6 +62,12 @@
     </dependency>
 
     <!-- Test dependencies -->
+    <dependency>
+      <groupId>org.eclipsefoundation</groupId>
+      <artifactId>quarkus-test-common</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>io.quarkus</groupId>
       <artifactId>quarkus-junit5</artifactId>
@@ -99,4 +106,4 @@
       </plugin>
     </plugins>
   </build>
-</project>
\ No newline at end of file
+</project>
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/api/DrupalOAuthAPI.java b/efservices/src/main/java/org/eclipsefoundation/efservices/api/DrupalOAuthAPI.java
index c5da60d14d3f6fedeaa56a4db5ad50eac7a2dd63..d68e70d10df989f58a6dbe42295f10001e83adaa 100644
--- a/efservices/src/main/java/org/eclipsefoundation/efservices/api/DrupalOAuthAPI.java
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/api/DrupalOAuthAPI.java
@@ -11,6 +11,10 @@
 **********************************************************************/
 package org.eclipsefoundation.efservices.api;
 
+import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
+import org.eclipsefoundation.efservices.api.models.DrupalOAuthData;
+import org.eclipsefoundation.efservices.api.models.DrupalUserInfo;
+
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.ws.rs.GET;
 import jakarta.ws.rs.HeaderParam;
@@ -18,13 +22,9 @@ import jakarta.ws.rs.POST;
 import jakarta.ws.rs.Path;
 import jakarta.ws.rs.PathParam;
 import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.HttpHeaders;
 import jakarta.ws.rs.core.MediaType;
 
-import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
-import org.eclipsefoundation.efservices.api.models.DrupalOAuthData;
-import org.eclipsefoundation.efservices.api.models.DrupalUserInfo;
-import org.jboss.resteasy.util.HttpHeaderNames;
-
 /**
  * Drupal OAuth2 token validation API binding
  */
@@ -54,5 +54,5 @@ public interface DrupalOAuthAPI {
      */
     @POST
     @Path("/userinfo")
-    DrupalUserInfo getUserInfoFromToken(@HeaderParam(HttpHeaderNames.AUTHORIZATION) String token);
+    DrupalUserInfo getUserInfoFromToken(@HeaderParam(HttpHeaders.AUTHORIZATION) String token);
 }
\ No newline at end of file
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/api/ProfileAPI.java b/efservices/src/main/java/org/eclipsefoundation/efservices/api/ProfileAPI.java
index d7c98ab298b099ab74180c40e5d79ad809d51a17..5007694e4fbf4dbe503a452e486cb9854315be43 100644
--- a/efservices/src/main/java/org/eclipsefoundation/efservices/api/ProfileAPI.java
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/api/ProfileAPI.java
@@ -13,6 +13,10 @@ package org.eclipsefoundation.efservices.api;
 
 import java.util.List;
 
+import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
+import org.eclipsefoundation.efservices.api.models.EfUser;
+import org.eclipsefoundation.efservices.api.models.UserSearchParams;
+
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.ws.rs.BeanParam;
 import jakarta.ws.rs.GET;
@@ -20,11 +24,7 @@ import jakarta.ws.rs.HeaderParam;
 import jakarta.ws.rs.Path;
 import jakarta.ws.rs.PathParam;
 import jakarta.ws.rs.Produces;
-
-import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
-import org.eclipsefoundation.efservices.api.models.EfUser;
-import org.eclipsefoundation.efservices.api.models.UserSearchParams;
-import org.jboss.resteasy.util.HttpHeaderNames;
+import jakarta.ws.rs.core.HttpHeaders;
 
 /**
  * Profile-api binding.
@@ -43,7 +43,7 @@ public interface ProfileAPI {
      */
     @GET
     @Path("/account/profile")
-    List<EfUser> getUsers(@HeaderParam(HttpHeaderNames.AUTHORIZATION) String token, @BeanParam UserSearchParams params);
+    List<EfUser> getUsers(@HeaderParam(HttpHeaders.AUTHORIZATION) String token, @BeanParam UserSearchParams params);
 
     /**
      * Fetches a profile that matches the given Ef username. An anauthenticated call
@@ -56,7 +56,7 @@ public interface ProfileAPI {
      */
     @GET
     @Path("/account/profile/{username}")
-    EfUser getUserByEfUsername(@HeaderParam(HttpHeaderNames.AUTHORIZATION) String token,
+    EfUser getUserByEfUsername(@HeaderParam(HttpHeaders.AUTHORIZATION) String token,
             @PathParam("username") String username);
 
     /**
@@ -70,6 +70,6 @@ public interface ProfileAPI {
      */
     @GET
     @Path("/github/profile/{handle}")
-    EfUser getUserByGithubHandle(@HeaderParam(HttpHeaderNames.AUTHORIZATION) String token,
+    EfUser getUserByGithubHandle(@HeaderParam(HttpHeaders.AUTHORIZATION) String token,
             @PathParam("handle") String handle);
 }
\ No newline at end of file
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/api/ProjectsAPI.java b/efservices/src/main/java/org/eclipsefoundation/efservices/api/ProjectsAPI.java
index cecf905730322a8ad588a0f431a70850c5888f6d..20c77a1e84bd7723190806913ffd610731e9542e 100644
--- a/efservices/src/main/java/org/eclipsefoundation/efservices/api/ProjectsAPI.java
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/api/ProjectsAPI.java
@@ -11,6 +11,10 @@
 **********************************************************************/
 package org.eclipsefoundation.efservices.api;
 
+import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
+import org.eclipsefoundation.core.service.APIMiddleware.BaseAPIParameters;
+
+import io.quarkus.vertx.http.Compressed;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.ws.rs.BeanParam;
 import jakarta.ws.rs.GET;
@@ -18,17 +22,12 @@ import jakarta.ws.rs.Path;
 import jakarta.ws.rs.QueryParam;
 import jakarta.ws.rs.core.Response;
 
-import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
-import org.eclipsefoundation.core.service.APIMiddleware.BaseAPIParameters;
-import org.jboss.resteasy.annotations.GZIP;
-
 /**
  * Project-API binding. Used to fetch Project and InterestGroup entities.
  */
 @ApplicationScoped
 @Path("api")
 @RegisterRestClient(configKey = "projects-api")
-@GZIP
 public interface ProjectsAPI {
 
     /**
@@ -40,6 +39,7 @@ public interface ProjectsAPI {
      * @return A Response containing the project entities if they exist.
      */
     @GET
+    @Compressed
     @Path("projects")
     Response getProjects(@BeanParam BaseAPIParameters params, @QueryParam("spec_project") int isSpecProject);
 
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/api/WorkingGroupsAPI.java b/efservices/src/main/java/org/eclipsefoundation/efservices/api/WorkingGroupsAPI.java
index f104a05018e88ed8604ee3fe1d3a1052380c3624..f3cfd5bd61ed9a66df39e79b60cd301baae9f4bc 100644
--- a/efservices/src/main/java/org/eclipsefoundation/efservices/api/WorkingGroupsAPI.java
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/api/WorkingGroupsAPI.java
@@ -36,15 +36,5 @@ public interface WorkingGroupsAPI {
      * @return response containing working group results.
      */
     @GET
-    public Response get(@BeanParam BaseAPIParameters baseParams);
-
-    /**
-     * Retrieve working groups by their status, such as incubating, active, or archived.
-     * 
-     * @param baseParams base pagination parameters
-     * @param statuses list of statuses to retrieve working groups for
-     * @return list of working groups that match the passed status filters
-     */
-    @GET
-    public Response getAllByStatuses(@BeanParam BaseAPIParameters baseParams, @QueryParam("status") List<String> statuses);
+    public Response get(@BeanParam BaseAPIParameters baseParams, @QueryParam("status") List<String> statuses);
 }
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/api/models/DrupalUserInfo.java b/efservices/src/main/java/org/eclipsefoundation/efservices/api/models/DrupalUserInfo.java
index a7aec28845a359d0e1bfe0a291059a9848aa1e36..b78dfaf7ac0043084174957a7cc6e665e8e957e7 100644
--- a/efservices/src/main/java/org/eclipsefoundation/efservices/api/models/DrupalUserInfo.java
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/api/models/DrupalUserInfo.java
@@ -11,38 +11,18 @@
 **********************************************************************/
 package org.eclipsefoundation.efservices.api.models;
 
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
-import com.google.auto.value.AutoValue;
-
 /**
  * Contains basic user data associated with a valid OAuth token. Used to access
  * basic information about the currently logged in user.
  */
-@AutoValue
-@JsonDeserialize(builder = AutoValue_DrupalUserInfo.Builder.class)
-public abstract class DrupalUserInfo {
-
-    public abstract String getSub();
-
-    public abstract String getName();
-
-    public abstract String getGithubHandle();
-
-    public static Builder builder() {
-        return new AutoValue_DrupalUserInfo.Builder();
-    }
-
-    @AutoValue.Builder
-    @JsonPOJOBuilder(withPrefix = "set")
-    public abstract static class Builder {
-
-        public abstract Builder setSub(String sub);
-
-        public abstract Builder setName(String name);
-
-        public abstract Builder setGithubHandle(String handle);
-
-        public abstract DrupalUserInfo build();
+public record DrupalUserInfo(String sub, String name, String githubHandle) {
+
+    /**
+     * Retrieves the uid of the user associated with the current token.
+     * 
+     * @return The uid of the user associated with the current token.
+     */
+    public String getCurrentUserUid() {
+        return this.sub();
     }
 }
\ No newline at end of file
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/api/models/UserSearchParams.java b/efservices/src/main/java/org/eclipsefoundation/efservices/api/models/UserSearchParams.java
index 2f0b7348fe7facc4c7fdb240f5eadd773c79a53d..8a71b7b45060000f651fdf901b8ba34c3e28b7eb 100644
--- a/efservices/src/main/java/org/eclipsefoundation/efservices/api/models/UserSearchParams.java
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/api/models/UserSearchParams.java
@@ -11,48 +11,33 @@
 **********************************************************************/
 package org.eclipsefoundation.efservices.api.models;
 
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
-import com.google.auto.value.AutoValue;
-
 import jakarta.annotation.Nullable;
 import jakarta.ws.rs.QueryParam;
 
 /**
  * Contains a set of query parameters used to perform authenticated user lookups with the ProfileService.
  */
-@AutoValue
-@JsonDeserialize(builder = AutoValue_UserSearchParams.Builder.class)
-public abstract class UserSearchParams {
+public class UserSearchParams {
 
     @Nullable
     @QueryParam("uid")
-    public abstract String getUid();
+    public String uid;
 
     @Nullable
     @QueryParam("name")
-    public abstract String getName();
+    public String name;
 
     @Nullable
     @QueryParam("mail")
-    public abstract String getMail();
-
-    public abstract Builder toBuilder();
-
-    public static Builder builder() {
-        return new AutoValue_UserSearchParams.Builder();
+    public String mail;
+    
+    public UserSearchParams() {
+        
     }
-
-    @AutoValue.Builder
-    @JsonPOJOBuilder(withPrefix = "set")
-    public abstract static class Builder {
-
-        public abstract Builder setUid(@Nullable String uid);
-
-        public abstract Builder setName(@Nullable String name);
-
-        public abstract Builder setMail(@Nullable String mail);
-
-        public abstract UserSearchParams build();
+    
+    public UserSearchParams(String uid, String name, String mail) {
+        this.uid = uid;
+        this.name = name;
+        this.mail = mail;
     }
 }
\ No newline at end of file
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/config/AuthenticatedRequestWrapperProvider.java b/efservices/src/main/java/org/eclipsefoundation/efservices/config/AuthenticatedRequestWrapperProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..f7c12db8350e40f22920805f37c6abf5d2f42315
--- /dev/null
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/config/AuthenticatedRequestWrapperProvider.java
@@ -0,0 +1,87 @@
+/*********************************************************************
+* Copyright (c) 2024 Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+/**
+ * 
+ */
+package org.eclipsefoundation.efservices.config;
+
+import java.lang.reflect.Method;
+
+import org.eclipsefoundation.efservices.api.models.DrupalOAuthData;
+import org.eclipsefoundation.efservices.helpers.DrupalAuthHelper;
+import org.eclipsefoundation.efservices.models.AuthenticatedRequestWrapper;
+import org.eclipsefoundation.efservices.namespace.RequestContextPropertyNames;
+import org.eclipsefoundation.efservices.services.DrupalOAuthService;
+import org.eclipsefoundation.efservices.services.ProfileService;
+import org.eclipsefoundation.http.annotations.AuthenticatedAlternate;
+import org.eclipsefoundation.http.config.OAuth2SecurityConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.enterprise.context.RequestScoped;
+import jakarta.enterprise.inject.Produces;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.HttpHeaders;
+
+/**
+ * 
+ */
+public class AuthenticatedRequestWrapperProvider {
+    private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticatedRequestWrapperProvider.class);
+
+    /**
+     * Using the passed context + services, retrieve the current user for the request. This does not use standard OIDC flow as the usual alt
+     * server does not properly implement the OAuth2 spec required for OIDC binding.
+     * 
+     * @param requestContext current HTTP request context
+     * @param info information about the endpoint called, used to check if alt authentication is enabled
+     * @param oauthService service binding to the OAuth2 service backing the alternate authentication
+     * @param profile instance for the EF user profile service, used in helper methods in the wrapper
+     * @param config values about the alternate authentication server to be used in the request
+     * @return the current authenticated request token and user, wrapped in a helper for ease of access
+     */
+    @Produces
+    @RequestScoped
+    public AuthenticatedRequestWrapper requestTokenWrapper(ContainerRequestContext requestContext, ResourceInfo info,
+            DrupalOAuthService oauthService, ProfileService profile, OAuth2SecurityConfig config) {
+        Method m = info.getResourceMethod();
+        AuthenticatedAlternate authenticated = m.getAnnotation(AuthenticatedAlternate.class);
+
+        if (authenticated != null) {
+            try {
+                String token = DrupalAuthHelper.stripBearerToken(requestContext.getHeaderString(HttpHeaders.AUTHORIZATION));
+
+                DrupalOAuthData tokenStatus = oauthService
+                        .validateTokenStatus(token, config.filter().validScopes(), config.filter().validClientIds());
+                if (tokenStatus != null) {
+
+                    requestContext.setProperty(RequestContextPropertyNames.TOKEN_STATUS, tokenStatus);
+
+                    if (tokenStatus.getUserId() != null) {
+                        // Fetch user data from token and set in context
+                        LOGGER.debug("Fetching user info for token with uid: {}", tokenStatus.getUserId());
+                        return new AuthenticatedRequestWrapper(tokenStatus, oauthService.getTokenUserInfo(token), profile);
+                    }
+                }
+                return new AuthenticatedRequestWrapper(tokenStatus, null, profile);
+            } catch (Exception e) {
+                // We want to prevent this from reaching user on profile queries.
+                LOGGER.debug("Invalid authentication", e);
+
+                // If the endpoint is authenticated and doesn't have a valid token, we deny the request
+                if (!authenticated.allowPartialResponse()) {
+                    throw e;
+                }
+            }
+        }
+        return new AuthenticatedRequestWrapper(null, null, profile);
+    }
+}
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/models/RequestUserWrapper.java b/efservices/src/main/java/org/eclipsefoundation/efservices/models/AuthenticatedRequestWrapper.java
similarity index 53%
rename from efservices/src/main/java/org/eclipsefoundation/efservices/models/RequestUserWrapper.java
rename to efservices/src/main/java/org/eclipsefoundation/efservices/models/AuthenticatedRequestWrapper.java
index e19ed94754353a2dd1a0ba1ce9e883e1bb667ed6..a63937301ab5a6b977314af03c8499a99ee224e7 100644
--- a/efservices/src/main/java/org/eclipsefoundation/efservices/models/RequestUserWrapper.java
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/models/AuthenticatedRequestWrapper.java
@@ -13,39 +13,38 @@ package org.eclipsefoundation.efservices.models;
 
 import java.util.Optional;
 
+import org.eclipsefoundation.efservices.api.models.DrupalOAuthData;
 import org.eclipsefoundation.efservices.api.models.DrupalUserInfo;
 import org.eclipsefoundation.efservices.api.models.EfUser;
 import org.eclipsefoundation.efservices.api.models.UserSearchParams;
-import org.eclipsefoundation.efservices.namespace.RequestContextPropertyNames;
 import org.eclipsefoundation.efservices.services.ProfileService;
 import org.eclipsefoundation.utils.exception.FinalForbiddenException;
 
-import jakarta.enterprise.context.RequestScoped;
-import jakarta.inject.Inject;
-import jakarta.servlet.http.HttpServletRequest;
-
 /**
- * A RequestScoped bean that wraps the DrupalUserInfo value set in the request chain. This bean is used to retrieve various information
- * about the user associated with the current token. To access this data, a DrupalUserInfo object must be set as the 'token_user' property
- * in the HttpServletRequest bound to the current request chain.
+ * A RequestScoped bean that wraps the DrupalOAuthData value set in the request chain. This bean is used to retrieve various information
+ * about the current token. To access this data, a DrupalOAuthData object must be set as the 'token_status' property in the
+ * HttpServletRequest bound to the current request chain.
  */
-@RequestScoped
-public class RequestUserWrapper {
-
+public class AuthenticatedRequestWrapper {
     private static final String NO_USER_ERR_MSG = "No user associated with this token";
 
+    private final DrupalOAuthData tokenStatus;
     private final DrupalUserInfo currentUser;
+    private final ProfileService profile;
 
-    @Inject
-    ProfileService profileService;
+    public AuthenticatedRequestWrapper(DrupalOAuthData tokenStatus, DrupalUserInfo currentUser, ProfileService profile) {
+        this.tokenStatus = tokenStatus;
+        this.currentUser = currentUser;
+        this.profile = profile;
+    }
 
     /**
-     * Gets the token user from the request and sets it. Returns a RequestUserWrapper instance.
+     * Retrieves the DrupalOAuthData bound to the current request chain.
      * 
-     * @param request The given HttpServletRequest
+     * @return The DrupalOAuthData bound to the current request.
      */
-    public RequestUserWrapper(HttpServletRequest request) {
-        this.currentUser = (DrupalUserInfo) request.getAttribute(RequestContextPropertyNames.TOKEN_USER);
+    public DrupalOAuthData getTokenStatus() {
+        return this.tokenStatus;
     }
 
     /**
@@ -61,39 +60,12 @@ public class RequestUserWrapper {
     }
 
     /**
-     * Retrieves the uid of the user associated with the current token.
-     * 
-     * @return The uid of the user associated with the current token.
-     */
-    public String getCurrentUserUid() {
-        if (currentUser == null) {
-            throw new FinalForbiddenException(NO_USER_ERR_MSG);
-        }
-        return this.currentUser.getSub();
-    }
-
-    /**
-     * Retrieves the ef username of the user associated with the current token.
+     * A simple check to determine if the current request has a valid token associated with it.
      * 
-     * @return The username of the user associated with the current token.
+     * @return True if valid token, false if not.
      */
-    public String getCurrentUserEfName() {
-        if (currentUser == null) {
-            throw new FinalForbiddenException(NO_USER_ERR_MSG);
-        }
-        return this.currentUser.getName();
-    }
-
-    /**
-     * Retrieves the GH handle of the user associated with the current token.
-     * 
-     * @return The GH handle of the user associated with the current token.
-     */
-    public String getCurrentUserGithubHandle() {
-        if (currentUser == null) {
-            throw new FinalForbiddenException(NO_USER_ERR_MSG);
-        }
-        return this.currentUser.getGithubHandle();
+    public boolean isAuthenticated() {
+        return tokenStatus != null;
     }
 
     /**
@@ -108,9 +80,9 @@ public class RequestUserWrapper {
         }
 
         // Fetch by username. Then fetch by gh handle if not found
-        Optional<EfUser> result = profileService
-                .fetchUserByUsername(getCurrentUserEfName(), false)
-                .or(() -> profileService.fetchUserByGhHandle(getCurrentUserGithubHandle(), false));
+        Optional<EfUser> result = profile
+                .fetchUserByUsername(currentUser.name(), false)
+                .or(() -> profile.fetchUserByGhHandle(currentUser.githubHandle(), false));
         if (result.isEmpty()) {
             throw new FinalForbiddenException(NO_USER_ERR_MSG);
         }
@@ -129,13 +101,13 @@ public class RequestUserWrapper {
         }
 
         // Perform user search, then fetch by Gh handle if not found.
-        Optional<EfUser> result = profileService
-                .performUserSearch(UserSearchParams.builder().setUid(getCurrentUserUid()).setName(getCurrentUserEfName()).build())
-                .or(() -> profileService.fetchUserByGhHandle(getCurrentUserGithubHandle(), true));
+        Optional<EfUser> result = profile
+                .performUserSearch(new UserSearchParams(currentUser.getCurrentUserUid(), currentUser.name(), null))
+                .or(() -> profile.fetchUserByGhHandle(currentUser.githubHandle(), true));
         if (result.isEmpty()) {
             throw new FinalForbiddenException(NO_USER_ERR_MSG);
         }
 
         return result.get();
     }
-}
\ No newline at end of file
+}
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/models/RequestTokenWrapper.java b/efservices/src/main/java/org/eclipsefoundation/efservices/models/RequestTokenWrapper.java
deleted file mode 100644
index 68d539a6c7c578de71c609bd533ea0c7f2db43d5..0000000000000000000000000000000000000000
--- a/efservices/src/main/java/org/eclipsefoundation/efservices/models/RequestTokenWrapper.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*********************************************************************
-* Copyright (c) 2023 Eclipse Foundation.
-*
-* This program and the accompanying materials are made
-* available under the terms of the Eclipse Public License 2.0
-* which is available at https://www.eclipse.org/legal/epl-2.0/
-*
-* Author: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
-*
-* SPDX-License-Identifier: EPL-2.0
-**********************************************************************/
-package org.eclipsefoundation.efservices.models;
-
-import jakarta.enterprise.context.RequestScoped;
-import jakarta.servlet.http.HttpServletRequest;
-
-import org.eclipsefoundation.efservices.api.models.DrupalOAuthData;
-import org.eclipsefoundation.efservices.namespace.RequestContextPropertyNames;
-
-/**
- * A RequestScoped bean that wraps the DrupalOAuthData value set in the request
- * chain. This bean is used to retrieve various information about the current
- * token. To access this data, a DrupalOAuthData object must be set as the
- * 'token_status' property in the HttpServletRequest bound to the current
- * request chain.
- */
-@RequestScoped
-public class RequestTokenWrapper {
-
-    private final DrupalOAuthData tokenStatus;
-
-    /**
-     * Gets the token info from the request and sets it. Rreturns a
-     * RequestTokenWrapper instance.
-     * 
-     * @param request The given HttpServletRequest
-     */
-    public RequestTokenWrapper(HttpServletRequest request) {
-        this.tokenStatus = (DrupalOAuthData) request.getAttribute(RequestContextPropertyNames.TOKEN_STATUS);
-    }
-
-    /**
-     * Retrieves the DrupalOAuthData bound to the current request chain.
-     * 
-     * @return The DrupalOAuthData bound to the current request.
-     */
-    public DrupalOAuthData getTokenStatus() {
-        return this.tokenStatus;
-    }
-
-    /**
-     * A simple check to determine if the current request has a valid token
-     * associated with it.
-     * 
-     * @return True if valid token, false if not.
-     */
-    public boolean isAuthenticated() {
-        return tokenStatus != null;
-    }
-}
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/precaches/WorkingGroupPrecacheProvider.java b/efservices/src/main/java/org/eclipsefoundation/efservices/precaches/WorkingGroupPrecacheProvider.java
index 0149571ef4174f9a85b5c9e0b8d212f2e587c83a..633f33781e9fa1b1a4872dadbd1e8623b354717f 100644
--- a/efservices/src/main/java/org/eclipsefoundation/efservices/precaches/WorkingGroupPrecacheProvider.java
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/precaches/WorkingGroupPrecacheProvider.java
@@ -46,7 +46,7 @@ public class WorkingGroupPrecacheProvider implements LoadingCacheProvider<Workin
     public List<WorkingGroup> fetchData(
             @MeterTag(resolver = CacheKeyClassTagResolver.class, key = METRICS_KEY_TAG_NAME) ParameterizedCacheKey k) {
         LOGGER.debug("LOADING PROJECTS WITH KEY: {}", k);
-        return middleware.getAll(params -> api.get(params), WorkingGroup.class);
+        return middleware.getAll(params -> api.get(params, null), WorkingGroup.class);
     }
 
     @Override
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/request/OAuthFilter.java b/efservices/src/main/java/org/eclipsefoundation/efservices/request/OAuthFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..69fc2bdc86b26dd579cebb8021e031d17a386c0b
--- /dev/null
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/request/OAuthFilter.java
@@ -0,0 +1,55 @@
+/*********************************************************************
+* Copyright (c) 2023 Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* Author: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.efservices.request;
+
+import org.eclipsefoundation.efservices.models.AuthenticatedRequestWrapper;
+import org.eclipsefoundation.http.config.OAuth2SecurityConfig;
+import org.jboss.resteasy.reactive.server.ServerRequestFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.UriInfo;
+
+/**
+ * This filter is used to validate the incoming Bearer tokens. Sets the current token user in the request context for use downstream.
+ */
+public class OAuthFilter {
+    private static final Logger LOGGER = LoggerFactory.getLogger(OAuthFilter.class);
+
+    private final OAuth2SecurityConfig config;
+    private final AuthenticatedRequestWrapper wrappedToken;
+
+    /**
+     * Default constructor for oauth filter, accepts required configuration for checking if filter is enabled, as well as the current
+     * requests wrapped token instance.
+     * 
+     * @param config oauth2 configuration for non-standard server binding
+     * @param wrappedToken oauth token wrapper associated with the current request
+     */
+    public OAuthFilter(OAuth2SecurityConfig config, AuthenticatedRequestWrapper wrappedToken) {
+        this.config = config;
+        this.wrappedToken = wrappedToken;
+    }
+
+    @ServerRequestFilter
+    public void filter(ContainerRequestContext requestContext, UriInfo uri, ResourceInfo info) {
+        if (Boolean.TRUE.equals(config.filter().enabled())) {
+            if (wrappedToken.isAuthenticated()) {
+                LOGGER.trace("User authenticated - {}", wrappedToken.getCurrentUser().name());
+            } else {
+                LOGGER.trace("User not authenticated for current request to {}", uri.getPath());
+            }
+        }
+    }
+}
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/services/impl/DefaultProfileService.java b/efservices/src/main/java/org/eclipsefoundation/efservices/services/impl/DefaultProfileService.java
index 0116b742c06033bd359786f198eccd1bba7bc3d3..6794e49b7cdae8fec7b69827513e20afc73825d1 100644
--- a/efservices/src/main/java/org/eclipsefoundation/efservices/services/impl/DefaultProfileService.java
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/services/impl/DefaultProfileService.java
@@ -24,12 +24,12 @@ import org.eclipsefoundation.efservices.api.models.UserSearchParams;
 import org.eclipsefoundation.efservices.namespace.EfServicesParameterNames;
 import org.eclipsefoundation.efservices.services.DrupalTokenService;
 import org.eclipsefoundation.efservices.services.ProfileService;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 
 /**
@@ -101,15 +101,15 @@ public class DefaultProfileService implements ProfileService {
      * @return A MultivaluedMap containing the given cache key params
      */
     private MultivaluedMap<String, String> buildSearchCacheParams(UserSearchParams params) {
-        MultivaluedMap<String, String> cacheParams = new MultivaluedMapImpl<>();
-        if (params.getUid() != null) {
-            cacheParams.add(EfServicesParameterNames.UID_RAW, params.getUid().toString());
+        MultivaluedMap<String, String> cacheParams = new MultivaluedHashMap<>();
+        if (params.uid != null) {
+            cacheParams.add(EfServicesParameterNames.UID_RAW, params.uid);
         }
-        if (StringUtils.isNotBlank(params.getName())) {
-            cacheParams.add(EfServicesParameterNames.NAME_RAW, params.getName());
+        if (StringUtils.isNotBlank(params.name)) {
+            cacheParams.add(EfServicesParameterNames.NAME_RAW, params.name);
         }
-        if (StringUtils.isNotBlank(params.getMail())) {
-            cacheParams.add(EfServicesParameterNames.MAIL_RAW, params.getMail());
+        if (StringUtils.isNotBlank(params.mail)) {
+            cacheParams.add(EfServicesParameterNames.MAIL_RAW, params.mail);
         }
         return cacheParams;
     }
@@ -125,7 +125,7 @@ public class DefaultProfileService implements ProfileService {
      * @return A MultivaluedMap containing the desired cache strategy.
      */
     private MultivaluedMap<String, String> buildCacheStrategy(String strategy, String visibility) {
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add(EfServicesParameterNames.STRATEGY.getName(), strategy);
         params.add(EfServicesParameterNames.VISIBILITY.getName(), visibility);
         return params;
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/services/impl/DefaultProjectService.java b/efservices/src/main/java/org/eclipsefoundation/efservices/services/impl/DefaultProjectService.java
index 76be9d2a54cec4c2da8a8f7a3339474e23a1b430..5f511ec0b1e6c18a4c4624a954165cb247fa8672 100644
--- a/efservices/src/main/java/org/eclipsefoundation/efservices/services/impl/DefaultProjectService.java
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/services/impl/DefaultProjectService.java
@@ -20,13 +20,13 @@ import org.eclipsefoundation.efservices.api.models.InterestGroup;
 import org.eclipsefoundation.efservices.api.models.Project;
 import org.eclipsefoundation.efservices.namespace.EfServicesParameterNames;
 import org.eclipsefoundation.efservices.services.ProjectService;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 
 import io.quarkus.runtime.Startup;
 import jakarta.annotation.PostConstruct;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.enterprise.inject.Instance;
 import jakarta.inject.Inject;
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 
 /**
@@ -60,12 +60,12 @@ public class DefaultProjectService implements ProjectService {
         return cacheManager.getList(ParameterizedCacheKey.builder()
                 .setId(DEFAULT_CACHE_ID)
                 .setClazz(Project.class)
-                .setParams(new MultivaluedMapImpl<>()).build());
+                .setParams(new MultivaluedHashMap<>()).build());
     }
 
     @Override
     public List<Project> getAllSpecProjects() {
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add(EfServicesParameterNames.SPEC_PROJECT_RAW, "1");
         return cacheManager.getList(ParameterizedCacheKey.builder()
                 .setId(DEFAULT_CACHE_ID)
@@ -78,6 +78,6 @@ public class DefaultProjectService implements ProjectService {
         return cacheManager.getList(ParameterizedCacheKey.builder()
                 .setId(DEFAULT_CACHE_ID)
                 .setClazz(InterestGroup.class)
-                .setParams(new MultivaluedMapImpl<>()).build());
+                .setParams(new MultivaluedHashMap<>()).build());
     }
 }
diff --git a/efservices/src/main/java/org/eclipsefoundation/efservices/services/impl/DefaultWorkingGroupService.java b/efservices/src/main/java/org/eclipsefoundation/efservices/services/impl/DefaultWorkingGroupService.java
index 3a3f1645632138cba46788c135194adfbfaae698..9e049f9a3cc10663617e185fd5069f55c588e873 100644
--- a/efservices/src/main/java/org/eclipsefoundation/efservices/services/impl/DefaultWorkingGroupService.java
+++ b/efservices/src/main/java/org/eclipsefoundation/efservices/services/impl/DefaultWorkingGroupService.java
@@ -28,69 +28,65 @@ import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
 
 /**
- * Retrieves working groups related to the Eclipse Foundation, as well as provides some basic filters built-in for ease of use.
+ * Retrieves working groups related to the Eclipse Foundation, as well as
+ * provides some basic filters built-in for ease of use.
  * 
  * @author Martin Lowe
  */
 @ApplicationScoped
 public class DefaultWorkingGroupService implements WorkingGroupService {
 
-    @Inject
-    LoadingCacheManager cache;
+	@Inject
+	LoadingCacheManager cache;
 
-    @Override
-    public List<WorkingGroup> get() {
-        return new ArrayList<>(cache.getList(ParameterizedCacheKey.builder().setId("all").setClazz(WorkingGroup.class).build()));
-    }
+	@Override
+	public List<WorkingGroup> get() {
+		return new ArrayList<>(
+				cache.getList(ParameterizedCacheKey.builder().setId("all").setClazz(WorkingGroup.class).build()));
+	}
 
-    @Override
-    public List<WorkingGroup> get(List<String> parentOrgs, List<String> statuses) {
-        return get()
-                .stream()
-                .filter(wg -> filterByParentOrganizations(parentOrgs, wg))
-                .filter(wg -> filterByProjectStatuses(statuses, wg))
-                .collect(Collectors.toList());
-    }
+	@Override
+	public List<WorkingGroup> get(List<String> parentOrgs, List<String> statuses) {
+		return get().stream().filter(wg -> filterByParentOrganizations(parentOrgs, wg))
+				.filter(wg -> filterByProjectStatuses(statuses, wg)).collect(Collectors.toList());
+	}
 
-    @Override
-    public Optional<WorkingGroup> getByName(String name) {
-        return get().stream().filter(wg -> wg.getAlias().equalsIgnoreCase(name)).findFirst();
-    }
+	@Override
+	public Optional<WorkingGroup> getByName(String name) {
+		return get().stream().filter(wg -> wg.getAlias().equalsIgnoreCase(name)).findFirst();
+	}
 
-    @Override
-    public Optional<WorkingGroup> getByAgreementId(String docId) {
-        Optional<Entry<String, List<String>>> entry = getWGPADocumentIDs()
-                .entrySet()
-                .stream()
-                .filter(e -> e.getValue().contains(docId))
-                .findFirst();
-        return entry.isEmpty() ? Optional.empty() : getByName(entry.get().getKey());
-    }
+	@Override
+	public Optional<WorkingGroup> getByAgreementId(String docId) {
+		Optional<Entry<String, List<String>>> entry = getWGPADocumentIDs().entrySet().stream()
+				.filter(e -> e.getValue().contains(docId)).findFirst();
+		return entry.isEmpty() ? Optional.empty() : getByName(entry.get().getKey());
+	}
 
-    @Override
-    public Map<String, List<String>> getWGPADocumentIDs() {
-        return get().stream().collect(Collectors.toMap(WorkingGroup::getAlias, this::extractWGPADocumentIDs));
-    }
+	@Override
+	public Map<String, List<String>> getWGPADocumentIDs() {
+		return get().stream().collect(Collectors.toMap(WorkingGroup::getAlias, this::extractWGPADocumentIDs));
+	}
 
-    private List<String> extractWGPADocumentIDs(WorkingGroup wg) {
-        List<String> ids = new ArrayList<>();
-        WorkingGroupParticipationAgreement iwgpa = wg.getResources().getParticipationAgreements().getIndividual();
-        if (iwgpa != null) {
-            ids.add(iwgpa.getDocumentId());
-        }
-        WorkingGroupParticipationAgreement wgpa = wg.getResources().getParticipationAgreements().getOrganization();
-        if (wgpa != null) {
-            ids.add(wgpa.getDocumentId());
-        }
-        return ids;
-    }
+	private List<String> extractWGPADocumentIDs(WorkingGroup wg) {
+		List<String> ids = new ArrayList<>();
+		WorkingGroupParticipationAgreement iwgpa = wg.getResources().getParticipationAgreements().getIndividual();
+		if (iwgpa != null) {
+			ids.add(iwgpa.getDocumentId());
+		}
+		WorkingGroupParticipationAgreement wgpa = wg.getResources().getParticipationAgreements().getOrganization();
+		if (wgpa != null) {
+			ids.add(wgpa.getDocumentId());
+		}
+		return ids;
+	}
 
-    private boolean filterByParentOrganizations(List<String> parentOrganizations, WorkingGroup wg) {
-        return parentOrganizations == null || parentOrganizations.isEmpty() ? true
-                : parentOrganizations.contains(wg.getParentOrganization());
-    }
+	private boolean filterByParentOrganizations(List<String> parentOrganizations, WorkingGroup wg) {
+		return (parentOrganizations == null || parentOrganizations.isEmpty())
+				|| parentOrganizations.contains(wg.getParentOrganization());
+	}
 
-    private boolean filterByProjectStatuses(List<String> statuses, WorkingGroup wg) {
-        return statuses == null || statuses.isEmpty() ? true : statuses.contains(wg.getStatus());
-    }
+	private boolean filterByProjectStatuses(List<String> statuses, WorkingGroup wg) {
+		return (statuses == null || statuses.isEmpty()) || statuses.contains(wg.getStatus());
+	}
 }
diff --git a/efservices/src/main/resources/application.properties b/efservices/src/main/resources/application.properties
index 166adb6fe8aa953c56af6f15657e0860c61f922b..b7b04728e43a71b42ef001027d94a1d344cfc6dc 100644
--- a/efservices/src/main/resources/application.properties
+++ b/efservices/src/main/resources/application.properties
@@ -1,3 +1,6 @@
+## Required for compression of REST client calls
+quarkus.http.enable-compression=true
+
 eclipse.cache.loading."projects".timeout=10
 eclipse.cache.loading."projects".refresh-after=PT1H
 
diff --git a/efservices/src/test/java/org/eclipsefoundation/efservices/request/OAuthFilterTest.java b/efservices/src/test/java/org/eclipsefoundation/efservices/request/OAuthFilterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f8dd5c6b5a41c58a2727875db6f46b2ebe27f94
--- /dev/null
+++ b/efservices/src/test/java/org/eclipsefoundation/efservices/request/OAuthFilterTest.java
@@ -0,0 +1,105 @@
+/*********************************************************************
+* Copyright (c) 2024 Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+/**
+ * 
+ */
+package org.eclipsefoundation.efservices.request;
+
+import java.util.Map;
+import java.util.Optional;
+
+import org.eclipsefoundation.efservices.test.AlternateAuthenticationFilterTestProfile;
+import org.eclipsefoundation.testing.helpers.TestCaseHelper;
+import org.eclipsefoundation.testing.models.EndpointTestBuilder;
+import org.eclipsefoundation.testing.models.EndpointTestCase;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.TestProfile;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.Response.Status;
+
+/**
+ * 
+ */
+@QuarkusTest
+@TestInstance(Lifecycle.PER_CLASS)
+@TestProfile(AlternateAuthenticationFilterTestProfile.class)
+public class OAuthFilterTest {
+    public static final String STANDARD_AUTH_URL = "authenticated";
+    public static final String PARTIAL_AUTH_URL = STANDARD_AUTH_URL + "/partial";
+
+    public static final Optional<Map<String, Object>> VALID_USER_AUTH_HEADER = Optional
+            .of(Map.of(HttpHeaders.AUTHORIZATION, "Bearer token5"));
+    public static final Optional<Map<String, Object>> INVALID_ANON_AUTH_HEADER = Optional
+            .of(Map.of(HttpHeaders.AUTHORIZATION, "Bearer othertoken"));
+
+    public static final EndpointTestCase STANDARD_AUTH_WITH_USER_SUCCESS = TestCaseHelper
+            .prepareTestCase(STANDARD_AUTH_URL, new String[] {}, null)
+            .setHeaderParams(VALID_USER_AUTH_HEADER)
+            .build();
+    public static final EndpointTestCase PARTIAL_AUTH_USER_SUCCESS = TestCaseHelper
+            .prepareTestCase(PARTIAL_AUTH_URL, new String[] {}, null)
+            .setHeaderParams(VALID_USER_AUTH_HEADER)
+            .build();
+
+    @Test
+    void oauthFilter_success() {
+        EndpointTestBuilder.from(STANDARD_AUTH_WITH_USER_SUCCESS).run();
+    }
+
+    @Test
+    void oauthFilter_failure_invalidAuth() {
+        // Invalid token, we want this to fail
+        EndpointTestBuilder
+                .from(TestCaseHelper
+                        .prepareTestCase(STANDARD_AUTH_URL, new String[] {}, null)
+                        .setHeaderParams(INVALID_ANON_AUTH_HEADER)
+                        .setStatusCode(403)
+                        .build())
+                .run();
+    }
+
+    @Test
+    void oauthFilter_failure_noAuth() {
+        // No auth token, we want this to fail
+        EndpointTestBuilder.from(TestCaseHelper.prepareTestCase(STANDARD_AUTH_URL, new String[] {}, null).setStatusCode(403).build()).run();
+    }
+
+    @Test
+    void oauthFilterPartialAuth_success() {
+        EndpointTestBuilder.from(PARTIAL_AUTH_USER_SUCCESS).run();
+    }
+
+    @Test
+    void oauthFilterPartialAuth_failure_invalidAuth() {
+        // Invalid token, we want this to fail
+        EndpointTestBuilder
+                .from(TestCaseHelper
+                        .prepareTestCase(PARTIAL_AUTH_URL, new String[] {}, null)
+                        .setHeaderParams(INVALID_ANON_AUTH_HEADER)
+                        .setStatusCode(Status.NO_CONTENT.getStatusCode())
+                        .build())
+                .run();
+    }
+
+    @Test
+    void oauthFilterPartialAuth_failure_noAuth() {
+        // No auth token, we want this to fail
+        EndpointTestBuilder
+                .from(TestCaseHelper
+                        .prepareTestCase(PARTIAL_AUTH_URL, new String[] {}, null)
+                        .setStatusCode(Status.NO_CONTENT.getStatusCode())
+                        .build())
+                .run();
+    }
+}
diff --git a/efservices/src/test/java/org/eclipsefoundation/efservices/services/AccountServiceTest.java b/efservices/src/test/java/org/eclipsefoundation/efservices/services/AccountServiceTest.java
index 99cae4e257dfa603c98e4d4cdd768ab058a59ed8..b136f965a653193ce5e7b1678ebc27ddd74c7f4a 100644
--- a/efservices/src/test/java/org/eclipsefoundation/efservices/services/AccountServiceTest.java
+++ b/efservices/src/test/java/org/eclipsefoundation/efservices/services/AccountServiceTest.java
@@ -101,20 +101,20 @@ class ProfileServiceTest {
     @Test
     void testSearchUser_success() {
         // Valid uid
-        UserSearchParams params = UserSearchParams.builder().setUid("666").build();
+        UserSearchParams params = new UserSearchParams("666", null, null);
         Optional<EfUser> result = profileService.performUserSearch(params);
         Assertions.assertTrue(result.isPresent(), String.format(SEARCH_NOT_FOUND_MSG_FORMAT, params.toString()));
         Assertions.assertEquals("666", result.get().getUid());
 
         // Invalid uid. Valid name
-        params = params.toBuilder().setUid("12").setName("firstlast").build();
+        params = new UserSearchParams("12", "firstlast", null);
         result = profileService.performUserSearch(params);
         Assertions.assertTrue(result.isPresent(), String.format(SEARCH_NOT_FOUND_MSG_FORMAT, params.toString()));
         Assertions.assertEquals("666", result.get().getUid());
         Assertions.assertEquals("firstlast", result.get().getName());
 
         // Invalid uid and name. Valid email
-        params = params.toBuilder().setUid("12").setName("wrongname").setMail("firstlast@test.com").build();
+        params = new UserSearchParams("12", "wrongname", "firstlast@test.com");
         result = profileService.performUserSearch(params);
         Assertions.assertTrue(result.isPresent(), String.format(SEARCH_NOT_FOUND_MSG_FORMAT, params.toString()));
         Assertions.assertEquals("666", result.get().getUid());
@@ -125,17 +125,17 @@ class ProfileServiceTest {
     @Test
     void testSearchUser_failure_notfound() {
         // Invalid uid
-        UserSearchParams params = UserSearchParams.builder().setUid("12").build();
+        UserSearchParams params = new UserSearchParams("12", null, null);
         Optional<EfUser> result = profileService.performUserSearch(params);
         Assertions.assertTrue(result.isEmpty());
 
         // Invalid uid and name
-        params = params.toBuilder().setUid("12").setName("wrongname").build();
+        params = new UserSearchParams("12", "wrongname", null);
         result = profileService.performUserSearch(params);
         Assertions.assertTrue(result.isEmpty());
 
         // Invalid uid, name, and email
-        params = params.toBuilder().setUid("12").setName("wrongname").setMail("wrongemail@test.co").build();
+        params = new UserSearchParams("12", "wrongname", "wrongemail@test.co");
         result = profileService.performUserSearch(params);
         Assertions.assertTrue(result.isEmpty());
     }
diff --git a/efservices/src/test/java/org/eclipsefoundation/efservices/test/AlternateAuthenticationFilterTestProfile.java b/efservices/src/test/java/org/eclipsefoundation/efservices/test/AlternateAuthenticationFilterTestProfile.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f691b9524ccda0354c476b7f0e7c377bab17d35
--- /dev/null
+++ b/efservices/src/test/java/org/eclipsefoundation/efservices/test/AlternateAuthenticationFilterTestProfile.java
@@ -0,0 +1,34 @@
+/*********************************************************************
+* Copyright (c) 2024 Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.efservices.test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import io.quarkus.test.junit.QuarkusTestProfile;
+
+public class AlternateAuthenticationFilterTestProfile implements QuarkusTestProfile {
+
+    // private immutable copy of the configs for auth state
+    private static Map<String, String> configOverrides;
+
+    @Override
+    public Map<String, String> getConfigOverrides() {
+        if (AlternateAuthenticationFilterTestProfile.configOverrides == null) {
+            Map<String, String> tmp = new HashMap<>();
+            tmp.put("eclipse.security.oauth2.filter.enabled", "true");
+            tmp.put("eclipse.security.oauth2.filter.valid-scopes", "admin");
+            tmp.put("eclipse.security.oauth2.filter.valid-client-ids", "test-id");
+            AlternateAuthenticationFilterTestProfile.configOverrides = Collections.unmodifiableMap(tmp);
+        }
+        return configOverrides;
+    }
+}
diff --git a/efservices/src/test/java/org/eclipsefoundation/efservices/test/api/MockDrupalOAuthAPI.java b/efservices/src/test/java/org/eclipsefoundation/efservices/test/api/MockDrupalOAuthAPI.java
index c2efef0d765cd2f59f41e39f84f47ad53662c6cf..efbf4413929645795e47671dee20cc11f03481d0 100644
--- a/efservices/src/test/java/org/eclipsefoundation/efservices/test/api/MockDrupalOAuthAPI.java
+++ b/efservices/src/test/java/org/eclipsefoundation/efservices/test/api/MockDrupalOAuthAPI.java
@@ -36,65 +36,63 @@ public class MockDrupalOAuthAPI implements DrupalOAuthAPI {
 
     public MockDrupalOAuthAPI() {
         tokens = new ArrayList<>();
-        tokens.addAll(Arrays.asList(
-                DrupalOAuthData.builder()
-                        .setAccessToken("token1")
-                        .setClientId("client-id")
-                        .setExpires(1674111182)
-                        .setScope("read write")
-                        .build(),
-                DrupalOAuthData.builder()
-                        .setAccessToken("token2")
-                        .setClientId("test-id")
-                        .setUserId("42")
-                        .setExpires(Instant.now().getEpochSecond() + 20000)
-                        .setScope("read write admin")
-                        .build(),
-                DrupalOAuthData.builder()
-                        .setAccessToken("token3")
-                        .setClientId("test-id")
-                        .setExpires(1234567890)
-                        .setScope("read admin")
-                        .build(),
-                DrupalOAuthData.builder()
-                        .setAccessToken("token4")
-                        .setClientId("client-id")
-                        .setExpires(Instant.now().getEpochSecond() + 20000)
-                        .setScope("read write")
-                        .build(),
-                DrupalOAuthData.builder()
-                        .setAccessToken("token5")
-                        .setClientId("test-id")
-                        .setUserId("333")
-                        .setExpires(Instant.now().getEpochSecond() + 20000)
-                        .setScope("admin")
-                        .build(),
-                DrupalOAuthData.builder()
-                        .setAccessToken("token6")
-                        .setClientId("test-id")
-                        .setExpires(Instant.now().getEpochSecond() + 20000)
-                        .setScope("read write admin")
-                        .build(),
-                DrupalOAuthData.builder()
-                        .setAccessToken("token7")
-                        .setClientId("test-id")
-                        .setUserId("444")
-                        .setExpires(Instant.now().getEpochSecond() + 20000)
-                        .setScope("read write admin")
-                        .build()));
+        tokens
+                .addAll(Arrays
+                        .asList(DrupalOAuthData
+                                .builder()
+                                .setAccessToken("token1")
+                                .setClientId("client-id")
+                                .setExpires(1674111182)
+                                .setScope("read write")
+                                .build(),
+                                DrupalOAuthData
+                                        .builder()
+                                        .setAccessToken("token2")
+                                        .setClientId("test-id")
+                                        .setUserId("42")
+                                        .setExpires(Instant.now().getEpochSecond() + 20000)
+                                        .setScope("read write admin")
+                                        .build(),
+                                DrupalOAuthData
+                                        .builder()
+                                        .setAccessToken("token3")
+                                        .setClientId("test-id")
+                                        .setExpires(1234567890)
+                                        .setScope("read admin")
+                                        .build(),
+                                DrupalOAuthData
+                                        .builder()
+                                        .setAccessToken("token4")
+                                        .setClientId("client-id")
+                                        .setExpires(Instant.now().getEpochSecond() + 20000)
+                                        .setScope("read write")
+                                        .build(),
+                                DrupalOAuthData
+                                        .builder()
+                                        .setAccessToken("token5")
+                                        .setClientId("test-id")
+                                        .setUserId("333")
+                                        .setExpires(Instant.now().getEpochSecond() + 20000)
+                                        .setScope("admin")
+                                        .build(),
+                                DrupalOAuthData
+                                        .builder()
+                                        .setAccessToken("token6")
+                                        .setClientId("test-id")
+                                        .setExpires(Instant.now().getEpochSecond() + 20000)
+                                        .setScope("read write admin")
+                                        .build(),
+                                DrupalOAuthData
+                                        .builder()
+                                        .setAccessToken("token7")
+                                        .setClientId("test-id")
+                                        .setUserId("444")
+                                        .setExpires(Instant.now().getEpochSecond() + 20000)
+                                        .setScope("read write admin")
+                                        .build()));
 
         users = new ArrayList<>();
-        users.addAll(Arrays.asList(
-                DrupalUserInfo.builder()
-                        .setSub("42")
-                        .setName("fakeuser")
-                        .setGithubHandle("fakeuser")
-                        .build(),
-                DrupalUserInfo.builder()
-                        .setSub("333")
-                        .setName("otheruser")
-                        .setGithubHandle("other")
-                        .build()));
+        users.addAll(Arrays.asList(new DrupalUserInfo("42", "fakeuser", "fakeuser"), new DrupalUserInfo("333", "otheruser", "other")));
     }
 
     @Override
@@ -109,7 +107,6 @@ public class MockDrupalOAuthAPI implements DrupalOAuthAPI {
             throw new FinalForbiddenException("The access token provided is invalid");
         }
 
-        return users.stream().filter(u -> u.getSub().equalsIgnoreCase(tokenInfo.getUserId())).findFirst()
-                .orElse(null);
+        return users.stream().filter(u -> u.sub().equalsIgnoreCase(tokenInfo.getUserId())).findFirst().orElse(null);
     }
 }
\ No newline at end of file
diff --git a/efservices/src/test/java/org/eclipsefoundation/efservices/test/api/MockProfileAPI.java b/efservices/src/test/java/org/eclipsefoundation/efservices/test/api/MockProfileAPI.java
index 6cf480cfd25c11b720a37b67c4ddf9810f327acd..9aae6745d3c808b6634b13fe85d4b4e7cbd5fdb1 100644
--- a/efservices/src/test/java/org/eclipsefoundation/efservices/test/api/MockProfileAPI.java
+++ b/efservices/src/test/java/org/eclipsefoundation/efservices/test/api/MockProfileAPI.java
@@ -17,11 +17,6 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Optional;
-import java.util.stream.Collectors;
-
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.inject.Inject;
-import jakarta.ws.rs.NotFoundException;
 
 import org.apache.commons.lang3.StringUtils;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -34,6 +29,9 @@ import org.eclipsefoundation.efservices.helpers.DrupalAuthHelper;
 import org.eclipsefoundation.efservices.services.DrupalOAuthService;
 
 import io.quarkus.test.Mock;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.NotFoundException;
 
 @Mock
 @RestClient
@@ -52,92 +50,98 @@ public class MockProfileAPI implements ProfileAPI {
 
     public MockProfileAPI() {
         this.users = new ArrayList<>();
-        this.users.addAll(Arrays.asList(
-                EfUser.builder()
-                        .setUid("666")
-                        .setName("firstlast")
-                        .setGithubHandle("handle")
-                        .setMail("firstlast@test.com")
-                        .setPicture("pic url")
-                        .setFirstName("fake")
-                        .setLastName("user")
-                        .setFullName("fake user")
-                        .setPublisherAgreements(new HashMap<>())
-                        .setTwitterHandle("")
-                        .setOrg("null")
-                        .setJobTitle("employee")
-                        .setWebsite("site url")
-                        .setCountry(Country.builder().setCode("CA").setName("Canada").build())
-                        .setInterests(Arrays.asList())
-                        .build(),
-                EfUser.builder()
-                        .setUid("42")
-                        .setName("fakeuser")
-                        .setPicture("pic url")
-                        .setFirstName("fake")
-                        .setLastName("user")
-                        .setFullName("fake user")
-                        .setMail("fakeuser@test.com")
-                        .setPublisherAgreements(new HashMap<>())
-                        .setGithubHandle("fakeuser")
-                        .setTwitterHandle("")
-                        .setOrg("null")
-                        .setJobTitle("employee")
-                        .setWebsite("site url")
-                        .setCountry(Country.builder().setCode("CA").setName("Canada").build())
-                        .setInterests(Arrays.asList())
-                        .build(),
-                EfUser.builder()
-                        .setUid("333")
-                        .setName("name")
-                        .setGithubHandle("name")
-                        .setMail("name@test.com")
-                        .setPicture("pic url")
-                        .setFirstName("fake")
-                        .setLastName("user")
-                        .setFullName("fake user")
-                        .setPublisherAgreements(new HashMap<>())
-                        .setTwitterHandle("")
-                        .setOrg("null")
-                        .setJobTitle("employee")
-                        .setWebsite("site url")
-                        .setCountry(Country.builder().setCode("CA").setName("Canada").build())
-                        .setInterests(Arrays.asList())
-                        .build(),
-                EfUser.builder()
-                        .setUid("11")
-                        .setName("testtesterson")
-                        .setGithubHandle("mctesty")
-                        .setMail("testtesterson@test.com")
-                        .setPicture("pic url")
-                        .setFirstName("fake")
-                        .setLastName("user")
-                        .setFullName("fake user")
-                        .setPublisherAgreements(new HashMap<>())
-                        .setTwitterHandle("")
-                        .setOrg("null")
-                        .setJobTitle("employee")
-                        .setWebsite("site url")
-                        .setCountry(Country.builder().setCode("CA").setName("Canada").build())
-                        .setInterests(Arrays.asList())
-                        .build(),
-                EfUser.builder()
-                        .setUid("444")
-                        .setName("nodoc")
-                        .setGithubHandle("nodoc")
-                        .setMail("nodoc@test.com")
-                        .setPicture("pic url")
-                        .setFirstName("fake")
-                        .setLastName("user")
-                        .setFullName("fake user")
-                        .setPublisherAgreements(new HashMap<>())
-                        .setTwitterHandle("")
-                        .setOrg("null")
-                        .setJobTitle("employee")
-                        .setWebsite("site url")
-                        .setCountry(Country.builder().setCode("CA").setName("Canada").build())
-                        .setInterests(Collections.emptyList())
-                        .build()));
+        this.users
+                .addAll(Arrays
+                        .asList(EfUser
+                                .builder()
+                                .setUid("666")
+                                .setName("firstlast")
+                                .setGithubHandle("handle")
+                                .setMail("firstlast@test.com")
+                                .setPicture("pic url")
+                                .setFirstName("fake")
+                                .setLastName("user")
+                                .setFullName("fake user")
+                                .setPublisherAgreements(new HashMap<>())
+                                .setTwitterHandle("")
+                                .setOrg("null")
+                                .setJobTitle("employee")
+                                .setWebsite("site url")
+                                .setCountry(Country.builder().setCode("CA").setName("Canada").build())
+                                .setInterests(Arrays.asList())
+                                .build(),
+                                EfUser
+                                        .builder()
+                                        .setUid("42")
+                                        .setName("fakeuser")
+                                        .setPicture("pic url")
+                                        .setFirstName("fake")
+                                        .setLastName("user")
+                                        .setFullName("fake user")
+                                        .setMail("fakeuser@test.com")
+                                        .setPublisherAgreements(new HashMap<>())
+                                        .setGithubHandle("fakeuser")
+                                        .setTwitterHandle("")
+                                        .setOrg("null")
+                                        .setJobTitle("employee")
+                                        .setWebsite("site url")
+                                        .setCountry(Country.builder().setCode("CA").setName("Canada").build())
+                                        .setInterests(Arrays.asList())
+                                        .build(),
+                                EfUser
+                                        .builder()
+                                        .setUid("333")
+                                        .setName("name")
+                                        .setGithubHandle("name")
+                                        .setMail("name@test.com")
+                                        .setPicture("pic url")
+                                        .setFirstName("fake")
+                                        .setLastName("user")
+                                        .setFullName("fake user")
+                                        .setPublisherAgreements(new HashMap<>())
+                                        .setTwitterHandle("")
+                                        .setOrg("null")
+                                        .setJobTitle("employee")
+                                        .setWebsite("site url")
+                                        .setCountry(Country.builder().setCode("CA").setName("Canada").build())
+                                        .setInterests(Arrays.asList())
+                                        .build(),
+                                EfUser
+                                        .builder()
+                                        .setUid("11")
+                                        .setName("testtesterson")
+                                        .setGithubHandle("mctesty")
+                                        .setMail("testtesterson@test.com")
+                                        .setPicture("pic url")
+                                        .setFirstName("fake")
+                                        .setLastName("user")
+                                        .setFullName("fake user")
+                                        .setPublisherAgreements(new HashMap<>())
+                                        .setTwitterHandle("")
+                                        .setOrg("null")
+                                        .setJobTitle("employee")
+                                        .setWebsite("site url")
+                                        .setCountry(Country.builder().setCode("CA").setName("Canada").build())
+                                        .setInterests(Arrays.asList())
+                                        .build(),
+                                EfUser
+                                        .builder()
+                                        .setUid("444")
+                                        .setName("nodoc")
+                                        .setGithubHandle("nodoc")
+                                        .setMail("nodoc@test.com")
+                                        .setPicture("pic url")
+                                        .setFirstName("fake")
+                                        .setLastName("user")
+                                        .setFullName("fake user")
+                                        .setPublisherAgreements(new HashMap<>())
+                                        .setTwitterHandle("")
+                                        .setOrg("null")
+                                        .setJobTitle("employee")
+                                        .setWebsite("site url")
+                                        .setCountry(Country.builder().setCode("CA").setName("Canada").build())
+                                        .setInterests(Collections.emptyList())
+                                        .build()));
     }
 
     @Override
@@ -145,24 +149,21 @@ public class MockProfileAPI implements ProfileAPI {
         // Ensure request is authenticated
         oauthService.validateTokenStatus(DrupalAuthHelper.stripBearerToken(token), validScopes, validClientIds);
 
-        if (params.getUid() == null && StringUtils.isBlank(params.getMail()) && StringUtils.isBlank(params.getName())) {
+        if (params.uid == null && StringUtils.isBlank(params.mail) && StringUtils.isBlank(params.name)) {
             return Collections.emptyList();
         }
 
         List<EfUser> results = Collections.emptyList();
 
         // Only filter via additional fields if it can't find with previous ones
-        if (params.getUid() != null) {
-            results = users.stream().filter(u -> u.getUid().equalsIgnoreCase(params.getUid()))
-                    .collect(Collectors.toList());
+        if (params.uid != null) {
+            results = users.stream().filter(u -> u.getUid().equalsIgnoreCase(params.uid)).toList();
         }
-        if (StringUtils.isNotBlank(params.getName()) && results.isEmpty()) {
-            results = users.stream().filter(u -> u.getName().equalsIgnoreCase(params.getName()))
-                    .collect(Collectors.toList());
+        if (StringUtils.isNotBlank(params.name) && results.isEmpty()) {
+            results = users.stream().filter(u -> u.getName().equalsIgnoreCase(params.name)).toList();
         }
-        if (StringUtils.isNotBlank(params.getMail()) && results.isEmpty()) {
-            results = users.stream().filter(u -> u.getMail().equalsIgnoreCase(params.getMail()))
-                    .collect(Collectors.toList());
+        if (StringUtils.isNotBlank(params.mail) && results.isEmpty()) {
+            results = users.stream().filter(u -> u.getMail().equalsIgnoreCase(params.mail)).toList();
         }
 
         return results;
@@ -189,8 +190,7 @@ public class MockProfileAPI implements ProfileAPI {
     }
 
     /*
-     * Strips the public fields from the incoming EfUser entity if the request if
-     * not properly authenticated.
+     * Strips the public fields from the incoming EfUser entity if the request if not properly authenticated.
      */
     private EfUser privateProfileFilter(String token, EfUser user) {
         try {
@@ -198,12 +198,7 @@ public class MockProfileAPI implements ProfileAPI {
             oauthService.validateTokenStatus(DrupalAuthHelper.stripBearerToken(token), validScopes, validClientIds);
             return user;
         } catch (Exception e) {
-            return user.toBuilder()
-                    .setMail("")
-                    .setCountry(Country.builder()
-                            .setCode(null)
-                            .setName(null).build())
-                    .build();
+            return user.toBuilder().setMail("").setCountry(Country.builder().setCode(null).setName(null).build()).build();
         }
     }
 }
diff --git a/efservices/src/test/java/org/eclipsefoundation/efservices/test/api/MockWorkingGroupAPI.java b/efservices/src/test/java/org/eclipsefoundation/efservices/test/api/MockWorkingGroupAPI.java
index 2fdf211184221fd65cd8f51bb228e5deedccbb28..92c0156a4399f9d8bd5b7b471c3af6953dd2bcaf 100644
--- a/efservices/src/test/java/org/eclipsefoundation/efservices/test/api/MockWorkingGroupAPI.java
+++ b/efservices/src/test/java/org/eclipsefoundation/efservices/test/api/MockWorkingGroupAPI.java
@@ -61,13 +61,8 @@ public class MockWorkingGroupAPI implements WorkingGroupsAPI {
     }
 
     @Override
-    public Response get(BaseAPIParameters baseParams) {
-        return Response.ok(wgs).build();
-    }
-
-    @Override
-    public Response getAllByStatuses(BaseAPIParameters baseParams, List<String> statuses) {
-        return Response.ok(wgs.stream().filter(wg -> statuses.contains(wg.getStatus())).collect(Collectors.toList())).build();
+    public Response get(BaseAPIParameters baseParams, List<String> statuses) {
+        return Response.ok(wgs.stream().filter(wg -> statuses == null || statuses.contains(wg.getStatus())).toList()).build();
     }
 
     private WorkingGroup.Builder buildBasic(String alias) {
diff --git a/efservices/src/test/java/org/eclipsefoundation/efservices/test/resources/TestResources.java b/efservices/src/test/java/org/eclipsefoundation/efservices/test/resources/TestResources.java
new file mode 100644
index 0000000000000000000000000000000000000000..260361a030ef8b0d54d0ce5dc70169cfa3bf539a
--- /dev/null
+++ b/efservices/src/test/java/org/eclipsefoundation/efservices/test/resources/TestResources.java
@@ -0,0 +1,50 @@
+/*********************************************************************
+* Copyright (c) 2024 Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+/**
+ * 
+ */
+package org.eclipsefoundation.efservices.test.resources;
+
+import org.eclipsefoundation.efservices.models.AuthenticatedRequestWrapper;
+import org.eclipsefoundation.http.annotations.AuthenticatedAlternate;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.Status;
+
+/**
+ * Test resource for alternate authentication
+ */
+@Path("authenticated")
+public class TestResources {
+    
+    @Inject
+    AuthenticatedRequestWrapper altAuthUser;
+
+    @GET
+    @AuthenticatedAlternate
+    public Response getAuthenticated() {
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("partial")
+    @AuthenticatedAlternate(allowPartialResponse = true)
+    public Response getAuthenticatedOptional() {
+        if (altAuthUser.isAuthenticated()) {
+            return Response.ok().build();
+        }
+        // use slightly different response for validation
+        return Response.status(Status.NO_CONTENT).build();
+    }
+
+}
diff --git a/http/pom.xml b/http/pom.xml
index 621a4e2a06ff59a013f6691b75853534c6fd6058..94bc176472ff8751fcda132097097d6b47291682 100644
--- a/http/pom.xml
+++ b/http/pom.xml
@@ -9,7 +9,7 @@
     <parent>
         <groupId>org.eclipsefoundation</groupId>
         <artifactId>quarkus-commons</artifactId>
-        <version>1.0.3-SNAPSHOT</version>
+        <version>1.1.0</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <properties>
@@ -23,15 +23,11 @@
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-resteasy</artifactId>
+            <artifactId>quarkus-resteasy-reactive</artifactId>
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-resteasy-jackson</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-undertow</artifactId>
+            <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
@@ -65,7 +61,7 @@
 
         <dependency>
             <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-resteasy-qute</artifactId>
+            <artifactId>quarkus-resteasy-reactive-qute</artifactId>
         </dependency>
         <!-- Test dependencies -->
         <dependency>
@@ -121,4 +117,4 @@
             </plugin>
         </plugins>
     </build>
-</project>
\ No newline at end of file
+</project>
diff --git a/http/src/main/java/org/eclipsefoundation/http/annotations/AuthenticatedAlternate.java b/http/src/main/java/org/eclipsefoundation/http/annotations/AuthenticatedAlternate.java
new file mode 100644
index 0000000000000000000000000000000000000000..52684f4f834ed58f7bae349b1f89bb3338df9659
--- /dev/null
+++ b/http/src/main/java/org/eclipsefoundation/http/annotations/AuthenticatedAlternate.java
@@ -0,0 +1,28 @@
+/*********************************************************************
+* Copyright (c) 2023 Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* Author: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.http.annotations;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * A Runtime annotation used to allow full blocking on some endpoints, while allowing a partial profile responses.
+ */
+@Retention(RUNTIME)
+@Target(METHOD)
+public @interface AuthenticatedAlternate {
+
+    boolean allowPartialResponse() default false;
+}
diff --git a/http/src/main/java/org/eclipsefoundation/http/config/AdditionalUserDataProvider.java b/http/src/main/java/org/eclipsefoundation/http/config/AdditionalUserDataProvider.java
index 291a0fd9cbcc04c97661988bb4f6f147f2c6ed4e..3fab409212b3579f3c5ee470f5e6e2f1b98ebf26 100644
--- a/http/src/main/java/org/eclipsefoundation/http/config/AdditionalUserDataProvider.java
+++ b/http/src/main/java/org/eclipsefoundation/http/config/AdditionalUserDataProvider.java
@@ -16,7 +16,7 @@ import org.eclipsefoundation.utils.model.AdditionalUserData;
 import io.quarkus.arc.DefaultBean;
 import io.quarkus.arc.Unremovable;
 import jakarta.enterprise.context.Dependent;
-import jakarta.enterprise.context.SessionScoped;
+import jakarta.enterprise.context.RequestScoped;
 import jakarta.enterprise.inject.Produces;
 
 /**
@@ -32,7 +32,7 @@ public class AdditionalUserDataProvider {
 
     @Produces
     @DefaultBean
-    @SessionScoped
+    @RequestScoped
     public AdditionalUserData generator() {
         return new AdditionalUserData();
     }
diff --git a/http/src/main/java/org/eclipsefoundation/http/model/DefaultRequestWrapper.java b/http/src/main/java/org/eclipsefoundation/http/model/DefaultRequestWrapper.java
index 5e0e9cd69280bd91c7ed58f41f66f5c2284a70f5..d90a32303b644c60c23fa0e6f431d5b187496579 100644
--- a/http/src/main/java/org/eclipsefoundation/http/model/DefaultRequestWrapper.java
+++ b/http/src/main/java/org/eclipsefoundation/http/model/DefaultRequestWrapper.java
@@ -26,15 +26,15 @@ import org.eclipsefoundation.http.namespace.DefaultUrlParameterNames;
 import org.eclipsefoundation.http.namespace.RequestHeaderNames;
 import org.eclipsefoundation.http.request.CacheBypassFilter;
 import org.eclipsefoundation.utils.namespace.UrlParameterNamespace.UrlParameter;
-import org.jboss.resteasy.core.ResteasyContext;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 
 import io.quarkus.arc.Unremovable;
 import io.quarkus.security.identity.SecurityIdentity;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.HttpServerResponse;
 import jakarta.enterprise.context.RequestScoped;
 import jakarta.inject.Inject;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.UriInfo;
 
@@ -50,7 +50,7 @@ public class DefaultRequestWrapper implements RequestWrapper {
     private static final String EMPTY_KEY_MESSAGE = "Key must not be null or blank";
 
     private Map<String, List<String>> params;
-    private MultivaluedMap<String, String> headers;
+    private MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
 
     @Inject
     SecurityIdentity ident;
@@ -58,17 +58,14 @@ public class DefaultRequestWrapper implements RequestWrapper {
     @Inject
     PaginationConfig config;
 
-    private UriInfo uriInfo;
-    private HttpServletRequest request;
-    private HttpServletResponse response;
-
-    /** Generates a wrapper around the context data available from the servlet container. */
-    public DefaultRequestWrapper() {
-        this.headers = new MultivaluedMapImpl<>();
-        this.uriInfo = ResteasyContext.getContextData(UriInfo.class);
-        this.request = ResteasyContext.getContextData(HttpServletRequest.class);
-        this.response = ResteasyContext.getContextData(HttpServletResponse.class);
-    }
+    @Inject
+    UriInfo uriInfo;
+    @Inject
+    HttpServerRequest request;
+    @Inject
+    ContainerRequestContext requestContext;
+    @Inject
+    HttpServerResponse response;
 
     /**
      * Retrieves the first value set in a list from the map for a given key.
@@ -163,7 +160,7 @@ public class DefaultRequestWrapper implements RequestWrapper {
      */
     @Override
     public MultivaluedMap<String, String> asMap() {
-        MultivaluedMap<String, String> out = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> out = new MultivaluedHashMap<>();
         getParams().forEach((key, values) -> out.addAll(key, new ArrayList<>(values)));
         return out;
     }
@@ -200,7 +197,7 @@ public class DefaultRequestWrapper implements RequestWrapper {
      */
     @Override
     public Optional<Object> getAttribute(String key) {
-        return Optional.ofNullable(request.getAttribute(key));
+        return Optional.ofNullable(requestContext.getProperty(key));
     }
 
     /**
@@ -210,7 +207,7 @@ public class DefaultRequestWrapper implements RequestWrapper {
      */
     @Override
     public boolean isCacheBypass() {
-        Object attr = request.getAttribute(CacheBypassFilter.ATTRIBUTE_NAME);
+        Object attr = requestContext.getProperty(CacheBypassFilter.ATTRIBUTE_NAME);
         // if we have the attribute set on the request, return it. otherwise, false.
         return attr instanceof Boolean ? (boolean) attr : Boolean.FALSE;
     }
@@ -229,7 +226,7 @@ public class DefaultRequestWrapper implements RequestWrapper {
     @Override
     public String getResponseHeader(String key) {
         if (getResponse() != null) {
-            return getResponse().getHeader(key);
+            return getResponse().headers().get(key);
         }
         return headers.getFirst(key);
     }
@@ -254,15 +251,12 @@ public class DefaultRequestWrapper implements RequestWrapper {
     @Override
     public void setHeader(String name, String value) {
         if (getResponse() != null) {
-            getResponse().setHeader(name, value);
+            getResponse().headers().add(name, value);
         }
         headers.add(name, value);
     }
 
-    protected HttpServletResponse getResponse() {
-        if (response == null) {
-            response = ResteasyContext.getContextData(HttpServletResponse.class);
-        }
+    protected HttpServerResponse getResponse() {
         return response;
     }
 
@@ -299,8 +293,8 @@ public class DefaultRequestWrapper implements RequestWrapper {
     public String toString() {
         StringBuilder sb = new StringBuilder();
         sb.append("RequestWrapper [");
-        sb.append("ip=").append(request.getRemoteAddr());
-        sb.append(", uri=").append(request.getRequestURI());
+        sb.append("ip=").append(request.remoteAddress());
+        sb.append(", uri=").append(request.uri());
         sb.append(", params=").append(getParams());
         return sb.toString();
     }
diff --git a/http/src/main/java/org/eclipsefoundation/http/model/FlatRequestWrapper.java b/http/src/main/java/org/eclipsefoundation/http/model/FlatRequestWrapper.java
index 4c5ebe22f563452de0117586420f61073c4f1748..774106bbb3eeee54abf84dc116b819845b117979 100644
--- a/http/src/main/java/org/eclipsefoundation/http/model/FlatRequestWrapper.java
+++ b/http/src/main/java/org/eclipsefoundation/http/model/FlatRequestWrapper.java
@@ -22,10 +22,10 @@ import java.util.Optional;
 import org.apache.commons.lang3.StringUtils;
 import org.eclipsefoundation.http.namespace.DefaultUrlParameterNames;
 import org.eclipsefoundation.utils.namespace.UrlParameterNamespace.UrlParameter;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 
 import io.quarkus.security.identity.SecurityIdentity;
 import io.quarkus.security.runtime.QuarkusSecurityIdentity;
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 
 /**
@@ -35,8 +35,8 @@ import jakarta.ws.rs.core.MultivaluedMap;
  *
  */
 public class FlatRequestWrapper implements RequestWrapper {
-    private MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
-    private MultivaluedMap<String, String> headers = new MultivaluedMapImpl<>();
+    private MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
+    private MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
     private URI endpoint;
 
     private static final int DEFAULT_FLAT_PAGE_SIZE = 1000;
@@ -84,7 +84,7 @@ public class FlatRequestWrapper implements RequestWrapper {
 
     @Override
     public MultivaluedMap<String, String> asMap() {
-        MultivaluedMap<String, String> out = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> out = new MultivaluedHashMap<>();
         getParams().forEach(out::addAll);
         return out;
     }
diff --git a/http/src/main/java/org/eclipsefoundation/http/request/CSRFSecurityFilter.java b/http/src/main/java/org/eclipsefoundation/http/request/CSRFSecurityFilter.java
index 1290eaf3a7944f53cd95138c0bc8e1e473751110..0a8e07fcc225eb3abb988e7858f57250ece14618 100644
--- a/http/src/main/java/org/eclipsefoundation/http/request/CSRFSecurityFilter.java
+++ b/http/src/main/java/org/eclipsefoundation/http/request/CSRFSecurityFilter.java
@@ -22,65 +22,57 @@ import org.eclipsefoundation.utils.config.CSRFSecurityConfig;
 import org.eclipsefoundation.utils.exception.FinalForbiddenException;
 import org.eclipsefoundation.utils.helper.CSRFHelper;
 import org.eclipsefoundation.utils.model.AdditionalUserData;
-import org.jboss.resteasy.core.interception.jaxrs.PostMatchContainerRequestContext;
+import org.jboss.resteasy.reactive.server.ServerRequestFilter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import io.undertow.httpcore.HttpMethodNames;
-import jakarta.enterprise.inject.Instance;
-import jakarta.inject.Inject;
-import jakarta.servlet.http.HttpServletRequest;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.HttpServerRequest;
 import jakarta.ws.rs.container.ContainerRequestContext;
-import jakarta.ws.rs.container.ContainerRequestFilter;
-import jakarta.ws.rs.core.Context;
-import jakarta.ws.rs.ext.Provider;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.SecurityContext;
 
 /**
- * Creates a security layer in front of mutation requests to require CSRF tokens
- * (if enabled). This layer does not perform the check of the token in-case
- * there are other conditions that would rebuff the request.
+ * Creates a security layer in front of mutation requests to require CSRF tokens (if enabled). This layer does not perform the check of the
+ * token in-case there are other conditions that would rebuff the request.
  * 
  * @author Martin Lowe
  */
-@Provider
-public class CSRFSecurityFilter implements ContainerRequestFilter {
+public class CSRFSecurityFilter {
     public static final Logger LOGGER = LoggerFactory.getLogger(CSRFSecurityFilter.class);
 
-    @Inject
-    Instance<CSRFSecurityConfig> config;
+    private final CSRFSecurityConfig config;
+    private final CSRFHelper csrf;
+    private final AdditionalUserData aud;
 
-    @Context
-    HttpServletRequest httpServletRequest;
-    @Inject
-    Instance<CSRFHelper> csrf;
-    @Inject
-    AdditionalUserData aud;
-
-    @Override
-    public void filter(ContainerRequestContext requestContext) throws IOException {
-        if (config.get().enabled()) {
+    public CSRFSecurityFilter(CSRFHelper csrf, AdditionalUserData aud, CSRFSecurityConfig config) {
+        this.config = config;
+        this.csrf = csrf;
+        this.aud = aud;
+    }
 
+    @ServerRequestFilter
+    public void filter(ContainerRequestContext requestContext, ResourceInfo info, HttpServerRequest request) throws IOException {
+        if (config.enabled()) {
             // Reflect method and get annotation
-            Method m = ((PostMatchContainerRequestContext) requestContext).getResourceMethod().getMethod();
+            Method m = info.getResourceMethod();
             Csrf annotation = m.getAnnotation(Csrf.class);
 
-            if ((annotation != null && annotation.enabled())
-                    || (annotation == null && isMutationAction(requestContext.getMethod()))) {
-                validateCsrfToken(requestContext.getHeaderString(RequestHeaderNames.CSRF_TOKEN));
+            if ((annotation != null && annotation.enabled()) || (annotation == null && isMutationAction(requestContext.getMethod()))) {
+                validateCsrfToken(requestContext.getHeaderString(RequestHeaderNames.CSRF_TOKEN), request,
+                        requestContext.getSecurityContext());
             }
         }
     }
 
     /**
-     * Check if the HTTP method indicates a mutation action such as DELETE, POST, or
-     * PUT.
+     * Check if the HTTP method indicates a mutation action such as DELETE, POST, or PUT.
      * 
      * @param method The given HTTP method
      * @return True if DELETE, POST, or PUT
      */
     private boolean isMutationAction(String method) {
-        return HttpMethodNames.DELETE.equals(method) || HttpMethodNames.POST.equals(method)
-                || HttpMethodNames.PUT.equals(method);
+        return HttpMethod.DELETE.name().equals(method) || HttpMethod.POST.name().equals(method) || HttpMethod.PUT.name().equals(method);
     }
 
     /**
@@ -88,16 +80,16 @@ public class CSRFSecurityFilter implements ContainerRequestFilter {
      * 
      * @param token The request CSRF token
      */
-    private void validateCsrfToken(String token) {
+    private void validateCsrfToken(String token, HttpServerRequest request, SecurityContext context) {
         // Validate presence
         if (StringUtils.isBlank(token)) {
             throw new FinalForbiddenException("No CSRF token passed for mutation call, refusing connection");
-        } else if (config.get().distributedMode().enabled()) {
+        } else if (config.distributedMode().enabled()) {
             // distributed mode should return the stored token if it exists
-            csrf.get().compareCSRF(csrf.get().getNewCSRFToken(httpServletRequest), token);
+            csrf.compareCSRF(csrf.getNewCSRFToken(request, context), token);
         } else {
             // run comparison. If error, exception will be thrown
-            csrf.get().compareCSRF(aud.getCsrf(), token);
+            csrf.compareCSRF(aud.getCsrf(), token);
         }
     }
 }
diff --git a/http/src/main/java/org/eclipsefoundation/http/request/CacheBypassFilter.java b/http/src/main/java/org/eclipsefoundation/http/request/CacheBypassFilter.java
index e7cc3f081202434ac11ce1542662842307657794..fcd114ddd164245e840503d0eb52aebf74727a23 100644
--- a/http/src/main/java/org/eclipsefoundation/http/request/CacheBypassFilter.java
+++ b/http/src/main/java/org/eclipsefoundation/http/request/CacheBypassFilter.java
@@ -13,14 +13,14 @@ package org.eclipsefoundation.http.request;
 
 import java.io.IOException;
 
+import org.jboss.resteasy.reactive.server.ServerRequestFilter;
+
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.HttpServerResponse;
 import jakarta.enterprise.inject.Instance;
 import jakarta.inject.Inject;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
 import jakarta.ws.rs.container.ContainerRequestContext;
-import jakarta.ws.rs.container.ContainerRequestFilter;
-import jakarta.ws.rs.core.Context;
-import jakarta.ws.rs.ext.Provider;
+import jakarta.ws.rs.core.Response;
 
 /**
  * Checks passed parameters and if any match one of the criteria for bypassing
@@ -30,35 +30,29 @@ import jakarta.ws.rs.ext.Provider;
  * @author Martin Lowe
  *
  */
-@Provider
-public class CacheBypassFilter implements ContainerRequestFilter {
+public class CacheBypassFilter {
 	public static final String ATTRIBUTE_NAME = "bypass-cache";
 
 	@Inject
 	Instance<BypassCondition> conditions;
 
-	@Context
-	HttpServletRequest request;
-
-	@Context
-	HttpServletResponse response;
-
-	@Override
-	public void filter(ContainerRequestContext requestContext) throws IOException {
+	@ServerRequestFilter
+	public Response filter(ContainerRequestContext requestContext, HttpServerRequest request, HttpServerResponse response) throws IOException {
 		// check for random sort order, which always bypasses cache
 		for (BypassCondition cond : conditions) {
-			if (cond.matches(requestContext, request)) {
-				setBypass();
-				return;
+			if (cond.matches(requestContext)) {
+				setBypass(requestContext, response);
+				return null;
 			}
 		}
-		request.setAttribute(ATTRIBUTE_NAME, Boolean.FALSE);
+		requestContext.setProperty(ATTRIBUTE_NAME, Boolean.FALSE);
+		return null;
 	}
 
-	private void setBypass() {
-		request.setAttribute(ATTRIBUTE_NAME, Boolean.TRUE);
+	private void setBypass(ContainerRequestContext requestContext, HttpServerResponse response) {
+		requestContext.setProperty(ATTRIBUTE_NAME, Boolean.TRUE);
 		// no-store should be used as cache bypass should not return
-		response.setHeader("Cache-Control", "no-store");
+		response.putHeader("Cache-Control", "no-store");
 	}
 
 	/**
@@ -74,10 +68,8 @@ public class CacheBypassFilter implements ContainerRequestFilter {
 		 * should bypass the cache layer.
 		 * 
 		 * @param requestContext the current requests container context
-		 * @param request        raw servlet request containing more information about
-		 *                       the request
 		 * @return true if the request should bypass the cache, false otherwise.
 		 */
-		boolean matches(ContainerRequestContext requestContext, HttpServletRequest request);
+		boolean matches(ContainerRequestContext requestContext);
 	}
 }
diff --git a/http/src/main/java/org/eclipsefoundation/http/request/OptionalPathFilter.java b/http/src/main/java/org/eclipsefoundation/http/request/OptionalPathFilter.java
index 739478092c7b5f9096373b0d3d8936147089e397..1ead0736a11b741888e3ae4d46dd286758419d20 100644
--- a/http/src/main/java/org/eclipsefoundation/http/request/OptionalPathFilter.java
+++ b/http/src/main/java/org/eclipsefoundation/http/request/OptionalPathFilter.java
@@ -4,21 +4,22 @@ import java.io.IOException;
 import java.lang.reflect.Method;
 import java.util.Optional;
 
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.eclipsefoundation.http.annotations.OptionalPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import jakarta.annotation.Priority;
 import jakarta.enterprise.inject.Instance;
 import jakarta.ws.rs.container.ContainerRequestContext;
 import jakarta.ws.rs.container.ContainerRequestFilter;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.Context;
 import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.Response.Status;
 import jakarta.ws.rs.ext.Provider;
 
-import org.eclipse.microprofile.config.ConfigProvider;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-import org.eclipsefoundation.http.annotations.OptionalPath;
-import org.jboss.resteasy.core.interception.jaxrs.PostMatchContainerRequestContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 /**
  * Does lookups on the current path to see if the resource is disabled.
  * 
@@ -33,10 +34,13 @@ public class OptionalPathFilter implements ContainerRequestFilter {
     @ConfigProperty(name = "eclipse.optional-resources.enabled", defaultValue = "false")
     Instance<Boolean> optionalResourcesEnabled;
 
+    @Context
+    ResourceInfo info;
+
     @Override
     public void filter(ContainerRequestContext requestContext) throws IOException {
         // check annotation on target endpoint to be sure that endpoint is enabled
-        Method m = ((PostMatchContainerRequestContext) requestContext).getResourceMethod().getMethod();
+        Method m = info.getResourceMethod();
         OptionalPath opt = m.getAnnotation(OptionalPath.class);
         if (opt != null) {
             if (Boolean.FALSE.equals(optionalResourcesEnabled.get())) {
diff --git a/http/src/main/java/org/eclipsefoundation/http/request/SecuredResourceFilter.java b/http/src/main/java/org/eclipsefoundation/http/request/SecuredResourceFilter.java
index 51f84a840a56308b1b799147ee5c1eab0d10fbf7..72ec74a841eb92ff90d8a65b04e0d895e4c9f85f 100644
--- a/http/src/main/java/org/eclipsefoundation/http/request/SecuredResourceFilter.java
+++ b/http/src/main/java/org/eclipsefoundation/http/request/SecuredResourceFilter.java
@@ -14,24 +14,24 @@ package org.eclipsefoundation.http.request;
 import java.io.IOException;
 import java.lang.reflect.Method;
 
-import jakarta.annotation.Priority;
-import jakarta.enterprise.inject.Instance;
-import jakarta.inject.Inject;
-import jakarta.ws.rs.container.ContainerRequestContext;
-import jakarta.ws.rs.container.ContainerRequestFilter;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Response.Status;
-import jakarta.ws.rs.ext.Provider;
-
 import org.apache.commons.lang3.StringUtils;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.eclipsefoundation.http.annotations.KeySecured;
 import org.eclipsefoundation.http.helper.SecureResourceKey;
-import org.jboss.resteasy.core.interception.jaxrs.PostMatchContainerRequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import io.quarkus.runtime.configuration.ConfigUtils;
+import jakarta.annotation.Priority;
+import jakarta.enterprise.inject.Instance;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerRequestFilter;
+import jakarta.ws.rs.container.ResourceInfo;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.Status;
+import jakarta.ws.rs.ext.Provider;
 
 /**
  * Checks if the current resource is protected by the shared {@link SecureResourceKey} and evaluates the key to make
@@ -50,10 +50,13 @@ public class SecuredResourceFilter implements ContainerRequestFilter {
     @Inject
     SecureResourceKey key;
 
+    @Context
+    ResourceInfo info;
+
     @Override
     public void filter(ContainerRequestContext requestContext) throws IOException {
         // check annotation on target endpoint to be sure that endpoint is enabled
-        Method m = ((PostMatchContainerRequestContext) requestContext).getResourceMethod().getMethod();
+        Method m = info.getResourceMethod();
         KeySecured opt = m.getAnnotation(KeySecured.class);
         if (opt != null) {
             // retrieve the passed key from the parameters and abort request if it doesn't match
diff --git a/http/src/main/java/org/eclipsefoundation/http/response/CSRFHeaderFilter.java b/http/src/main/java/org/eclipsefoundation/http/response/CSRFHeaderFilter.java
index 2ff962b4b98bdc51060077a8ecad5d291f1bc89f..927015aa92e753a3b7a671dd8862790630fcfd3a 100644
--- a/http/src/main/java/org/eclipsefoundation/http/response/CSRFHeaderFilter.java
+++ b/http/src/main/java/org/eclipsefoundation/http/response/CSRFHeaderFilter.java
@@ -11,50 +11,41 @@
 **********************************************************************/
 package org.eclipsefoundation.http.response;
 
-import java.io.IOException;
-
 import org.eclipsefoundation.http.namespace.RequestHeaderNames;
 import org.eclipsefoundation.utils.config.CSRFSecurityConfig;
 import org.eclipsefoundation.utils.helper.CSRFHelper;
 import org.eclipsefoundation.utils.model.AdditionalUserData;
+import org.jboss.resteasy.reactive.server.ServerResponseFilter;
 
-import jakarta.enterprise.inject.Instance;
-import jakarta.inject.Inject;
-import jakarta.servlet.http.HttpServletRequest;
+import io.vertx.core.http.HttpServerRequest;
 import jakarta.ws.rs.container.ContainerRequestContext;
 import jakarta.ws.rs.container.ContainerResponseContext;
-import jakarta.ws.rs.container.ContainerResponseFilter;
-import jakarta.ws.rs.core.Context;
-import jakarta.ws.rs.ext.Provider;
 
 /**
  * Injects the CSRF header token into the response when enabled for a server.
  *
  * @author Martin Lowe
  */
-@Provider
-public class CSRFHeaderFilter implements ContainerResponseFilter {
-
-    @Inject
-    Instance<CSRFSecurityConfig> config;
+public class CSRFHeaderFilter {
 
-    @Context
-    HttpServletRequest httpServletRequest;
+    private final CSRFSecurityConfig config;
+    private final CSRFHelper csrf;
+    private final AdditionalUserData aud;
 
-    @Inject
-    CSRFHelper csrf;
-    @Inject
-    AdditionalUserData aud;
+    public CSRFHeaderFilter(CSRFHelper csrf, AdditionalUserData aud, CSRFSecurityConfig config) {
+        this.config = config;
+        this.csrf = csrf;
+        this.aud = aud;
+    }
 
-    @Override
-    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
-            throws IOException {
+    @ServerResponseFilter
+    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext, HttpServerRequest request) {
         // only attach if CSRF is enabled for the current runtime
-        if (config.get().enabled()) {
+        if (config.enabled()) {
             // generate the token
-            String token = csrf.getNewCSRFToken(httpServletRequest);
+            String token = csrf.getNewCSRFToken(request, requestContext.getSecurityContext());
             // store token in session if not distributed mode
-            if (aud.getCsrf() == null && !config.get().distributedMode().enabled()) {
+            if (aud.getCsrf() == null && !config.distributedMode().enabled()) {
                 aud.setCsrf(token);
             }
             // attach the current CSRF token as a header on the request
diff --git a/http/src/main/java/org/eclipsefoundation/http/response/PaginatedResultsFilter.java b/http/src/main/java/org/eclipsefoundation/http/response/PaginatedResultsFilter.java
index 8a12e91aae92428a893628ac29dab55eb4728129..633cd18f5d01973274a428d7782b7a54bafb5fb5 100644
--- a/http/src/main/java/org/eclipsefoundation/http/response/PaginatedResultsFilter.java
+++ b/http/src/main/java/org/eclipsefoundation/http/response/PaginatedResultsFilter.java
@@ -14,250 +14,227 @@ package org.eclipsefoundation.http.response;
 
 import java.io.IOException;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
-import java.util.stream.Collectors;
 
-import jakarta.annotation.Priority;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipsefoundation.http.annotations.Pagination;
+import org.eclipsefoundation.http.config.PaginationConfig;
+import org.eclipsefoundation.http.namespace.DefaultUrlParameterNames;
+import org.jboss.resteasy.reactive.server.ServerResponseFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import jakarta.enterprise.inject.Instance;
 import jakarta.inject.Inject;
-import jakarta.servlet.http.HttpServletResponse;
-import jakarta.ws.rs.container.ContainerRequestContext;
 import jakarta.ws.rs.container.ContainerResponseContext;
-import jakarta.ws.rs.container.ContainerResponseFilter;
 import jakarta.ws.rs.container.ResourceInfo;
-import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.Link;
 import jakarta.ws.rs.core.MultivaluedMap;
 import jakarta.ws.rs.core.UriBuilder;
 import jakarta.ws.rs.core.UriInfo;
-import jakarta.ws.rs.ext.Provider;
-
-import org.apache.commons.lang3.StringUtils;
-import org.eclipsefoundation.http.annotations.Pagination;
-import org.eclipsefoundation.http.config.PaginationConfig;
-import org.eclipsefoundation.http.namespace.DefaultUrlParameterNames;
-import org.jboss.resteasy.core.ResteasyContext;
-import org.jboss.resteasy.spi.LinkHeader;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Adds pagination and Link headers to the response by slicing the response
- * entity if its a list entity. This will not
- * dig into complex entities to avoid false positives.
+ * entity if its a list entity. This will not dig into complex entities to avoid
+ * false positives.
  *
  * @author Martin Lowe
  */
-@Provider
-@Priority(5)
-public class PaginatedResultsFilter implements ContainerResponseFilter {
-    private static final Logger LOGGER = LoggerFactory.getLogger(PaginatedResultsFilter.class);
-    // should be set whenever we pass a limited subset to the response to be
-    // paginated of a larger subset
-    public static final String MAX_RESULTS_SIZE_HEADER = "X-Max-Result-Size";
-    // should be set whenever we request data that has a maximum page size that is
-    // different than the default here
-    public static final String MAX_PAGE_SIZE_HEADER = "X-Max-Page-Size";
-
-    @Inject
-    Instance<PaginationConfig> config;
-
-    @Context
-    HttpServletResponse response;
-    @Context
-    ResourceInfo resourceInfo;
-
-    @Override
-    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
-            throws IOException {
-
-        if (checkPaginationAnnotation() && config.get().filter().enabled()) {
-            Object entity = responseContext.getEntity();
-
-            // only try and paginate if there are multiple entities
-            if (entity instanceof Set) {
-                paginateResults(responseContext, (new TreeSet<>((Set<?>) entity)).stream()
-                        .collect(Collectors.toList()));
-            } else if (entity instanceof List) {
-                paginateResults(responseContext, (List<?>) entity);
-            }
-        }
-    }
-
-    private void paginateResults(ContainerResponseContext responseContext, List<?> listEntity) {
-        int pageSize = getCurrentLimit(responseContext);
-        // if available, use max results header value
-        String rawMaxSize = getResponseHeader(responseContext, MAX_RESULTS_SIZE_HEADER);
-        int maxSize = listEntity.size();
-        if (StringUtils.isNumeric(rawMaxSize)) {
-            maxSize = Integer.valueOf(rawMaxSize);
-        }
-        LOGGER.trace("Using max results of {} with page size {}", maxSize, pageSize);
-        int page = getRequestedPage(maxSize, pageSize);
-
-        int lastPage = (int) Math.ceil((double) maxSize / pageSize);
-        // slice if the results set is larger than page size
-        if (listEntity.size() > pageSize) {
-            // set the sliced array as the entity
-            responseContext
-                    .setEntity(listEntity
-                            .subList(getArrayLimitedNumber(listEntity, Math.max(0, page - 1) * pageSize),
-                                    getArrayLimitedNumber(listEntity, pageSize * page)));
-        }
-        // set the link header to the response
-        responseContext.getHeaders().add("Link", createLinkHeader(page, lastPage));
-    }
-
-    /**
-     * Checks the current method for pagination annotations and if present, checks
-     * to make sure pagination is enabled. Defaults to using pagination if the
-     * pagination annotation is missing or cannot be read.
-     * 
-     * @return true if pagination should be enabled, false otherwise
-     */
-    private boolean checkPaginationAnnotation() {
-
-        // method can be null sometimes for quarkus native endpoints
-        Method method = resourceInfo.getResourceMethod();
-        if (method != null) {
-            Pagination annotation = method.getAnnotation(Pagination.class);
-            return annotation == null || annotation.value();
-        }
-        return true;
-    }
-
-    /**
-     * Gets a header value if available, checking first the servlet response then
-     * the mutable response wrapper.
-     * 
-     * @param responseContext the mutable response wrapper
-     * @param headerName      the header to retrieve
-     * @return the header value if set, null otherwise.
-     */
-    private String getResponseHeader(ContainerResponseContext responseContext, String headerName) {
-        String rawHeaderVal = response.getHeader(headerName);
-        if (rawHeaderVal == null) {
-            rawHeaderVal = responseContext.getHeaderString(headerName);
-        }
-        return rawHeaderVal;
-    }
-
-    private LinkHeader createLinkHeader(int page, int lastPage) {
-        // add link headers for paginated page hints
-
-        UriBuilder builder = getUriInfo().getRequestUriBuilder();
-        LinkHeader lh = new LinkHeader();
-        // add first + last page link headers
-        lh.addLink("this page of results", "self", buildHref(builder, page), "");
-        lh.addLink("first page of results", "first", buildHref(builder, 1), "");
-        lh.addLink("last page of results", "last", buildHref(builder, lastPage), "");
-        // add next/prev if needed
-        if (page > 1) {
-            lh.addLink("previous page of results", "prev", buildHref(builder, page - 1), "");
-        }
-        if (page < lastPage) {
-            lh.addLink("next page of results", "next", buildHref(builder, page + 1), "");
-        }
-        return lh;
-    }
-
-    /**
-     * Gets the current requested page, rounding down to max if larger than the max
-     * page number, and up if below 1.
-     *
-     * @param listEntity list entity used to determine the number of pages present
-     *                   for current call.
-     * @return the current page number if set, the last page if greater, or 1 if not
-     *         set or negative.
-     */
-    private int getRequestedPage(int maxSize, int pageSize) {
-        MultivaluedMap<String, String> params = getUriInfo().getQueryParameters();
-        if (params.containsKey(DefaultUrlParameterNames.PAGE.getName())) {
-            try {
-                int page = Integer.parseInt(params.getFirst(DefaultUrlParameterNames.PAGE.getName()));
-                // use double cast int to allow ceil call to round up for pages
-                int maxPage = (int) Math.ceil((double) maxSize / pageSize);
-
-                // get page, with min of 1 and max of last page
-                return Math.min(Math.max(1, page), maxPage);
-            } catch (NumberFormatException e) {
-                // page isn't a number, just return
-                LOGGER.error("Passed bad page value: {}", params.getFirst("page"));
-                return 1;
-            }
-        }
-        return 1;
-    }
-
-    /**
-     * Allows for external bindings to affect the current page size, defaulting to
-     * the internal set configuration.
-     * 
-     * @param responseContext
-     * @return
-     */
-    private int getCurrentLimit(ContainerResponseContext responseContext) {
-        // check the pagesize param
-        MultivaluedMap<String, String> params = getUriInfo().getQueryParameters();
-        if (params.containsKey(DefaultUrlParameterNames.PAGESIZE.getName())
-                && StringUtils.isNumeric(params.getFirst(DefaultUrlParameterNames.PAGESIZE.getName()))) {
-            int pageSize = Integer.parseInt(params.getFirst(DefaultUrlParameterNames.PAGESIZE.getName()));
-            int maxPageSize = getInternalMaxPageSize(responseContext);
-            return Math.min(pageSize, maxPageSize);
-        }
-        return getInternalMaxPageSize(responseContext);
-    }
-
-    /**
-     * Returns the max page size as defined by internal metrics (ignoring pagesize
-     * params).
-     * 
-     * @return the internal max page size.
-     */
-    private int getInternalMaxPageSize(ContainerResponseContext responseContext) {
-        String rawPageSize = getResponseHeader(responseContext, MAX_PAGE_SIZE_HEADER);
-        if (StringUtils.isNotBlank(rawPageSize)) {
-            try {
-                return Integer.parseInt(rawPageSize);
-            } catch (NumberFormatException e) {
-                // page size isn't a number, allow to return default outside current scope
-            }
-        }
-        return config.get().filter().defaultPageSize();
-    }
-
-    /**
-     * Builds an href for a paginated link using the BaseUri UriBuilder from the
-     * UriInfo object, replacing just the page query parameter.
-     *
-     * @param builder base URI builder from the UriInfo object.
-     * @param page    the page to link to in the returned link
-     * @return fully qualified HREF for the paginated results
-     */
-    private String buildHref(UriBuilder builder, int page) {
-        // Force scheme of header links to be a given value, useful for proxied requests
-        if (config.get().filter().scheme().enforce()) {
-            return builder.scheme(config.get().filter().scheme().value()).replaceQueryParam("page", page).build()
-                    .toString();
-        }
-        return builder.replaceQueryParam("page", page).build().toString();
-    }
-
-    /**
-     * Gets an int bound by the size of a list.
-     *
-     * @param list the list to bind the number by
-     * @param num  the number to check for exceeding bounds.
-     * @return the passed number if its within the size of the given array, 0 if the
-     *         number is negative, and the array size if greater than the maximum
-     *         bounds.
-     */
-    private int getArrayLimitedNumber(List<?> list, int num) {
-        return Math.min(list.size(), Math.max(0, num));
-    }
-
-    private UriInfo getUriInfo() {
-        return ResteasyContext.getContextData(UriInfo.class);
-    }
+public class PaginatedResultsFilter {
+	private static final Logger LOGGER = LoggerFactory.getLogger(PaginatedResultsFilter.class);
+	// should be set whenever we pass a limited subset to the response to be
+	// paginated of a larger subset
+	public static final String MAX_RESULTS_SIZE_HEADER = "X-Max-Result-Size";
+	// should be set whenever we request data that has a maximum page size that is
+	// different than the default here
+	public static final String MAX_PAGE_SIZE_HEADER = "X-Max-Page-Size";
+
+	@Inject
+	Instance<PaginationConfig> config;
+
+	@ServerResponseFilter
+	public void filter(ResourceInfo resourceInfo, UriInfo uriInfo, ContainerResponseContext responseContext)
+			throws IOException {
+
+		if (checkPaginationAnnotation(resourceInfo) && config.get().filter().enabled()) {
+			Object entity = responseContext.getEntity();
+
+			// only try and paginate if there are multiple entities
+			if (entity instanceof Set) {
+				paginateResults(responseContext, uriInfo, (new TreeSet<>((Set<?>) entity)).stream().toList());
+			} else if (entity instanceof List) {
+				paginateResults(responseContext, uriInfo, (List<?>) entity);
+			}
+		}
+	}
+
+	private void paginateResults(ContainerResponseContext responseContext, UriInfo uriInfo, List<?> listEntity) {
+		int pageSize = getCurrentLimit(uriInfo, responseContext);
+		// if available, use max results header value
+		String rawMaxSize = getResponseHeader(responseContext, MAX_RESULTS_SIZE_HEADER);
+		int maxSize = listEntity.size();
+		if (StringUtils.isNumeric(rawMaxSize)) {
+			maxSize = Integer.valueOf(rawMaxSize);
+		}
+		LOGGER.trace("Using max results of {} with page size {}", maxSize, pageSize);
+		int page = getRequestedPage(uriInfo, maxSize, pageSize);
+
+		int lastPage = (int) Math.ceil((double) maxSize / pageSize);
+		// slice if the results set is larger than page size
+		if (listEntity.size() > pageSize) {
+			// set the sliced array as the entity
+			responseContext
+					.setEntity(listEntity.subList(getArrayLimitedNumber(listEntity, Math.max(0, page - 1) * pageSize),
+							getArrayLimitedNumber(listEntity, pageSize * page)));
+		}
+		// set the link header to the response
+		responseContext.getHeaders().put("Link",
+				createLinkHeader(uriInfo, page, lastPage).stream().map(l -> (Object) l).toList());
+	}
+
+	/**
+	 * Checks the current method for pagination annotations and if present, checks
+	 * to make sure pagination is enabled. Defaults to using pagination if the
+	 * pagination annotation is missing or cannot be read.
+	 * 
+	 * @return true if pagination should be enabled, false otherwise
+	 */
+	private boolean checkPaginationAnnotation(ResourceInfo resourceInfo) {
+		// method can be null sometimes for quarkus native endpoints
+		Method method = resourceInfo.getResourceMethod();
+		if (method != null) {
+			Pagination annotation = method.getAnnotation(Pagination.class);
+			return annotation == null || annotation.value();
+		}
+		return true;
+	}
+
+	/**
+	 * Gets a header value if available, checking first the servlet response then
+	 * the mutable response wrapper.
+	 * 
+	 * @param responseContext the response context
+	 * @param headerName      the header to retrieve
+	 * @return the header value if set, null otherwise.
+	 */
+	private String getResponseHeader(ContainerResponseContext responseContext, String headerName) {
+		return responseContext.getHeaderString(headerName);
+	}
+
+	private List<Link> createLinkHeader(UriInfo uriInfo, int page, int lastPage) {
+		// add link headers for paginated page hints
+
+		UriBuilder builder = uriInfo.getRequestUriBuilder();
+		List<Link> links = new ArrayList<>();
+		// add first + last page link headers
+		links.add(Link.fromUri(buildHref(builder, 1)).rel("first").title("first page of results").build());
+		links.add(Link.fromUri(buildHref(builder, page)).rel("self").title("this page of results").build());
+		links.add(Link.fromUri(buildHref(builder, lastPage)).rel("last").title("last page of results").build());
+		// add next/prev if needed
+		if (page > 1) {
+			links.add(Link.fromUri(buildHref(builder, page - 1)).rel("prev").title("previous page of results").build());
+		}
+		if (page < lastPage) {
+			links.add(Link.fromUri(buildHref(builder, page + 1)).rel("next").title("next page of results").build());
+		}
+		return links;
+	}
+
+	/**
+	 * Gets the current requested page, rounding down to max if larger than the max
+	 * page number, and up if below 1.
+	 *
+	 * @param listEntity list entity used to determine the number of pages present
+	 *                   for current call.
+	 * @return the current page number if set, the last page if greater, or 1 if not
+	 *         set or negative.
+	 */
+	private int getRequestedPage(UriInfo uriInfo, int maxSize, int pageSize) {
+		MultivaluedMap<String, String> params = uriInfo.getQueryParameters();
+		if (params.containsKey(DefaultUrlParameterNames.PAGE.getName())) {
+			try {
+				int page = Integer.parseInt(params.getFirst(DefaultUrlParameterNames.PAGE.getName()));
+				// use double cast int to allow ceil call to round up for pages
+				int maxPage = (int) Math.ceil((double) maxSize / pageSize);
+
+				// get page, with min of 1 and max of last page
+				return Math.min(Math.max(1, page), maxPage);
+			} catch (NumberFormatException e) {
+				// page isn't a number, just return
+				LOGGER.error("Passed bad page value: {}", params.getFirst("page"));
+				return 1;
+			}
+		}
+		return 1;
+	}
+
+	/**
+	 * Allows for external bindings to affect the current page size, defaulting to
+	 * the internal set configuration.
+	 * 
+	 * @param responseContext
+	 * @return
+	 */
+	private int getCurrentLimit(UriInfo uriInfo, ContainerResponseContext responseContext) {
+		// check the pagesize param
+		MultivaluedMap<String, String> params = uriInfo.getQueryParameters();
+		if (params.containsKey(DefaultUrlParameterNames.PAGESIZE.getName())
+				&& StringUtils.isNumeric(params.getFirst(DefaultUrlParameterNames.PAGESIZE.getName()))) {
+			int pageSize = Integer.parseInt(params.getFirst(DefaultUrlParameterNames.PAGESIZE.getName()));
+			int maxPageSize = getInternalMaxPageSize(responseContext);
+			return Math.min(pageSize, maxPageSize);
+		}
+		return getInternalMaxPageSize(responseContext);
+	}
+
+	/**
+	 * Returns the max page size as defined by internal metrics (ignoring pagesize
+	 * params).
+	 * 
+	 * @return the internal max page size.
+	 */
+	private int getInternalMaxPageSize(ContainerResponseContext responseContext) {
+		String rawPageSize = getResponseHeader(responseContext, MAX_PAGE_SIZE_HEADER);
+		if (StringUtils.isNotBlank(rawPageSize)) {
+			try {
+				return Integer.parseInt(rawPageSize);
+			} catch (NumberFormatException e) {
+				// page size isn't a number, allow to return default outside current scope
+			}
+		}
+		return config.get().filter().defaultPageSize();
+	}
+
+	/**
+	 * Builds an href for a paginated link using the BaseUri UriBuilder from the
+	 * UriInfo object, replacing just the page query parameter.
+	 *
+	 * @param builder base URI builder from the UriInfo object.
+	 * @param page    the page to link to in the returned link
+	 * @return fully qualified HREF for the paginated results
+	 */
+	private String buildHref(UriBuilder builder, int page) {
+		// Force scheme of header links to be a given value, useful for proxied requests
+		if (config.get().filter().scheme().enforce()) {
+			return builder.scheme(config.get().filter().scheme().value()).replaceQueryParam("page", page).build()
+					.toString();
+		}
+		return builder.replaceQueryParam("page", page).build().toString();
+	}
+
+	/**
+	 * Gets an int bound by the size of a list.
+	 *
+	 * @param list the list to bind the number by
+	 * @param num  the number to check for exceeding bounds.
+	 * @return the passed number if its within the size of the given array, 0 if the
+	 *         number is negative, and the array size if greater than the maximum
+	 *         bounds.
+	 */
+	private int getArrayLimitedNumber(List<?> list, int num) {
+		return Math.min(list.size(), Math.max(0, num));
+	}
 }
diff --git a/http/src/main/resources/application.properties b/http/src/main/resources/application.properties
index 866efd1b42805c2211c102f2d457ce74797bcca0..3a0fcd8f49c3497ab4218261ee0156635623ca09 100644
--- a/http/src/main/resources/application.properties
+++ b/http/src/main/resources/application.properties
@@ -2,6 +2,10 @@
 quarkus.oauth2.enabled=false
 quarkus.oauth2.introspection-url=http://accounts.eclipse.org/oauth2/introspect
 
+## CSRF settings
+quarkus.csrf-reactive.token-header-name=x-csrf-token
+quarkus.csrf-reactive.cookie-http-only=false
+
 # MISC
 quarkus.resteasy.gzip.enabled=true
 quarkus.http.port=8090
diff --git a/http/src/test/java/org/eclipsefoundation/http/authenticated/request/CSRFSecurityFilterTest.java b/http/src/test/java/org/eclipsefoundation/http/authenticated/request/CSRFSecurityFilterTest.java
deleted file mode 100644
index ca7d26a3629e530cf338695dd3c1c32b08ef14a9..0000000000000000000000000000000000000000
--- a/http/src/test/java/org/eclipsefoundation/http/authenticated/request/CSRFSecurityFilterTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*********************************************************************
-* Copyright (c) 2022, 2024 Eclipse Foundation.
-*
-* This program and the accompanying materials are made
-* available under the terms of the Eclipse Public License 2.0
-* which is available at https://www.eclipse.org/legal/epl-2.0/
-*
-* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
-*
-* SPDX-License-Identifier: EPL-2.0
-**********************************************************************/
-package org.eclipsefoundation.http.authenticated.request;
-
-import static io.restassured.RestAssured.given;
-
-import org.eclipsefoundation.http.namespace.RequestHeaderNames;
-import org.eclipsefoundation.http.test.AuthenticatedTestProfile;
-import org.junit.jupiter.api.Test;
-
-import io.quarkus.test.junit.QuarkusTest;
-import io.quarkus.test.junit.TestProfile;
-import io.restassured.filter.session.SessionFilter;
-import io.restassured.response.Response;
-import jakarta.ws.rs.core.Response.Status;
-
-/**
- * Test the CSRF security filter which can block requests based on presence of CSRF token. This makes use of the
- * authenticated test profile to reduce complexity of testing other facets of the core lib that have no interactions
- * with security.
- * 
- * @author Martin Lowe
- *
- */
-@QuarkusTest
-@TestProfile(AuthenticatedTestProfile.class)
-class CSRFSecurityFilterTest {
-
-    @Test
-    void validateNoToken() {
-
-        // CSRF enabled via annotation
-        given().when().get("/test").then().statusCode(Status.FORBIDDEN.getStatusCode());
-
-        // CSRF enabled by default for mutation calls via configs
-        given().when().post("/test").then().statusCode(Status.FORBIDDEN.getStatusCode());
-        given().when().put("/test").then().statusCode(Status.FORBIDDEN.getStatusCode());
-        given().when().delete("/test").then().statusCode(Status.FORBIDDEN.getStatusCode());
-
-        // No token required
-        given().when().get("/test/unguarded").then().statusCode(Status.OK.getStatusCode());
-
-        // CSRF requirement removed via annotation
-        given().when().post("/test/unguarded").then().statusCode(Status.OK.getStatusCode());
-    }
-
-    @Test
-    void validateWrongToken() {
-        // do a good request to trigger the build of the header internally
-        given().when().get("/test/unguarded").then().statusCode(Status.OK.getStatusCode());
-        // expect rebuff as no CSRF token was passed
-        given()
-                .header(RequestHeaderNames.CSRF_TOKEN, "bad-header-value")
-                .when()
-                .get("/test")
-                .then()
-                .statusCode(Status.FORBIDDEN.getStatusCode());
-        given()
-                .header(RequestHeaderNames.CSRF_TOKEN, "bad-header-value")
-                .when()
-                .post("/test")
-                .then()
-                .statusCode(Status.FORBIDDEN.getStatusCode());
-        given()
-                .header(RequestHeaderNames.CSRF_TOKEN, "bad-header-value")
-                .when()
-                .put("/test")
-                .then()
-                .statusCode(Status.FORBIDDEN.getStatusCode());
-        given()
-                .header(RequestHeaderNames.CSRF_TOKEN, "bad-header-value")
-                .when()
-                .delete("/test")
-                .then()
-                .statusCode(Status.FORBIDDEN.getStatusCode());
-    }
-
-    @Test
-    void validateRightCSRFToken() {
-        SessionFilter sessionFilter = new SessionFilter();
-        // do a good request to trigger the build of the header internally
-        Response r = given().filter(sessionFilter).when().get("/test/unguarded");
-        String expectedHeader = r.getHeader(RequestHeaderNames.CSRF_TOKEN);
-
-        // expect rebuff as no CSRF token was passed
-        given()
-                .filter(sessionFilter)
-                .header(RequestHeaderNames.CSRF_TOKEN, expectedHeader)
-                .when()
-                .post("/test")
-                .then()
-                .statusCode(Status.OK.getStatusCode());
-        given()
-                .filter(sessionFilter)
-                .header(RequestHeaderNames.CSRF_TOKEN, expectedHeader)
-                .when()
-                .delete("/test")
-                .then()
-                .statusCode(Status.OK.getStatusCode());
-        given()
-                .filter(sessionFilter)
-                .header(RequestHeaderNames.CSRF_TOKEN, expectedHeader)
-                .when()
-                .put("/test")
-                .then()
-                .statusCode(Status.OK.getStatusCode());
-        given()
-                .filter(sessionFilter)
-                .header(RequestHeaderNames.CSRF_TOKEN, expectedHeader)
-                .when()
-                .get("/test")
-                .then()
-                .statusCode(Status.OK.getStatusCode());
-    }
-}
diff --git a/http/src/test/java/org/eclipsefoundation/http/request/CacheBypassFilterTest.java b/http/src/test/java/org/eclipsefoundation/http/request/CacheBypassFilterTest.java
index 41d3c911e76a7954c23c8425724c2163eaa46d23..05f40b2168f340c3dad09255fc02baac5e14c873 100644
--- a/http/src/test/java/org/eclipsefoundation/http/request/CacheBypassFilterTest.java
+++ b/http/src/test/java/org/eclipsefoundation/http/request/CacheBypassFilterTest.java
@@ -13,15 +13,13 @@ package org.eclipsefoundation.http.request;
 
 import static io.restassured.RestAssured.given;
 
-import jakarta.enterprise.context.Dependent;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.ws.rs.container.ContainerRequestContext;
-
 import org.eclipsefoundation.http.request.CacheBypassFilter.BypassCondition;
 import org.hamcrest.Matchers;
 import org.junit.jupiter.api.Test;
 
 import io.quarkus.test.junit.QuarkusTest;
+import jakarta.enterprise.context.Dependent;
+import jakarta.ws.rs.container.ContainerRequestContext;
 
 /**
  * Basic tests to ensure that the bypass condition filters can activate as intended on requests.
@@ -49,8 +47,8 @@ class CacheBypassFilterTest {
     @Dependent
     public static class TestBypassCondition implements BypassCondition {
         @Override
-        public boolean matches(ContainerRequestContext requestContext, HttpServletRequest request) {
-            return "true".equalsIgnoreCase(request.getHeader("Use-Test-Bypass"));
+        public boolean matches(ContainerRequestContext requestContext) {
+            return "true".equalsIgnoreCase(requestContext.getHeaderString("Use-Test-Bypass"));
         }
     }
 }
diff --git a/http/src/test/java/org/eclipsefoundation/http/resource/LoggerResourceTest.java b/http/src/test/java/org/eclipsefoundation/http/resource/LoggerResourceTest.java
index 4878021fdd686076f1f18bf0f19a43052da41a9d..c9128cddfc37ba9da2a7644d91df57a14e310785 100644
--- a/http/src/test/java/org/eclipsefoundation/http/resource/LoggerResourceTest.java
+++ b/http/src/test/java/org/eclipsefoundation/http/resource/LoggerResourceTest.java
@@ -11,11 +11,8 @@ package org.eclipsefoundation.http.resource;
 
 import static io.restassured.RestAssured.given;
 
-import java.util.List;
 import java.util.UUID;
-
-import jakarta.inject.Inject;
-import jakarta.ws.rs.core.Response.Status;
+import java.util.stream.Stream;
 
 import org.eclipsefoundation.http.helper.SecureResourceKey;
 import org.eclipsefoundation.http.resource.LoggerResource.LoggerWrapper;
@@ -23,6 +20,8 @@ import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 import io.quarkus.test.junit.QuarkusTest;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.core.Response.Status;
 
 @QuarkusTest
 class LoggerResourceTest {
@@ -40,7 +39,8 @@ class LoggerResourceTest {
 
     @Test
     void updateLogger_usesInstanceKey() {
-        given().when().get("/loggers?key={key}", UUID.randomUUID().toString()).then().statusCode(Status.FORBIDDEN.getStatusCode());
+        given().when().get("/loggers?key={key}", UUID.randomUUID().toString()).then()
+                .statusCode(Status.FORBIDDEN.getStatusCode());
         given()
                 .when()
                 .get("/loggers?key={key}&clazz={clazz}&level={level}", key.getKey(), VALID_CLASS_NAME, VALID_LOG_LEVEL)
@@ -66,7 +66,8 @@ class LoggerResourceTest {
     void updateLogger_error_failsInvalidClass() {
         given()
                 .when()
-                .get("/loggers?key={key}&clazz={clazz}&level={level}", key.getKey(), "org.eclipsefoundation.core.resource.NotARealClass",
+                .get("/loggers?key={key}&clazz={clazz}&level={level}", key.getKey(),
+                        "org.eclipsefoundation.core.resource.NotARealClass",
                         VALID_LOG_LEVEL)
                 .then()
                 .statusCode(Status.BAD_REQUEST.getStatusCode());
@@ -83,23 +84,27 @@ class LoggerResourceTest {
 
     @Test
     void getCurrentLoggers_usesInstanceKey() {
-        given().when().get("/loggers/all?key={key}", UUID.randomUUID().toString()).then().statusCode(Status.FORBIDDEN.getStatusCode());
+        given().when().get("/loggers/all?key={key}", UUID.randomUUID().toString()).then()
+                .statusCode(Status.FORBIDDEN.getStatusCode());
         given().when().get("/loggers/all?key={key}", key.getKey()).then().statusCode(Status.OK.getStatusCode());
     }
 
     @Test
     void getCurrentLoggers_containsEfAndBaseAppLoggers() {
-        // do the call to the loggers endpoint, and convert the response to a list of returned loggers
-        List<LoggerWrapper> loggers = given()
+        // do the call to the loggers endpoint, and convert the response to a list of
+        // returned loggers
+        LoggerWrapper[] loggers = given()
                 .when()
                 .get("/loggers/all?key={key}", key.getKey())
                 .then()
                 .extract()
-                .jsonPath()
-                .getList("", LoggerWrapper.class);
-        // do 2 assertions to check we have both application and base app loggers present
-        Assertions.assertTrue(loggers.stream().anyMatch(loggerName -> loggerName.getName().startsWith("org.eclipsefoundation")));
-        Assertions.assertTrue(loggers.stream().anyMatch(loggerName -> !loggerName.getName().startsWith("org.eclipsefoundation")));
+                .as(LoggerWrapper[].class);
+        // do 2 assertions to check we have both application and base app loggers
+        // present
+        Assertions.assertTrue(
+                Stream.of(loggers).anyMatch(loggerName -> loggerName.getName().startsWith("org.eclipsefoundation")));
+        Assertions.assertTrue(
+                Stream.of(loggers).anyMatch(loggerName -> !loggerName.getName().startsWith("org.eclipsefoundation")));
     }
 
     @Test
@@ -114,15 +119,16 @@ class LoggerResourceTest {
 
     @Test
     void getApplicationLoggers_onlyContainsEclipseNamespace() {
-        // do the call to the loggers endpoint, and convert the response to a list of returned loggers
-        List<LoggerWrapper> loggers = given()
+        // do the call to the loggers endpoint, and convert the response to a list of
+        // returned loggers
+        LoggerWrapper[] loggers = given()
                 .when()
                 .get("/loggers/application?key={key}", key.getKey())
                 .then()
                 .extract()
-                .jsonPath()
-                .getList("", LoggerWrapper.class);
+                .as(LoggerWrapper[].class);
         // do assertion to check we have only application loggers present
-        Assertions.assertTrue(loggers.stream().anyMatch(loggerName -> loggerName.getName().startsWith("org.eclipsefoundation")));
+        Assertions.assertTrue(
+                Stream.of(loggers).anyMatch(loggerName -> loggerName.getName().startsWith("org.eclipsefoundation")));
     }
 }
diff --git a/http/src/test/java/org/eclipsefoundation/http/test/resources/TestResource.java b/http/src/test/java/org/eclipsefoundation/http/test/resources/TestResource.java
index 2cac673d617da302ddce727fa9aca55f254dae30..29f9d4c6270403ec7562b5c72cfb55f1e525dbc9 100644
--- a/http/src/test/java/org/eclipsefoundation/http/test/resources/TestResource.java
+++ b/http/src/test/java/org/eclipsefoundation/http/test/resources/TestResource.java
@@ -18,8 +18,6 @@ import org.eclipsefoundation.http.annotations.Csrf;
 import org.eclipsefoundation.http.model.RequestWrapper;
 import org.eclipsefoundation.http.namespace.DefaultUrlParameterNames;
 import org.eclipsefoundation.http.response.PaginatedResultsFilter;
-import org.eclipsefoundation.utils.helper.CSRFHelper;
-import org.eclipsefoundation.utils.model.AdditionalUserData;
 
 import jakarta.inject.Inject;
 import jakarta.ws.rs.DELETE;
@@ -41,23 +39,8 @@ public class TestResource {
     public static final String PAGINATION_HEADER_RESULT_SIZE = "30";
     public static final String PAGINATION_HEADER_PAGE_SIZE_DEFAULT = "10";
 
-    @Inject
-    CSRFHelper csrf;
-    @Inject
-    AdditionalUserData aud;
     @Inject
     RequestWrapper wrap;
-    /**
-     * Basic sample GET call that can be gated through CSRF if enabled to protect the data further.
-     * 
-     * @param passedCsrf the passed CSRF header value
-     * @return empty ok response if CSRF is disabled or properly passed, Status.FORBIDDEN.getStatusCode() response otherwise.
-     */
-    @GET
-    @Csrf
-    public Response getGuarded() {
-        return Response.ok().build();
-    }
 
     /**
      * Basic sample GET call that is not gated through CSRF. This could represent a user data endpoint, or a straight CSRF endpoint to
diff --git a/http/src/test/resources/application.properties b/http/src/test/resources/application.properties
index 09cf33f9d7b8a780b8ebcb5cc1a9fc33102691c3..a61947c43b33d79b9b79ad905bb45507b44b581b 100644
--- a/http/src/test/resources/application.properties
+++ b/http/src/test/resources/application.properties
@@ -1,4 +1,7 @@
-quarkus.jacoco.includes=**/request/**/*
+quarkus.jacoco.includes=**/http/**/*
+
+## CSRF sample signature token - only used in testing
+quarkus.csrf-reactive.token-signature-key=SUmkysx2ejh5&sghSah8z3khws!xvmQU
 
 ## OAUTH CONFIG
 quarkus.oauth2.enabled=true
diff --git a/persistence/deployment/pom.xml b/persistence/deployment/pom.xml
index 9773295a5625d170dbf69dadc286805cc92c6c23..a9dc1e183a37917a376fe08657cdc7dbd6b14893 100644
--- a/persistence/deployment/pom.xml
+++ b/persistence/deployment/pom.xml
@@ -11,7 +11,7 @@
     <parent>
         <groupId>org.eclipsefoundation</groupId>
         <artifactId>quarkus-persistence-parent</artifactId>
-        <version>1.0.3-SNAPSHOT</version>
+        <version>1.1.0</version>
     </parent>
     <artifactId>quarkus-persistence-deployment</artifactId>
     <name>Persistence - Deployment</name>
@@ -31,15 +31,11 @@
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-resteasy-deployment</artifactId>
+            <artifactId>quarkus-resteasy-reactive-deployment</artifactId>
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-resteasy-jackson-deployment</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-undertow-deployment</artifactId>
+            <artifactId>quarkus-resteasy-reactive-jackson-deployment</artifactId>
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
@@ -67,7 +63,7 @@
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
-            <artifactId>quarkus-resteasy-qute-deployment</artifactId>
+            <artifactId>quarkus-resteasy-reactive-qute-deployment</artifactId>
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
@@ -90,4 +86,4 @@
             </plugin>
         </plugins>
     </build>
-</project>
\ No newline at end of file
+</project>
diff --git a/persistence/pom.xml b/persistence/pom.xml
index 8a1384197b693dfc1a95c15582ba0b6834673e88..c23ec1a9f62543aefdc46ecd119b0f12ccdd9987 100644
--- a/persistence/pom.xml
+++ b/persistence/pom.xml
@@ -10,7 +10,7 @@
     <parent>
         <groupId>org.eclipsefoundation</groupId>
         <artifactId>quarkus-commons</artifactId>
-        <version>1.0.3-SNAPSHOT</version>
+        <version>1.1.0</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modules>
diff --git a/persistence/runtime/pom.xml b/persistence/runtime/pom.xml
index dd9d861870449d247f6de7fdff16b669210fcf61..e7e7cdb072db49e76bad7879084f3eb69902efa0 100644
--- a/persistence/runtime/pom.xml
+++ b/persistence/runtime/pom.xml
@@ -7,7 +7,7 @@
     <parent>
         <groupId>org.eclipsefoundation</groupId>
         <artifactId>quarkus-persistence-parent</artifactId>
-        <version>1.0.3-SNAPSHOT</version>
+        <version>1.1.0</version>
     </parent>
     <artifactId>quarkus-persistence</artifactId>
     <name>Persistence - Runtime</name>
diff --git a/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/model/DistributedCSRFGenerator.java b/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/model/DistributedCSRFGenerator.java
index 1c0b8474eeda37a52e9780ebac6b41d983e5a3fc..74f616154e006e699c4725f61477f0f72737ea2a 100644
--- a/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/model/DistributedCSRFGenerator.java
+++ b/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/model/DistributedCSRFGenerator.java
@@ -23,18 +23,19 @@ import org.eclipsefoundation.persistence.dto.DistributedCSRFToken;
 import org.eclipsefoundation.persistence.dto.filter.DistributedCSRFTokenFilter;
 import org.eclipsefoundation.utils.helper.DateTimeHelper;
 import org.eclipsefoundation.utils.model.CSRFGenerator.DefaultCSRFGenerator;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
+import org.eclipsefoundation.utils.namespace.AdditionalHttpHeaders;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import io.undertow.httpcore.HttpHeaderNames;
-import jakarta.servlet.http.HttpServletRequest;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.vertx.core.http.HttpServerRequest;
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.SecurityContext;
 
 /**
- * Using IP address and useragent, create a fingerprint for the current user that will be used to access a stored
- * distributed CSRF token. If one does not yet exist, one will be generated using the default method, stored for future
- * reference, and returned.
+ * Using IP address and useragent, create a fingerprint for the current user that will be used to access a stored distributed CSRF token. If
+ * one does not yet exist, one will be generated using the default method, stored for future reference, and returned.
  * 
  * @author Martin Lowe
  *
@@ -56,17 +57,16 @@ public class DistributedCSRFGenerator extends DefaultCSRFGenerator {
     }
 
     @Override
-    public String getCSRFToken(HttpServletRequest httpServletRequest) {
+    public String getCSRFToken(HttpServerRequest request, SecurityContext context) {
         // generate a non-root query
-        MultivaluedMap<String, String> params = getQueryParameters(httpServletRequest);
-        RDBMSQuery<DistributedCSRFToken> q = new RDBMSQuery<>(
-                new FlatRequestWrapper(URI.create(httpServletRequest.getRequestURL().toString())), filter, params);
+        MultivaluedMap<String, String> params = getQueryParameters(request, context);
+        RDBMSQuery<DistributedCSRFToken> q = new RDBMSQuery<>(new FlatRequestWrapper(URI.create(request.uri())), filter, params);
         q.setRoot(false);
         // attempt to read existing tokens
         List<DistributedCSRFToken> tokens = manager.get(q);
         if (tokens.isEmpty()) {
             // generate a new token to be stored in the distributed persistence table
-            String token = super.getCSRFToken(httpServletRequest);
+            String token = super.getCSRFToken(request, context);
             DistributedCSRFToken t = new DistributedCSRFToken();
             t.setIpAddress(params.getFirst(IP_PARAM));
             t.setToken(token);
@@ -97,34 +97,34 @@ public class DistributedCSRFGenerator extends DefaultCSRFGenerator {
         return null;
     }
 
-    public void destroyCurrentToken(HttpServletRequest httpServletRequest) {
-        MultivaluedMap<String, String> params = getQueryParameters(httpServletRequest);
+    public void destroyCurrentToken(HttpServerRequest request, SecurityContext context) {
+        MultivaluedMap<String, String> params = getQueryParameters(request, context);
         LOGGER
                 .error("Destroying retrieving CSRF entry for current user; IP: {}, UA: {}", params.getFirst(IP_PARAM),
                         params.getFirst(USERAGENT_PARAM));
-        manager.delete(new RDBMSQuery<>(new FlatRequestWrapper(URI.create(httpServletRequest.getRequestURL().toString())), filter, params));
+        manager.delete(new RDBMSQuery<>(new FlatRequestWrapper(URI.create(request.uri())), filter, params));
     }
 
-    private MultivaluedMap<String, String> getQueryParameters(HttpServletRequest httpServletRequest) {
+    private MultivaluedMap<String, String> getQueryParameters(HttpServerRequest request, SecurityContext context) {
         // get the markers used to identify a user (outside of a unique session ID)
-        String ipAddr = getClientIpAddress(httpServletRequest);
-        String userAgent = httpServletRequest.getHeader(HttpHeaderNames.USER_AGENT);
+        String ipAddr = getClientIpAddress(request);
+        String userAgent = request.getHeader(HttpHeaderNames.USER_AGENT);
         // Iss #109 - Truncate the value if it's too long to keep table entries managable
         if (userAgent.length() > 255) {
             userAgent = userAgent.substring(0, 250);
         }
-        Principal user = httpServletRequest.getUserPrincipal();
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        Principal user = context.getUserPrincipal();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add(IP_PARAM, ipAddr);
         params.add(USERAGENT_PARAM, userAgent);
         params.add(USER_PARAM, user != null ? user.getName() : null);
         return params;
     }
 
-    private String getClientIpAddress(HttpServletRequest request) {
-        String forwardedFor = request.getHeader(HttpHeaderNames.X_FORWARDED_FOR);
+    private String getClientIpAddress(HttpServerRequest request) {
+        String forwardedFor = request.getHeader(AdditionalHttpHeaders.X_FORWARDED_FOR);
         if (forwardedFor == null) {
-            return request.getRemoteAddr();
+            return request.remoteAddress().host();
         } else {
             // get the first most address in forwarded chain
             return new StringTokenizer(forwardedFor, ",").nextToken().trim();
diff --git a/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/model/RDBMSQuery.java b/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/model/RDBMSQuery.java
index bbd313519236ff30717e2a796b5ed3fe68257e5a..9aa072cae9731cff9947d7385bcbb54500596982 100644
--- a/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/model/RDBMSQuery.java
+++ b/persistence/runtime/src/main/java/org/eclipsefoundation/persistence/model/RDBMSQuery.java
@@ -15,19 +15,19 @@ import java.util.List;
 import java.util.Optional;
 
 import org.apache.commons.lang3.StringUtils;
+import org.eclipsefoundation.http.model.RequestWrapper;
+import org.eclipsefoundation.http.namespace.DefaultUrlParameterNames;
 import org.eclipsefoundation.persistence.dto.BareNode;
 import org.eclipsefoundation.persistence.dto.filter.DtoFilter;
 import org.eclipsefoundation.persistence.helper.SortableHelper;
 import org.eclipsefoundation.persistence.helper.SortableHelper.Sortable;
 import org.eclipsefoundation.persistence.namespace.PersistenceUrlParameterNames;
 import org.eclipsefoundation.persistence.namespace.SortOrder;
-import org.eclipsefoundation.http.model.RequestWrapper;
-import org.eclipsefoundation.http.namespace.DefaultUrlParameterNames;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
-import org.jboss.resteasy.specimpl.UnmodifiableMultivaluedMap;
+import org.jboss.resteasy.reactive.common.util.UnmodifiableMultivaluedMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 
 /**
@@ -55,7 +55,7 @@ public class RDBMSQuery<T extends BareNode> {
     public RDBMSQuery(RequestWrapper wrapper, DtoFilter<T> dtoFilter, MultivaluedMap<String, String> params) {
         this.wrapper = wrapper;
         this.dtoFilter = dtoFilter;
-        this.params = new MultivaluedMapImpl<>();
+        this.params = new MultivaluedHashMap<>();
         wrapper.asMap().forEach((key, valueList) -> this.params.addAll(key, valueList));
         if (params != null) {
             // replace the values set in the param map
diff --git a/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/dao/DefaultHibernateDaoTest.java b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/dao/DefaultHibernateDaoTest.java
index 88fb5d7f3e79c0737f3a8a60b8751dbfb625f618..3ce7f02756dc963aff034bbeab99ba0ff982d784 100644
--- a/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/dao/DefaultHibernateDaoTest.java
+++ b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/dao/DefaultHibernateDaoTest.java
@@ -16,19 +16,19 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 
+import org.eclipsefoundation.http.model.FlatRequestWrapper;
+import org.eclipsefoundation.http.namespace.DefaultUrlParameterNames;
 import org.eclipsefoundation.persistence.model.RDBMSQuery;
 import org.eclipsefoundation.persistence.test.dto.PersonAddress;
 import org.eclipsefoundation.persistence.test.dto.PersonAddress.PersonAddressFilter;
 import org.eclipsefoundation.persistence.test.dto.PersonDTO;
 import org.eclipsefoundation.persistence.test.dto.PersonDTO.PersonDTOFilter;
-import org.eclipsefoundation.http.model.FlatRequestWrapper;
-import org.eclipsefoundation.http.namespace.DefaultUrlParameterNames;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 import io.quarkus.test.junit.QuarkusTest;
 import jakarta.inject.Inject;
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 
 /**
@@ -176,7 +176,7 @@ class DefaultHibernateDaoTest {
      */
     private RDBMSQuery<PersonDTO> getBasicQuery(String id) {
         // set up query for existing data
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add(DefaultUrlParameterNames.ID.getName(), id);
         return new RDBMSQuery<>(new FlatRequestWrapper(URI.create("https://eclipse.org")), filter, params);
     }
@@ -189,7 +189,7 @@ class DefaultHibernateDaoTest {
      */
     private RDBMSQuery<PersonAddress> getPersonAddressQuery(String personId) {
         // set up query for existing data
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add("person_id", personId);
         return new RDBMSQuery<>(new FlatRequestWrapper(URI.create("https://eclipse.org")), paFilter, params);
     }
diff --git a/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/model/DistributedCSRFGeneratorTest.java b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/model/DistributedCSRFGeneratorTest.java
index c38ca77d550d932e8e6621cc0685e29d70f38481..0d03e244e1a4acdeffdf4614b499704d4a2475a9 100644
--- a/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/model/DistributedCSRFGeneratorTest.java
+++ b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/model/DistributedCSRFGeneratorTest.java
@@ -10,17 +10,19 @@ import org.eclipsefoundation.http.model.RequestWrapper;
 import org.eclipsefoundation.persistence.dao.PersistenceDao;
 import org.eclipsefoundation.persistence.dto.DistributedCSRFToken;
 import org.eclipsefoundation.persistence.dto.filter.DistributedCSRFTokenFilter;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
+import org.eclipsefoundation.utils.namespace.AdditionalHttpHeaders;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 
+import io.netty.handler.codec.http.HttpHeaderNames;
 import io.quarkus.test.junit.QuarkusTest;
-import io.undertow.httpcore.HttpHeaderNames;
+import io.vertx.core.http.HttpServerRequest;
 import jakarta.inject.Inject;
-import jakarta.servlet.http.HttpServletRequest;
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.SecurityContext;
 
 @QuarkusTest
 class DistributedCSRFGeneratorTest {
@@ -46,21 +48,23 @@ class DistributedCSRFGeneratorTest {
         RequestWrapper wrap = new FlatRequestWrapper(URI.create(url));
 
         // set up parameters to check for token before and after test
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add(DistributedCSRFGenerator.IP_PARAM, ip);
         params.add(DistributedCSRFGenerator.USERAGENT_PARAM, userAgent);
 
         Assertions.assertTrue(dao.get(new RDBMSQuery<>(wrap, filter, params)).isEmpty(), "Expected no tokens for unique useragent in test");
 
         // set up mocked request to forward to the generator
-        HttpServletRequest mockedRequest = Mockito.mock(HttpServletRequest.class);
-        Mockito.when(mockedRequest.getRequestURL()).thenReturn(new StringBuffer(url));
-        Mockito.when(mockedRequest.getHeader(HttpHeaderNames.X_FORWARDED_FOR)).thenReturn(ip);
+        HttpServerRequest mockedRequest = Mockito.mock(HttpServerRequest.class);
+        Mockito.when(mockedRequest.uri()).thenReturn(url);
+        Mockito.when(mockedRequest.getHeader(AdditionalHttpHeaders.X_FORWARDED_FOR)).thenReturn(ip);
         Mockito.when(mockedRequest.getHeader(HttpHeaderNames.USER_AGENT)).thenReturn(userAgent);
-        Mockito.when(mockedRequest.getUserPrincipal()).thenReturn(p);
+        
+        SecurityContext mockedSecurity = Mockito.mock(SecurityContext.class);
+        Mockito.when(mockedSecurity.getUserPrincipal()).thenReturn(p);
 
         // generate the token, which should persist the token
-        String token = this.generator.getCSRFToken(mockedRequest);
+        String token = this.generator.getCSRFToken(mockedRequest, mockedSecurity);
         // get the tokens in the database w/ the same params
         List<DistributedCSRFToken> tokens = dao.get(new RDBMSQuery<>(wrap, filter, params));
         // check that we have entries
diff --git a/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/model/SqlBackedPaginationResolverTest.java b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/model/SqlBackedPaginationResolverTest.java
index 37114c68e1c0e8cb8f12f4bc01e52f55bbc37ff9..a91d9a6793341ff8f230144ccd0637929ac794d6 100644
--- a/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/model/SqlBackedPaginationResolverTest.java
+++ b/persistence/runtime/src/test/java/org/eclipsefoundation/persistence/model/SqlBackedPaginationResolverTest.java
@@ -17,13 +17,12 @@ import java.util.UUID;
 
 import org.eclipsefoundation.caching.model.ParameterizedCacheKey;
 import org.eclipsefoundation.core.service.PaginationHeaderService;
+import org.eclipsefoundation.http.model.FlatRequestWrapper;
+import org.eclipsefoundation.http.response.PaginatedResultsFilter;
 import org.eclipsefoundation.persistence.dao.PersistenceDao;
 import org.eclipsefoundation.persistence.test.dto.PersonDTO;
 import org.eclipsefoundation.persistence.test.dto.PersonDTO.PersonDTOFilter;
 import org.eclipsefoundation.persistence.test.namespace.PersistenceTestParameterNames;
-import org.eclipsefoundation.http.model.FlatRequestWrapper;
-import org.eclipsefoundation.http.response.PaginatedResultsFilter;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -32,6 +31,7 @@ import io.quarkus.cache.CacheName;
 import io.quarkus.cache.CaffeineCache;
 import io.quarkus.test.junit.QuarkusTest;
 import jakarta.inject.Inject;
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 
 /**
@@ -102,7 +102,7 @@ class SqlBackedPaginationResolverTest {
     void generateEntry_success_respectsFilters() {
         // set up the test with a filter
         FlatRequestWrapper wrap = new FlatRequestWrapper(URI.create("http://eclipse.org/sample/endpoint/" + UUID.randomUUID().toString()));
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add(PersistenceTestParameterNames.AT_LEAST_OF_AGE.getName(), "40");
         RDBMSQuery<PersonDTO> q = new RDBMSQuery<>(wrap, filter, params);
         // these fields should equal the headers in the result map
@@ -151,7 +151,7 @@ class SqlBackedPaginationResolverTest {
         Assertions.assertEquals(Integer.toString(limit), results.get(PaginatedResultsFilter.MAX_PAGE_SIZE_HEADER));
 
         // rerun with different params
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add(PersistenceTestParameterNames.AT_LEAST_OF_AGE.getName(), "40");
         q = new RDBMSQuery<>(wrap, filter, params);
         long newCount = dao.count(q);
@@ -241,7 +241,7 @@ class SqlBackedPaginationResolverTest {
         // set up context source to be used in fallback scenario. No filters are available initially
         FlatRequestWrapper primaryWrap = new FlatRequestWrapper(
                 URI.create("http://eclipse.org/sample/endpoint/" + UUID.randomUUID().toString()));
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add(PersistenceTestParameterNames.AT_LEAST_OF_AGE.getName(), "100");
         RDBMSQuery<PersonDTO> q = new RDBMSQuery<>(primaryWrap, filter, params);
         QueryPlayback contextSource = new QueryPlayback(q, dao);
diff --git a/pom.xml b/pom.xml
index 84ad669e55f1c65b376e29b5e9981620f227312e..1db6d4e5f24f740fadf259fe385f2a9e6fcd5e40 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
     <groupId>org.eclipsefoundation</groupId>
     <artifactId>quarkus-commons</artifactId>
     <name>Java SDK Commons</name>
-    <version>1.0.3-SNAPSHOT</version>
+    <version>1.1.0</version>
     <packaging>pom</packaging>
     <properties>
         <compiler-plugin.version>3.11.0</compiler-plugin.version>
diff --git a/testing/pom.xml b/testing/pom.xml
index 1e552045f9448991064ee24580a2075cf6ef63ff..10c4f54338d4b868fd76de0ac7653b0fccde06fb 100644
--- a/testing/pom.xml
+++ b/testing/pom.xml
@@ -9,7 +9,7 @@
     <parent>
         <groupId>org.eclipsefoundation</groupId>
         <artifactId>quarkus-commons</artifactId>
-        <version>1.0.3-SNAPSHOT</version>
+        <version>1.1.0</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <properties>
@@ -93,4 +93,4 @@
             </plugin>
         </plugins>
     </build>
-</project>
\ No newline at end of file
+</project>
diff --git a/testing/src/test/java/org/eclipsefoundation/testing/models/EndpointTestBuilderTest.java b/testing/src/test/java/org/eclipsefoundation/testing/models/EndpointTestBuilderTest.java
index 742f5ff88bd7eff0c8ff67017fd8717d63b3d128..72d567501343f6c3f561a91995eaecac0dc45179 100644
--- a/testing/src/test/java/org/eclipsefoundation/testing/models/EndpointTestBuilderTest.java
+++ b/testing/src/test/java/org/eclipsefoundation/testing/models/EndpointTestBuilderTest.java
@@ -52,6 +52,7 @@ class EndpointTestBuilderTest {
     private static final EndpointTestCase GET_NOT_FOUND = TestCaseHelper
             .prepareTestCase("nope", new String[] {}, SchemaNamespaceHelper.ERROR_SCHEMA_PATH)
             .setStatusCode(Status.NOT_FOUND.getStatusCode())
+            .setHeaderParams(Optional.of(Map.of("Accept", "application/json")))
             .setBodyValidationParams(Map.of("status_code", Status.NOT_FOUND.getStatusCode()))
             .build();
     private static final EndpointTestCase GET_BAD_REQUEST = TestCaseHelper
diff --git a/utils/pom.xml b/utils/pom.xml
index 47b0ce328774e7d9d7163615f16b319ed628d8f9..a141969446f8f6d9558b040f3c1e0b115f352d7a 100644
--- a/utils/pom.xml
+++ b/utils/pom.xml
@@ -9,7 +9,7 @@
   <parent>
     <groupId>org.eclipsefoundation</groupId>
     <artifactId>quarkus-commons</artifactId>
-    <version>1.0.3-SNAPSHOT</version>
+    <version>1.1.0</version>
     <relativePath>../pom.xml</relativePath>
   </parent>
   <dependencies>
@@ -21,11 +21,7 @@
     <!-- Required for session scoping + HTTP request classes -->
     <dependency>
       <groupId>io.quarkus</groupId>
-      <artifactId>quarkus-resteasy</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>io.quarkus</groupId>
-      <artifactId>quarkus-undertow</artifactId>
+      <artifactId>quarkus-resteasy-reactive</artifactId>
     </dependency>
     <!-- Adds logging bindings for more natural logging -->
     <dependency>
@@ -77,4 +73,4 @@
       </plugin>
     </plugins>
   </build>
-</project>
\ No newline at end of file
+</project>
diff --git a/utils/src/main/java/org/eclipsefoundation/utils/helper/CSRFHelper.java b/utils/src/main/java/org/eclipsefoundation/utils/helper/CSRFHelper.java
index 54ec005748c78e05b2118d68e0d5f56a839bba41..47629291ee6fe2c8d13d66788cd5f89fd64155ae 100644
--- a/utils/src/main/java/org/eclipsefoundation/utils/helper/CSRFHelper.java
+++ b/utils/src/main/java/org/eclipsefoundation/utils/helper/CSRFHelper.java
@@ -22,10 +22,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import io.quarkus.arc.Unremovable;
+import io.vertx.core.http.HttpServerRequest;
 import jakarta.enterprise.inject.Instance;
 import jakarta.inject.Inject;
 import jakarta.inject.Singleton;
-import jakarta.servlet.http.HttpServletRequest;
+import jakarta.ws.rs.core.SecurityContext;
 
 /**
  * Helper class for interacting with CSRF tokens within the server. Generates secure CSRF tokens and compares them to the copy that exists
@@ -50,8 +51,8 @@ public final class CSRFHelper {
      *
      * @return a cryptographically-secure CSRF token to use in a session.
      */
-    public String getNewCSRFToken(HttpServletRequest httpServletRequest) {
-        return generator.getCSRFToken(httpServletRequest);
+    public String getNewCSRFToken(HttpServerRequest request, SecurityContext context) {
+        return generator.getCSRFToken(request, context);
     }
 
     /**
@@ -61,9 +62,9 @@ public final class CSRFHelper {
      * @param httpServletRequest the request context
      * @return the CSRF token for the current request.
      */
-    public String getSessionCSRFToken(AdditionalUserData aud, HttpServletRequest httpServletRequest) {
+    public String getSessionCSRFToken(AdditionalUserData aud, HttpServerRequest request, SecurityContext context) {
         if (config.get().distributedMode().enabled()) {
-            return generator.getCSRFToken(httpServletRequest);
+            return generator.getCSRFToken(request, context);
         } else {
             return aud.getCsrf();
         }
diff --git a/utils/src/main/java/org/eclipsefoundation/utils/helper/ParameterHelper.java b/utils/src/main/java/org/eclipsefoundation/utils/helper/ParameterHelper.java
index 2de456eb184b0556546236fa4fa16f9a354ce9e7..aa83f068dfb02bbcebaf19b497ceca76ba2c4d6b 100644
--- a/utils/src/main/java/org/eclipsefoundation/utils/helper/ParameterHelper.java
+++ b/utils/src/main/java/org/eclipsefoundation/utils/helper/ParameterHelper.java
@@ -17,6 +17,10 @@ import java.util.Map.Entry;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.eclipsefoundation.utils.namespace.UrlParameterNamespace;
+
+import io.quarkus.arc.Unremovable;
+import io.quarkus.runtime.Startup;
 import jakarta.annotation.PostConstruct;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.enterprise.inject.Instance;
@@ -24,12 +28,6 @@ import jakarta.inject.Inject;
 import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 
-import org.eclipsefoundation.utils.namespace.UrlParameterNamespace;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
-
-import io.quarkus.arc.Unremovable;
-import io.quarkus.runtime.Startup;
-
 /**
  * Helper for parameter lookups and filtering.
  * 
@@ -75,7 +73,7 @@ public class ParameterHelper {
                     // merge the 2 lists and return
                     prevVal.addAll(addVals);
                     return prevVal;
-                }, MultivaluedMapImpl<String, String>::new));
+                }, MultivaluedHashMap<String, String>::new));
     }
 
     /**
diff --git a/utils/src/main/java/org/eclipsefoundation/utils/model/CSRFGenerator.java b/utils/src/main/java/org/eclipsefoundation/utils/model/CSRFGenerator.java
index 19cac22b05149594e9e2c422051f985fb663dea9..23eb2d7b3728ee4d2ccfa1fe08f2a6345623f534 100644
--- a/utils/src/main/java/org/eclipsefoundation/utils/model/CSRFGenerator.java
+++ b/utils/src/main/java/org/eclipsefoundation/utils/model/CSRFGenerator.java
@@ -13,15 +13,15 @@ package org.eclipsefoundation.utils.model;
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.util.HexFormat;
 import java.util.Optional;
 import java.util.UUID;
 
-import jakarta.servlet.http.HttpServletRequest;
-
 import org.eclipse.microprofile.config.ConfigProvider;
 import org.eclipsefoundation.utils.namespace.MicroprofilePropertyNames;
 
-import io.undertow.util.HexConverter;
+import io.vertx.core.http.HttpServerRequest;
+import jakarta.ws.rs.core.SecurityContext;
 
 /**
  * Interface used to generate random hardened tokens for use in requests.
@@ -32,18 +32,17 @@ import io.undertow.util.HexConverter;
 public interface CSRFGenerator {
 
     /**
-     * Generates a random secure CSRF token to be used in requests. This token should be cryptographically secure and random
-     * to ensure that it cannot be generated from an external source.
+     * Generates a random secure CSRF token to be used in requests. This token should be cryptographically secure and random to ensure that
+     * it cannot be generated from an external source.
      * 
      * @param requestContext current request context that can be used for fingerprinting the request if required.
      * @return a random encoded string token
      */
-    public String getCSRFToken(HttpServletRequest httpServletRequest);
+    public String getCSRFToken(HttpServerRequest request, SecurityContext context);
 
     /**
-     * Default implementation of the CSRF generator, will use secure randoms generated on the fly at runtime to generate
-     * random seed values as base of token. These values will be hashed and salted to provide extra hardening of the value
-     * to make it harder to predict.
+     * Default implementation of the CSRF generator, will use secure randoms generated on the fly at runtime to generate random seed values
+     * as base of token. These values will be hashed and salted to provide extra hardening of the value to make it harder to predict.
      * 
      * @author Martin Lowe
      *
@@ -51,7 +50,7 @@ public interface CSRFGenerator {
     public static class DefaultCSRFGenerator implements CSRFGenerator {
 
         @Override
-        public String getCSRFToken(HttpServletRequest httpServletRequest) {
+        public String getCSRFToken(HttpServerRequest request, SecurityContext context) {
             Optional<String> salt = ConfigProvider.getConfig().getOptionalValue(MicroprofilePropertyNames.CSRF_TOKEN_SALT, String.class);
 
             // create new digest to hash the result
@@ -70,7 +69,7 @@ public interface CSRFGenerator {
             // hash the results using the message digest
             byte[] array = md.digest(preHash.getBytes());
             // convert back to a hex string to act as a token
-            return HexConverter.convertToHexString(array);
+            return HexFormat.of().formatHex(array);
         }
     }
 }
diff --git a/utils/src/main/java/org/eclipsefoundation/utils/namespace/AdditionalHttpHeaders.java b/utils/src/main/java/org/eclipsefoundation/utils/namespace/AdditionalHttpHeaders.java
new file mode 100644
index 0000000000000000000000000000000000000000..7355c587d6a64572ed5681f6dd431619429bc80e
--- /dev/null
+++ b/utils/src/main/java/org/eclipsefoundation/utils/namespace/AdditionalHttpHeaders.java
@@ -0,0 +1,20 @@
+/*********************************************************************
+* Copyright (c) 2024 Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+/**
+ * 
+ */
+package org.eclipsefoundation.utils.namespace;
+
+/**
+ * 
+ */
+public class AdditionalHttpHeaders {
+    public final static String X_FORWARDED_FOR = "X-Forwarded-For";
+}
diff --git a/utils/src/main/resources/application.properties b/utils/src/main/resources/application.properties
new file mode 100644
index 0000000000000000000000000000000000000000..c664252918b6159df7c1fb4128c557d155e484d3
--- /dev/null
+++ b/utils/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+## CSRF should be disabled by default
+quarkus.csrf-reactive.enabled=false
\ No newline at end of file
diff --git a/utils/src/test/java/org/eclipsefoundation/utils/authenticated/helper/CSRFHelperTest.java b/utils/src/test/java/org/eclipsefoundation/utils/authenticated/helper/CSRFHelperTest.java
index 443b93f69f4cc336c8cfb805aa22420af7905dbb..8a56355069ac501156ff80abdf4fc350a39a5994 100644
--- a/utils/src/test/java/org/eclipsefoundation/utils/authenticated/helper/CSRFHelperTest.java
+++ b/utils/src/test/java/org/eclipsefoundation/utils/authenticated/helper/CSRFHelperTest.java
@@ -11,9 +11,6 @@
 **********************************************************************/
 package org.eclipsefoundation.utils.authenticated.helper;
 
-import jakarta.inject.Inject;
-import jakarta.servlet.http.HttpServletRequest;
-
 import org.eclipsefoundation.utils.exception.FinalForbiddenException;
 import org.eclipsefoundation.utils.helper.CSRFHelper;
 import org.eclipsefoundation.utils.test.AuthenticatedTestProfile;
@@ -24,6 +21,9 @@ import org.mockito.Mockito;
 
 import io.quarkus.test.junit.QuarkusTest;
 import io.quarkus.test.junit.TestProfile;
+import io.vertx.core.http.HttpServerRequest;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.core.SecurityContext;
 
 /**
  * Test CSRF functionality from the helper directly using the authentication secured test profile.
@@ -36,18 +36,20 @@ class CSRFHelperTest {
 
     @Inject
     CSRFHelper csrf;
-    
-    private static HttpServletRequest mockRequest;
+
+    private static HttpServerRequest mockRequest;
+    private static SecurityContext mockContext;
 
     @BeforeAll
     public static void setup() {
-        CSRFHelperTest.mockRequest = Mockito.mock(HttpServletRequest.class);
+        CSRFHelperTest.mockRequest = Mockito.mock(HttpServerRequest.class);
+        CSRFHelperTest.mockContext = Mockito.mock(SecurityContext.class);
     }
-    
+
     @Test
     void compareCSRF_validToken() {
         // generate a token to use in test
-        String csrfToken = csrf.getNewCSRFToken(mockRequest);
+        String csrfToken = csrf.getNewCSRFToken(mockRequest, mockContext);
 
         // this should not throw as the tokens match
         Assertions.assertDoesNotThrow(() -> csrf.compareCSRF(csrfToken, csrfToken));
@@ -56,7 +58,7 @@ class CSRFHelperTest {
     @Test
     void compareCSRF_invalidToken() {
         // generate a token to use in test
-        String csrfToken = csrf.getNewCSRFToken(mockRequest);
+        String csrfToken = csrf.getNewCSRFToken(mockRequest, mockContext);
 
         // this should throw as the tokens are not the same
         Assertions.assertThrows(FinalForbiddenException.class, () -> csrf.compareCSRF(csrfToken, "some-other-value"));
@@ -65,7 +67,7 @@ class CSRFHelperTest {
     @Test
     void compareCSRF_noSubmittedToken() {
         // generate a token to use in test
-        String csrfToken = csrf.getNewCSRFToken(mockRequest);
+        String csrfToken = csrf.getNewCSRFToken(mockRequest, mockContext);
         // this should throw as the tokens are not the same
         Assertions.assertThrows(FinalForbiddenException.class, () -> csrf.compareCSRF(csrfToken, null));
         Assertions.assertThrows(FinalForbiddenException.class, () -> csrf.compareCSRF(csrfToken, ""));
diff --git a/utils/src/test/java/org/eclipsefoundation/utils/helper/ParameterHelperTest.java b/utils/src/test/java/org/eclipsefoundation/utils/helper/ParameterHelperTest.java
index ae43908e8c517313cefe3f9d3dacd85f1d38a249..3aab3544bb617344f553fef8210bc984bfa9e798 100644
--- a/utils/src/test/java/org/eclipsefoundation/utils/helper/ParameterHelperTest.java
+++ b/utils/src/test/java/org/eclipsefoundation/utils/helper/ParameterHelperTest.java
@@ -5,17 +5,18 @@ import java.util.Collections;
 import java.util.List;
 
 import org.eclipsefoundation.utils.namespace.UrlParameterNamespace;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 import io.quarkus.test.junit.QuarkusTest;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
+import jakarta.ws.rs.core.MultivaluedHashMap;
 import jakarta.ws.rs.core.MultivaluedMap;
 
 /**
- * Contains base tests for confirming that parameter helper filters as expected based on registered parameters.
+ * Contains base tests for confirming that parameter helper filters as expected
+ * based on registered parameters.
  */
 @QuarkusTest
 class ParameterHelperTest {
@@ -26,7 +27,7 @@ class ParameterHelperTest {
     @Test
     void filterUnknownParameters_success_retainsKnownParameters() {
         // set up params with basic params that are tracked
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add("id", "sample");
 
         MultivaluedMap<String, String> actualParams = helper.filterUnknownParameters(params);
@@ -36,17 +37,19 @@ class ParameterHelperTest {
     @Test
     void filterUnknownParameters_success_removesUnknownParameters() {
         // set up params with basic params that are tracked
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
         params.add("some-unknown-parameter", "sample");
 
         MultivaluedMap<String, String> actualParams = helper.filterUnknownParameters(params);
-        Assertions.assertTrue(actualParams.isEmpty(), "Parameter map had an unexpected value when it expected value to be filtered");
+        Assertions.assertTrue(actualParams.isEmpty(),
+                "Parameter map had an unexpected value when it expected value to be filtered");
     }
 
     @Test
     void filterUnknownParameters_success_detectsCustomNamespaces() {
         // set up params with basic params that are tracked
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        MultivaluedMap<String, String> params = new MultivaluedHashMap<>();
+
         params.add(TestUrlParameterNamespace.SAMPLE_URL_PARAM_NAME, "sample");
 
         MultivaluedMap<String, String> actualParams = helper.filterUnknownParameters(params);
@@ -65,7 +68,8 @@ class ParameterHelperTest {
 
     @Test
     void parseQueryString_success() {
-        MultivaluedMap<String, String> out = ParameterHelper.parseQueryString("sample=1&fair_param=simple&sample=some string");
+        MultivaluedMap<String, String> out = ParameterHelper
+                .parseQueryString("sample=1&fair_param=simple&sample=some string");
         // check for multiple values on same key
         Assertions.assertNotNull(out.get("sample"));
         Assertions.assertEquals(2, out.get("sample").size());