diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4d78da942d090b651569fefaa892967de2f887a0..2fc1917708e58e1c62166e76c2f77bd8cde0f15a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,14 +4,17 @@ variables:
   OSDU_GCP_VENDOR: gcp
   OSDU_GCP_SERVICE: notification
   OSDU_GCP_REGISTER_BASE_URL: https://os-register-attcrcktoa-uc.a.run.app/api/register/v1
-  OSDU_GCP_ENV_VARS: APP_PROJECT=$OSDU_GCP_PROJECT,APP_ENTITLEMENTS=$OSDU_GCP_ENTITLEMENTS_URL,APP_REGISTER=$OSDU_GCP_REGISTER_BASE_URL,APP_GOOGLEAUDIENCE=$GOOGLE_AUDIENCE
+  OSDU_GCP_ENV_VARS: APP_PROJECT=$OSDU_GCP_PROJECT,APP_ENTITLEMENTS=$OSDU_GCP_ENTITLEMENTS_V2_URL,APP_REGISTER=$OSDU_GCP_REGISTER_BASE_URL,APP_GOOGLEAUDIENCE=$GOOGLE_AUDIENCE,PARTITION_API=$OSDU_GCP_PARTITION_API,GOOGLE_AUDIENCES=$GOOGLE_AUDIENCE
   OSDU_GCP_ENVIRONMENT: dev_gke
   OSDU_GCP_LOG_LEVEL: INFO
+  OSDU_GCP_HELM_PACKAGE_CHARTS: "devops/gcp/deploy devops/gcp/configmap"
 
   AWS_BUILD_SUBDIR: provider/notification-aws/build-aws
   AWS_TEST_SUBDIR: testing/notification-test-aws
   AWS_SERVICE: notification
   AWS_ENVIRONMENT: dev
+  AWS_DEPLOY_TARGET: EKS
+  AWS_EKS_DEPLOYMENT_NAME: os-notification
 
   AZURE_SERVICE: notification
   AZURE_BUILD_SUBDIR: provider/notification-azure
diff --git a/NOTICE b/NOTICE
index 9bcef882e976b6025479d4d9691d0a847a57e4ad..31690502fe7bc60b37552c42ae2d6705b1460c08 100644
--- a/NOTICE
+++ b/NOTICE
@@ -9,13 +9,6 @@ The following software have components provided under the terms of this license:
 
 - Android SDK (from https://www.android.com/)
 
-========================================================================
-Apache-1.1
-========================================================================
-The following software have components provided under the terms of this license:
-
-- StAX (from http://stax.codehaus.org/)
-
 ========================================================================
 Apache-2.0
 ========================================================================
@@ -23,22 +16,7 @@ The following software have components provided under the terms of this license:
 
 - AMQP 1.0 JMS Spring Boot AutoConfiguration (from https://repo1.maven.org/maven2/org/amqphub/spring/amqp-10-jms-spring-boot-autoconfigure)
 - AMQP 1.0 JMS Spring Boot Starter (from https://repo1.maven.org/maven2/org/amqphub/spring/amqp-10-jms-spring-boot-starter)
-- ASM Core (from )
 - ASM based accessors helper used by json-smart (from )
-- AWS Event Stream (from https://github.com/awslabs/aws-eventstream-java)
-- AWS Java SDK :: AWS Core (from https://aws.amazon.com/sdkforjava)
-- AWS Java SDK :: Annotations (from )
-- AWS Java SDK :: Auth (from https://aws.amazon.com/sdkforjava)
-- AWS Java SDK :: Core :: Protocols :: AWS Json Protocol (from https://aws.amazon.com/sdkforjava)
-- AWS Java SDK :: Core :: Protocols :: Protocol Core (from https://aws.amazon.com/sdkforjava)
-- AWS Java SDK :: HTTP Client Interface (from )
-- AWS Java SDK :: HTTP Clients :: Apache (from )
-- AWS Java SDK :: HTTP Clients :: Netty Non-Blocking I/O (from )
-- AWS Java SDK :: Profiles (from https://aws.amazon.com/sdkforjava)
-- AWS Java SDK :: Regions (from )
-- AWS Java SDK :: SDK Core (from https://aws.amazon.com/sdkforjava)
-- AWS Java SDK :: Services :: AWS Simple Systems Management (SSM) (from https://aws.amazon.com/sdkforjava)
-- AWS Java SDK :: Utilities (from )
 - AWS Java SDK for AWS Elemental MediaLive (from https://aws.amazon.com/sdkforjava)
 - AWS Java SDK for AWS KMS (from https://aws.amazon.com/sdkforjava)
 - AWS Java SDK for AWS Lambda (from https://aws.amazon.com/sdkforjava)
@@ -51,266 +29,280 @@ The following software have components provided under the terms of this license:
 - AWS Java SDK for Amazon SNS (from https://aws.amazon.com/sdkforjava)
 - AWS Java SDK for Amazon SQS (from https://aws.amazon.com/sdkforjava)
 - AWS Java SDK for the AWS Simple Systems Management (SSM) Service (from https://aws.amazon.com/sdkforjava)
-- AWS SDK for Java - BOM (from https://aws.amazon.com/sdkforjava)
 - AWS SDK for Java - Core (from https://aws.amazon.com/sdkforjava)
-- Adapter: RxJava (from )
-- Apache Commons Codec (from http://commons.apache.org/proper/commons-codec/)
+- Adapter: RxJava (from https://repo1.maven.org/maven2/com/squareup/retrofit2/adapter-rxjava)
+- Apache Commons Codec (from https://commons.apache.org/proper/commons-codec/)
 - Apache Commons Collections (from http://commons.apache.org/proper/commons-collections/)
+- Apache Commons IO (from https://commons.apache.org/proper/commons-io/)
 - Apache Commons Lang (from http://commons.apache.org/proper/commons-lang/)
 - Apache Commons Logging (from http://commons.apache.org/proper/commons-logging/)
 - Apache Commons Logging (from http://commons.apache.org/proper/commons-logging/)
 - Apache Geronimo JMS Spec 2.0 (from http://geronimo.apache.org/maven/${siteId}/${version})
 - Apache HttpAsyncClient (from http://hc.apache.org/httpcomponents-asyncclient)
-- Apache HttpClient (from http://hc.apache.org/httpcomponents-client)
-- Apache HttpClient Cache (from http://hc.apache.org/httpcomponents-client)
-- Apache HttpCore (from http://hc.apache.org/httpcomponents-core-ga)
 - Apache HttpCore NIO (from http://hc.apache.org/httpcomponents-core-ga)
-- Apache Log4j API (from )
-- Apache Log4j Core (from )
-- Apache Log4j JUL Adapter (from )
-- Apache Log4j SLF4J Binding (from )
-- Apache Log4j to SLF4J Adapter (from )
-- AssertJ fluent assertions (from )
-- Asynchronous Http Client (from )
-- Asynchronous Http Client Netty Utils (from )
-- Azure AD Spring Security Integration Spring Boot Starter (from https://github.com/Microsoft/azure-spring-boot)
-- Azure Metrics Spring Boot Starter (from https://github.com/Microsoft/azure-spring-boot)
+- Apache Log4j API (from https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-api)
+- Apache Log4j Core (from https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-core)
+- Apache Log4j JUL Adapter (from https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-jul)
+- Apache Log4j SLF4J Binding (from https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-slf4j-impl)
+- Apache Log4j to SLF4J Adapter (from https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-to-slf4j)
+- AssertJ fluent assertions (from https://repo1.maven.org/maven2/org/assertj/assertj-core)
+- Asynchronous Http Client (from https://repo1.maven.org/maven2/org/asynchttpclient/async-http-client)
+- Asynchronous Http Client Netty Utils (from https://repo1.maven.org/maven2/org/asynchttpclient/async-http-client-netty-utils)
+- AutoValue Annotations (from https://github.com/google/auto/tree/master/value)
+- Azure Spring Boot Starter for Azure AD Spring Security Integration (from https://github.com/Azure/azure-sdk-for-java)
 - Bean Validation API (from http://beanvalidation.org)
-- Byte Buddy (without dependencies) (from )
-- Byte Buddy Java agent (from )
+- Brave (from https://repo1.maven.org/maven2/io/zipkin/brave/brave)
+- Brave Instrumentation: Http Adapters (from https://repo1.maven.org/maven2/io/zipkin/brave/brave-instrumentation-http)
+- Brave instrumentation for Reactor Netty HTTP (from https://github.com/reactor/reactor-netty)
+- Byte Buddy (without dependencies) (from https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy)
+- Byte Buddy agent (from https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy-agent)
 - ClassMate (from http://github.com/cowtowncoder/java-classmate)
-- Cloud Storage JSON API v1-rev58-1.21.0 (from )
-- Commons IO (from http://commons.apache.org/io/)
-- Converter: Jackson (from )
-- Elastic JNA Distribution (from https://github.com/java-native-access/jna)
-- Elasticsearch: 5.0.0-alpha5 (from https://github.com/elastic/elasticsearch)
+- Cloud Storage JSON API v1-rev20210914-1.32.1 (from https://repo1.maven.org/maven2/com/google/apis/google-api-services-storage)
+- Converter: Jackson (from https://repo1.maven.org/maven2/com/squareup/retrofit2/converter-jackson)
+- Core functionality for the Reactor Netty library (from https://github.com/reactor/reactor-netty)
+- Elastic JNA Distribution (from https://github.com/elastic/jna-build)
 - Expression Language 3.0 (from http://uel.java.net)
-- Expression Language 3.0 (from https://projects.eclipse.org/projects/ee4j.el)
 - FindBugs-jsr305 (from http://findbugs.sourceforge.net/)
-- Google APIs Client Library for Java (from )
-- Google App Engine extensions to the Google HTTP Client Library for Java. (from )
-- Google Cloud Core (from https://github.com/GoogleCloudPlatform/google-cloud-java/tree/master/google-cloud-core)
-- Google Cloud Core HTTP (from https://github.com/GoogleCloudPlatform/google-cloud-java/tree/master/google-cloud-core-http)
-- Google Cloud Core gRPC (from https://github.com/GoogleCloudPlatform/google-cloud-java/tree/master/google-cloud-core-grpc)
-- Google Cloud Datastore (from https://github.com/GoogleCloudPlatform/google-cloud-java/tree/master/google-cloud-datastore)
-- Google Cloud Key Management Service (KMS) API v1-rev22-1.23.0 (from )
-- Google Cloud Logging (from https://github.com/GoogleCloudPlatform/google-cloud-java/tree/master/google-cloud-logging)
-- Google Cloud Pub/Sub (from https://github.com/GoogleCloudPlatform/google-cloud-java/tree/master/google-cloud-pubsub)
-- Google Cloud Storage (from https://github.com/GoogleCloudPlatform/google-cloud-java/tree/master/google-cloud-storage)
-- Google HTTP Client Library for Java (from https://github.com/google/google-http-java-client.git)
-- Google HTTP Client Library for Java (from https://github.com/google/google-http-java-client.git)
-- Google OAuth Client Library for Java (from )
-- Gson (from https://github.com/google/gson)
-- Guava InternalFutureFailureAccess and InternalFutures (from )
-- Guava InternalFutureFailureAccess and InternalFutures (from )
-- Guava ListenableFuture only (from )
-- Guava: Google Core Libraries for Java (from https://github.com/google/guava.git)
-- Guava: Google Core Libraries for Java (from https://github.com/google/guava.git)
-- HPPC Collections (from http://labs.carrotsearch.com)
-- Hibernate Validator Engine (from )
-- Hibernate Validator Engine (from )
+- GSON extensions to the Google HTTP Client Library for Java. (from https://repo1.maven.org/maven2/com/google/http-client/google-http-client-gson)
+- Google APIs Client Library for Java (from https://repo1.maven.org/maven2/com/google/api-client/google-api-client)
+- Google App Engine extensions to the Google HTTP Client Library for Java. (from https://repo1.maven.org/maven2/com/google/http-client/google-http-client-appengine)
+- Google Cloud Core (from https://github.com/googleapis/java-core)
+- Google Cloud Core HTTP (from https://github.com/googleapis/java-core)
+- Google Cloud Core gRPC (from https://github.com/googleapis/google-cloud-java/tree/master/google-cloud-clients/google-cloud-core-grpc)
+- Google Cloud Datastore (from https://github.com/googleapis/java-datastore)
+- Google Cloud IAM Service Account Credentials (from https://github.com/googleapis/java-iamcredentials)
+- Google Cloud Key Management Service (KMS) API v1-rev9-1.22.0 (from https://repo1.maven.org/maven2/com/google/apis/google-api-services-cloudkms)
+- Google Cloud Logging (from https://github.com/googleapis/google-cloud-java/tree/master/google-cloud-clients/google-cloud-logging)
+- Google Cloud Pub/Sub (from https://github.com/googleapis/java-pubsub)
+- Google Cloud Storage (from https://github.com/googleapis/java-storage)
+- Google HTTP Client Library for Java (from https://repo1.maven.org/maven2/com/google/http-client/google-http-client)
+- Google HTTP Client Library for Java (from https://repo1.maven.org/maven2/com/google/http-client/google-http-client)
+- Google OAuth Client Library for Java (from https://repo1.maven.org/maven2/com/google/oauth-client/google-oauth-client)
+- Gson (from https://repo1.maven.org/maven2/com/google/code/gson/gson)
+- Gson (from https://repo1.maven.org/maven2/com/google/code/gson/gson)
+- Guava InternalFutureFailureAccess and InternalFutures (from https://repo1.maven.org/maven2/com/google/guava/failureaccess)
+- Guava InternalFutureFailureAccess and InternalFutures (from https://repo1.maven.org/maven2/com/google/guava/failureaccess)
+- Guava: Google Core Libraries for Java (from https://github.com/google/guava)
+- Guava: Google Core Libraries for Java (from https://github.com/google/guava)
+- HPPC Collections (from https://repo1.maven.org/maven2/com/carrotsearch/hppc)
+- HTTP functionality for the Reactor Netty library (from https://github.com/reactor/reactor-netty)
+- Hibernate Validator Engine (from https://repo1.maven.org/maven2/org/hibernate/validator/hibernate-validator)
+- Hibernate Validator Engine (from https://repo1.maven.org/maven2/org/hibernate/validator/hibernate-validator)
+- HttpClient (from http://hc.apache.org/httpcomponents-client)
+- HttpClient Cache (from http://hc.apache.org/httpcomponents-client)
+- HttpCore (from http://hc.apache.org/httpcomponents-core-ga)
 - IBM COS Java SDK for Amazon S3 (from https://github.com/ibm/ibm-cos-sdk-java)
 - IBM COS Java SDK for COS KMS (from https://github.com/ibm/ibm-cos-sdk-java)
 - IBM COS SDK For Java (from https://github.com/ibm/ibm-cos-sdk-java)
 - IBM COS SDK for Java - Core (from https://github.com/ibm/ibm-cos-sdk-java)
-- Identity and Access Management (IAM) API v1-rev247-1.23.0 (from )
-- Identity and Access Management (IAM) API v1-rev247-1.23.0 (from )
-- IntelliJ IDEA Annotations (from http://www.jetbrains.org)
+- Identity and Access Management (IAM) API v1-rev284-1.25.0 (from https://repo1.maven.org/maven2/com/google/apis/google-api-services-iam)
+- Identity and Access Management (IAM) API v1-rev284-1.25.0 (from https://repo1.maven.org/maven2/com/google/apis/google-api-services-iam)
 - J2ObjC Annotations (from https://github.com/google/j2objc/)
 - JBoss Logging 3 (from http://www.jboss.org)
+- JBoss Threads (from https://repo1.maven.org/maven2/org/jboss/threads/jboss-threads)
 - JCIP Annotations under Apache License (from http://stephenc.github.com/jcip-annotations)
 - JMES Path Query library (from https://aws.amazon.com/sdkforjava)
-- JSON Small and Fast Parser (from http://www.minidev.net/)
-- JSON Web Token support for the JVM (from https://github.com/jwtk/jjwt.git)
+- JSON Small and Fast Parser (from https://repo1.maven.org/maven2/net/minidev/json-smart)
+- JSON Web Token support for the JVM (from https://repo1.maven.org/maven2/io/jsonwebtoken/jjwt)
 - JSON library from Android SDK (from http://developer.android.com/sdk)
 - JSONassert (from https://github.com/skyscreamer/JSONassert)
+- JSR107 API and SPI (from https://github.com/jsr107/jsr107spec)
 - Jackson (from http://jackson.codehaus.org)
-- Jackson 2 extensions to the Google HTTP Client Library for Java. (from https://github.com/google/google-http-java-client.git/google-http-client-jackson2)
-- Jackson dataformat: CBOR (from http://github.com/FasterXML/jackson-dataformats-binary)
+- Jackson 2 extensions to the Google HTTP Client Library for Java. (from https://repo1.maven.org/maven2/com/google/http-client/google-http-client-jackson2)
 - Jackson dataformat: CBOR (from http://github.com/FasterXML/jackson-dataformats-binary)
-- Jackson datatype: JSR310 (from http://wiki.fasterxml.com/JacksonModuleJSR310)
-- Jackson datatype: JSR310 (from http://wiki.fasterxml.com/JacksonModuleJSR310)
-- Jackson extensions to the Google HTTP Client Library for Java. (from )
-- Jackson-annotations (from http://github.com/FasterXML/jackson)
+- Jackson dataformat: Smile (from http://github.com/FasterXML/jackson-dataformats-binary)
+- Jackson datatype: JSR310 (from https://repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-jsr310)
+- Jackson datatype: Joda (from https://github.com/FasterXML/jackson-datatype-joda)
+- Jackson datatype: jdk8 (from https://repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-jdk8)
+- Jackson extensions to the Google HTTP Client Library for Java. (from https://repo1.maven.org/maven2/com/google/http-client/google-http-client-jackson)
+- Jackson module: Afterburner (from https://github.com/FasterXML/jackson-modules-base)
+- Jackson module: JAXB Annotations (from https://github.com/FasterXML/jackson-modules-base)
 - Jackson-annotations (from http://github.com/FasterXML/jackson)
 - Jackson-core (from https://github.com/FasterXML/jackson-core)
 - Jackson-core (from https://github.com/FasterXML/jackson-core)
-- Jackson-dataformat-Smile (from http://github.com/FasterXML/jackson-dataformat-smile)
-- Jackson-dataformat-Smile (from http://github.com/FasterXML/jackson-dataformat-smile)
 - Jackson-dataformat-XML (from http://wiki.fasterxml.com/JacksonExtensionXmlDataBinding)
 - Jackson-dataformat-YAML (from https://github.com/FasterXML/jackson)
-- Jackson-dataformat-YAML (from https://github.com/FasterXML/jackson)
-- Jackson-datatype-Joda (from http://wiki.fasterxml.com/JacksonModuleJoda)
-- Jackson-datatype-jdk8 (from )
-- Jackson-datatype-jdk8 (from )
-- Jackson-module-Afterburner (from http://wiki.fasterxml.com/JacksonHome)
-- Jackson-module-JAXB-annotations (from http://wiki.fasterxml.com/JacksonJAXBAnnotations)
-- Jackson-module-parameter-names (from )
-- Jackson-module-parameter-names (from )
+- Jackson-module-parameter-names (from https://repo1.maven.org/maven2/com/fasterxml/jackson/module/jackson-module-parameter-names)
 - Jakarta Bean Validation API (from https://beanvalidation.org)
+- Jakarta Expression Language Implementation (from https://projects.eclipse.org/projects/ee4j.el)
 - Java Native Access (from https://github.com/java-native-access/jna)
 - Java Native Access Platform (from https://github.com/java-native-access/jna)
+- Java Servlet 4.0 API (from )
+- Java Servlet 4.0 API (from )
 - Java Servlet API (from https://projects.eclipse.org/projects/ee4j.servlet)
 - Java Servlet API (from http://servlet-spec.java.net)
 - Java UUID Generator (from http://wiki.fasterxml.com/JugHome)
 - Javassist (from http://www.javassist.org/)
 - Javassist (from http://www.javassist.org/)
-- Joda-Time (from http://www.joda.org/joda-time/)
-- Json Path (from https://github.com/jayway/JsonPath)
+- JetBrains Java Annotations (from https://github.com/JetBrains/java-annotations)
+- Joda-Time (from https://www.joda.org/joda-time/)
 - KeePassJava2 :: All (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/KeePassJava2)
 - KeePassJava2 :: DOM (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/KeePassJava2-dom)
 - KeePassJava2 :: JAXB (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/KeePassJava2-jaxb)
 - KeePassJava2 :: KDB (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/KeePassJava2-kdb)
 - KeePassJava2 :: KDBX (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/KeePassJava2-kdbx)
 - KeePassJava2 :: Simple (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/KeePassJava2-simple)
-- Logback Contrib :: JSON :: Classic (from )
-- Logback Contrib :: JSON :: Core (from )
-- Logback Contrib :: Jackson (from )
-- Lucene Common Analyzers (from )
-- Lucene Core (from )
-- Lucene Grouping (from )
-- Lucene Highlighter (from )
-- Lucene Join (from )
-- Lucene Memory (from )
-- Lucene Memory (from )
-- Lucene Miscellaneous (from )
-- Lucene Queries (from )
-- Lucene QueryParsers (from )
-- Lucene Sandbox (from )
-- Lucene Spatial (from )
-- Lucene Spatial 3D (from )
-- Lucene Spatial Extras (from )
-- Lucene Suggest (from )
-- MapStruct Core (from )
-- Metrics Core (from https://github.com/dropwizard/metrics)
-- Microsoft Application Insights Java SDK Core (from https://github.com/Microsoft/ApplicationInsights-Java)
+- Logback Contrib :: JSON :: Classic (from https://repo1.maven.org/maven2/ch/qos/logback/contrib/logback-json-classic)
+- Logback Contrib :: JSON :: Core (from https://repo1.maven.org/maven2/ch/qos/logback/contrib/logback-json-core)
+- Logback Contrib :: Jackson (from https://repo1.maven.org/maven2/ch/qos/logback/contrib/logback-jackson)
+- Lucene Common Analyzers (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-analyzers-common)
+- Lucene Core (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-core)
+- Lucene Grouping (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-grouping)
+- Lucene Highlighter (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-highlighter)
+- Lucene Join (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-join)
+- Lucene Memory (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-backward-codecs)
+- Lucene Memory (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-memory)
+- Lucene Miscellaneous (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-misc)
+- Lucene Queries (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-queries)
+- Lucene QueryParsers (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-queryparser)
+- Lucene Sandbox (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-sandbox)
+- Lucene Spatial (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-spatial)
+- Lucene Spatial 3D (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-spatial3d)
+- Lucene Spatial Extras (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-spatial-extras)
+- Lucene Suggest (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-suggest)
+- MapStruct Core (from https://repo1.maven.org/maven2/org/mapstruct/mapstruct)
+- Metrics Core (from https://repo1.maven.org/maven2/io/dropwizard/metrics/metrics-core)
 - Microsoft Application Insights Java SDK Spring Boot starter (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Java SDK Web Module (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Log4j 2 Appender (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Azure Java Core Library (from https://github.com/Azure/azure-sdk-for-java)
 - Microsoft Azure Netty HTTP Client Library (from https://github.com/Azure/azure-sdk-for-java)
 - Microsoft Azure SDK for SQL API of Azure Cosmos DB Service (from https://github.com/Azure/azure-sdk-for-java)
-- Mockito (from http://mockito.org)
 - Mockito (from http://www.mockito.org)
-- Netty Reactive Streams HTTP support (from )
-- Netty Reactive Streams Implementation (from )
-- Netty/Buffer (from http://netty.io/)
-- Netty/Buffer (from http://netty.io/)
-- Netty/Codec (from )
-- Netty/Codec (from )
-- Netty/Codec/HTTP (from )
-- Netty/Codec/HTTP (from )
-- Netty/Codec/HTTP2 (from )
-- Netty/Codec/HTTP2 (from )
-- Netty/Codec/Socks (from )
-- Netty/Common (from )
-- Netty/Common (from )
-- Netty/Handler (from )
-- Netty/Handler (from )
-- Netty/Handler/Proxy (from )
-- Netty/Resolver (from )
-- Netty/Resolver (from )
-- Netty/TomcatNative [BoringSSL - Static] (from )
-- Netty/Transport (from http://netty.io/)
-- Netty/Transport (from http://netty.io/)
-- Netty/Transport/Native/Unix/Common (from )
-- Netty/Transport/Native/Unix/Common (from )
-- Nimbus Content Type (from https://bitbucket.org/connect2id/nimbus-content-type)
+- Netty/Buffer (from https://repo1.maven.org/maven2/io/netty/netty-buffer)
+- Netty/Buffer (from https://repo1.maven.org/maven2/io/netty/netty-buffer)
+- Netty/Codec (from https://repo1.maven.org/maven2/io/netty/netty-codec)
+- Netty/Codec (from https://repo1.maven.org/maven2/io/netty/netty-codec)
+- Netty/Codec/DNS (from https://repo1.maven.org/maven2/io/netty/netty-codec-dns)
+- Netty/Codec/HTTP (from https://repo1.maven.org/maven2/io/netty/netty-codec-http)
+- Netty/Codec/HTTP (from https://repo1.maven.org/maven2/io/netty/netty-codec-http)
+- Netty/Codec/HTTP2 (from https://repo1.maven.org/maven2/io/netty/netty-codec-http2)
+- Netty/Codec/HTTP2 (from https://repo1.maven.org/maven2/io/netty/netty-codec-http2)
+- Netty/Codec/Socks (from https://repo1.maven.org/maven2/io/netty/netty-codec-socks)
+- Netty/Common (from https://repo1.maven.org/maven2/io/netty/netty-common)
+- Netty/Common (from https://repo1.maven.org/maven2/io/netty/netty-common)
+- Netty/Handler (from https://repo1.maven.org/maven2/io/netty/netty-handler)
+- Netty/Handler (from https://repo1.maven.org/maven2/io/netty/netty-handler)
+- Netty/Handler/Proxy (from https://repo1.maven.org/maven2/io/netty/netty-handler-proxy)
+- Netty/Resolver (from https://repo1.maven.org/maven2/io/netty/netty-resolver)
+- Netty/Resolver (from https://repo1.maven.org/maven2/io/netty/netty-resolver)
+- Netty/Resolver/DNS (from https://repo1.maven.org/maven2/io/netty/netty-resolver-dns)
+- Netty/TomcatNative [BoringSSL - Static] (from https://repo1.maven.org/maven2/io/netty/netty-tcnative-boringssl-static)
+- Netty/Transport (from https://repo1.maven.org/maven2/io/netty/netty-transport)
+- Netty/Transport (from https://repo1.maven.org/maven2/io/netty/netty-transport)
+- Netty/Transport/Native/Unix/Common (from https://repo1.maven.org/maven2/io/netty/netty-transport-native-unix-common)
+- Netty/Transport/Native/Unix/Common (from https://repo1.maven.org/maven2/io/netty/netty-transport-native-unix-common)
 - Nimbus Content Type (from https://bitbucket.org/connect2id/nimbus-content-type)
 - Nimbus JOSE+JWT (from https://bitbucket.org/connect2id/nimbus-jose-jwt)
 - Nimbus JOSE+JWT (from https://bitbucket.org/connect2id/nimbus-jose-jwt)
 - Nimbus JOSE+JWT (from https://bitbucket.org/connect2id/nimbus-jose-jwt)
 - Nimbus LangTag (from https://bitbucket.org/connect2id/nimbus-language-tags)
+- Nimbus LangTag (from https://bitbucket.org/connect2id/nimbus-language-tags)
 - Non-Blocking Reactive Foundation for the JVM (from https://github.com/reactor/reactor)
 - OAuth 2.0 SDK with OpenID Connect extensions (from https://bitbucket.org/connect2id/oauth-2.0-sdk-with-openid-connect-extensions)
 - OAuth 2.0 SDK with OpenID Connect extensions (from https://bitbucket.org/connect2id/oauth-2.0-sdk-with-openid-connect-extensions)
 - Objenesis (from http://objenesis.org)
-- OkHttp (from )
-- OkHttp (from )
-- OkHttp Logging Interceptor (from )
-- OkHttp URLConnection (from )
-- OkHttp URLConnection (from )
-- Okio (from )
+- OkHttp (from https://repo1.maven.org/maven2/com/squareup/okhttp3/okhttp)
+- OkHttp (from https://repo1.maven.org/maven2/com/squareup/okhttp3/okhttp)
+- OkHttp Logging Interceptor (from https://repo1.maven.org/maven2/com/squareup/okhttp3/logging-interceptor)
+- OpenCensus (from https://github.com/census-instrumentation/opencensus-java)
 - OpenCensus (from https://github.com/census-instrumentation/opencensus-java)
 - OpenCensus (from https://github.com/census-instrumentation/opencensus-java)
 - OpenCensus (from https://github.com/census-instrumentation/opencensus-java)
 - PWDB :: Database (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/database)
 - PowerMock (from http://www.powermock.org)
-- Protocol Buffer extensions to the Google HTTP Client Library for Java. (from )
+- PowerMock (from http://www.powermock.org)
+- PowerMock (from http://www.powermock.org)
+- PowerMock (from http://www.powermock.org)
+- PowerMock (from http://www.powermock.org)
+- PowerMock (from http://www.powermock.org)
+- Protocol Buffer extensions to the Google HTTP Client Library for Java. (from https://repo1.maven.org/maven2/com/google/http-client/google-http-client-protobuf)
+- Proton-J (from https://repo1.maven.org/maven2/org/apache/qpid/proton-j)
 - QpidJMS Client (from )
-- Reactive Streams Netty driver (from https://github.com/reactor/reactor-netty)
-- Retrofit (from )
-- Simple XML (from http://simple.sourceforge.net)
+- Reactor Netty with all modules (from https://github.com/reactor/reactor-netty)
+- Retrofit (from https://repo1.maven.org/maven2/com/squareup/retrofit2/retrofit)
 - SnakeYAML (from http://www.snakeyaml.org)
 - Spring AOP (from https://github.com/spring-projects/spring-framework)
 - Spring Beans (from https://github.com/spring-projects/spring-framework)
-- Spring Boot (from http://projects.spring.io/spring-boot/)
-- Spring Boot Actuator (from http://projects.spring.io/spring-boot/)
+- Spring Boot (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot)
+- Spring Boot AOP Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-aop)
+- Spring Boot Actuator (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-actuator)
 - Spring Boot Actuator AutoConfigure (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-actuator-autoconfigure)
-- Spring Boot Actuator Starter (from http://projects.spring.io/spring-boot/)
-- Spring Boot AutoConfigure (from http://projects.spring.io/spring-boot/)
-- Spring Boot Dependencies (from http://projects.spring.io/spring-boot/)
+- Spring Boot Actuator Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-actuator)
+- Spring Boot AutoConfigure (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-autoconfigure)
 - Spring Boot Json Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-json)
-- Spring Boot Log4J2 Starter (from http://projects.spring.io/spring-boot/)
-- Spring Boot Logging Starter (from http://projects.spring.io/spring-boot/)
-- Spring Boot Security Starter (from http://projects.spring.io/spring-boot/)
-- Spring Boot Starter (from http://projects.spring.io/spring-boot/)
-- Spring Boot Test (from http://projects.spring.io/spring-boot/)
-- Spring Boot Test Auto-Configure (from http://projects.spring.io/spring-boot/)
-- Spring Boot Test Starter (from http://projects.spring.io/spring-boot/)
-- Spring Boot Tomcat Starter (from http://projects.spring.io/spring-boot/)
-- Spring Boot Undertow Starter (from http://projects.spring.io/spring-boot/)
-- Spring Boot Undertow Starter (from http://projects.spring.io/spring-boot/)
-- Spring Boot Validation Starter (from http://projects.spring.io/spring-boot/)
-- Spring Boot Validation Starter (from http://projects.spring.io/spring-boot/)
-- Spring Boot Web Starter (from http://projects.spring.io/spring-boot/)
+- Spring Boot Logging Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-logging)
+- Spring Boot Security Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-security)
+- Spring Boot Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter)
+- Spring Boot Test (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-test)
+- Spring Boot Test Auto-Configure (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-test-autoconfigure)
+- Spring Boot Test Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test)
+- Spring Boot Tomcat Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-tomcat)
+- Spring Boot Validation Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-validation)
+- Spring Boot Validation Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-validation)
+- Spring Boot Web Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-web)
+- Spring Boot Web Starter (from https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-web)
 - Spring Commons Logging Bridge (from https://github.com/spring-projects/spring-framework)
 - Spring Context (from https://github.com/spring-projects/spring-framework)
 - Spring Core (from https://github.com/spring-projects/spring-framework)
-- Spring Data Core (from )
+- Spring Data Core (from https://repo1.maven.org/maven2/org/springframework/data/spring-data-commons)
 - Spring Expression Language (SpEL) (from https://github.com/spring-projects/spring-framework)
 - Spring JMS (from https://github.com/spring-projects/spring-framework)
 - Spring Messaging (from https://github.com/spring-projects/spring-framework)
-- Spring Plugin - Core (from )
-- Spring Plugin - Metadata Extension (from )
+- Spring Plugin - Metadata Extension (from https://repo1.maven.org/maven2/org/springframework/plugin/spring-plugin-metadata)
+- Spring Plugin Core (from https://repo1.maven.org/maven2/org/springframework/plugin/spring-plugin-core)
 - Spring TestContext Framework (from https://github.com/spring-projects/spring-framework)
 - Spring Transaction (from https://github.com/spring-projects/spring-framework)
 - Spring Web (from https://github.com/spring-projects/spring-framework)
 - Spring Web MVC (from https://github.com/spring-projects/spring-framework)
-- StAX (from http://stax.codehaus.org/)
-- StAX API (from http://stax.codehaus.org/)
+- Spring WebFlux (from https://github.com/spring-projects/spring-framework)
 - T-Digest (from https://github.com/tdunning/t-digest)
-- Undertow Core (from )
-- Undertow Core (from )
-- Undertow Servlet (from )
-- Undertow WebSockets JSR356 implementations (from )
+- Undertow Core (from https://repo1.maven.org/maven2/io/undertow/undertow-core)
+- Undertow Core (from https://repo1.maven.org/maven2/io/undertow/undertow-core)
+- Undertow Servlet (from https://repo1.maven.org/maven2/io/undertow/undertow-servlet)
+- Undertow Servlet (from https://repo1.maven.org/maven2/io/undertow/undertow-servlet)
+- Undertow WebSockets JSR356 implementations (from https://repo1.maven.org/maven2/io/undertow/undertow-websockets-jsr)
+- Undertow WebSockets JSR356 implementations (from https://repo1.maven.org/maven2/io/undertow/undertow-websockets-jsr)
+- Vavr (from http://vavr.io)
+- Vavr Match (from http://vavr.io)
+- WildFly Client Configuration (from )
 - Woodstox (from https://github.com/FasterXML/woodstox)
 - XNIO API (from http://www.jboss.org/xnio)
-- XNIO NIO Implementation (from )
+- XNIO API (from http://www.jboss.org/xnio)
+- XNIO NIO Implementation (from https://repo1.maven.org/maven2/org/jboss/xnio/xnio-nio)
+- XNIO NIO Implementation (from https://repo1.maven.org/maven2/org/jboss/xnio/xnio-nio)
+- Zipkin Core Library (from https://repo1.maven.org/maven2/io/zipkin/zipkin2/zipkin)
+- Zipkin Reporter Brave (from https://repo1.maven.org/maven2/io/zipkin/reporter2/zipkin-reporter-brave)
+- Zipkin Reporter: Core (from https://repo1.maven.org/maven2/io/zipkin/reporter2/zipkin-reporter)
 - aalto-xml (from )
 - aggs-matrix-stats (from https://github.com/elastic/elasticsearch)
-- aws-ssm-java-caching-client (from https://github.com/awslabs/aws-ssm-java-caching-client)
-- cli (from https://github.com/elastic/elasticsearch)
-- com.google.api.grpc:grpc-google-cloud-pubsub-v1 (from https://github.com/googleapis/googleapis)
-- com.google.api.grpc:proto-google-cloud-logging-v2 (from https://github.com/googleapis/googleapis)
-- com.google.api.grpc:proto-google-cloud-pubsub-v1 (from https://github.com/googleapis/googleapis)
-- com.google.api.grpc:proto-google-common-protos (from https://github.com/googleapis/googleapis)
-- com.google.api.grpc:proto-google-iam-v1 (from https://github.com/googleapis/googleapis)
+- asm (from http://asm.ow2.io/)
 - compiler (from http://github.com/spullara/mustache.java)
-- datastore-v1-proto-client (from )
+- core (from https://github.com/elastic/elasticsearch)
+- datastore-v1-proto-client (from https://repo1.maven.org/maven2/com/google/cloud/datastore/datastore-v1-proto-client)
+- elasticsearch-cli (from https://github.com/elastic/elasticsearch)
 - elasticsearch-core (from https://github.com/elastic/elasticsearch)
-- error-prone annotations (from )
-- error-prone annotations (from )
+- elasticsearch-secure-sm (from https://github.com/elastic/elasticsearch)
+- elasticsearch-x-content (from https://github.com/elastic/elasticsearch)
+- error-prone annotations (from https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations)
+- error-prone annotations (from https://repo1.maven.org/maven2/com/google/errorprone/error_prone_annotations)
+- grpc-google-cloud-pubsub-v1 (from https://repo1.maven.org/maven2/com/google/api/grpc/grpc-google-cloud-pubsub-v1)
 - io.grpc:grpc-alts (from https://github.com/grpc/grpc-java)
 - io.grpc:grpc-api (from https://github.com/grpc/grpc-java)
 - io.grpc:grpc-auth (from https://github.com/grpc/grpc-java)
 - io.grpc:grpc-context (from https://github.com/grpc/grpc-java)
+- io.grpc:grpc-context (from https://github.com/grpc/grpc-java)
+- io.grpc:grpc-core (from https://github.com/grpc/grpc-java)
 - io.grpc:grpc-core (from https://github.com/grpc/grpc-java)
 - io.grpc:grpc-grpclb (from https://github.com/grpc/grpc-java)
 - io.grpc:grpc-netty-shaded (from https://github.com/grpc/grpc-java)
+- io.grpc:grpc-netty-shaded (from https://github.com/grpc/grpc-java)
 - io.grpc:grpc-protobuf (from https://github.com/grpc/grpc-java)
+- io.grpc:grpc-protobuf (from https://github.com/grpc/grpc-java)
+- io.grpc:grpc-protobuf-lite (from https://github.com/grpc/grpc-java)
 - io.grpc:grpc-protobuf-lite (from https://github.com/grpc/grpc-java)
 - io.grpc:grpc-stub (from https://github.com/grpc/grpc-java)
+- io.grpc:grpc-stub (from https://github.com/grpc/grpc-java)
 - ion-java (from https://github.com/amznlabs/ion-java/)
 - ion-java (from https://github.com/amznlabs/ion-java/)
 - jackson-databind (from http://github.com/FasterXML/jackson)
@@ -321,31 +313,56 @@ The following software have components provided under the terms of this license:
 - javax.inject (from http://code.google.com/p/atinject/)
 - jose4j (from https://bitbucket.org/b_c/jose4j/)
 - lang-mustache (from https://github.com/elastic/elasticsearch)
-- lettuce (from http://github.com/mp911de/lettuce/wiki)
+- lettuce (from https://github.com/lettuce-io/lettuce-core/wiki)
 - micrometer-core (from https://github.com/micrometer-metrics/micrometer)
 - micrometer-registry-azure-monitor (from https://github.com/micrometer-metrics/micrometer)
+- mockito-core (from http://mockito.org)
+- nio-multipart-parser (from )
+- nio-stream-storage (from https://github.com/synchronoss/nio-stream-storage)
+- okhttp-urlconnection (from https://github.com/square/okhttp)
+- okhttp-urlconnection (from https://github.com/square/okhttp)
+- okio (from https://github.com/square/okio/)
+- okio (from https://github.com/square/okio/)
 - org.apiguardian:apiguardian-api (from https://github.com/apiguardian-team/apiguardian)
+- org.conscrypt:conscrypt-openjdk-uber (from https://conscrypt.org/)
 - org.opentest4j:opentest4j (from https://github.com/ota4j-team/opentest4j)
 - org.xmlunit:xmlunit-core (from http://www.xmlunit.org/)
 - parent-join (from https://github.com/elastic/elasticsearch)
-- powermock-api-support (from )
-- powermock-core (from http://www.powermock.org)
-- powermock-module-junit4 (from http://www.powermock.org)
-- powermock-module-junit4-common (from )
-- powermock-reflect (from )
-- proto-google-cloud-datastore-v1 (from https://github.com/googleapis/api-client-staging)
-- proton-j (from )
+- perfmark:perfmark-api (from https://github.com/perfmark/perfmark)
+- project ':json-path' (from https://github.com/jayway/JsonPath)
+- proto-google-cloud-datastore-v1 (from https://github.com/googleapis/java-datastore/proto-google-cloud-datastore-v1)
+- proto-google-cloud-iamcredentials-v1 (from https://github.com/googleapis/java-iamcredentials/proto-google-cloud-iamcredentials-v1)
+- proto-google-cloud-logging-v2 (from https://repo1.maven.org/maven2/com/google/api/grpc/proto-google-cloud-logging-v2)
+- proto-google-cloud-pubsub-v1 (from https://github.com/googleapis/java-pubsub/proto-google-cloud-pubsub-v1)
+- proto-google-common-protos (from https://github.com/googleapis/java-iam/proto-google-common-protos)
+- proto-google-common-protos (from https://github.com/googleapis/java-iam/proto-google-common-protos)
+- proto-google-iam-v1 (from https://github.com/googleapis/java-iam/proto-google-iam-v1)
 - rank-eval (from https://github.com/elastic/elasticsearch)
+- resilience4j (from https://resilience4j.readme.io)
+- resilience4j (from https://resilience4j.readme.io)
+- resilience4j (from https://resilience4j.readme.io)
+- resilience4j (from https://resilience4j.readme.io)
+- resilience4j (from https://resilience4j.readme.io)
+- resilience4j (from https://resilience4j.readme.io)
+- resilience4j (from https://resilience4j.readme.io)
+- resilience4j (from https://resilience4j.readme.io)
 - rest (from https://github.com/elastic/elasticsearch)
 - rest-high-level (from https://github.com/elastic/elasticsearch)
 - rxjava (from https://github.com/ReactiveX/RxJava)
-- secure-sm (from https://github.com/elastic/elasticsearch)
+- spring-boot-dependencies (from https://spring.io/projects/spring-boot)
+- spring-boot-starter-log4j2 (from https://spring.io/projects/spring-boot)
+- spring-boot-starter-reactor-netty (from https://spring.io/projects/spring-boot)
+- spring-boot-starter-undertow (from https://spring.io/projects/spring-boot)
+- spring-boot-starter-undertow (from https://spring.io/projects/spring-boot)
+- spring-boot-starter-webflux (from https://spring.io/projects/spring-boot)
+- spring-security-config (from http://spring.io/spring-security)
 - spring-security-config (from http://spring.io/spring-security)
 - spring-security-core (from http://spring.io/spring-security)
 - spring-security-oauth2-core (from http://spring.io/spring-security)
 - spring-security-oauth2-jose (from http://spring.io/spring-security)
 - spring-security-oauth2-resource-server (from http://spring.io/spring-security)
 - spring-security-web (from http://spring.io/spring-security)
+- spring-security-web (from http://spring.io/spring-security)
 - springfox-core (from https://github.com/springfox/springfox)
 - springfox-schema (from https://github.com/springfox/springfox)
 - springfox-spi (from https://github.com/springfox/springfox)
@@ -353,63 +370,59 @@ The following software have components provided under the terms of this license:
 - springfox-swagger-common (from https://github.com/springfox/springfox)
 - springfox-swagger-ui (from https://github.com/springfox/springfox)
 - springfox-swagger2 (from https://github.com/springfox/springfox)
-- swagger-annotations (from )
-- swagger-jaxrs (from )
-- swagger-models (from )
+- swagger-annotations (from https://repo1.maven.org/maven2/io/swagger/swagger-annotations)
+- swagger-jaxrs (from https://repo1.maven.org/maven2/io/swagger/swagger-jaxrs)
+- swagger-models (from https://repo1.maven.org/maven2/io/swagger/swagger-models)
 - tomcat-embed-core (from http://tomcat.apache.org/)
-- tomcat-embed-el (from http://tomcat.apache.org/)
-- tomcat-embed-websocket (from http://tomcat.apache.org/)
-- x-content (from https://github.com/elastic/elasticsearch)
+- tomcat-embed-el (from https://tomcat.apache.org/)
+- tomcat-embed-websocket (from https://tomcat.apache.org/)
+- wildfly-common (from https://repo1.maven.org/maven2/org/wildfly/common/wildfly-common)
 
 ========================================================================
 BSD-2-Clause
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- API Common (from https://github.com/googleapis)
-- GAX (Google Api eXtensions) (from https://github.com/googleapis)
-- GAX (Google Api eXtensions) (from https://github.com/googleapis)
-- GAX (Google Api eXtensions) (from https://github.com/googleapis)
-- Hamcrest Core (from http://hamcrest.org/)
-- Lucene Common Analyzers (from )
-- StAX (from http://stax.codehaus.org/)
+- API Common (from https://github.com/googleapis/api-common-java)
+- GAX (Google Api eXtensions) for Java (from https://github.com/googleapis/gax-java)
+- GAX (Google Api eXtensions) for Java (from https://github.com/googleapis/gax-java)
+- GAX (Google Api eXtensions) for Java (from https://github.com/googleapis/gax-java)
+- Lucene Common Analyzers (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-analyzers-common)
+- Lucene Core (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-core)
+- Reflections (from http://github.com/ronmamo/reflections)
 - Stax2 API (from http://github.com/FasterXML/stax2-api)
+- ThreeTen backport (from https://www.threeten.org/threetenbp)
 
 ========================================================================
 BSD-3-Clause
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- API Common (from https://github.com/googleapis)
-- ASM Core (from )
-- Apache Commons Codec (from http://commons.apache.org/proper/commons-codec/)
-- GAX (Google Api eXtensions) (from https://github.com/googleapis)
-- GAX (Google Api eXtensions) (from https://github.com/googleapis)
-- GAX (Google Api eXtensions) (from https://github.com/googleapis)
-- Google APIs Client Library for Java (from )
-- Google Auth Library for Java - Credentials (from )
-- Google Auth Library for Java - OAuth2 HTTP (from )
-- Hamcrest library (from )
-- JavaBeans Activation Framework API jar (from )
-- Lucene Common Analyzers (from )
-- Lucene Core (from )
-- Lucene Suggest (from )
-- Microsoft Application Insights Java SDK Core (from https://github.com/Microsoft/ApplicationInsights-Java)
+- API Common (from https://github.com/googleapis/api-common-java)
+- Apache Commons Codec (from https://commons.apache.org/proper/commons-codec/)
+- GAX (Google Api eXtensions) for Java (from https://github.com/googleapis/gax-java)
+- GAX (Google Api eXtensions) for Java (from https://github.com/googleapis/gax-java)
+- GAX (Google Api eXtensions) for Java (from https://github.com/googleapis/gax-java)
+- Google APIs Client Library for Java (from https://repo1.maven.org/maven2/com/google/api-client/google-api-client)
+- Google Auth Library for Java - Credentials (from https://repo1.maven.org/maven2/com/google/auth/google-auth-library-credentials)
+- Google Auth Library for Java - OAuth2 HTTP (from https://repo1.maven.org/maven2/com/google/auth/google-auth-library-oauth2-http)
+- Lucene Common Analyzers (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-analyzers-common)
+- Lucene Core (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-core)
+- Lucene Suggest (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-suggest)
 - Microsoft Application Insights Java SDK Spring Boot starter (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Java SDK Web Module (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Log4j 2 Appender (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Mockito (from http://www.mockito.org)
-- NanoHttpd-Core (from )
-- Netty/Codec/HTTP (from )
-- Netty/Codec/HTTP (from )
-- Protocol Buffer Java API (from https://developers.google.com/protocol-buffers/)
-- Protocol Buffers [Util] (from )
+- Netty/Codec/HTTP (from https://repo1.maven.org/maven2/io/netty/netty-codec-http)
+- Netty/Codec/HTTP (from https://repo1.maven.org/maven2/io/netty/netty-codec-http)
+- Protocol Buffers [Core] (from https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java)
+- Protocol Buffers [Core] (from https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java)
+- Protocol Buffers [Util] (from https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java-util)
 - Reflections (from http://github.com/ronmamo/reflections)
 - SnakeYAML (from http://www.snakeyaml.org)
 - Spring Core (from https://github.com/spring-projects/spring-framework)
-- Stax2 API (from http://github.com/FasterXML/stax2-api)
 - ThreeTen backport (from https://www.threeten.org/threetenbp)
-- jakarta.xml.bind-api (from )
+- asm (from http://asm.ow2.io/)
 
 ========================================================================
 CC-BY-2.5
@@ -424,7 +437,6 @@ CC-BY-4.0
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- Microsoft Application Insights Java SDK Core (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Java SDK Spring Boot starter (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Java SDK Web Module (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Log4j 2 Appender (from https://github.com/Microsoft/ApplicationInsights-Java)
@@ -434,9 +446,6 @@ CC0-1.0
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- XNIO API (from http://www.jboss.org/xnio)
-- XNIO NIO Implementation (from )
-- reactive-streams (from http://www.reactive-streams.org/)
 - reactive-streams (from http://www.reactive-streams.org/)
 
 ========================================================================
@@ -444,25 +453,26 @@ CDDL-1.0
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- Common Annotations 1.2 API (from )
+- JAXB Reference Implementation (from http://jaxb.java.net/)
 - JavaBeans Activation Framework API jar (from )
-- Old JAXB Core (from )
-- Old JAXB Runtime (from )
-- javax.annotation-api (from http://jcp.org/en/jsr/detail?id=250)
+- Old JAXB Core (from https://eclipse-ee4j.github.io/jaxb-ri/)
 
 ========================================================================
 CDDL-1.1
 ========================================================================
 The following software have components provided under the terms of this license:
 
+- Common Annotations 1.2 API (from )
 - Expression Language 3.0 (from http://uel.java.net)
-- Java Architecture For XML Binding (from )
-- Java Architecture For XML Binding (from )
+- Java Architecture for XML Binding (from http://jaxb.java.net/)
+- Java Architecture for XML Binding (from http://jaxb.java.net/)
+- Java Servlet 4.0 API (from )
 - Java Servlet API (from http://servlet-spec.java.net)
-- Java(TM) API for WebSocket (from )
+- Java(TM) API for WebSocket (from https://repo1.maven.org/maven2/org/jboss/spec/javax/websocket/jboss-websocket-api_1.1_spec)
 - JavaBeans Activation Framework (from )
 - JavaBeans(TM) Activation Framework (from http://java.sun.com/javase/technologies/desktop/javabeans/jaf/index.jsp)
-- JavaMail API (from )
+- JavaMail API (from https://repo1.maven.org/maven2/com/sun/mail/javax.mail)
+- javax.annotation-api (from http://jcp.org/en/jsr/detail?id=250)
 - tomcat-embed-core (from http://tomcat.apache.org/)
 
 ========================================================================
@@ -472,43 +482,57 @@ The following software have components provided under the terms of this license:
 
 - JUnit (from http://junit.org)
 
+========================================================================
+DOC
+========================================================================
+The following software have components provided under the terms of this license:
+
+- Lucene Core (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-core)
+- Woodstox (from https://github.com/FasterXML/woodstox)
+
 ========================================================================
 EPL-1.0
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- Expression Language 3.0 (from https://projects.eclipse.org/projects/ee4j.el)
+- AspectJ Weaver (from https://www.eclipse.org/aspectj/)
+- Common Annotations 1.3 API (from )
 - JUnit Jupiter (Aggregator) (from https://junit.org/junit5/)
+- JUnit Jupiter API (from https://junit.org/junit5/)
+- JUnit Jupiter Engine (from https://junit.org/junit5/)
+- JUnit Jupiter Params (from https://junit.org/junit5/)
+- JUnit Platform Commons (from https://junit.org/junit5/)
+- JUnit Platform Engine API (from https://junit.org/junit5/)
+- Jakarta Expression Language Implementation (from https://projects.eclipse.org/projects/ee4j.el)
+- Java Servlet 4.0 API (from )
 - Java Servlet API (from https://projects.eclipse.org/projects/ee4j.servlet)
-- Logback Classic Module (from )
-- Logback Contrib :: JSON :: Classic (from )
-- Logback Contrib :: JSON :: Core (from )
-- Logback Contrib :: Jackson (from )
-- Logback Core Module (from )
-- Microsoft Application Insights Java SDK Core (from https://github.com/Microsoft/ApplicationInsights-Java)
+- Java(TM) API for WebSocket (from https://repo1.maven.org/maven2/org/jboss/spec/javax/websocket/jboss-websocket-api_1.1_spec)
+- Logback Classic Module (from http://logback.qos.ch)
+- Logback Contrib :: JSON :: Classic (from https://repo1.maven.org/maven2/ch/qos/logback/contrib/logback-json-classic)
+- Logback Contrib :: JSON :: Core (from https://repo1.maven.org/maven2/ch/qos/logback/contrib/logback-json-core)
+- Logback Contrib :: Jackson (from https://repo1.maven.org/maven2/ch/qos/logback/contrib/logback-jackson)
+- Logback Core Module (from http://logback.qos.ch)
 - Microsoft Application Insights Java SDK Spring Boot starter (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Java SDK Web Module (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Log4j 2 Appender (from https://github.com/Microsoft/ApplicationInsights-Java)
 - SnakeYAML (from http://www.snakeyaml.org)
-- org.junit.jupiter:junit-jupiter-api (from http://junit.org/junit5/)
-- org.junit.jupiter:junit-jupiter-engine (from http://junit.org/junit5/)
-- org.junit.jupiter:junit-jupiter-params (from http://junit.org/junit5/)
-- org.junit.platform:junit-platform-commons (from http://junit.org/junit5/)
-- org.junit.platform:junit-platform-engine (from http://junit.org/junit5/)
 
 ========================================================================
 EPL-2.0
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- Expression Language 3.0 (from https://projects.eclipse.org/projects/ee4j.el)
+- Common Annotations 1.3 API (from )
 - JUnit Jupiter (Aggregator) (from https://junit.org/junit5/)
+- JUnit Jupiter API (from https://junit.org/junit5/)
+- JUnit Jupiter Engine (from https://junit.org/junit5/)
+- JUnit Jupiter Params (from https://junit.org/junit5/)
+- JUnit Platform Commons (from https://junit.org/junit5/)
+- JUnit Platform Engine API (from https://junit.org/junit5/)
+- Jakarta Expression Language Implementation (from https://projects.eclipse.org/projects/ee4j.el)
+- Java Servlet 4.0 API (from )
 - Java Servlet API (from https://projects.eclipse.org/projects/ee4j.servlet)
-- org.junit.jupiter:junit-jupiter-api (from http://junit.org/junit5/)
-- org.junit.jupiter:junit-jupiter-engine (from http://junit.org/junit5/)
-- org.junit.jupiter:junit-jupiter-params (from http://junit.org/junit5/)
-- org.junit.platform:junit-platform-commons (from http://junit.org/junit5/)
-- org.junit.platform:junit-platform-engine (from http://junit.org/junit5/)
+- Java(TM) API for WebSocket (from https://repo1.maven.org/maven2/org/jboss/spec/javax/websocket/jboss-websocket-api_1.1_spec)
 
 ========================================================================
 GPL-2.0-only
@@ -517,15 +541,14 @@ The following software have components provided under the terms of this license:
 
 - Common Annotations 1.2 API (from )
 - Expression Language 3.0 (from http://uel.java.net)
-- Java Architecture For XML Binding (from )
-- Java Architecture For XML Binding (from )
+- JAXB Reference Implementation (from http://jaxb.java.net/)
+- Java Architecture for XML Binding (from http://jaxb.java.net/)
+- Java Architecture for XML Binding (from http://jaxb.java.net/)
+- Java Servlet 4.0 API (from )
 - Java Servlet API (from http://servlet-spec.java.net)
-- Java(TM) API for WebSocket (from )
+- Java(TM) API for WebSocket (from https://repo1.maven.org/maven2/org/jboss/spec/javax/websocket/jboss-websocket-api_1.1_spec)
 - JavaBeans Activation Framework (from )
-- JavaBeans Activation Framework API jar (from )
-- JavaMail API (from )
-- Old JAXB Core (from )
-- Old JAXB Runtime (from )
+- Old JAXB Core (from https://eclipse-ee4j.github.io/jaxb-ri/)
 - javax.annotation-api (from http://jcp.org/en/jsr/detail?id=250)
 - tomcat-embed-core (from http://tomcat.apache.org/)
 
@@ -542,18 +565,20 @@ GPL-2.0-with-classpath-exception
 The following software have components provided under the terms of this license:
 
 - Checker Qual (from https://checkerframework.org)
+- Common Annotations 1.3 API (from )
 - Expression Language 3.0 (from http://uel.java.net)
-- Expression Language 3.0 (from https://projects.eclipse.org/projects/ee4j.el)
-- Java Architecture For XML Binding (from )
-- Java Architecture For XML Binding (from )
-- Java Servlet API (from https://projects.eclipse.org/projects/ee4j.servlet)
+- JAXB Reference Implementation (from http://jaxb.java.net/)
+- Jakarta Expression Language Implementation (from https://projects.eclipse.org/projects/ee4j.el)
+- Java Architecture for XML Binding (from http://jaxb.java.net/)
+- Java Architecture for XML Binding (from http://jaxb.java.net/)
+- Java Servlet 4.0 API (from )
+- Java Servlet 4.0 API (from )
 - Java Servlet API (from http://servlet-spec.java.net)
-- Java(TM) API for WebSocket (from )
+- Java Servlet API (from https://projects.eclipse.org/projects/ee4j.servlet)
+- Java(TM) API for WebSocket (from https://repo1.maven.org/maven2/org/jboss/spec/javax/websocket/jboss-websocket-api_1.1_spec)
+- Java(TM) API for WebSocket (from https://repo1.maven.org/maven2/org/jboss/spec/javax/websocket/jboss-websocket-api_1.1_spec)
 - JavaBeans Activation Framework (from )
-- JavaBeans Activation Framework API jar (from )
-- JavaMail API (from )
-- Old JAXB Core (from )
-- Old JAXB Runtime (from )
+- Old JAXB Core (from https://eclipse-ee4j.github.io/jaxb-ri/)
 - javax.annotation-api (from http://jcp.org/en/jsr/detail?id=250)
 - tomcat-embed-core (from http://tomcat.apache.org/)
 
@@ -562,13 +587,23 @@ GPL-3.0-only
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- Expression Language 3.0 (from https://projects.eclipse.org/projects/ee4j.el)
+- Common Annotations 1.3 API (from )
+- JAXB Reference Implementation (from http://jaxb.java.net/)
+- Jakarta Expression Language Implementation (from https://projects.eclipse.org/projects/ee4j.el)
+- Java Servlet 4.0 API (from )
+- Java Servlet 4.0 API (from )
 - Java Servlet API (from https://projects.eclipse.org/projects/ee4j.servlet)
-- Java(TM) API for WebSocket (from )
-- Old JAXB Core (from )
-- Old JAXB Runtime (from )
+- Java(TM) API for WebSocket (from https://repo1.maven.org/maven2/org/jboss/spec/javax/websocket/jboss-websocket-api_1.1_spec)
+- Old JAXB Core (from https://eclipse-ee4j.github.io/jaxb-ri/)
 - Project Lombok (from https://projectlombok.org)
-- SnakeYAML (from http://www.snakeyaml.org)
+
+========================================================================
+ImageMagick
+========================================================================
+The following software have components provided under the terms of this license:
+
+- Stax2 API (from http://github.com/FasterXML/stax2-api)
+- Woodstox (from https://github.com/FasterXML/woodstox)
 
 ========================================================================
 JSON
@@ -582,28 +617,27 @@ LGPL-2.1-only
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- Elastic JNA Distribution (from https://github.com/java-native-access/jna)
+- Elastic JNA Distribution (from https://github.com/elastic/jna-build)
 - Java Native Access (from https://github.com/java-native-access/jna)
 - Java Native Access Platform (from https://github.com/java-native-access/jna)
 - Javassist (from http://www.javassist.org/)
 - Javassist (from http://www.javassist.org/)
-- Logback Classic Module (from )
-- Logback Contrib :: JSON :: Classic (from )
-- Logback Contrib :: JSON :: Core (from )
-- Logback Contrib :: Jackson (from )
-- Logback Core Module (from )
-- Microsoft Application Insights Java SDK Core (from https://github.com/Microsoft/ApplicationInsights-Java)
+- Logback Classic Module (from http://logback.qos.ch)
+- Logback Contrib :: JSON :: Classic (from https://repo1.maven.org/maven2/ch/qos/logback/contrib/logback-json-classic)
+- Logback Contrib :: JSON :: Core (from https://repo1.maven.org/maven2/ch/qos/logback/contrib/logback-json-core)
+- Logback Contrib :: Jackson (from https://repo1.maven.org/maven2/ch/qos/logback/contrib/logback-jackson)
+- Logback Core Module (from http://logback.qos.ch)
 - Microsoft Application Insights Java SDK Spring Boot starter (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Java SDK Web Module (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Log4j 2 Appender (from https://github.com/Microsoft/ApplicationInsights-Java)
-- XNIO API (from http://www.jboss.org/xnio)
 
 ========================================================================
 LGPL-2.1-or-later
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- Java Native Access Platform (from https://github.com/java-native-access/jna)
+- JBoss Threads (from https://repo1.maven.org/maven2/org/jboss/threads/jboss-threads)
+- Javassist (from http://www.javassist.org/)
 - Javassist (from http://www.javassist.org/)
 - SnakeYAML (from http://www.snakeyaml.org)
 
@@ -612,8 +646,8 @@ LGPL-3.0-only
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- Apache Log4j API (from )
-- Apache Log4j Core (from )
+- Apache Log4j API (from https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-api)
+- Apache Log4j Core (from https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-core)
 
 ========================================================================
 MIT
@@ -621,22 +655,20 @@ MIT
 The following software have components provided under the terms of this license:
 
 - AWS Java SDK for AWS Lambda (from https://aws.amazon.com/sdkforjava)
-- Animal Sniffer Annotations (from )
-- Azure AD Spring Security Integration Spring Boot Starter (from https://github.com/Microsoft/azure-spring-boot)
+- Animal Sniffer Annotations (from https://repo1.maven.org/maven2/org/codehaus/mojo/animal-sniffer-annotations)
+- Animal Sniffer Annotations (from https://repo1.maven.org/maven2/org/codehaus/mojo/animal-sniffer-annotations)
 - Azure Java Client Authentication Library for AutoRest (from https://github.com/Azure/autorest-clientruntime-for-java)
 - Azure Java Client Runtime for ARM (from https://github.com/Azure/autorest-clientruntime-for-java)
 - Azure Java Client Runtime for AutoRest (from https://github.com/Azure/autorest-clientruntime-for-java)
-- Azure Metrics Spring Boot Starter (from https://github.com/Microsoft/azure-spring-boot)
-- Azure Spring Boot AutoConfigure (from https://github.com/Microsoft/azure-spring-boot)
+- Azure Spring Boot AutoConfigure (from https://github.com/Azure/azure-sdk-for-java)
+- Checker Qual (from https://checkerframework.org)
 - Checker Qual (from https://checkerframework.org)
 - Checker Qual (from https://checkerframework.org)
 - Extensions on Apache Proton-J library (from https://github.com/Azure/qpid-proton-j-extensions)
-- JOpt Simple (from http://pholser.github.io/jopt-simple)
+- JOpt Simple (from http://pholser.github.com/jopt-simple)
 - JUL to SLF4J bridge (from http://www.slf4j.org)
 - Java Client Runtime for AutoRest (from https://github.com/Azure/autorest-clientruntime-for-java)
-- Java JWT (from http://www.jwt.io)
-- Java JWT (from http://www.jwt.io)
-- Lucene Core (from )
+- Lucene Core (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-core)
 - Microsoft Application Insights Java SDK Core (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Java SDK Spring Boot starter (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Java SDK Web Module (from https://github.com/Microsoft/ApplicationInsights-Java)
@@ -655,11 +687,10 @@ The following software have components provided under the terms of this license:
 - Microsoft Azure common module for Storage (from https://github.com/Azure/azure-sdk-for-java)
 - Microsoft Azure internal Avro module for Storage (from https://github.com/Azure/azure-sdk-for-java)
 - Mockito (from http://www.mockito.org)
-- Mockito (from http://mockito.org)
-- Netty/Codec/HTTP (from )
-- Netty/Codec/HTTP (from )
-- Netty/Common (from )
-- Netty/Common (from )
+- Netty/Codec/HTTP (from https://repo1.maven.org/maven2/io/netty/netty-codec-http)
+- Netty/Codec/HTTP (from https://repo1.maven.org/maven2/io/netty/netty-codec-http)
+- Netty/Common (from https://repo1.maven.org/maven2/io/netty/netty-common)
+- Netty/Common (from https://repo1.maven.org/maven2/io/netty/netty-common)
 - Project Lombok (from https://projectlombok.org)
 - SLF4J API Module (from http://www.slf4j.org)
 - Spongy Castle (from http://rtyley.github.io/spongycastle/)
@@ -667,6 +698,10 @@ The following software have components provided under the terms of this license:
 - adal4j (from https://github.com/AzureAD/azure-activedirectory-library-for-java)
 - azure-documentdb (from https://azure.microsoft.com/en-us/services/cosmos-db/)
 - documentdb-bulkexecutor (from http://azure.microsoft.com/en-us/services/documentdb/)
+- java jwt (from https://github.com/auth0/java-jwt)
+- java jwt (from https://github.com/auth0/java-jwt)
+- micrometer-core (from https://github.com/micrometer-metrics/micrometer)
+- mockito-core (from http://mockito.org)
 - mockito-junit-jupiter (from https://github.com/mockito/mockito)
 - msal4j (from https://github.com/AzureAD/microsoft-authentication-library-for-java)
 - msal4j-persistence-extension (from https://github.com/AzureAD/microsoft-authentication-extensions-for-java)
@@ -687,28 +722,23 @@ The following software have components provided under the terms of this license:
 
 - Javassist (from http://www.javassist.org/)
 - Javassist (from http://www.javassist.org/)
+- OkHttp (from https://repo1.maven.org/maven2/com/squareup/okhttp3/okhttp)
 
 ========================================================================
-PHP-3.01
+MS-RL
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- JavaBeans Activation Framework API jar (from )
-- jakarta.xml.bind-api (from )
+- Microsoft Application Insights Java SDK Core (from https://github.com/Microsoft/ApplicationInsights-Java)
 
 ========================================================================
 Public-Domain
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- HdrHistogram (from http://hdrhistogram.github.io/HdrHistogram/)
-- LatencyUtils (from http://latencyutils.github.io/LatencyUtils/)
-- Old JAXB Core (from )
-- Old JAXB Runtime (from )
+- JAXB Reference Implementation (from http://jaxb.java.net/)
+- Old JAXB Core (from https://eclipse-ee4j.github.io/jaxb-ri/)
 - Spongy Castle (from http://rtyley.github.io/spongycastle/)
-- XNIO API (from http://www.jboss.org/xnio)
-- XNIO NIO Implementation (from )
-- reactive-streams (from http://www.reactive-streams.org/)
 
 ========================================================================
 SPL-1.0
@@ -718,6 +748,13 @@ The following software have components provided under the terms of this license:
 - Checker Qual (from https://checkerframework.org)
 - Checker Qual (from https://checkerframework.org)
 
+========================================================================
+SunPro
+========================================================================
+The following software have components provided under the terms of this license:
+
+- Lucene Core (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-core)
+
 ========================================================================
 WTFPL
 ========================================================================
@@ -725,17 +762,23 @@ The following software have components provided under the terms of this license:
 
 - Reflections (from http://github.com/ronmamo/reflections)
 
+========================================================================
+X11
+========================================================================
+The following software have components provided under the terms of this license:
+
+- Lucene Core (from https://repo1.maven.org/maven2/org/apache/lucene/lucene-core)
+
 ========================================================================
 public-domain
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- AWS Java SDK :: SDK Core (from https://aws.amazon.com/sdkforjava)
-- Asynchronous Http Client (from )
-- Guava: Google Core Libraries for Java (from https://github.com/google/guava.git)
-- Guava: Google Core Libraries for Java (from https://github.com/google/guava.git)
+- Asynchronous Http Client (from https://repo1.maven.org/maven2/org/asynchttpclient/async-http-client)
+- Guava: Google Core Libraries for Java (from https://github.com/google/guava)
+- Guava: Google Core Libraries for Java (from https://github.com/google/guava)
 - HdrHistogram (from http://hdrhistogram.github.io/HdrHistogram/)
-- Joda-Time (from http://www.joda.org/joda-time/)
+- Joda-Time (from https://www.joda.org/joda-time/)
 - LatencyUtils (from http://latencyutils.github.io/LatencyUtils/)
 - Microsoft Application Insights Java SDK Core (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Azure SDK for EventGrid Management (from https://github.com/Azure/azure-sdk-for-java)
@@ -743,7 +786,6 @@ The following software have components provided under the terms of this license:
 - Microsoft Azure client library for Blob Storage (from https://github.com/Azure/azure-sdk-for-java)
 - Project Lombok (from https://projectlombok.org)
 - Spring Web (from https://github.com/spring-projects/spring-framework)
-- StAX API (from http://stax.codehaus.org/)
 - azure-documentdb (from https://azure.microsoft.com/en-us/services/cosmos-db/)
 - msal4j (from https://github.com/AzureAD/microsoft-authentication-library-for-java)
 - reactive-streams (from http://www.reactive-streams.org/)
@@ -753,17 +795,16 @@ unknown
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- Byte Buddy (without dependencies) (from )
-- Common Annotations 1.2 API (from )
+- Byte Buddy (without dependencies) (from https://repo1.maven.org/maven2/net/bytebuddy/byte-buddy)
+- Checker Qual (from https://checkerframework.org)
+- JSON in Java (from https://github.com/douglascrockford/JSON-java)
 - JUnit (from http://junit.org)
 - JUnit Jupiter (Aggregator) (from https://junit.org/junit5/)
-- JavaBeans Activation Framework API jar (from )
+- JUnit Jupiter API (from https://junit.org/junit5/)
+- JUnit Jupiter Engine (from https://junit.org/junit5/)
+- JUnit Jupiter Params (from https://junit.org/junit5/)
+- JUnit Platform Commons (from https://junit.org/junit5/)
+- JUnit Platform Engine API (from https://junit.org/junit5/)
 - Spongy Castle (from http://rtyley.github.io/spongycastle/)
-- jakarta.xml.bind-api (from )
-- org.junit.jupiter:junit-jupiter-api (from http://junit.org/junit5/)
-- org.junit.jupiter:junit-jupiter-engine (from http://junit.org/junit5/)
-- org.junit.jupiter:junit-jupiter-params (from http://junit.org/junit5/)
-- org.junit.platform:junit-platform-commons (from http://junit.org/junit5/)
-- org.junit.platform:junit-platform-engine (from http://junit.org/junit5/)
 
 
diff --git a/devops/azure/chart/helm-config.yaml b/devops/azure/chart/helm-config.yaml
index 9323d6f1afcf141b010c15d465491515ba8de25c..325ceab14ff42e7390ee5eba6e9982d33d5d6ec8 100644
--- a/devops/azure/chart/helm-config.yaml
+++ b/devops/azure/chart/helm-config.yaml
@@ -17,6 +17,8 @@ global:
 
   # Service(s) Replica Count
   replicaCount: 1
+  nodepool: services
+  isAutoscalingEnabled: false
 
 ################################################################################
 # Specify the Gitlab branch being used for image creation
@@ -26,3 +28,5 @@ image:
   repository: #{container-registry}#.azurecr.io
   branch: #{ENVIRONMENT_NAME}#
   tag: #{Build.SourceVersion}#
+
+istioDnsHost: #{ISTIO_DNS_HOST}#
\ No newline at end of file
diff --git a/devops/azure/chart/templates/authSB.yaml b/devops/azure/chart/templates/authSB.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..50e54fb1281dc4c6759c1d4327b16325ffbcb258
--- /dev/null
+++ b/devops/azure/chart/templates/authSB.yaml
@@ -0,0 +1,33 @@
+# Source: istio/templates/notification.yaml
+#  Copyright © Microsoft Corporation
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+apiVersion: security.istio.io/v1beta1
+kind: AuthorizationPolicy
+metadata:
+  name: notification-sb-jwt-authz
+  namespace: osdu
+spec:
+  selector:
+    matchLabels:
+      app: notification-sb
+  action: DENY
+  rules:
+    - from:
+        - source:
+            notRequestPrincipals: ["*"]
+      to:
+        - operation:
+            notPaths: ["/","*/swagger-resources","*/swagger",
+                       "/api/notification/v1/swagger-resources/*","*/swagger-ui.html","*/actuator/health"]
\ No newline at end of file
diff --git a/devops/azure/chart/templates/deployment.yaml b/devops/azure/chart/templates/deployment.yaml
index e34555ef94f284c34bad1677db94762323afb2e8..a6f9651b77df6cc74a70074ced49168103aaca52 100644
--- a/devops/azure/chart/templates/deployment.yaml
+++ b/devops/azure/chart/templates/deployment.yaml
@@ -28,6 +28,10 @@ spec:
         app: {{ .Chart.Name }}
         aadpodidbinding: osdu-identity
     spec:
+{{- if .Values.global.isAutoscalingEnabled }}
+      nodeSelector:
+        nodepool: {{ .Values.global.nodepool }}
+{{- end }}
       volumes:
         - name: azure-keyvault
           csi:
@@ -58,6 +62,8 @@ spec:
               value: /api/notification/v1
             - name: server_port
               value: "80"
+            - name: notification_spring_logging_level
+              value: INFO
             - name: KEYVAULT_URI
               valueFrom:
                 configMapKeyRef:
@@ -77,9 +83,27 @@ spec:
               value: osdu-db
             - name: entitlements_service_endpoint
               value: http://entitlements/api/entitlements/v2
+            - name: entitlements_service_api_key
+              value: "OBSOLETE"
             - name: registeration_service_endpoint
               value: http://register/api/register/v1
             - name: partition_service_endpoint
               value: http://partition/api/partition/v1
             - name: maxCacheSize
-              value:  "20"
\ No newline at end of file
+              value:  "20"
+            - name: max_concurrent_calls
+              value: "3"
+            - name: executor_n_threads
+              value: "32"
+            - name: max_lock_renew_duration_seconds
+              value: "2000"
+            - name: initial_subscription_manager_delay_seconds
+              value: "0"
+            - name: consecutive_subscription_manager_delay_seconds
+              value: "1800"
+            - name: service_bus_enabled
+              value: "false"
+            - name: event_grid_to_service_bus_enabled
+              value: "false"
+            - name: event_grid_enabled
+              value: "true"
\ No newline at end of file
diff --git a/devops/azure/chart/templates/deploymentSB.yaml b/devops/azure/chart/templates/deploymentSB.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e254ef27454ef8ef09ddec45304a26da3ba0e46f
--- /dev/null
+++ b/devops/azure/chart/templates/deploymentSB.yaml
@@ -0,0 +1,105 @@
+#  Copyright © Microsoft Corporation
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ .Release.Name }}-sb
+  namespace: osdu
+spec:
+  replicas: {{ .Values.global.replicaCount }}
+  selector:
+    matchLabels:
+      app: {{ .Chart.Name }}-sb
+  template:
+    metadata:
+      labels:
+        app: {{ .Chart.Name }}-sb
+        aadpodidbinding: osdu-identity
+    spec:
+      volumes:
+        - name: azure-keyvault
+          csi:
+            driver: secrets-store.csi.k8s.io
+            readOnly: true
+            volumeAttributes:
+              secretProviderClass: azure-keyvault
+      containers:
+        - name: {{ .Chart.Name }}-sb
+          image: {{ .Values.image.repository }}/{{ .Chart.Name }}-{{ .Values.image.branch }}:{{ .Values.image.tag | default .Chart.AppVersion }}
+          imagePullPolicy: Always
+          ports:
+            - containerPort: 81
+          readinessProbe:
+            httpGet:
+              path: /api/notification/v1/swagger-ui.html
+              port: 81
+          volumeMounts:
+            - name: azure-keyvault
+              mountPath: "/mnt/azure-keyvault"
+              readOnly: true
+          env:
+            - name: spring_application_name
+              value: notification-sb-azure
+            - name: LOG_PREFIX
+              value: "notification-sb"
+            - name: server.servlet.contextPath
+              value: /api/notification/v1
+            - name: server_port
+              value: "81"
+            - name: notification_spring_logging_level
+              value: INFO
+            - name: KEYVAULT_URI
+              valueFrom:
+                configMapKeyRef:
+                  name: osdu-svc-properties
+                  key: ENV_KEYVAULT
+            - name: aad_client_id
+              valueFrom:
+                secretKeyRef:
+                  name: active-directory
+                  key: application-appid
+            - name: appinsights_key
+              valueFrom:
+                secretKeyRef:
+                  name: central-logging
+                  key: appinsights
+            - name: cosmosdb_database
+              value: osdu-db
+            - name: entitlements_service_endpoint
+              value: http://entitlements/api/entitlements/v2
+            - name: entitlements_service_api_key
+              value: "OBSOLETE"
+            - name: registeration_service_endpoint
+              value: http://register/api/register/v1
+            - name: partition_service_endpoint
+              value: http://partition/api/partition/v1
+            - name: maxCacheSize
+              value:  "20"
+            - name: max_concurrent_calls
+              value: "3"
+            - name: executor_n_threads
+              value: "32"
+            - name: max_lock_renew_duration_seconds
+              value: "500"
+            - name: initial_subscription_manager_delay_seconds
+              value: "0"
+            - name: consecutive_subscription_manager_delay_seconds
+              value: "600"
+            - name: service_bus_enabled
+              value: "true"
+            - name: event_grid_to_service_bus_enabled
+              value: "false"
+            - name: event_grid_enabled
+              value: "false"
\ No newline at end of file
diff --git a/devops/azure/chart/templates/serviceSB.yaml b/devops/azure/chart/templates/serviceSB.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..616d3e28c07a0ef0695c940f903d61b0454ba25b
--- /dev/null
+++ b/devops/azure/chart/templates/serviceSB.yaml
@@ -0,0 +1,27 @@
+#  Copyright © Microsoft Corporation
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Chart.Name }}-sb
+  namespace: osdu
+spec:
+  type: ClusterIP
+  ports:
+    - protocol: TCP
+      port: 81
+      targetPort: 81
+  selector:
+    app: {{ .Chart.Name }}-sb
\ No newline at end of file
diff --git a/devops/azure/chart/templates/virtual-service.yaml b/devops/azure/chart/templates/virtual-service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8229d11265b27a3e60df969de6ee8d0b04315bc4
--- /dev/null
+++ b/devops/azure/chart/templates/virtual-service.yaml
@@ -0,0 +1,37 @@
+---
+# Source: /devops/azure/chart/templates/virtual-service.yaml
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+  name: {{ .Chart.Name }}
+  namespace: osdu
+spec:
+  hosts:
+  - "{{ .Values.istioDnsHost }}"
+  gateways:
+  - istio-gateway
+  http:  
+  - match:
+    - uri:
+        prefix: "/api/{{ .Chart.Name }}/v1"
+    route:
+    - destination:
+        host: {{ .Chart.Name }}
+        port:
+          number: 80
+    corsPolicy:
+      maxAge: "60m"
+      allowCredentials: true
+      allowHeaders:
+      - Authorization
+      - Data-Partition-Id
+      - Correlation-Id
+      - Content-Type
+      allowMethods:
+      - POST
+      - GET
+      - PUT
+      - PATCH
+      - DELETE
+      allowOrigins:
+      - prefix: "*" 
\ No newline at end of file
diff --git a/devops/azure/chart/values.yaml b/devops/azure/chart/values.yaml
index d503dd73deaa4d89c63c0bc034cac4354c4970b2..04027457beffc4da0c986211f30c669a348a291a 100644
--- a/devops/azure/chart/values.yaml
+++ b/devops/azure/chart/values.yaml
@@ -14,8 +14,12 @@
 
 global:
   replicaCount: 1
+  nodepool: services
+  isAutoscalingEnabled: false
 
 image:
   repository: community.opengroup.org:5555/osdu/platform/system/notification
   branch: master
-  tag: latest
\ No newline at end of file
+  tag: latest
+
+istioDnsHost: ""
\ No newline at end of file
diff --git a/devops/azure/development-pipeline.yml b/devops/azure/development-pipeline.yml
index 532aa11e8b05cca1b058dc0b25f68efca0f6c51d..eca20d42ae0d6678d4b2b21ff820a58657982be8 100644
--- a/devops/azure/development-pipeline.yml
+++ b/devops/azure/development-pipeline.yml
@@ -57,8 +57,8 @@ stages:
     parameters:
       mavenGoal: 'package'
       mavenPublishJUnitResults: true
-      serviceCoreMavenOptions: '-P notification-core --settings .mvn/community-maven.settings.xml'
-      mavenOptions: '-P notification-azure --settings .mvn/community-maven.settings.xml -Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
+      serviceCoreMavenOptions: '-pl notification-core --settings .mvn/community-maven.settings.xml -Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
+      mavenOptions: '-pl provider/notification-azure --settings .mvn/community-maven.settings.xml -Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
       copyFileContents: |
         pom.xml
         provider/notification-azure/maven/settings.xml
diff --git a/devops/azure/pipeline.yml b/devops/azure/pipeline.yml
index 13617a7552be024dd921f877b6d371190c2a6c8c..f5c86d139932a3f7c90e5aa8e632f67b81d3b2e2 100644
--- a/devops/azure/pipeline.yml
+++ b/devops/azure/pipeline.yml
@@ -57,8 +57,9 @@ stages:
     parameters:
       mavenGoal: 'package'
       mavenPublishJUnitResults: true
-      serviceCoreMavenOptions: '-P notification-core --settings .mvn/community-maven.settings.xml'
-      mavenOptions: '-P notification-azure --settings .mvn/community-maven.settings.xml -Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
+      serviceCoreMavenOptions: '-pl notification-core --settings .mvn/community-maven.settings.xml -Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
+      mavenOptions: '-pl provider/notification-azure --settings .mvn/community-maven.settings.xml -Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
+
       copyFileContents: |
         pom.xml
         provider/notification-azure/maven/settings.xml
diff --git a/devops/gcp/configmap/Chart.yaml b/devops/gcp/configmap/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..601fcf729aeb8cd65be3bc6aec5a08d15c4a8dc0
--- /dev/null
+++ b/devops/gcp/configmap/Chart.yaml
@@ -0,0 +1,24 @@
+apiVersion: v2
+name: gcp-notification-configmap
+description: A Helm chart for Kubernetes
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 0.1.0
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application. Versions are not expected to
+# follow Semantic Versioning. They should reflect the version the application is using.
+# It is recommended to use it with quotes.
+appVersion: "1.16.0"
diff --git a/devops/gcp/configmap/templates/notification-configmap.yaml b/devops/gcp/configmap/templates/notification-configmap.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1c1ce1b79705a62cb36a1ab3db469f0b7e2347fc
--- /dev/null
+++ b/devops/gcp/configmap/templates/notification-configmap.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  labels:
+    app: "{{ .Values.conf.app_name }}"
+  name: "{{ .Values.conf.configmap }}"
+  namespace: "{{ .Release.Namespace }}"
+data:
+  LOG_LEVEL: "{{ .Values.data.log_level }}"
+  APP_PROJECT: "{{ .Values.data.app_project }}"
+  APP_ENTITLEMENTS: "{{ .Values.data.app_entitlements }}"
+  APP_REGISTER: "{{ .Values.data.app_register }}"
+  APP_GOOGLEAUDIENCE: "{{ .Values.data.app_googleaudience }}"
+  PARTITION_API: "{{ .Values.data.partition_api }}"
+  GOOGLE_AUDIENCES: "{{ .Values.data.google_audiences }}"
diff --git a/devops/gcp/configmap/values.yaml b/devops/gcp/configmap/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..36510b00e6b14022d3a4b1daf3b376c700bb9752
--- /dev/null
+++ b/devops/gcp/configmap/values.yaml
@@ -0,0 +1,11 @@
+data:
+  log_level: "INFO"
+  app_project: ""
+  app_entitlements: "http://entitlements/api/entitlements/v2/"
+  app_register: "http://register/api/register/v1"
+  app_googleaudience: ""
+  partition_api: "http://partition/api/partition/v1/"
+  google_audiences: ""
+conf:
+  configmap: "notification-config"
+  app_name: "notification"
diff --git a/devops/gcp/deploy/Chart.yaml b/devops/gcp/deploy/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ef8338da0cf56eaadbf1aaee05d2a3fdcff24f1c
--- /dev/null
+++ b/devops/gcp/deploy/Chart.yaml
@@ -0,0 +1,24 @@
+apiVersion: v2
+name: gcp-notification-deploy
+description: A Helm chart for Kubernetes
+
+# A chart can be either an 'application' or a 'library' chart.
+#
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 0.1.0
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application. Versions are not expected to
+# follow Semantic Versioning. They should reflect the version the application is using.
+# It is recommended to use it with quotes.
+appVersion: "1.16.0"
diff --git a/devops/gcp/deploy/templates/deployment.yaml b/devops/gcp/deploy/templates/deployment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b3d3b4cc336c616f9d904da01f2a45dd99bf6105
--- /dev/null
+++ b/devops/gcp/deploy/templates/deployment.yaml
@@ -0,0 +1,38 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app: "{{ .Values.conf.app_name }}"
+  name: "{{ .Values.conf.app_name }}"
+  namespace: "{{ .Release.Namespace }}"
+spec:
+  selector:
+    matchLabels:
+      app: "{{ .Values.conf.app_name }}"
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: "{{ .Values.conf.app_name }}"
+      annotations:
+        rollme: {{ randAlphaNum 5 | quote }}
+    spec:
+      containers:
+        - name: "{{ .Values.conf.app_name }}"
+          image: "{{ .Values.data.image }}"
+          envFrom:
+          - configMapRef:
+              name: "{{ .Values.conf.configmap }}"
+          securityContext:
+            allowPrivilegeEscalation: false
+            runAsUser: 0
+          ports:
+            - containerPort: 8080
+          resources:
+            requests:
+              cpu: "{{ .Values.data.requests_cpu }}"
+              memory: "{{ .Values.data.requests_memory }}"
+            limits:
+              cpu: "{{ .Values.data.limits_cpu }}"
+              memory: "{{ .Values.data.limits_memory }}"
+      serviceAccountName: "{{ .Values.data.serviceAccountName }}"
diff --git a/devops/gcp/deploy/templates/service.yaml b/devops/gcp/deploy/templates/service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d92e1b6fb4b7890067aaf4d6b46c8310162d4d6e
--- /dev/null
+++ b/devops/gcp/deploy/templates/service.yaml
@@ -0,0 +1,18 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: "{{ .Values.conf.app_name }}"
+  annotations:
+    cloud.google.com/neg: '{"ingress": true}'
+  namespace: "{{ .Release.Namespace }}"
+  labels:
+    app: "{{ .Values.conf.app_name }}"
+    service: "{{ .Values.conf.app_name }}"
+spec:
+  ports:
+    - protocol: TCP
+      port: 80
+      targetPort: 8080
+      name: http
+  selector:
+    app: "{{ .Values.conf.app_name }}"
diff --git a/devops/gcp/deploy/templates/virtual-service.yaml b/devops/gcp/deploy/templates/virtual-service.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ba166b2c2e6511f89b1bd16d296944a32d656f24
--- /dev/null
+++ b/devops/gcp/deploy/templates/virtual-service.yaml
@@ -0,0 +1,19 @@
+apiVersion: networking.istio.io/v1alpha3
+kind: VirtualService
+metadata:
+  name: "{{ .Values.conf.app_name }}"
+  namespace: "{{ .Release.Namespace }}"
+spec:
+  hosts:
+    - "*"
+  gateways:
+    - service-gateway
+  http:
+    - match:
+        - uri:
+            prefix: "/api/notification"
+      route:
+        - destination:
+            port:
+              number: 80
+            host: "{{ .Values.conf.app_name }}.{{ .Release.Namespace }}.svc.cluster.local"
diff --git a/devops/gcp/deploy/values.yaml b/devops/gcp/deploy/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..85ec3f779968f9308d3b5435e3c4788ae3b20036
--- /dev/null
+++ b/devops/gcp/deploy/values.yaml
@@ -0,0 +1,11 @@
+data:
+  requests_cpu: "0.25"
+  requests_memory: "256M"
+  limits_cpu: "1"
+  limits_memory: "1G"
+  serviceAccountName: ""
+  image: ""
+
+conf:
+  configmap: "notification-config"
+  app_name: "notification"
diff --git a/docs/api/notification_openapi.yaml b/docs/api/notification_openapi.yaml
index e65325415809b7d5d4740c30e7d8eb53042c58da..f4ec41d72dd53d55d9b03d29cf4e579b6c5a98d8 100644
--- a/docs/api/notification_openapi.yaml
+++ b/docs/api/notification_openapi.yaml
@@ -12,6 +12,8 @@ info:
 tags:
   - name: pubsub-endpoint
     description: Pubsub Endpoint
+  - name: info
+    description: Version info endpoint
 paths:
   /push-handlers/records-changed:
     post:
@@ -45,6 +47,21 @@ paths:
       security:
         - JWT:
             - global
+  /info:
+    get:
+      tags:
+        - info
+      summary: "Version info"
+      description: "For deployment available public `/info` endpoint, \
+            \ which provides build and git related information."
+      operationId: "Version info"
+      produces:
+        - "application/json"
+      responses:
+        200:
+          description: "Version info."
+          schema:
+            $ref: "#/components/schemas/VersionInfo"
 servers:
   - url: https://evq.csp.osdu.com/api/notification/v1
     description: EVT
@@ -66,4 +83,44 @@ components:
           type: string
         statusCodeValue:
           type: integer
-          format: int32
\ No newline at end of file
+          format: int32
+    VersionInfo:
+      type: "object"
+      properties:
+        groupId:
+          type: "string"
+          description: "Maven artifact group ID."
+        actifactId:
+          type: "string"
+          description: "Maven artifact ID."
+        version:
+          type: "string"
+          description: "Maven artifact version"
+        buildTime:
+          type: "string"
+          description: "Maven artifact build time"
+        branch:
+          type: "string"
+          description: "Current git branch"
+        commitId:
+          type: "string"
+          description: "Latest commit hash"
+        commitMessage:
+          type: "string"
+          description: "Latest commit message"
+        connectedOuterServices:
+          type: "array"
+          description: "Connected outer services information"
+          items:
+            $ref: "#/components/schemas/ConnectedOuterService"
+      description: "Version info."
+    ConnectedOuterService:
+      type: "object"
+      properties:
+        name:
+          type: "string"
+          description: "Connected outer service name."
+        version:
+          type: "string"
+          description: "Connected outer service version."
+      description: "Connected outer service information."
\ No newline at end of file
diff --git a/docs/tutorial/DataNotification.md b/docs/tutorial/DataNotification.md
index 93cc3a0d6f184626e6eeafcc77e218ea08a17945..a590cc37baf27a67299eb82db132b8309ea56e40 100644
--- a/docs/tutorial/DataNotification.md
+++ b/docs/tutorial/DataNotification.md
@@ -11,6 +11,7 @@
     * [Delete a Subscription by ID](#delete-subscription)
     * [Handle notifications](#process-messages)
     * [Update secret for a Subscription](#update-subscription)
+* [Version info endpoint](#version-info-endpoint)
 * [Current Limitations](#limitation)
 
 ## Introduction <a name="introduction"></a>
@@ -600,6 +601,42 @@ curl --request PUT \
 
 [Back to Table of Contents](#TOC)
 
+## Version info endpoint
+For deployment available public `/info` endpoint, which provides build and git related information.
+#### Example response:
+```json
+{
+    "groupId": "org.opengroup.osdu",
+    "artifactId": "storage-gcp",
+    "version": "0.10.0-SNAPSHOT",
+    "buildTime": "2021-07-09T14:29:51.584Z",
+    "branch": "feature/GONRG-2681_Build_info",
+    "commitId": "7777",
+    "commitMessage": "Added copyright to version info properties file",
+    "connectedOuterServices": [
+      {
+        "name": "elasticSearch",
+        "version":"..."
+      },
+      {
+        "name": "postgresSql",
+        "version":"..."
+      },
+      {
+        "name": "redis",
+        "version":"..."
+      }
+    ]
+}
+```
+This endpoint takes information from files, generated by `spring-boot-maven-plugin`,
+`git-commit-id-plugin` plugins. Need to specify paths for generated files to matching
+properties:
+- `version.info.buildPropertiesPath`
+- `version.info.gitPropertiesPath`
+
+[Back to table of contents](#TOC)
+
 ## Current Limitations <a name="limitation"></a>
 - There is no filtering applied on messages (such as based on the kind etc.) at the moment in OSDU. All the messages will be pushed to consumers. 
 - Updates to existing records are notified as `create` event with attribute `recordUpdated` set to true.
diff --git a/notification-core/pom.xml b/notification-core/pom.xml
index 8ddbd8de557b76bf687e7f0d7dfe4bf67d779d83..b6f2e702fdcdb8a755d6e3890e08f7288063acb4 100644
--- a/notification-core/pom.xml
+++ b/notification-core/pom.xml
@@ -19,7 +19,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.opengroup.osdu</groupId>
     <artifactId>notification-core</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.12.0-SNAPSHOT</version>
     <name>notification-core</name>
     <description>Core module for the notification service</description>
     <packaging>jar</packaging>
@@ -27,7 +27,7 @@
     <parent>
 		<groupId>org.opengroup.osdu</groupId>
 		<artifactId>os-notification</artifactId>
-		<version>0.9.0-SNAPSHOT</version>
+		<version>0.12.0-SNAPSHOT</version>
 		<relativePath>../pom.xml</relativePath>
 	</parent>
 
@@ -36,6 +36,8 @@
         <maven.compiler.target>${java.version}</maven.compiler.target>
         <maven.compiler.source>${java.version}</maven.compiler.source>
         <springfox-version>2.7.0</springfox-version>
+        <netty.version>4.1.65.Final</netty.version>
+        <undertow.version>2.1.7.Final</undertow.version>
     </properties>
 
     <dependencies>
@@ -131,11 +133,6 @@
                 </exclusion>
             </exclusions>
         </dependency>
-        <dependency>
-            <groupId>io.undertow</groupId>
-            <artifactId>undertow-core</artifactId>
-            <version>2.0.27.Final</version>
-        </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-validation</artifactId>
@@ -215,6 +212,83 @@
             <artifactId>spring-test</artifactId>
             <scope>test</scope>
         </dependency>
+
+        <!-- overriding packages with known vulnerabilities -->
+        <!-- See: https://nvd.nist.gov/vuln/search/results?form_type=Advanced&results_type=overview&search_type=all&cpe_vendor=cpe%3A%2F%3Anetty&cpe_product=cpe%3A%2F%3Anetty%3Anetty&cpe_version=cpe%3A%2F%3Anetty%3Anetty%3A4.1.38-->
+        <!-- See: https://ossindex.sonatype.org/component/pkg:maven/com.google.oauth-client/google-oauth-client@1.30.1?utm_source=dependency-check&utm_medium=integration&utm_content=6.1.6-->
+        <!-- See: https://nvd.nist.gov/vuln/search/results?form_type=Advanced&results_type=overview&search_type=all&cpe_vendor=cpe%3A%2F%3Aredhat&cpe_product=cpe%3A%2F%3Aredhat%3Aundertow&cpe_version=cpe%3A%2F%3Aredhat%3Aundertow%3A2.0.23-->
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-transport</artifactId>
+            <version>${netty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-transport-native-unix-common</artifactId>
+            <version>${netty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-codec</artifactId>
+            <version>${netty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-buffer</artifactId>
+            <version>${netty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-common</artifactId>
+            <version>${netty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-resolver</artifactId>
+            <version>${netty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-handler</artifactId>
+            <version>${netty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-codec-http</artifactId>
+            <version>${netty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-codec-http2</artifactId>
+            <version>${netty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-transport-native-epoll</artifactId>
+            <version>${netty.version}</version>
+            <classifier>linux-x86_64</classifier>
+            <type>jar</type>
+        </dependency>
+        <dependency>
+            <groupId>com.google.oauth-client</groupId>
+            <artifactId>google-oauth-client</artifactId>
+            <version>1.31.5</version>
+        </dependency>
+        <dependency>
+            <groupId>io.undertow</groupId>
+            <artifactId>undertow-core</artifactId>
+            <version>${undertow.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.undertow</groupId>
+            <artifactId>undertow-servlet</artifactId>
+            <version>${undertow.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.undertow</groupId>
+            <artifactId>undertow-websockets-jsr</artifactId>
+            <version>${undertow.version}</version>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/notification-core/src/main/java/org/opengroup/osdu/notification/api/InfoApi.java b/notification-core/src/main/java/org/opengroup/osdu/notification/api/InfoApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..2df52563f2c31b62d4056eb8884eb78d42df0b7d
--- /dev/null
+++ b/notification-core/src/main/java/org/opengroup/osdu/notification/api/InfoApi.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.api;
+
+import java.io.IOException;
+import org.opengroup.osdu.core.common.info.VersionInfoBuilder;
+import org.opengroup.osdu.core.common.model.info.VersionInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping
+public class InfoApi {
+
+  @Autowired
+  private VersionInfoBuilder versionInfoBuilder;
+
+  @GetMapping(value = "/info", produces = MediaType.APPLICATION_JSON_VALUE)
+  public VersionInfo info() throws IOException {
+    return versionInfoBuilder.buildVersionInfo();
+  }
+}
\ No newline at end of file
diff --git a/notification-core/src/main/java/org/opengroup/osdu/notification/api/PubsubEndpoint.java b/notification-core/src/main/java/org/opengroup/osdu/notification/api/PubsubEndpoint.java
index d4407ed4382e596d3d6cf1e2d240ba8ab7857cef..33ea6281af557e5f028bd599e05f83779ccfe805 100644
--- a/notification-core/src/main/java/org/opengroup/osdu/notification/api/PubsubEndpoint.java
+++ b/notification-core/src/main/java/org/opengroup/osdu/notification/api/PubsubEndpoint.java
@@ -16,29 +16,13 @@
 
 package org.opengroup.osdu.notification.api;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.base.Strings;
-import com.google.gson.Gson;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonParser;
-import org.apache.http.HttpStatus;
-import org.opengroup.osdu.core.common.cryptographic.ISignatureService;
-import org.opengroup.osdu.core.common.http.HttpClient;
-import org.opengroup.osdu.core.common.http.HttpRequest;
 import org.opengroup.osdu.core.common.http.HttpResponse;
 import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
-import org.opengroup.osdu.core.common.model.http.AppException;
-import org.opengroup.osdu.core.common.model.http.DpsHeaders;
-import org.opengroup.osdu.core.common.model.notification.*;
-import org.opengroup.osdu.core.common.notification.ISubscriptionFactory;
-import org.opengroup.osdu.core.common.notification.ISubscriptionService;
-import org.opengroup.osdu.core.common.notification.SubscriptionException;
-import org.opengroup.osdu.notification.di.SubscriptionCacheFactory;
-import org.opengroup.osdu.notification.provider.interfaces.IPubsubHandshakeHandler;
 import org.opengroup.osdu.notification.provider.interfaces.IPubsubRequestBodyExtractor;
+import org.opengroup.osdu.notification.service.NotificationHandler;
 import org.opengroup.osdu.notification.utils.Config;
-import org.opengroup.osdu.notification.provider.interfaces.IGoogleServiceAccount;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -46,12 +30,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.context.annotation.RequestScope;
 
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
-
 @RestController
 @RequestScope
 @RequestMapping("/push-handlers")
@@ -59,29 +39,12 @@ public class PubsubEndpoint {
     @Autowired
     private IPubsubRequestBodyExtractor pubsubRequestBodyExtractor;
     @Autowired
-    private IPubsubHandshakeHandler pubsubHandshakeHandler;
-    @Autowired
-    private ISignatureService signatureService;
-    @Autowired
-    private HttpClient httpClient;
-    @Autowired
-    private IGoogleServiceAccount gsaTokenProvider;
+    private NotificationHandler notificationHandler;
     @Autowired
     private JaxRsDpsLog log;
-    @Autowired
-    private SubscriptionCacheFactory subscriptionCacheFactory;
-    @Autowired
-    private ISubscriptionFactory subscriptionFactory;
-    @Autowired
-    private DpsHeaders headers;
 
-    private static final String HMAC_TYPE = "HMAC";
-    private static final String GSA_TYPE = "GSA";
-    private final int WAITING_TIME = 30000;
     private final String ACKNOWLEDGE = "message acknowledged by client";
     private final String NOT_ACKNOWLEDGE = "message not acknowledged by client";
-    private static final Gson gson = new Gson();
-    private ObjectMapper objectMapper;
 
     @PostMapping("/records-changed")
     @PreAuthorize("@authorizationFilter.hasAnyPermission('" + Config.OPS + "', '" + Config.PUBSUB + "')")
@@ -89,92 +52,12 @@ public class PubsubEndpoint {
         String notificationId = this.pubsubRequestBodyExtractor.extractNotificationIdFromRequestBody();
         String pubsubMessage = this.pubsubRequestBodyExtractor.extractDataFromRequestBody();
         Map<String, String> headerAttributes = this.pubsubRequestBodyExtractor.extractAttributesFromRequestBody();
-
-        Subscription subscription = getSubscriptionFromCache(notificationId);
-        Secret secret = subscription.getSecret();
-        String endpoint = subscription.getPushEndpoint();
-
-        String secretType = secret.getSecretType();
-        String pushUrl = "";
-        Map<String, String> requestHeader = new HashMap<>();
-
-        if (secretType.equalsIgnoreCase(HMAC_TYPE)) {
-            this.log.info("receiving pubsub message, will send out hmac type request, pubsub message: " + pubsubMessage);
-            HmacSecret hmacSecret = (HmacSecret) secret;
-            String signedjwt = this.signatureService.getSignedSignature(endpoint, hmacSecret.getValue());
-            pushUrl = endpoint + "?hmac=" + signedjwt;
-        } else if (secretType.equalsIgnoreCase(GSA_TYPE)) {
-            this.log.info("receiving pubsub message, will send out gsa type request, pubsub message: " + pubsubMessage);
-            GsaSecret gsaSecret = (GsaSecret) secret;
-            GsaSecretValue gsaSecretValue = gsaSecret.getValue();
-
-            JsonParser jsonParser = new JsonParser();
-            JsonElement root = jsonParser.parse(gsaSecretValue.getKey());
-            String keyString = root.getAsJsonObject().toString();
-
-            String idToken = this.gsaTokenProvider.getIdToken(keyString, gsaSecretValue.getAudience());
-            pushUrl = endpoint;
-            requestHeader.put("Authorization", idToken);
-        }
-
-        this.log.info("sending out notification to endpoint: " + endpoint);
-        requestHeader.put(DpsHeaders.CONTENT_TYPE, "application/json");
-        requestHeader.put(DpsHeaders.CORRELATION_ID, headerAttributes.get(DpsHeaders.CORRELATION_ID));
-        requestHeader.put(DpsHeaders.DATA_PARTITION_ID, headerAttributes.get(DpsHeaders.DATA_PARTITION_ID));
-
-        HttpRequest request = HttpRequest.post().url(pushUrl).headers(requestHeader).body(pubsubMessage).connectionTimeout(WAITING_TIME).build();
-        HttpResponse response = httpClient.send(request);
+        HttpResponse response = notificationHandler.notifySubscriber(notificationId, pubsubMessage, headerAttributes);
         if (!response.isSuccessCode()) {
-            this.log.error(NOT_ACKNOWLEDGE);
-            return ResponseEntity.badRequest().body(NOT_ACKNOWLEDGE);
+            this.log.error(NOT_ACKNOWLEDGE + response.getBody());
+            return new ResponseEntity<String>(NOT_ACKNOWLEDGE, HttpStatus.valueOf(response.getResponseCode()));
         }
-        this.log.info(ACKNOWLEDGE);
-        return ResponseEntity.ok(ACKNOWLEDGE);
-    }
-
-    private Subscription getSubscriptionFromCache(String notificationId) throws Exception {
-        String subscriptionString = subscriptionCacheFactory.get(notificationId);
-        try {
-            if (Strings.isNullOrEmpty(subscriptionString))
-                subscriptionString = querySubscriptionAndUpdateCache(notificationId);
-            ObjectMapper objectMapper = this.getObjectMapper();
-            Subscription subscription = objectMapper.readValue(subscriptionString, Subscription.class);
-            return subscription;
-        } catch (IOException e) {
-            this.log.warning("Error Parsing subscription String to object.");
-            throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Error in getting subscription for notificationId:" + notificationId, "Unexpected error in pushing message", e);
-        } catch (SubscriptionException se) {
-            this.log.warning("Error query subscription from registration.");
-            throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Error in getting subscription for notificationId:" + notificationId, "Unexpected error in pushing message", se);
-        }
-    }
-
-    private String querySubscriptionAndUpdateCache(String notificationId) throws Exception {
-        ISubscriptionService service = subscriptionFactory.create(headers);
-
-        List<Subscription> subscriptionList = service.query(notificationId);
-        if (subscriptionList == null || subscriptionList.size() == 0) {
-            this.log.warning(String.format("Subscription with notification ID %s not found in registration", notificationId));
-            throw new AppException(HttpStatus.SC_NOT_FOUND, "Not found subscription for notificationId:" + notificationId, "Subscription not found");
-        }
-
-        Subscription subscription = subscriptionList.get(0);
-        String jsonSubscription = gson.toJson(subscription);
-        this.subscriptionCacheFactory.put(subscription.getNotificationId(), jsonSubscription);
-
-        return jsonSubscription;
-    }
-
-    //unit test purpose
-    protected ObjectMapper getObjectMapper() {
-        if (this.objectMapper == null) {
-            this.objectMapper = new ObjectMapper();
-        }
-        return this.objectMapper;
-    }
-
-    //unit test purpose
-    void setObjectMapper(ObjectMapper objectMapper) {
-        this.objectMapper = objectMapper;
+        this.log.debug(ACKNOWLEDGE);
+        return new ResponseEntity<String>(ACKNOWLEDGE, HttpStatus.OK);
     }
 }
diff --git a/notification-core/src/main/java/org/opengroup/osdu/notification/auth/AuthorizationFilter.java b/notification-core/src/main/java/org/opengroup/osdu/notification/auth/AuthorizationFilter.java
index 2eb23d060a1e3ce9e4abddd8fda4d2ce7a30e232..0d469306832359795a90ab339dd622f2a93a6d85 100644
--- a/notification-core/src/main/java/org/opengroup/osdu/notification/auth/AuthorizationFilter.java
+++ b/notification-core/src/main/java/org/opengroup/osdu/notification/auth/AuthorizationFilter.java
@@ -55,10 +55,9 @@ public class AuthorizationFilter {
         }
 
         String path = request.getServletPath();
-        if ("GET".equals(request.getMethod())) {
-            if (path.equals("/swagger-ui.html")) {
-                return true;
-            }
+        if ("GET".equals(request.getMethod()) &&
+           (path.equals("/swagger-ui.html") || path.equals("/info"))) {
+            return true;
         }
 
         if (Arrays.asList(requiredRoles).contains(Config.CRON) && requestInfoExt.isCronRequest()) {
diff --git a/notification-core/src/main/java/org/opengroup/osdu/notification/auth/GsaAuth.java b/notification-core/src/main/java/org/opengroup/osdu/notification/auth/GsaAuth.java
new file mode 100644
index 0000000000000000000000000000000000000000..565c6635802339ffafe8499da66974e8ad164c0e
--- /dev/null
+++ b/notification-core/src/main/java/org/opengroup/osdu/notification/auth/GsaAuth.java
@@ -0,0 +1,63 @@
+/*
+ *   Copyright 2017-2020, Schlumberger
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+package org.opengroup.osdu.notification.auth;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import org.opengroup.osdu.core.common.model.notification.GsaSecret;
+import org.opengroup.osdu.core.common.model.notification.GsaSecretValue;
+import org.opengroup.osdu.core.common.model.notification.Secret;
+import org.opengroup.osdu.notification.auth.interfaces.SecretAuth;
+import org.opengroup.osdu.notification.provider.interfaces.IGoogleServiceAccount;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.annotation.RequestScope;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class GsaAuth implements SecretAuth {
+    @Autowired
+    private IGoogleServiceAccount gsaTokenProvider;
+
+    private GsaSecret gsaSecret;
+
+    public void setSecret(Secret secret) {
+        this.gsaSecret = (GsaSecret) secret;
+    }
+
+    public Secret getSecret() {
+        return this.gsaSecret;
+    }
+
+    public String getPushUrl(String endpoint) throws Exception {
+        return endpoint;
+    }
+
+    public Map<String, String> getRequestHeaders() {
+        Map<String, String> requestHeader = new HashMap<>();
+        if (gsaSecret != null) {
+            GsaSecretValue gsaSecretValue = gsaSecret.getValue();
+            JsonParser jsonParser = new JsonParser();
+            JsonElement root = jsonParser.parse(gsaSecretValue.getKey());
+            String keyString = root.getAsJsonObject().toString();
+            String idToken = this.gsaTokenProvider.getIdToken(keyString, gsaSecretValue.getAudience());
+            requestHeader.put("Authorization", idToken);
+        }
+        return requestHeader;
+    }
+}
diff --git a/notification-core/src/main/java/org/opengroup/osdu/notification/auth/HmacAuth.java b/notification-core/src/main/java/org/opengroup/osdu/notification/auth/HmacAuth.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a2885e2d2aeb91b62e65564a0d37a10a282bb73
--- /dev/null
+++ b/notification-core/src/main/java/org/opengroup/osdu/notification/auth/HmacAuth.java
@@ -0,0 +1,56 @@
+/*
+ *   Copyright 2017-2020, Schlumberger
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+package org.opengroup.osdu.notification.auth;
+
+import org.opengroup.osdu.core.common.cryptographic.ISignatureService;
+import org.opengroup.osdu.core.common.model.notification.HmacSecret;
+import org.opengroup.osdu.core.common.model.notification.Secret;
+import org.opengroup.osdu.notification.auth.interfaces.SecretAuth;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.annotation.RequestScope;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class HmacAuth implements SecretAuth {
+    @Autowired
+    private ISignatureService signatureService;
+
+    private HmacSecret hmacSecret;
+
+    public void setSecret(Secret secret) {
+        this.hmacSecret = (HmacSecret) secret;
+    }
+
+    public Secret getSecret() {
+        return this.hmacSecret;
+    }
+
+    public String getPushUrl(String endpoint) throws Exception {
+        String pushUrl = endpoint;
+        String signedjwt = this.signatureService.getSignedSignature(endpoint, hmacSecret.getValue());
+        pushUrl += "?hmac=" + signedjwt;
+        return pushUrl;
+    }
+
+    public Map<String, String> getRequestHeaders() {
+        Map<String, String> requestHeader = new HashMap<>();
+        return requestHeader;
+
+    }
+}
diff --git a/notification-core/src/main/java/org/opengroup/osdu/notification/auth/factory/AuthFactory.java b/notification-core/src/main/java/org/opengroup/osdu/notification/auth/factory/AuthFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..5cedb532daabcf4806eb30dfffbbd97878b38750
--- /dev/null
+++ b/notification-core/src/main/java/org/opengroup/osdu/notification/auth/factory/AuthFactory.java
@@ -0,0 +1,49 @@
+/*
+ *   Copyright 2017-2020, Schlumberger
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+package org.opengroup.osdu.notification.auth.factory;
+
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.notification.auth.GsaAuth;
+import org.opengroup.osdu.notification.auth.HmacAuth;
+import org.opengroup.osdu.notification.auth.interfaces.SecretAuth;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.annotation.RequestScope;
+
+@Component
+public class AuthFactory {
+    private final String HMAC_TYPE = "HMAC";
+    private final String GSA_TYPE = "GSA";
+
+    @Autowired
+    private HmacAuth hmacAuth;
+    @Autowired
+    private GsaAuth gsaAuth;
+    @Autowired
+    private JaxRsDpsLog log;
+
+    public SecretAuth getSecretAuth(String secretType) {
+        switch (secretType.toUpperCase()) {
+            case HMAC_TYPE:
+                return hmacAuth;
+            case GSA_TYPE:
+                return gsaAuth;
+            default:
+                throw new AppException(404, "Secret Type Not Found", "Unrecognised secret type encountered :" + secretType);
+        }
+    }
+}
diff --git a/notification-core/src/main/java/org/opengroup/osdu/notification/auth/interfaces/SecretAuth.java b/notification-core/src/main/java/org/opengroup/osdu/notification/auth/interfaces/SecretAuth.java
new file mode 100644
index 0000000000000000000000000000000000000000..487a7f0acac68bcf12ddbfe0b05a6df742cb2d51
--- /dev/null
+++ b/notification-core/src/main/java/org/opengroup/osdu/notification/auth/interfaces/SecretAuth.java
@@ -0,0 +1,30 @@
+/*
+ *   Copyright 2017-2020, Schlumberger
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+package org.opengroup.osdu.notification.auth.interfaces;
+
+import org.opengroup.osdu.core.common.model.notification.Secret;
+
+import java.util.Map;
+
+public interface SecretAuth {
+    String getPushUrl(String endpoint) throws Exception;
+
+    void setSecret(Secret secret);
+
+    Secret getSecret();
+
+    Map<String, String> getRequestHeaders();
+}
diff --git a/notification-core/src/main/java/org/opengroup/osdu/notification/di/CredentialHeadersProvider.java b/notification-core/src/main/java/org/opengroup/osdu/notification/di/CredentialHeadersProvider.java
index c11ea04b671ed028c02c54fbe2edac0df2d894c5..85dc9d1dcc0d7582343942d33e862ab4a1a1c71a 100644
--- a/notification-core/src/main/java/org/opengroup/osdu/notification/di/CredentialHeadersProvider.java
+++ b/notification-core/src/main/java/org/opengroup/osdu/notification/di/CredentialHeadersProvider.java
@@ -21,6 +21,7 @@ import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient;
 import org.opengroup.osdu.notification.provider.interfaces.IPubsubRequestBodyExtractor;
 import org.springframework.beans.factory.FactoryBean;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.context.annotation.Primary;
 import org.springframework.stereotype.Component;
 
@@ -33,8 +34,9 @@ import org.springframework.web.context.annotation.RequestScope;
 import javax.servlet.http.HttpServletRequest;
 
 @Component
-@Primary
 @RequestScope
+@ConditionalOnProperty(value = "requestScope.enabled", havingValue = "true", matchIfMissing = true)
+@Primary
 public class CredentialHeadersProvider implements FactoryBean<DpsHeaders> {
 
     @Autowired
diff --git a/notification-core/src/main/java/org/opengroup/osdu/notification/di/SubscriptionCacheFactory.java b/notification-core/src/main/java/org/opengroup/osdu/notification/di/SubscriptionCacheFactory.java
index 5879641c8219a4dd4af318e5ce8da70ca3d5b0c5..0291e67f48be2d75a689fce3caa0d010ebd116ed 100644
--- a/notification-core/src/main/java/org/opengroup/osdu/notification/di/SubscriptionCacheFactory.java
+++ b/notification-core/src/main/java/org/opengroup/osdu/notification/di/SubscriptionCacheFactory.java
@@ -19,7 +19,10 @@ package org.opengroup.osdu.notification.di;
 import org.opengroup.osdu.core.common.cache.ICache;
 import org.opengroup.osdu.core.common.cache.MultiTenantCache;
 import org.opengroup.osdu.core.common.cache.VmCache;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.http.DpsHeaders;
 import org.opengroup.osdu.core.common.model.tenant.TenantInfo;
+import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
@@ -27,7 +30,9 @@ import org.springframework.stereotype.Component;
 @Component
 public class SubscriptionCacheFactory implements ICache<String, String> {
     @Autowired
-    private TenantInfo tenant;
+    private DpsHeaders headers;
+    @Autowired
+    private ITenantFactory tenantFactory;
 
     private MultiTenantCache<String> caches;
 
@@ -56,6 +61,10 @@ public class SubscriptionCacheFactory implements ICache<String, String> {
     }
 
     private ICache<String, String> partitionCache() {
-        return this.caches.get(String.format("%s:subscription", this.tenant.getDataPartitionId()));
+        TenantInfo tenantInfo = this.tenantFactory.getTenantInfo(this.headers.getPartitionIdWithFallbackToAccountId());
+        if (tenantInfo == null) {
+            throw AppException.createUnauthorized(String.format("could not retrieve tenant info for data partition id: %s", this.headers.getPartitionIdWithFallbackToAccountId()));
+        }
+        return this.caches.get(String.format("%s:subscription", tenantInfo.getDataPartitionId()));
     }
 }
diff --git a/notification-core/src/main/java/org/opengroup/osdu/notification/service/NotificationHandler.java b/notification-core/src/main/java/org/opengroup/osdu/notification/service/NotificationHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ba4a823ab5d54fa97e5f79ffa8bc2a926ed09cb
--- /dev/null
+++ b/notification-core/src/main/java/org/opengroup/osdu/notification/service/NotificationHandler.java
@@ -0,0 +1,72 @@
+/*
+ *   Copyright 2017-2020, Schlumberger
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.service;
+
+import org.opengroup.osdu.core.common.http.HttpClient;
+import org.opengroup.osdu.core.common.http.HttpRequest;
+import org.opengroup.osdu.core.common.http.HttpResponse;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.http.DpsHeaders;
+import org.opengroup.osdu.core.common.model.notification.*;
+import org.opengroup.osdu.notification.auth.factory.AuthFactory;
+import org.opengroup.osdu.notification.auth.interfaces.SecretAuth;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.annotation.RequestScope;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class NotificationHandler {
+    private final static Logger LOGGER = LoggerFactory.getLogger(NotificationHandler.class);
+    @Autowired
+    private HttpClient httpClient;
+    @Autowired
+    private SubscriptionHandler subscriptionHandler;
+    @Autowired
+    private AuthFactory authFactory;
+    @Value("${app.waitingTime:30000}")
+    private int WAITING_TIME;
+
+    public HttpResponse notifySubscriber(String notificationId, String pubsubMessage, Map<String, String> headerAttributes) throws Exception {
+        Subscription subscription = subscriptionHandler.getSubscriptionFromCache(notificationId);
+        Secret secret = subscription.getSecret();
+        String endpoint = subscription.getPushEndpoint();
+        String secretType = secret.getSecretType();
+        String pushUrl = "";
+        Map<String, String> requestHeader = new HashMap<String, String>();
+
+        // Authentication Secret
+        SecretAuth secretAuth = authFactory.getSecretAuth(secretType);
+        secretAuth.setSecret(secret);
+        pushUrl = secretAuth.getPushUrl(endpoint);
+        requestHeader = secretAuth.getRequestHeaders();
+
+        requestHeader.put(DpsHeaders.CONTENT_TYPE, "application/json");
+        requestHeader.put(DpsHeaders.CORRELATION_ID, headerAttributes.get(DpsHeaders.CORRELATION_ID));
+        requestHeader.put(DpsHeaders.DATA_PARTITION_ID, headerAttributes.get(DpsHeaders.DATA_PARTITION_ID));
+
+        HttpRequest request = HttpRequest.post().url(pushUrl).headers(requestHeader).body(pubsubMessage).connectionTimeout(WAITING_TIME).build();
+        HttpResponse response = httpClient.send(request);
+        this.LOGGER.debug("Sending out notification to endpoint: " + endpoint);
+        return response;
+    }
+}
diff --git a/notification-core/src/main/java/org/opengroup/osdu/notification/service/SubscriptionHandler.java b/notification-core/src/main/java/org/opengroup/osdu/notification/service/SubscriptionHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..016ca4f49a55e630b95bbdf0c7ace92359c25a02
--- /dev/null
+++ b/notification-core/src/main/java/org/opengroup/osdu/notification/service/SubscriptionHandler.java
@@ -0,0 +1,93 @@
+/*
+ *   Copyright 2017-2020, Schlumberger
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Strings;
+import com.google.gson.Gson;
+import org.apache.http.HttpStatus;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.http.DpsHeaders;
+import org.opengroup.osdu.core.common.model.notification.Subscription;
+import org.opengroup.osdu.core.common.notification.ISubscriptionFactory;
+import org.opengroup.osdu.core.common.notification.ISubscriptionService;
+import org.opengroup.osdu.core.common.notification.SubscriptionException;
+import org.opengroup.osdu.notification.di.SubscriptionCacheFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.List;
+
+@Component
+public class SubscriptionHandler {
+    @Autowired
+    private ISubscriptionFactory subscriptionFactory;
+    @Autowired
+    private SubscriptionCacheFactory subscriptionCacheFactory;
+    @Autowired
+    private JaxRsDpsLog log;
+    @Autowired
+    private DpsHeaders headers;
+
+    private static final Gson gson = new Gson();
+    private ObjectMapper objectMapper;
+
+    public Subscription getSubscriptionFromCache(String notificationId) throws IOException, SubscriptionException {
+        String subscriptionString = subscriptionCacheFactory.get(notificationId);
+        try {
+            if (Strings.isNullOrEmpty(subscriptionString))
+                subscriptionString = querySubscriptionAndUpdateCache(notificationId);
+            ObjectMapper objectMapper = this.getObjectMapper();
+            Subscription subscription = objectMapper.readValue(subscriptionString, Subscription.class);
+            return subscription;
+        } catch (IOException e) {
+            throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Error Parsing subscription String to object", "Unexpected error in pushing message", e);
+        } catch (SubscriptionException se) {
+            throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Error query subscription from registration", "Unexpected error in pushing message", se);
+        }
+    }
+
+    private String querySubscriptionAndUpdateCache(String notificationId) throws AppException, SubscriptionException {
+        ISubscriptionService service = subscriptionFactory.create(headers);
+
+        List<Subscription> subscriptionList = service.query(notificationId);
+        if (subscriptionList == null || subscriptionList.size() == 0) {
+            throw new AppException(HttpStatus.SC_NOT_FOUND, "Not found subscription for notificationId:" + notificationId, "Subscription not found");
+        }
+
+        Subscription subscription = subscriptionList.get(0);
+        String jsonSubscription = gson.toJson(subscription);
+        this.subscriptionCacheFactory.put(subscription.getNotificationId(), jsonSubscription);
+
+        return jsonSubscription;
+    }
+
+    //unit test purpose
+    protected ObjectMapper getObjectMapper() {
+        if (this.objectMapper == null) {
+            this.objectMapper = new ObjectMapper();
+        }
+        return this.objectMapper;
+    }
+
+    //unit test purpose
+    void setObjectMapper(ObjectMapper objectMapper) {
+        this.objectMapper = objectMapper;
+    }
+}
diff --git a/notification-core/src/test/java/org/opengroup/osdu/notification/api/InfoApiTest.java b/notification-core/src/test/java/org/opengroup/osdu/notification/api/InfoApiTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..343678e12a30ec13bcc98959d3166b55a10212a4
--- /dev/null
+++ b/notification-core/src/test/java/org/opengroup/osdu/notification/api/InfoApiTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opengroup.osdu.core.common.info.VersionInfoBuilder;
+import org.opengroup.osdu.core.common.model.info.VersionInfo;
+
+@RunWith(MockitoJUnitRunner.class)
+public class InfoApiTest {
+
+  @InjectMocks
+  private InfoApi sut;
+
+  @Mock
+  private VersionInfoBuilder versionInfoBuilder;
+
+  @Test
+  public void should_return200_getVersionInfo() throws IOException {
+    VersionInfo versionInfo = VersionInfo.builder()
+        .groupId("group")
+        .artifactId("artifact")
+        .version("0.1.0")
+        .buildTime("1000")
+        .branch("master")
+        .commitId("7777")
+        .commitMessage("Merge commit")
+        .build();
+    when(versionInfoBuilder.buildVersionInfo()).thenReturn(versionInfo);
+    VersionInfo response = this.sut.info();
+    assertEquals(versionInfo, response);
+  }
+}
diff --git a/notification-core/src/test/java/org/opengroup/osdu/notification/api/PubsubEndpointTests.java b/notification-core/src/test/java/org/opengroup/osdu/notification/api/PubsubEndpointTests.java
index 707a59fc951ab821160f71d35f766bc68ff39eff..ce98167953803ac6b257a31f38e5efb621fe27f0 100644
--- a/notification-core/src/test/java/org/opengroup/osdu/notification/api/PubsubEndpointTests.java
+++ b/notification-core/src/test/java/org/opengroup/osdu/notification/api/PubsubEndpointTests.java
@@ -16,39 +16,26 @@
 
 package org.opengroup.osdu.notification.api;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.opengroup.osdu.core.common.cryptographic.ISignatureService;
-import org.opengroup.osdu.core.common.http.HttpClient;
 import org.opengroup.osdu.core.common.http.HttpResponse;
 import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
-import org.opengroup.osdu.core.common.model.http.AppException;
 import org.opengroup.osdu.core.common.model.http.DpsHeaders;
-import org.opengroup.osdu.core.common.model.notification.Subscription;
-import org.opengroup.osdu.core.common.notification.ISubscriptionService;
 import org.opengroup.osdu.core.common.notification.SubscriptionException;
-import org.opengroup.osdu.core.common.notification.SubscriptionFactory;
-import org.opengroup.osdu.core.common.notification.SubscriptionService;
-import org.opengroup.osdu.notification.di.CredentialHeadersProvider;
-import org.opengroup.osdu.notification.di.SubscriptionCacheFactory;
-import org.opengroup.osdu.notification.provider.interfaces.IGoogleServiceAccount;
 import org.opengroup.osdu.notification.provider.interfaces.IPubsubRequestBodyExtractor;
+import org.opengroup.osdu.notification.service.NotificationHandler;
 import org.powermock.modules.junit4.PowerMockRunner;
 import org.springframework.http.ResponseEntity;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
 
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 @RunWith(PowerMockRunner.class)
@@ -56,31 +43,14 @@ public class PubsubEndpointTests {
     @Mock
     private IPubsubRequestBodyExtractor pubsubRequestBodyExtractor;
     @Mock
-    private ISignatureService signatureService;
-    @Mock
-    private HttpClient httpClient;
-    @Mock
-    private DpsHeaders headers;
-    @Mock
-    private SubscriptionCacheFactory subscriptionCacheFactory;
-    @Mock
-    private IGoogleServiceAccount googleIdTokenProducer;
+    private NotificationHandler notificationHandler;
     @Mock
     private JaxRsDpsLog log;
     @InjectMocks
     private PubsubEndpoint sut;
-    @Mock
-    private CredentialHeadersProvider credentialHeadersProvider;
-    @Mock
-    private SubscriptionFactory subscriptionFactory;
-    @Mock
-    private ObjectMapper objectMapper;
 
-    private static final String SIGNED_SIGNATURE = "testEncodedInfo.testSignature";
-    private static final String GOOGLE_ID_TOKEN = "testHeader.testPayload.testSignature";
     private static final String NOTIFICATION_ID = "test-notification-id";
     private static final String PUBSUB_MESSAGE = "test-pubsub-message-data";
-
     private HttpResponse response = new HttpResponse();
 
     @Before
@@ -90,163 +60,28 @@ public class PubsubEndpointTests {
     }
 
     @Test
-    public void should_return200_whenPubsubMessageValidAndSuccessCodeReturnedFromClient_hmac() throws Exception {
-        response.setResponseCode(200);
-
-        when(this.signatureService.getSignedSignature(any(), any())).thenReturn(SIGNED_SIGNATURE);
-        when(this.httpClient.send(any())).thenReturn(response);
-        when(this.subscriptionCacheFactory.get(any())).thenReturn(getHmacSubscription());
-        sut.setObjectMapper(new ObjectMapper());
-        ResponseEntity responseEntity = this.sut.recordChanged();
-        Assert.assertEquals(200, responseEntity.getStatusCode().value());
-        Assert.assertEquals("message acknowledged by client", responseEntity.getBody().toString());
-    }
-
-    @Test
-    public void should_return200_whenPubsubMessageValidAndSuccessCodeReturnedFromClient_gsa() throws Exception {
+    public void should_return200_whenPubsubMessageValidAndSuccessCodeReturnedFromNotificationHandler() throws Exception {
         response.setResponseCode(200);
-
-        when(this.googleIdTokenProducer.getIdToken(any(), any())).thenReturn(GOOGLE_ID_TOKEN);
-        when(this.httpClient.send(any())).thenReturn(response);
-        when(this.subscriptionCacheFactory.get(any())).thenReturn(getGsaSubscription());
-        sut.setObjectMapper(new ObjectMapper());
-
+        when(this.notificationHandler.notifySubscriber(NOTIFICATION_ID, PUBSUB_MESSAGE, new HashMap<>())).thenReturn(response);
         ResponseEntity responseEntity = this.sut.recordChanged();
         Assert.assertEquals(200, responseEntity.getStatusCode().value());
         Assert.assertEquals("message acknowledged by client", responseEntity.getBody().toString());
     }
 
     @Test
-    public void should_return400_whenSendOutRequestButNoSuccessCodeReturned_hmac() throws Exception {
-        response.setResponseCode(500);
-
-        when(this.signatureService.getSignedSignature(any(), any())).thenReturn(SIGNED_SIGNATURE);
-        when(this.httpClient.send(any())).thenReturn(response);
-        when(this.subscriptionCacheFactory.get(any())).thenReturn(getHmacSubscription());
-        sut.setObjectMapper(new ObjectMapper());
-
-        ResponseEntity responseEntity = this.sut.recordChanged();
-        Assert.assertEquals(400, responseEntity.getStatusCode().value());
-        Assert.assertEquals("message not acknowledged by client", responseEntity.getBody().toString());
-    }
-
-    @Test
-    public void should_return400_whenSendOutRequestButNoSuccessCodeReturned_gsa() throws Exception {
-        response.setResponseCode(500);
-
-        when(this.googleIdTokenProducer.getIdToken(any(), any())).thenReturn(GOOGLE_ID_TOKEN);
-        when(this.httpClient.send(any())).thenReturn(response);
-        when(this.subscriptionCacheFactory.get(any())).thenReturn(getGsaSubscription());
-        sut.setObjectMapper(new ObjectMapper());
-
+    public void should_return400_whenPubsubMessageValidAndFailureCodeReturnedFromNotificationHandler() throws Exception {
+        response.setResponseCode(400);
+        when(this.notificationHandler.notifySubscriber(NOTIFICATION_ID, PUBSUB_MESSAGE, new HashMap<>())).thenReturn(response);
         ResponseEntity responseEntity = this.sut.recordChanged();
         Assert.assertEquals(400, responseEntity.getStatusCode().value());
         Assert.assertEquals("message not acknowledged by client", responseEntity.getBody().toString());
     }
 
-    @Test(expected = AppException.class)
-    public void should_throwException_whenSubscriptionNotFound() throws Exception {
-        when(this.subscriptionCacheFactory.get(any())).thenReturn(null);
-        when(this.credentialHeadersProvider.getObject()).thenReturn(new DpsHeaders());
-        ISubscriptionService subscriptionService = mock(SubscriptionService.class);
-        when(this.subscriptionFactory.create(any())).thenReturn(subscriptionService);
-
-        HttpResponse response = new HttpResponse();
-        when(subscriptionService.query(any())).thenThrow(new SubscriptionException("error", response));
-        this.sut.recordChanged();
-        fail("should throw AppException");
-    }
-
-    @Test(expected = AppException.class)
-    public void should_throwException_whenSubscriptionParsingErrorOccurs() throws Exception {
-
-        when(this.subscriptionCacheFactory.get(any())).thenReturn(null);
-        when(this.credentialHeadersProvider.getObject()).thenReturn(new DpsHeaders());
-        ISubscriptionService subscriptionService = mock(SubscriptionService.class);
-        when(this.subscriptionFactory.create(any())).thenReturn(subscriptionService);
-
-        String jsonSubscription = this.getHmacSubscription();
-        ObjectMapper objectMapper = new ObjectMapper();
-        Subscription subscription = objectMapper.readValue(jsonSubscription, Subscription.class);
-        List<Subscription> queryResult = new ArrayList<>();
-        queryResult.add(subscription);
-
-        when(subscriptionService.query(any())).thenReturn(queryResult);
-
-        sut.setObjectMapper(this.objectMapper);
-        when(this.objectMapper.readValue(anyString(), any(Class.class))).thenThrow(new IOException());
+    @Test(expected = Exception.class)
+    public void should_return400_whenPubsubMessageValidAndNotificationHandlerThrowsException() throws Exception {
+        response.setResponseCode(400);
+        when(this.notificationHandler.notifySubscriber(NOTIFICATION_ID, PUBSUB_MESSAGE, new HashMap<>())).thenThrow(new Exception("error"));
         this.sut.recordChanged();
-        fail("should throw AppException");
-    }
-
-    @Test
-    public void should_return200_whenSubscriptionGotFromRegistration() throws Exception {
-        response.setResponseCode(200);
-
-        when(this.googleIdTokenProducer.getIdToken(any(), any())).thenReturn(GOOGLE_ID_TOKEN);
-        when(this.httpClient.send(any())).thenReturn(response);
-
-        when(this.subscriptionCacheFactory.get(any())).thenReturn(null);
-        when(this.credentialHeadersProvider.getObject()).thenReturn(new DpsHeaders());
-        ISubscriptionService subscriptionService = mock(SubscriptionService.class);
-        when(this.subscriptionFactory.create(any())).thenReturn(subscriptionService);
-        sut.setObjectMapper(new ObjectMapper());
-
-        String jsonSubscription = this.getHmacSubscription();
-        ObjectMapper objectMapper = new ObjectMapper();
-        // unit test purpose, not sure if this is osdu compliant
-        Subscription subscription = objectMapper.readValue(jsonSubscription, Subscription.class);
-        List<Subscription> queryResult = new ArrayList<>();
-        queryResult.add(subscription);
-        when(subscriptionService.query(any())).thenReturn(queryResult);
-        ResponseEntity responseEntity = this.sut.recordChanged();
-        Assert.assertEquals(200, responseEntity.getStatusCode().value());
-        Assert.assertEquals("message acknowledged by client", responseEntity.getBody().toString());
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void should_throwException_whenErrorGeneratingSignature_hmac() throws Exception {
-        IllegalArgumentException ex = new IllegalArgumentException("Error generating signed signature");
-
-        when(this.subscriptionCacheFactory.get(any())).thenReturn(getHmacSubscription());
-        when(this.signatureService.getSignedSignature(any(), any())).thenThrow(ex);
-        sut.setObjectMapper(new ObjectMapper());
-
-        this.sut.recordChanged();
-    }
-
-    private String getHmacSubscription() {
-        return "{\n" +
-                "\t\"name\": \"testSubscription\",\n" +
-                "\t\"description\": \"Description\",\n" +
-                "\t\"topic\": \"records-changed\",\n" +
-                "\t\"pushEndpoint\": \"http://challenge\",\n" +
-                "\t\"notificationId\": \"notificationId\",\n" +
-                "\t\"id\": \"id_1\",\n" +
-                "\t\"createdBy\": \"test@test.com\",\n" +
-                "\t\"secret\": {\n" +
-                "\t\t\"secretType\": \"HMAC\",\n" +
-                "\t\t\"value\": \"testsecret\"\n" +
-                "\t}\n" +
-                "}";
-    }
-
-    private String getGsaSubscription() {
-        return "{\n" +
-                "\t\"name\": \"testSubscription\",\n" +
-                "\t\"description\": \"Description\",\n" +
-                "\t\"topic\": \"records-changed\",\n" +
-                "\t\"pushEndpoint\": \"http:///gsa-challenge\",\n" +
-                "\t\"notificationId\": \"notificationId\",\n" +
-                "\t\"id\": \"id_1\",\n" +
-                "\t\"createdBy\": \"test@test.com\",\n" +
-                "\t\"secret\": {\n" +
-                "\t\t\"secretType\": \"GSA\",\n" +
-                "\t\t\"value\": {\n" +
-                "\t\t\t\"audience\":\"audience\",\n" +
-                "\t\t\t\"key\":\"keyFile\"\n" +
-                "\t\t}\n" +
-                "\t}\n" +
-                "}";
+        fail("should throw Exception");
     }
 }
diff --git a/notification-core/src/test/java/org/opengroup/osdu/notification/auth/GsaAuthTest.java b/notification-core/src/test/java/org/opengroup/osdu/notification/auth/GsaAuthTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..077db3917a777340d9483ac7fe0621ba770a9fed
--- /dev/null
+++ b/notification-core/src/test/java/org/opengroup/osdu/notification/auth/GsaAuthTest.java
@@ -0,0 +1,91 @@
+/*
+ *   Copyright 2017-2020, Schlumberger
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.auth;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.opengroup.osdu.core.common.model.notification.GsaSecret;
+import org.opengroup.osdu.core.common.model.notification.GsaSecretValue;
+import org.opengroup.osdu.core.common.model.notification.Subscription;
+import org.opengroup.osdu.notification.provider.interfaces.IGoogleServiceAccount;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.utils.Asserts;
+
+import java.util.Map;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+@RunWith(PowerMockRunner.class)
+public class GsaAuthTest {
+    @Mock
+    private IGoogleServiceAccount gsaTokenProvider;
+    @InjectMocks
+    private GsaAuth sut;
+
+    private static Subscription gsa_subscription;
+    private static final String GOOGLE_ID_TOKEN = "testHeader.testPayload.testSignature";
+
+    @BeforeClass
+    public static void setup() {
+        setGsa_subscription();
+    }
+
+    @Test
+    public void should_return_valid_EndpointAndHeaders_gsaClient() throws Exception {
+        GsaSecret secret = (GsaSecret) gsa_subscription.getSecret();
+        when(this.gsaTokenProvider.getIdToken(any(), any())).thenReturn(GOOGLE_ID_TOKEN);
+        sut.setSecret(gsa_subscription.getSecret());
+        Asserts.assertNotNull(sut.getSecret(), "Unable to set Secret");
+        Map<String, String> headers = sut.getRequestHeaders();
+        Assert.assertEquals(GOOGLE_ID_TOKEN, headers.get("Authorization"));
+        String pushUrl = sut.getPushUrl(gsa_subscription.getPushEndpoint());
+        Assert.assertEquals(pushUrl, gsa_subscription.getPushEndpoint());
+    }
+
+    @Test
+    public void should_return_emptyHeaders_when_secret_is_null() throws Exception {
+        GsaSecret secret = (GsaSecret) gsa_subscription.getSecret();
+        when(this.gsaTokenProvider.getIdToken(any(), any())).thenReturn(GOOGLE_ID_TOKEN);
+        Map<String, String> headers = sut.getRequestHeaders();
+        Assert.assertEquals(0, headers.size());
+        String pushUrl = sut.getPushUrl(gsa_subscription.getPushEndpoint());
+        Assert.assertEquals(pushUrl, gsa_subscription.getPushEndpoint());
+    }
+
+    private static void setGsa_subscription() {
+        gsa_subscription = new Subscription();
+        gsa_subscription.setName("gsa_test_subscription");
+        gsa_subscription.setPushEndpoint("http:///gsa-challenge");
+        gsa_subscription.setDescription("Description");
+        gsa_subscription.setTopic("records-changed");
+        gsa_subscription.setNotificationId("test-notification-id");
+        gsa_subscription.setId("id_1");
+        gsa_subscription.setCreatedBy("test@test.com");
+        GsaSecret secret = new GsaSecret();
+        GsaSecretValue value = new GsaSecretValue();
+        value.setAudience("audience");
+        value.setKey("{\"keyFile\":{\"key\":\"gsa\"}}");
+        secret.setValue(value);
+        gsa_subscription.setSecret(secret);
+    }
+
+}
diff --git a/notification-core/src/test/java/org/opengroup/osdu/notification/auth/HmacAuthTest.java b/notification-core/src/test/java/org/opengroup/osdu/notification/auth/HmacAuthTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..130beb4d81c0392cb9896527b25bfbc347533709
--- /dev/null
+++ b/notification-core/src/test/java/org/opengroup/osdu/notification/auth/HmacAuthTest.java
@@ -0,0 +1,84 @@
+/*
+ *   Copyright 2017-2020, Schlumberger
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.auth;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.opengroup.osdu.core.common.cryptographic.ISignatureService;
+import org.opengroup.osdu.core.common.model.notification.HmacSecret;
+import org.opengroup.osdu.core.common.model.notification.Subscription;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import java.util.Map;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.when;
+
+@RunWith(PowerMockRunner.class)
+public class HmacAuthTest {
+    @Mock
+    private ISignatureService signatureService;
+    @InjectMocks
+    private HmacAuth sut;
+
+    private static Subscription hmac_subscription;
+    private static final String SIGNED_SIGNATURE = "testEncodedInfo.testSignature";
+
+    @BeforeClass
+    public static void setup() {
+        setHmac_subscription();
+    }
+
+    @Test
+    public void should_return_valid_EndpointAndHeaders() throws Exception {
+        HmacSecret secret = (HmacSecret) hmac_subscription.getSecret();
+        when(this.signatureService.getSignedSignature(hmac_subscription.getPushEndpoint(), secret.getValue())).thenReturn(SIGNED_SIGNATURE);
+        sut.setSecret(hmac_subscription.getSecret());
+        Assert.assertEquals(secret, sut.getSecret());
+        Map<String, String> headers = sut.getRequestHeaders();
+        Assert.assertEquals(0, headers.size());
+        String pushUrl = sut.getPushUrl(hmac_subscription.getPushEndpoint());
+        Assert.assertEquals(hmac_subscription.getPushEndpoint() + "?hmac=" + SIGNED_SIGNATURE, pushUrl);
+    }
+
+    @Test(expected = Exception.class)
+    public void should_throwException_whenErrorGeneratingSignature_hmac() throws Exception {
+        Exception ex = new Exception("Error generating signed signature");
+        HmacSecret secret = (HmacSecret) hmac_subscription.getSecret();
+        when(this.signatureService.getSignedSignature(hmac_subscription.getPushEndpoint(), secret.getValue())).thenThrow(ex);
+        sut.getPushUrl(hmac_subscription.getPushEndpoint());
+        fail("should throw Exception");
+    }
+
+    private static void setHmac_subscription() {
+        hmac_subscription = new Subscription();
+        hmac_subscription.setName("hamc_test_subscription");
+        hmac_subscription.setPushEndpoint("http://challenge");
+        hmac_subscription.setDescription("Description");
+        hmac_subscription.setTopic("records-changed");
+        hmac_subscription.setNotificationId("test-notification-id");
+        hmac_subscription.setId("id_1");
+        hmac_subscription.setCreatedBy("test@test.com");
+        HmacSecret secret = new HmacSecret();
+        secret.setValue("testsecret");
+        hmac_subscription.setSecret(secret);
+    }
+}
diff --git a/notification-core/src/test/java/org/opengroup/osdu/notification/service/NotificationHandlerTests.java b/notification-core/src/test/java/org/opengroup/osdu/notification/service/NotificationHandlerTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c5f8636d7e9c9d2d3c4fc8ea652372524361415
--- /dev/null
+++ b/notification-core/src/test/java/org/opengroup/osdu/notification/service/NotificationHandlerTests.java
@@ -0,0 +1,137 @@
+/*
+ *   Copyright 2017-2020, Schlumberger
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.service;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.opengroup.osdu.core.common.http.HttpClient;
+import org.opengroup.osdu.core.common.http.HttpResponse;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.notification.*;
+import org.opengroup.osdu.core.common.notification.SubscriptionException;
+import org.opengroup.osdu.notification.auth.factory.AuthFactory;
+import org.opengroup.osdu.notification.auth.interfaces.SecretAuth;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+@RunWith(PowerMockRunner.class)
+public class NotificationHandlerTests {
+    @Mock
+    private SubscriptionHandler subscriptionHandler;
+    @Mock
+    private AuthFactory authFactory;
+    @Mock
+    private SecretAuth secretAuth;
+    @Mock
+    private HttpClient httpClient;
+    @Mock
+    private JaxRsDpsLog log;
+    @InjectMocks
+    private NotificationHandler sut;
+
+    private HttpResponse response = new HttpResponse();
+    private static final String NOTIFICATION_ID = "test-notification-id";
+    private static final String PUBSUB_MESSAGE = "test-pubsub-message-data";
+    private static Subscription gsa_subscription;
+    private static Subscription hmac_subscription;
+
+    @BeforeClass
+    public static void setup() {
+        setHmac_subscription();
+        setGsa_subscription();
+    }
+
+    @Test
+    public void should_return200_whenPubsubMessageValidAndSuccessCodeReturnedFromClient_gsa() throws Exception {
+        response.setResponseCode(200);
+        Map<String, String> headers = new HashMap<String, String>();
+        when(this.subscriptionHandler.getSubscriptionFromCache(this.NOTIFICATION_ID)).thenReturn(gsa_subscription);
+        when(this.authFactory.getSecretAuth(any())).thenReturn(secretAuth);
+        when(this.httpClient.send(any())).thenReturn(response);
+        when(this.secretAuth.getPushUrl(gsa_subscription.getPushEndpoint())).thenReturn(gsa_subscription.getPushEndpoint());
+        when(this.secretAuth.getRequestHeaders()).thenReturn(headers);
+        HttpResponse response = this.sut.notifySubscriber(this.NOTIFICATION_ID, this.PUBSUB_MESSAGE, headers);
+        Assert.assertEquals(200, response.getResponseCode());
+    }
+
+    @Test
+    public void should_return200_whenPubsubMessageValidAndSuccessCodeReturnedFromClient_hmac() throws Exception {
+        response.setResponseCode(200);
+        Map<String, String> headers = new HashMap<String, String>();
+        when(this.subscriptionHandler.getSubscriptionFromCache(this.NOTIFICATION_ID)).thenReturn(hmac_subscription);
+        when(this.authFactory.getSecretAuth(any())).thenReturn(secretAuth);
+        when(this.httpClient.send(any())).thenReturn(response);
+        when(this.secretAuth.getPushUrl(hmac_subscription.getPushEndpoint())).thenReturn(hmac_subscription.getPushEndpoint());
+        when(this.secretAuth.getRequestHeaders()).thenReturn(headers);
+        HttpResponse response = this.sut.notifySubscriber(this.NOTIFICATION_ID, this.PUBSUB_MESSAGE, headers);
+        Assert.assertEquals(200, response.getResponseCode());
+    }
+
+    @Test(expected = SubscriptionException.class)
+    public void should_throwException_whenSubscriptionHandlerThrowsException() throws Exception {
+        Map<String, String> headers = new HashMap<String, String>();
+        when(this.authFactory.getSecretAuth(any())).thenReturn(secretAuth);
+        when(this.httpClient.send(any())).thenReturn(response);
+        when(this.secretAuth.getPushUrl(gsa_subscription.getPushEndpoint())).thenReturn(gsa_subscription.getPushEndpoint());
+        when(this.secretAuth.getRequestHeaders()).thenReturn(headers);
+        when(subscriptionHandler.getSubscriptionFromCache(this.NOTIFICATION_ID)).thenThrow(new SubscriptionException("error", response));
+        this.sut.notifySubscriber(this.NOTIFICATION_ID, this.PUBSUB_MESSAGE, headers);
+        fail("should throw SubscriptionException");
+    }
+
+    private static void setGsa_subscription() {
+        gsa_subscription = new Subscription();
+        gsa_subscription.setName("gsa_test_subscription");
+        gsa_subscription.setPushEndpoint("http:///gsa-challenge");
+        gsa_subscription.setDescription("Description");
+        gsa_subscription.setTopic("records-changed");
+        gsa_subscription.setNotificationId(NOTIFICATION_ID);
+        gsa_subscription.setId("id_1");
+        gsa_subscription.setCreatedBy("test@test.com");
+        GsaSecret secret = new GsaSecret();
+        GsaSecretValue value = new GsaSecretValue();
+        value.setAudience("audience");
+        value.setKey("keyFile");
+        secret.setValue(value);
+        gsa_subscription.setSecret(secret);
+
+    }
+
+    private static void setHmac_subscription() {
+        hmac_subscription = new Subscription();
+        hmac_subscription.setName("hamc_test_subscription");
+        hmac_subscription.setPushEndpoint("http://challenge");
+        hmac_subscription.setDescription("Description");
+        hmac_subscription.setTopic("records-changed");
+        hmac_subscription.setNotificationId(NOTIFICATION_ID);
+        hmac_subscription.setId("id_1");
+        hmac_subscription.setCreatedBy("test@test.com");
+        HmacSecret secret = new HmacSecret();
+        secret.setValue("testsecret");
+        hmac_subscription.setSecret(secret);
+    }
+}
diff --git a/notification-core/src/test/java/org/opengroup/osdu/notification/service/SubscriptionHandlerTests.java b/notification-core/src/test/java/org/opengroup/osdu/notification/service/SubscriptionHandlerTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..aefb8b62c74d2a68000f07e2b713b085c0ebbc6a
--- /dev/null
+++ b/notification-core/src/test/java/org/opengroup/osdu/notification/service/SubscriptionHandlerTests.java
@@ -0,0 +1,119 @@
+/*
+ *   Copyright 2017-2020, Schlumberger
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.opengroup.osdu.core.common.http.HttpResponse;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.http.DpsHeaders;
+import org.opengroup.osdu.core.common.model.notification.Subscription;
+import org.opengroup.osdu.core.common.notification.ISubscriptionFactory;
+import org.opengroup.osdu.core.common.notification.ISubscriptionService;
+import org.opengroup.osdu.core.common.notification.SubscriptionException;
+import org.opengroup.osdu.core.common.notification.SubscriptionService;
+import org.opengroup.osdu.notification.di.SubscriptionCacheFactory;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(PowerMockRunner.class)
+public class SubscriptionHandlerTests {
+    @Mock
+    private ISubscriptionFactory subscriptionFactory;
+    @Mock
+    private SubscriptionCacheFactory subscriptionCacheFactory;
+    @Mock
+    private ObjectMapper objectMapper;
+    @InjectMocks
+    private SubscriptionHandler sut;
+
+    private static final String NOTIFICATION_ID = "test-notification-id";
+
+    @Test(expected = AppException.class)
+    public void should_throwException_whenSubscriptionNotFound() throws Exception {
+        when(this.subscriptionCacheFactory.get(any())).thenReturn(null);
+        ISubscriptionService subscriptionService = mock(SubscriptionService.class);
+        when(this.subscriptionFactory.create(any())).thenReturn(subscriptionService);
+        HttpResponse response = new HttpResponse();
+        when(subscriptionService.query(any())).thenThrow(new SubscriptionException("error", response));
+        this.sut.getSubscriptionFromCache(this.NOTIFICATION_ID);
+        fail("should throw AppException");
+    }
+
+    @Test(expected = AppException.class)
+    public void should_throwException_whenSubscriptionParsingErrorOccurs() throws Exception {
+        when(this.subscriptionCacheFactory.get(any())).thenReturn(null);
+        ISubscriptionService subscriptionService = mock(SubscriptionService.class);
+        when(this.subscriptionFactory.create(any())).thenReturn(subscriptionService);
+        String jsonSubscription = this.getHmacSubscription();
+        ObjectMapper objectMapper = new ObjectMapper();
+        Subscription subscription = objectMapper.readValue(jsonSubscription, Subscription.class);
+        List<Subscription> queryResult = new ArrayList<>();
+        queryResult.add(subscription);
+        when(subscriptionService.query(any())).thenReturn(queryResult);
+        sut.setObjectMapper(this.objectMapper);
+        when(this.objectMapper.readValue(anyString(), any(Class.class))).thenThrow(new IOException());
+        this.sut.getSubscriptionFromCache(NOTIFICATION_ID);
+        fail("should throw AppException");
+    }
+
+    @Test
+    public void should_return200_whenSubscriptionGotFromRegistration() throws Exception {
+        when(this.subscriptionCacheFactory.get(any())).thenReturn(null);
+        ISubscriptionService subscriptionService = mock(SubscriptionService.class);
+        when(this.subscriptionFactory.create(any())).thenReturn(subscriptionService);
+        sut.setObjectMapper(new ObjectMapper());
+        String jsonSubscription = this.getHmacSubscription();
+        ObjectMapper objectMapper = new ObjectMapper();
+        Subscription subscription = objectMapper.readValue(jsonSubscription, Subscription.class);
+        List<Subscription> queryResult = new ArrayList<>();
+        queryResult.add(subscription);
+        when(subscriptionService.query(any())).thenReturn(queryResult);
+        Subscription response = this.sut.getSubscriptionFromCache(NOTIFICATION_ID);
+        Assert.assertEquals("testSubscription", response.getName());
+    }
+
+    private String getHmacSubscription() {
+        return "{\n" +
+                "\t\"name\": \"testSubscription\",\n" +
+                "\t\"description\": \"Description\",\n" +
+                "\t\"topic\": \"records-changed\",\n" +
+                "\t\"pushEndpoint\": \"http://challenge\",\n" +
+                "\t\"notificationId\": \"notificationId\",\n" +
+                "\t\"id\": \"id_1\",\n" +
+                "\t\"createdBy\": \"test@test.com\",\n" +
+                "\t\"secret\": {\n" +
+                "\t\t\"secretType\": \"HMAC\",\n" +
+                "\t\t\"value\": \"testsecret\"\n" +
+                "\t}\n" +
+                "}";
+    }
+}
diff --git a/pom.xml b/pom.xml
index 4bd703019b2e183525b7a103262be38a46fa796a..f06e315558e4c86423f415e1f82873410511a079 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,14 +18,14 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>org.opengroup.osdu</groupId>
 	<artifactId>os-notification</artifactId>
-	<version>0.9.0-SNAPSHOT</version>
+	<version>0.12.0-SNAPSHOT</version>
 	<description>Root Notification Service project</description>
 
 	<properties>
 		<java.version>8</java.version>
 		<maven.compiler.target>${java.version}</maven.compiler.target>
 		<maven.compiler.source>${java.version}</maven.compiler.source>
-		<os-core-common.version>0.6.9</os-core-common.version>
+		<os-core-common.version>0.11.0</os-core-common.version>
 	</properties>
 
 	<licenses>
@@ -43,7 +43,7 @@
 			<dependency>
 				<groupId>org.springframework.boot</groupId>
 				<artifactId>spring-boot-dependencies</artifactId>
-				<version>2.1.7.RELEASE</version>
+				<version>2.1.18.RELEASE</version>
 				<type>pom</type>
 				<scope>import</scope>
 			</dependency>
@@ -53,6 +53,24 @@
 				<artifactId>os-core-common</artifactId>
 				<version>${os-core-common.version}</version>
 			</dependency>
+
+			<!-- overriding packages with known vulnerabilities -->
+			<!-- See: https://nvd.nist.gov/vuln/search/results?form_type=Advanced&results_type=overview&search_type=all&cpe_vendor=cpe%3A%2F%3Afasterxml&cpe_product=cpe%3A%2F%3Afasterxml%3Ajackson-databind&cpe_version=cpe%3A%2F%3Afasterxml%3Ajackson-databind%3A2.9.9-->
+		<dependency>
+				<groupId>com.fasterxml.jackson.core</groupId>
+				<artifactId>jackson-core</artifactId>
+				<version>2.12.3</version>
+			</dependency>
+			<dependency>
+				<groupId>com.fasterxml.jackson.core</groupId>
+				<artifactId>jackson-databind</artifactId>
+				<version>2.12.3</version>
+			</dependency>
+			<dependency>
+				<groupId>com.fasterxml.jackson.core</groupId>
+				<artifactId>jackson-annotations</artifactId>
+				<version>2.12.3</version>
+			</dependency>
 		</dependencies>
 	</dependencyManagement>
 
@@ -71,6 +89,7 @@
 		<module>provider/notification-azure</module>
 		<module>provider/notification-ibm</module>
 		<module>provider/notification-aws</module>
+		<module>provider/notification-reference</module>
 	</modules>
 
 	<repositories>
@@ -110,4 +129,44 @@
 		</profile>
 	</profiles>
 
+	<build>
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<groupId>org.springframework.boot</groupId>
+					<artifactId>spring-boot-maven-plugin</artifactId>
+					<executions>
+						<execution>
+							<id>build-info</id>
+							<goals>
+								<goal>build-info</goal>
+							</goals>
+						</execution>
+					</executions>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+		<plugins>
+			<plugin>
+				<groupId>pl.project13.maven</groupId>
+				<artifactId>git-commit-id-plugin</artifactId>
+				<version>4.0.5</version>
+				<executions>
+					<execution>
+						<goals>
+							<goal>revision</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<verbose>true</verbose>
+					<dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
+					<generateGitPropertiesFile>true</generateGitPropertiesFile>
+					<generateGitPropertiesFilename>
+						${project.build.outputDirectory}/git.properties
+					</generateGitPropertiesFilename>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
 </project>
diff --git a/provider/notification-aws/build-aws/buildspec.yaml b/provider/notification-aws/build-aws/buildspec.yaml
index e5fc2bd6ed3d59236c0bdfba4a0308f4c33302fb..6d134addb8b5e83b8f9b07b83d24b9586dd41090 100644
--- a/provider/notification-aws/build-aws/buildspec.yaml
+++ b/provider/notification-aws/build-aws/buildspec.yaml
@@ -21,6 +21,11 @@ env:
   secrets-manager:
     DOCKER_USERNAME: /osdu/devops/docker_credentials:username
     DOCKER_PASSWORD: /osdu/devops/docker_credentials:password
+    SONAR_USERNAME: /osdu/devops/sonar_credentials:username
+    SONAR_PASSWORD: /osdu/devops/sonar_credentials:password
+  
+  parameter-store:
+    SONAR_URL: /osdu/devops/sonar_url
 
 phases:
   install:
@@ -58,7 +63,7 @@ phases:
       - printenv
 
       - echo "Building primary service assemblies..."
-      - mvn -ntp -B test install -pl notification-core,provider/notification-aws -Ddeployment.environment=prod
+      - mvn -ntp -B test install sonar:sonar -pl .,notification-core,provider/notification-aws -Ddeployment.environment=prod -Dsonar.login=${SONAR_USERNAME} -Dsonar.password=${SONAR_PASSWORD} -Dsonar.branch.name=${BRANCH_NAME} 
 
       - echo "Building integration testing assemblies and gathering artifacts..."
       - ./testing/notification-test-aws/build-aws/prepare-dist.sh
@@ -78,6 +83,9 @@ phases:
         python provider/notification-aws/build-aws/build-info.py --branch ${CODEBUILD_SOURCE_VERSION} --commit ${CODEBUILD_RESOLVED_SOURCE_VERSION} \
           --buildid ${CODEBUILD_BUILD_ID} --buildnumber ${CODEBUILD_BUILD_NUMBER} --reponame ${REPO_NAME} --outdir ${OUTPUT_DIR} \
           --artifact ${ECR_IMAGE}
+  post_build:
+    commands:
+      - cp provider/notification-aws/target/dependency-check-report.html ${OUTPUT_DIR}
 reports:
   SurefireReports: # CodeBuild will create a report group called "SurefireReports".
     files: #Store all of the files
diff --git a/provider/notification-aws/maven/settings.xml b/provider/notification-aws/maven/settings.xml
index 3dbde15f47c27d083537fa2f0b280f97f9aa54b5..3bd1cd4aa7ed183241e62e75d2b7f1a3f5ebc7aa 100644
--- a/provider/notification-aws/maven/settings.xml
+++ b/provider/notification-aws/maven/settings.xml
@@ -1,18 +1,19 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-  Copyright © 2020 Amazon Web Services
 
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.​
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
 
-       http://www.apache.org/licenses/LICENSE-2.0
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
 
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
 -->
 
 <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
@@ -53,6 +54,17 @@
                 <azure.devops.token>no-default</azure.devops.token>
             </properties>
         </profile>
+        <profile>
+            <id>sonar</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <properties>
+                <sonar.host.url>
+                    ${env.SONAR_URL}
+                </sonar.host.url>
+            </properties>
+        </profile>
     </profiles>
 
     <servers>
@@ -63,15 +75,14 @@
         </server>
     </servers>
 
-    <!-- CodeArtifact doesn't support external repos yet that aren't Maven Central.  ETA Q4 2020. -->
-    <!-- <mirrors> -->
-    <!-- <mirror> -->
-    <!-- <id>aws-osdu-dev-maven</id> -->
-    <!-- <name>aws-osdu-dev-maven</name> -->
-    <!-- <url>https://osdu-dev-888733619319.d.codeartifact.us-east-1.amazonaws.com/maven/osdu-maven/</url> -->
-    <!-- <mirrorOf>*,!gitlab-os-core-common-maven</mirrorOf> -->
-    <!-- </mirror> -->
-    <!-- </mirrors> -->
+    <mirrors>
+        <mirror>
+            <id>aws-osdu-dev-maven</id>
+            <name>aws-osdu-dev-maven</name>
+            <url>https://osdu-dev-${AWS_ACCOUNT_ID}.d.codeartifact.us-east-1.amazonaws.com/maven/osdu-maven/</url>
+            <mirrorOf>central,!gitlab-os-core-common-maven,!gitlab-os-core-lib-aws-maven</mirrorOf>
+        </mirror>
+    </mirrors>
 
     <activeProfiles>
         <activeProfile>credentialsConfiguration</activeProfile>
diff --git a/provider/notification-aws/pom.xml b/provider/notification-aws/pom.xml
index 55eb27000c6286ab2a4efa1083565df55292d3e4..ff238277d58b6aae0506a19021bb1f318c4c5c12 100644
--- a/provider/notification-aws/pom.xml
+++ b/provider/notification-aws/pom.xml
@@ -19,7 +19,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.opengroup.osdu</groupId>
     <artifactId>notification-aws</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.12.0-SNAPSHOT</version>
     <name>notification-aws</name>
     <description>AWS implementation for Notification service</description>
     <packaging>jar</packaging>
@@ -27,7 +27,7 @@
     <parent>
         <groupId>org.opengroup.osdu</groupId>
         <artifactId>os-notification</artifactId>
-        <version>0.9.0-SNAPSHOT</version>
+        <version>0.12.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 
@@ -35,20 +35,14 @@
         <java.version>8</java.version>
         <maven.compiler.target>${java.version}</maven.compiler.target>
         <maven.compiler.source>${java.version}</maven.compiler.source>
-        <aws.version>1.11.637</aws.version>
+        <aws.version>1.11.1018</aws.version>
     </properties>
 
     <dependencies>
-      <!--   <dependency>
-            <groupId>org.opengroup.osdu</groupId>
-            <artifactId>os-core-common</artifactId>
-        </dependency> -->
-
-
         <dependency>
             <groupId>org.opengroup.osdu.core.aws</groupId>
             <artifactId>os-core-lib-aws</artifactId>
-            <version>0.9.1-SNAPSHOT</version>
+            <version>0.11.0</version>
         </dependency>
 
         <!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-secretsmanager -->
@@ -61,7 +55,7 @@
        <dependency>
             <groupId>org.opengroup.osdu</groupId>
             <artifactId>notification-core</artifactId>
-            <version>0.9.0-SNAPSHOT</version>
+            <version>0.12.0-SNAPSHOT</version>
         </dependency>
 
         <dependency>
@@ -94,6 +88,7 @@
             <version>4.12</version>
             <scope>test</scope>
         </dependency>
+
     </dependencies>
 
     <build>
@@ -121,6 +116,18 @@
                     <failOnMissingWebXml>false</failOnMissingWebXml>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.owasp</groupId>
+                <artifactId>dependency-check-maven</artifactId>
+                <version>6.2.2</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 </project>
diff --git a/provider/notification-aws/src/main/resources/application.properties b/provider/notification-aws/src/main/resources/application.properties
index 704966d16d904a03b2c712057b97a0772d96bdac..476714e0d2e4c37fee01a61125079f30fdcf454b 100644
--- a/provider/notification-aws/src/main/resources/application.properties
+++ b/provider/notification-aws/src/main/resources/application.properties
@@ -19,7 +19,7 @@ server.port=${APPLICATION_PORT:8080}
 
 AUTHORIZE_API=${ENTITLEMENTS_BASE_URL}/api/entitlements/v2
 PARTITION_API=${ENTITLEMENTS_BASE_URL}/api/partition/v1
-REGISTER_SERVICE_URL=${ENTITLEMENTS_BASE_URL}/api/register/v1
+REGISTER_SERVICE_URL=${REGISTER_BASE_URL}/api/register/v1
 
 aws.ssm=${SSM_ENABLED:True}
 aws.environment=${RESOURCE_PREFIX}
@@ -48,3 +48,5 @@ server.ssl.key-store=${SSL_KEY_STORE_PATH:/certs/osduonaws.p12}
 server.ssl.key-alias=${SSL_KEY_ALIAS:osduonaws}
 server.ssl.key-password=${SSL_KEY_PASSWORD:}
 server.ssl.key-store-password=${SSL_KEY_STORE_PASSWORD:}
+
+spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
\ No newline at end of file
diff --git a/provider/notification-azure/GUIDELINES_FOR_USING_NOTIFICATION.md b/provider/notification-azure/docs/GUIDELINES_FOR_USING_NOTIFICATION.md
similarity index 100%
rename from provider/notification-azure/GUIDELINES_FOR_USING_NOTIFICATION.md
rename to provider/notification-azure/docs/GUIDELINES_FOR_USING_NOTIFICATION.md
diff --git a/provider/notification-azure/docs/MIGRATION.md b/provider/notification-azure/docs/MIGRATION.md
new file mode 100644
index 0000000000000000000000000000000000000000..db89d26264619f07288f50e927aa147213183ef8
--- /dev/null
+++ b/provider/notification-azure/docs/MIGRATION.md
@@ -0,0 +1,85 @@
+## Introduction
+
+The document talks about the plan to move from Event Grid to Service Bus. The major consumer of the same iss
+Notification Service. As Notification Service is consumed by external customers, so a clean migration path is needed.
+
+## Goals
+
+The Migration must happen respecting the following
+
+1. No re-registration
+2. Zero downtime.
+3. No notification loss.
+
+#### Prerequisites
+
+1. Please verify that the topic you want to use exists. If not,
+   follow [this](https://community.opengroup.org/osdu/platform/system/notification/-/blob/master/provider/notification-azure/PLAYBOOK_FOR_TOPIC_CREATION.md)
+   guide to create one.
+2. Install
+   the [latest version](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.1)
+   of PowerShell available for your operating system.
+
+## How to do the migration
+
+Migration is something which must be performed by SRE. The flags must be switched in a sequence.The flags are controlled
+by deployment.yaml for the service. Following are the steps needed for successful migration.
+
+1. Have 2 deployment of Notification Service running before migration:
+    1. Deployment 1,having event_grid_enabled.
+    2. Deployment 2,having service_bus_enabled.The consecutive_subscription_manager_delay_seconds should not be set much
+       higher as it will pile up alot of SB messages because of the longer time of listening new subscribers on the fly.
+       **The number of pods for both the deployments should be managed as per the load during migration**
+2. Get list of subscriptions per partition and prepare migrationConfig.json [Manual-from azure portal]:
+3. Complete powershell Az module installation and Azure login by running script
+   - [migrationSetup.ps1](https://community.opengroup.org/osdu/platform/system/notification/-/blob/master/provider/notification-azure/src/main/resources/migrationSetup.ps1)
+   .
+
+**Note:The Azure Az PowerShell module works with PowerShell 7.x and later on all platforms.To check your PowerShell
+version, run the following command from within a PowerShell session:$PSVersionTable.PSVersion**
+
+4. Create the subscribers on Service Bus with the same notification id as in CosmosDB by providing migrationConfig.json
+   to the
+   script-[migrationToServiceBus.ps1](https://community.opengroup.org/osdu/platform/system/notification/-/blob/master/provider/notification-azure/src/main/resources/migrationToServiceBus.ps1)
+   . All the subscriptions from one Event grid topic will be moved to service bus topic for one execution of above
+   mentioned script.We need to rerun script for multiple topic across multiple partitions.
+5. Turn on **Service bus flags** and turn off **Event Grid flags** in Producer Services. For example Storage service
+   publishes to Service bus and Event grid both as of now. During migration,while we are moving to Service bus
+   completely we have to stop publishing to Event Grid as a part of migration, so we can eventually disable it and move
+   to Service Bus completely.Same applies to other producer services like -Legal, Schema
+   etc. [Manual- Configuring deployment.yaml for Legal, Schema, Storage Services]
+6. Wait for Event Grid subscribers to drain.[Manual-from azure portal]
+   **Note: If there are delivery failures,then retry can occur after a longer duration,EG should be kept enabled for
+   sufficiently long time**
+7. Turn on **Service bus flags** in Register Service.[Manual]
+8. Event Grid Subscriber clean up.[Manual-from azure portal]
+
+The 3rd and 4th steps would be performed by the scripts in the order given below :
+** Powershell must be elevated to admin.**
+
+1. [migrationSetup.ps1](https://community.opengroup.org/osdu/platform/system/notification/-/blob/master/provider/notification-azure/src/main/resources/migrationSetup.ps1)
+2. [migrationToServiceBus.ps1](https://community.opengroup.org/osdu/platform/system/notification/-/blob/master/provider/notification-azure/src/main/resources/migrationToServiceBus.ps1)
+
+## List of Feature Flags to be used from deployment.yaml of respective services
+
+1. Notification Service
+    1. service_bus_enabled
+    2. event_grid_enabled
+2. Register Service
+    1. azure_serviceBus_enabled
+    2. azure_eventGrid_enabled
+3. Producer Services
+    1. Storage Service : azure_publishToEventGrid
+    2. Legal Service : azure.publishToEventGrid
+    3. Schema Service : event_grid_enabled
+
+## Post Migration Plan
+
+1. Redeploy Notification Service to have only 1 deployment with service_bus_enabled set to true and event_grid_enabled
+   set to false.The number of pods can be managed as per the load
+
+## Note
+
+There would be duplication of notifications that accounts for the time when producer services will be publishing to both
+Service bus and Event grid at any time during migration.For example Storage service by default publish to both.We have
+to use Publish flags carefully to avoid duplication  
\ No newline at end of file
diff --git a/provider/notification-azure/PLAYBOOK_FOR_TOPIC_CREATION.md b/provider/notification-azure/docs/PLAYBOOK_FOR_TOPIC_CREATION.md
similarity index 100%
rename from provider/notification-azure/PLAYBOOK_FOR_TOPIC_CREATION.md
rename to provider/notification-azure/docs/PLAYBOOK_FOR_TOPIC_CREATION.md
diff --git a/provider/notification-azure/pom.xml b/provider/notification-azure/pom.xml
index 40f6b48feed203ace47de72652ace01ad81f12a0..5a324bcada1460417a3ccfbd9e60f3db49e72d6a 100644
--- a/provider/notification-azure/pom.xml
+++ b/provider/notification-azure/pom.xml
@@ -18,7 +18,7 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <artifactId>notification-azure</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.12.0-SNAPSHOT</version>
     <name>notification-azure</name>
     <description>Azure implementation for Notification service</description>
     <packaging>jar</packaging>
@@ -26,7 +26,7 @@
   <parent>
     <groupId>org.opengroup.osdu</groupId>
     <artifactId>os-notification</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.12.0-SNAPSHOT</version>
     <relativePath>../../pom.xml</relativePath>
   </parent>
 
@@ -35,18 +35,30 @@
     <maven.compiler.target>${java.version}</maven.compiler.target>
     <maven.compiler.source>${java.version}</maven.compiler.source>
     <jacoco-maven-plugin.version>0.8.2</jacoco-maven-plugin.version>
-    <osdu.notification-core.version>0.9.0-SNAPSHOT</osdu.notification-core.version>
+    <osdu.notification-core.version>0.12.0-SNAPSHOT</osdu.notification-core.version>
     <springframework.version>4.3.0.RELEASE</springframework.version>
-    <reactor.netty.version>0.9.0.RELEASE</reactor.netty.version>
+    <reactor.netty.version>0.11.0.RELEASE</reactor.netty.version>
     <reactor.core.version>3.3.0.RELEASE</reactor.core.version>
-    <osdu.corelibazure.version>0.0.66</osdu.corelibazure.version>
+    <osdu.corelibazure.version>0.11.0</osdu.corelibazure.version>
     <junit.version>5.6.0</junit.version>
     <jjwt.version>3.8.1</jjwt.version>
     <mockito.version>2.23.0</mockito.version>
+    <spring-boot.version>2.1.18.RELEASE</spring-boot.version>
+    <jackson.version>2.11.4</jackson.version>
+    <reactor-core.version>3.4.6</reactor-core.version>
+    <reactor-netty.version>1.0.7</reactor-netty.version>
+    <oauth2-oidc-sdk.version>6.0</oauth2-oidc-sdk.version>
   </properties>
 
   <dependencyManagement>
     <dependencies>
+      <dependency>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-dependencies</artifactId>
+        <version>${spring-boot.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
       <!-- Inherit managed dependencies from core-lib-azure -->
       <dependency>
         <groupId>org.opengroup.osdu</groupId>
@@ -91,11 +103,45 @@
       </exclusions>
     </dependency>
 
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-core</artifactId>
+      <version>${jackson.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+      <version>${jackson.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.fasterxml.jackson.dataformat</groupId>
+      <artifactId>jackson-dataformat-xml</artifactId>
+      <version>${jackson.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>io.projectreactor.netty</groupId>
+      <artifactId>reactor-netty</artifactId>
+      <version>${reactor-netty.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>io.projectreactor</groupId>
+      <artifactId>reactor-core</artifactId>
+      <version>${reactor-core.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.nimbusds</groupId>
+      <artifactId>oauth2-oidc-sdk</artifactId>
+      <version>${oauth2-oidc-sdk.version}</version>
+    </dependency>
+
 
     <!-- Azure Dependencies -->
     <dependency>
-      <groupId>com.microsoft.azure</groupId>
-      <artifactId>azure-active-directory-spring-boot-starter</artifactId>
+      <groupId>com.azure.spring</groupId>
+      <artifactId>azure-spring-boot-starter-active-directory</artifactId>
     </dependency>
 
     <!-- Test Dependencies -->
@@ -116,6 +162,11 @@
       <version>${junit.version}</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-junit-jupiter</artifactId>
@@ -163,7 +214,6 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
-        <version>2.4.2</version>
         <configuration>
           <useSystemClassLoader>false</useSystemClassLoader>
           <threadCount>1</threadCount>
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/Application.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/Application.java
index 79a9ffdb69a44139abcefd6ad4f0b292256ca62f..c9f2e556dc0a4d03d5b936907a21be12b716267e 100644
--- a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/Application.java
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/Application.java
@@ -14,18 +14,48 @@
 
 package org.opengroup.osdu.notification.provider.azure;
 
+import org.opengroup.osdu.notification.provider.azure.messageBus.interfaces.ISubscriptionManager;
+import org.opengroup.osdu.notification.provider.azure.messageBus.thread.ThreadScopeBeanFactoryPostProcessor;
+import org.opengroup.osdu.notification.provider.azure.util.AzureServiceBusConfig;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.scheduling.annotation.EnableAsync;
 
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
 @SpringBootApplication
 @ComponentScan({"org.opengroup.osdu"})
 @EnableAsync
 public class Application {
 
     public static void main(String[] args) {
-        SpringApplication.run(new Class[]{Application.class}, args);
+
+        ApplicationContext context = SpringApplication.run(new Class[]{Application.class}, args);
+        // Subscribe To Notification Event for Service Bus Notification Processing
+        AzureServiceBusConfig azureServiceBusConfig = context.getBean(AzureServiceBusConfig.class);
+        if (Boolean.parseBoolean(azureServiceBusConfig.getServiceBusEnabled())) {
+            ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
+            ISubscriptionManager subscriptionManager = context.getBean(ISubscriptionManager.class);
+            /*
+              Here the initialSubscriptionManagerDelay is used to have a delay before the first execution.
+              Every consecutive execution will take place after a delay of consecutiveSubscriptionManagerDelay.
+              If any of the execution exceeds the time consecutiveSubscriptionManagerDelay then next execution
+              will begin immediately after the current execution is completed.
+             */
+            executorService.scheduleAtFixedRate(subscriptionManager, Integer.parseUnsignedInt(azureServiceBusConfig.getInitialSubscriptionManagerDelay()),
+                    Integer.parseUnsignedInt(azureServiceBusConfig.getConsecutiveSubscriptionManagerDelay()), TimeUnit.SECONDS);
+        }
+    }
+
+    @Bean
+    public static BeanFactoryPostProcessor beanFactoryPostProcessor() {
+        return new ThreadScopeBeanFactoryPostProcessor();
     }
 }
 
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/MessageHandler.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/MessageHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..bef7ffd10d50865a05591beaa13e90394ff9c882
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/MessageHandler.java
@@ -0,0 +1,52 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus;
+
+import com.microsoft.azure.servicebus.ExceptionPhase;
+import com.microsoft.azure.servicebus.IMessage;
+import com.microsoft.azure.servicebus.IMessageHandler;
+import com.microsoft.azure.servicebus.SubscriptionClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.CompletableFuture;
+
+public class MessageHandler implements IMessageHandler {
+
+    private final static Logger LOGGER = LoggerFactory.getLogger(MessageHandler.class);
+    private final SubscriptionClient receiveClient;
+    private ProcessNotification processNotification;
+
+    public MessageHandler(SubscriptionClient client, ProcessNotification processNotification) {
+        this.receiveClient = client;
+        this.processNotification = processNotification;
+    }
+
+    @Override
+    public CompletableFuture<Void> onMessageAsync(IMessage message) {
+        try {
+            this.processNotification.performNotification(message, receiveClient.getSubscriptionName());
+            return this.receiveClient.completeAsync(message.getLockToken());
+        } catch (Exception e) {
+            LOGGER.error("Unable to process the Notification : " + e);
+            return this.receiveClient.abandonAsync(message.getLockToken());
+        }
+    }
+
+    @Override
+    public void notifyException(Throwable throwable, ExceptionPhase exceptionPhase) {
+        LOGGER.error("{} - {}", exceptionPhase, throwable.getMessage());
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/ProcessNotification.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/ProcessNotification.java
new file mode 100644
index 0000000000000000000000000000000000000000..e33e641f59ce8c0caa222c77574f5376e124e388
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/ProcessNotification.java
@@ -0,0 +1,72 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus;
+
+import com.microsoft.azure.servicebus.IMessage;
+import org.opengroup.osdu.core.common.http.HttpResponse;
+import org.opengroup.osdu.core.common.model.http.DpsHeaders;
+import org.opengroup.osdu.notification.provider.azure.messageBus.thread.ThreadScopeContextHolder;
+import org.opengroup.osdu.notification.provider.azure.models.NotificationContent;
+import org.opengroup.osdu.notification.provider.azure.messageBus.extractor.RequestBodyAdapter;
+import org.opengroup.osdu.notification.provider.azure.messageBus.thread.ThreadDpsHeaders;
+import org.opengroup.osdu.notification.provider.azure.util.MDCContextMap;
+import org.opengroup.osdu.notification.service.NotificationHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConditionalOnExpression("${azure.serviceBus.enabled:true} || ${azure.eventGridToServiceBus.enabled:true}")
+public class ProcessNotification {
+    private final String NOT_ACKNOWLEDGE = "message not acknowledged by client";
+    private final static Logger LOGGER = LoggerFactory.getLogger(ProcessNotification.class);
+    @Autowired
+    private NotificationHandler notificationHandler;
+    @Autowired
+    private RequestBodyAdapter requestBodyAdapter;
+    @Autowired
+    private ThreadDpsHeaders dpsHeaders;
+    @Autowired
+    private MDCContextMap mdcContextMap;
+
+    public void performNotification(IMessage message, String subscriptionName) throws Exception {
+        try {
+            NotificationContent notificationContent = requestBodyAdapter.extractNotificationContent(message, subscriptionName);
+
+            String dataPartitionId = notificationContent.getExtractAttributes().get(DpsHeaders.DATA_PARTITION_ID);
+            String correlationId = notificationContent.getExtractAttributes().get(DpsHeaders.CORRELATION_ID);
+
+            MDC.setContextMap(mdcContextMap.getContextMap(correlationId, dataPartitionId));
+            dpsHeaders.setThreadContext(dataPartitionId, correlationId);
+
+            LOGGER.info("Notification process started for message with id: {}", message.getMessageId());
+
+            HttpResponse response = notificationHandler.notifySubscriber(notificationContent.getNotificationId(),
+                    notificationContent.getData(), notificationContent.getExtractAttributes());
+            if (!response.isSuccessCode()) {
+                throw new Exception(NOT_ACKNOWLEDGE);
+            }
+        } catch (Exception e) {
+            LOGGER.error(String.format("An error occurred performing Notification for message with ID: ", message.getMessageId()), e);
+            throw e;
+        } finally {
+            ThreadScopeContextHolder.getContext().clear();
+            MDC.clear();
+        }
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/SubscriptionClientFactImpl.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/SubscriptionClientFactImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..a42ca37f435a0864f5c43e5d6a412d077cf7ffbb
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/SubscriptionClientFactImpl.java
@@ -0,0 +1,42 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus;
+
+import com.microsoft.azure.servicebus.SubscriptionClient;
+import com.microsoft.azure.servicebus.primitives.ServiceBusException;
+import org.opengroup.osdu.azure.servicebus.ISubscriptionClientFactory;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConditionalOnExpression("${azure.serviceBus.enabled:true} || ${azure.eventGridToServiceBus.enabled:true}")
+public class SubscriptionClientFactImpl {
+    private final static Logger LOGGER = LoggerFactory.getLogger(SubscriptionClientFactImpl.class);
+    @Autowired
+    private ISubscriptionClientFactory subscriptionClientFactory;
+
+    public SubscriptionClient getSubscriptionClient(String dataPartition, String sbTopic, String sbSubscription) throws ServiceBusException, InterruptedException {
+        try {
+            return subscriptionClientFactory.getClient(dataPartition, sbTopic, sbSubscription);
+        } catch (ServiceBusException | InterruptedException e) {
+            LOGGER.error("Unexpected error creating Subscription Client", e);
+            throw new AppException(500, "Server Error", "Unexpected error creating Subscription Client", e);
+        }
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/SubscriptionManagerImpl.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/SubscriptionManagerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..9edeecf9f76f048e289361c2b47a0439d587aa36
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/SubscriptionManagerImpl.java
@@ -0,0 +1,139 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus;
+
+import com.microsoft.azure.servicebus.MessageHandlerOptions;
+import com.microsoft.azure.servicebus.SubscriptionClient;
+import com.microsoft.azure.servicebus.management.ManagementClient;
+import com.microsoft.azure.servicebus.primitives.ConnectionStringBuilder;
+import com.microsoft.azure.servicebus.primitives.ServiceBusException;
+import org.opengroup.osdu.azure.cosmosdb.CosmosStore;
+import org.opengroup.osdu.azure.partition.PartitionInfoAzure;
+import org.opengroup.osdu.azure.partition.PartitionServiceClient;
+import org.opengroup.osdu.azure.serviceBusManager.IManagementClientFactory;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.notification.Subscription;
+import org.opengroup.osdu.core.common.model.tenant.TenantInfo;
+import org.opengroup.osdu.core.common.notification.ISubscriptionFactory;
+import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory;
+import org.opengroup.osdu.notification.provider.azure.messageBus.interfaces.ISubscriptionManager;
+import org.opengroup.osdu.notification.provider.azure.messageBus.models.TopicSubscriptions;
+import org.opengroup.osdu.notification.provider.azure.util.AzureServiceBusConfig;
+import org.opengroup.osdu.notification.provider.azure.util.AzureCosmosProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.stereotype.Component;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+
+@Component
+@ConditionalOnExpression("${azure.serviceBus.enabled:true} || ${azure.eventGridToServiceBus.enabled:true}")
+public class SubscriptionManagerImpl implements ISubscriptionManager {
+    private final static Logger LOGGER = LoggerFactory.getLogger(SubscriptionManagerImpl.class);
+    @Autowired
+    private TopicSubscriptions topicSubscriptions;
+    @Autowired
+    private SubscriptionClientFactImpl subscriptionClientFactory;
+    @Autowired
+    private ProcessNotification processNotification;
+    @Autowired
+    private ITenantFactory tenantFactory;
+    @Autowired
+    private ISubscriptionFactory subscriptionFactory;
+    @Autowired
+    private PartitionServiceClient partitionService;
+    @Autowired
+    private CosmosStore cosmosStore;
+    @Autowired
+    private AzureCosmosProperties azureCosmosProperties;
+    @Autowired
+    private AzureServiceBusConfig azureServiceBusConfig;
+    @Autowired
+    private IManagementClientFactory factory;
+
+    @Override
+    public void subscribeNotificationsEvent() {
+
+        List<String> tenantList = tenantFactory.listTenantInfo().stream().map(TenantInfo::getDataPartitionId)
+                .collect(Collectors.toList());
+        ExecutorService executorService = Executors
+                .newFixedThreadPool(Integer.parseUnsignedInt(azureServiceBusConfig.getNThreads()));
+        for (String partition : tenantList) {
+            try {
+                List<Subscription> subscriptionsList = cosmosStore.findAllItems(partition, azureCosmosProperties.cosmosDBName(),
+                        azureCosmosProperties.registerSubscriptionContainerName(), Subscription.class);
+
+                ManagementClient managementClient = factory.getManager(partition);
+                for (Subscription subscription : subscriptionsList) {
+                    // To check if its a not new subscription.
+                    if (!this.topicSubscriptions.checkIfNewTopicSubscription(partition, subscription.getTopic(), subscription.getNotificationId())) {
+                        // Update existing subscriptions and skip registration
+                        this.topicSubscriptions.updateCurrentTopicSubscriptions(partition, subscription.getTopic(), subscription.getNotificationId());
+
+                    } else {
+
+                        /* This check is added if a Cosmos subscription is created but the corresponding service bus
+                       subscription is still not created or creation is in progress.We do not register message handler
+                       with the subscription client as it will throw entity not found exception and unregistering is not supported.
+                       Check if its a new Subscription Client */
+                        if (managementClient.topicExists(subscription.getTopic()) && managementClient.subscriptionExists(subscription.getTopic(), subscription.getNotificationId())) {
+                            try {
+                                SubscriptionClient subscriptionClient = this.subscriptionClientFactory
+                                        .getSubscriptionClient(partition, subscription.getTopic(), subscription.getNotificationId());
+                                registerMessageHandler(subscriptionClient, executorService);
+                                this.topicSubscriptions.updateCurrentTopicSubscriptions(partition, subscription.getTopic(), subscription.getNotificationId());
+                            } catch (InterruptedException | ServiceBusException e) {
+                                LOGGER.error("Error while creating or registering subscription client {}", e.getMessage(), e);
+                            } catch (Exception e) {
+                                LOGGER.error("Unknown exception occurred while creating or registering subscription client: ", e);
+                            }
+                        }
+                    }
+                }
+
+            } catch (AppException e) {
+                LOGGER.error("Error creating Cosmos Client {}", e.getMessage(), e);
+            } catch (Exception e) {
+                LOGGER.error("An exception occurred while subscribing to Notification Event : ", e);
+            }
+        }
+        this.topicSubscriptions.clearTopicSubscriptions();
+
+    }
+
+    private void registerMessageHandler(SubscriptionClient subscriptionClient, ExecutorService executorService) throws ServiceBusException, InterruptedException {
+
+        MessageHandler messageHandler = new MessageHandler(subscriptionClient, processNotification);
+        subscriptionClient.registerMessageHandler(
+                messageHandler,
+                new MessageHandlerOptions(Integer.parseUnsignedInt(azureServiceBusConfig.getMaxConcurrentCalls()),
+                        false,
+                        Duration.ofSeconds(Integer.parseUnsignedInt(azureServiceBusConfig.getMaxLockRenewDurationInSeconds())),
+                        Duration.ofSeconds(1)
+                ),
+                executorService);
+    }
+
+    @Override
+    public void run() {
+        subscribeNotificationsEvent();
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/extractor/EventGridServiceBusRequestBodyExtractor.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/extractor/EventGridServiceBusRequestBodyExtractor.java
new file mode 100644
index 0000000000000000000000000000000000000000..cac95d9777a48303350beb26c87200fc80e4a6af
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/extractor/EventGridServiceBusRequestBodyExtractor.java
@@ -0,0 +1,97 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus.extractor;
+
+import com.google.common.base.Preconditions;
+import com.google.gson.Gson;
+import com.microsoft.azure.servicebus.IMessage;
+import lombok.SneakyThrows;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.notification.provider.azure.models.NotificationEventGridServiceBusRequest;
+import org.opengroup.osdu.notification.provider.azure.models.NotificationRecordsChangedData;
+import org.opengroup.osdu.notification.provider.azure.messageBus.interfaces.IPullRequestBodyExtractor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.ScopedProxyMode;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+@Component
+@Scope(value = "ThreadScope", proxyMode = ScopedProxyMode.TARGET_CLASS)
+@ConditionalOnProperty(value = "azure.eventGridToServiceBus.enabled", havingValue = "true", matchIfMissing = false)
+public class EventGridServiceBusRequestBodyExtractor implements IPullRequestBodyExtractor {
+    private static final Gson GSON = new Gson();
+    private NotificationEventGridServiceBusRequest notificationRequest;
+    private NotificationRecordsChangedData notificationRecordsChangedData;
+    private IMessage message;
+
+    public void InitializeExtractor(IMessage message) {
+
+        this.message = message;
+        this.notificationRequest = extractNotificationRequestFromMessageBody();
+    }
+
+    public Map<String, String> extractAttributesFromRequestBody() {
+
+        Map<String, String> attributes = new HashMap<>();
+        attributes.put("correlation-id", this.notificationRecordsChangedData.getCorrelationId());
+        attributes.put("data-partition-id", this.notificationRecordsChangedData.getDataPartitionId());
+        attributes.put("account-id", this.notificationRecordsChangedData.getAccountId());
+        return attributes;
+    }
+
+    public String extractDataFromRequestBody() {
+
+        return notificationRecordsChangedData.getData().toString();
+    }
+
+    @SneakyThrows
+    private NotificationEventGridServiceBusRequest extractNotificationRequestFromMessageBody() {
+
+        NotificationEventGridServiceBusRequest notificationRequest = null;
+        try {
+            String requestBody = new String(message.getMessageBody().getBinaryData().get(0), UTF_8);
+            NotificationEventGridServiceBusRequest[] notificationRequestArray = GSON.fromJson(requestBody, NotificationEventGridServiceBusRequest[].class);
+            notificationRequest = notificationRequestArray[0];
+            extractNotificationData(notificationRequest);
+        } catch (Exception e) {
+            throw new AppException(HttpStatus.BAD_REQUEST.value(), "Request payload parsing error",
+                    "Unable to parse request payload.", "Request contents are null or empty", e);
+        }
+        return notificationRequest;
+    }
+
+    private void extractNotificationData(NotificationEventGridServiceBusRequest notificationRequest) {
+
+        String notifData = notificationRequest.getData().toString();
+        NotificationRecordsChangedData notificationRecordsChangedData = GSON.fromJson(notifData, NotificationRecordsChangedData.class);
+        verifyNotificationData(notificationRecordsChangedData);
+        this.notificationRecordsChangedData = notificationRecordsChangedData;
+    }
+
+    private void verifyNotificationData(NotificationRecordsChangedData notificationRecordsChangedData) {
+
+        Preconditions.checkNotNull(notificationRecordsChangedData, "Request payload parsing error");
+        Preconditions.checkNotNull(notificationRecordsChangedData.getData(), "Request payload parsing error");
+        Preconditions.checkNotNull(notificationRecordsChangedData.getCorrelationId(), "Request payload parsing error");
+        Preconditions.checkNotNull(notificationRecordsChangedData.getDataPartitionId(), "Request payload parsing error");
+    }
+}
+
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/extractor/RequestBodyAdapter.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/extractor/RequestBodyAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c1d9db4b231966ec112249f1cf8915f2ddb5c51
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/extractor/RequestBodyAdapter.java
@@ -0,0 +1,40 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus.extractor;
+
+import com.microsoft.azure.servicebus.IMessage;
+import org.opengroup.osdu.notification.provider.azure.models.NotificationContent;
+import org.opengroup.osdu.notification.provider.azure.messageBus.interfaces.IPullRequestBodyExtractor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Component
+@ConditionalOnExpression("${azure.serviceBus.enabled:true} || ${azure.eventGridToServiceBus.enabled:true}")
+public class RequestBodyAdapter {
+    @Autowired
+    IPullRequestBodyExtractor extractor;
+
+    public NotificationContent extractNotificationContent(IMessage message, String subscriptionName) {
+
+        extractor.InitializeExtractor(message);
+        String notificationData = extractor.extractDataFromRequestBody();
+        Map<String, String> headerAttributes = extractor.extractAttributesFromRequestBody();
+        NotificationContent notificationContent = NotificationContent.mapFrom(subscriptionName, notificationData, headerAttributes, false);
+        return notificationContent;
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/extractor/ServiceBusRequestBodyExtractor.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/extractor/ServiceBusRequestBodyExtractor.java
new file mode 100644
index 0000000000000000000000000000000000000000..070029c6be6fb7e2f73c50636d0047517fdaf57d
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/extractor/ServiceBusRequestBodyExtractor.java
@@ -0,0 +1,95 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus.extractor;
+
+import com.google.common.base.Preconditions;
+import com.google.gson.Gson;
+import com.microsoft.azure.servicebus.IMessage;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.notification.provider.azure.models.NotificationRecordsChangedData;
+import org.opengroup.osdu.notification.provider.azure.models.NotificationServiceBusRequest;
+import org.opengroup.osdu.notification.provider.azure.messageBus.interfaces.IPullRequestBodyExtractor;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.ScopedProxyMode;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+@Component
+@Scope(value = "ThreadScope", proxyMode = ScopedProxyMode.TARGET_CLASS)
+@ConditionalOnProperty(value = "azure.serviceBus.enabled", havingValue = "true", matchIfMissing = false)
+public class ServiceBusRequestBodyExtractor implements IPullRequestBodyExtractor {
+    private IMessage message;
+    private static final Gson GSON = new Gson();
+    private NotificationServiceBusRequest notificationRequest;
+    private NotificationRecordsChangedData notificationRecordsChangedData;
+
+    public void InitializeExtractor(IMessage message) {
+
+        this.message = message;
+        this.notificationRequest = extractNotificationRequestFromMessageBody();
+    }
+
+    public Map<String, String> extractAttributesFromRequestBody() {
+
+        Map<String, String> attributes = new HashMap<>();
+        attributes.put("correlation-id", this.notificationRecordsChangedData.getCorrelationId());
+        attributes.put("data-partition-id", this.notificationRecordsChangedData.getDataPartitionId());
+        attributes.put("account-id", this.notificationRecordsChangedData.getAccountId());
+        return attributes;
+    }
+
+    public String extractDataFromRequestBody() {
+        return notificationRecordsChangedData.getData().toString();
+    }
+
+    private NotificationServiceBusRequest extractNotificationRequestFromMessageBody() {
+
+        NotificationServiceBusRequest notificationRequest = null;
+        try {
+            String requestBody = new String(message.getMessageBody().getBinaryData().get(0), UTF_8);
+            NotificationServiceBusRequest notificationRequestArray = GSON.fromJson(requestBody, NotificationServiceBusRequest.class);
+            notificationRequest = notificationRequestArray;
+            extractNotificationData(notificationRequest);
+        } catch (Exception e) {
+            throw new AppException(HttpStatus.BAD_REQUEST.value(), "Request payload parsing error",
+                    "Unable to parse request payload.", "Request contents are null or empty", e);
+        }
+        return notificationRequest;
+
+    }
+
+    private void extractNotificationData(NotificationServiceBusRequest notificationRequest) {
+
+        String notifData = notificationRequest.getMessage().toString();
+        NotificationRecordsChangedData notificationRecordsChangedData = GSON.fromJson(notifData, NotificationRecordsChangedData.class);
+        verifyNotificationData(notificationRecordsChangedData);
+        this.notificationRecordsChangedData = notificationRecordsChangedData;
+    }
+
+    private void verifyNotificationData(NotificationRecordsChangedData notificationRecordsChangedData) {
+
+        Preconditions.checkNotNull(notificationRecordsChangedData, "Request payload parsing error");
+        Preconditions.checkNotNull(notificationRecordsChangedData.getData(), "Request payload parsing error");
+        Preconditions.checkNotNull(notificationRecordsChangedData.getCorrelationId(), "Request payload parsing error");
+        Preconditions.checkNotNull(notificationRecordsChangedData.getDataPartitionId(), "Request payload parsing error");
+    }
+
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/interfaces/IPullRequestBodyExtractor.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/interfaces/IPullRequestBodyExtractor.java
new file mode 100644
index 0000000000000000000000000000000000000000..bea354845a940a7897f4e4f97d311d969c8d7e3c
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/interfaces/IPullRequestBodyExtractor.java
@@ -0,0 +1,27 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus.interfaces;
+
+import com.microsoft.azure.servicebus.IMessage;
+
+import java.util.Map;
+
+public interface IPullRequestBodyExtractor {
+    void InitializeExtractor(IMessage message);
+
+    Map<String, String> extractAttributesFromRequestBody();
+
+    String extractDataFromRequestBody();
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/interfaces/ISubscriptionManager.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/interfaces/ISubscriptionManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c8e726c4351a26fc38b0aff842b8b728a9274e9
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/interfaces/ISubscriptionManager.java
@@ -0,0 +1,19 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus.interfaces;
+
+public interface ISubscriptionManager extends Runnable {
+    void subscribeNotificationsEvent();
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/models/TopicSubscriptions.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/models/TopicSubscriptions.java
new file mode 100644
index 0000000000000000000000000000000000000000..92eb9abbaf015c5605d4990eece4ab00b13070f7
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/models/TopicSubscriptions.java
@@ -0,0 +1,52 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus.models;
+
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Component
+public class TopicSubscriptions {
+
+    private Map<String, Map<String, List<String>>> existingTopicSubscriptions = new HashMap<>();
+    private Map<String, Map<String, List<String>>> currentTopicSubscriptions = new HashMap<>();
+
+    public boolean checkIfNewTopicSubscription(String partition, String sbTopicName, String subscriptionName) {
+
+        if (existingTopicSubscriptions.get(partition) == null ||
+                existingTopicSubscriptions.get(partition).get(sbTopicName) == null ||
+                !existingTopicSubscriptions.get(partition).get(sbTopicName).contains(subscriptionName))
+            return true;
+        return false;
+    }
+
+    public void updateCurrentTopicSubscriptions(String partition, String sbTopicName, String subscriptionName) {
+        // Update the active subscriptions
+        currentTopicSubscriptions.putIfAbsent(partition, new HashMap<String, List<String>>());
+        currentTopicSubscriptions.get(partition).putIfAbsent(sbTopicName, new ArrayList<>());
+        currentTopicSubscriptions.get(partition).get(sbTopicName).add(subscriptionName);
+    }
+
+    public void clearTopicSubscriptions() {
+        // Deletes the old subscriptions for next run
+        this.existingTopicSubscriptions.clear();
+        this.existingTopicSubscriptions.putAll(this.currentTopicSubscriptions);
+        this.currentTopicSubscriptions.clear();
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadDpsHeaders.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadDpsHeaders.java
new file mode 100644
index 0000000000000000000000000000000000000000..b02fe38df5244618ca5cd0f9657c571780874598
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadDpsHeaders.java
@@ -0,0 +1,48 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus.thread;
+
+import org.opengroup.osdu.core.common.model.http.DpsHeaders;
+import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.context.annotation.Primary;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.ScopedProxyMode;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+@Scope(value = "ThreadScope", proxyMode = ScopedProxyMode.TARGET_CLASS)
+@ConditionalOnExpression("${azure.serviceBus.enabled:true} || ${azure.eventGridToServiceBus.enabled:true}")
+@Primary
+public class ThreadDpsHeaders extends DpsHeaders {
+    @Autowired
+    private IServiceAccountJwtClient serviceAccountJwtClient;
+
+    public void setThreadContext(String dataPartitionId, String correlationId) {
+        Map<String, String> headers = new HashMap<>();
+        headers.put(DpsHeaders.DATA_PARTITION_ID, dataPartitionId);
+        headers.put(DpsHeaders.CORRELATION_ID, correlationId);
+        String authToken = this.serviceAccountJwtClient.getIdToken(dataPartitionId);
+        headers.put(DpsHeaders.AUTHORIZATION, authToken);
+        this.addFromMap(headers);
+    }
+
+}
+
+
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadScope.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadScope.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3445775194f3986d7fbb2e7e71696789a4ad0c1
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadScope.java
@@ -0,0 +1,75 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus.thread;
+
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.beans.factory.config.Scope;
+
+/**
+ * Thread scope which allows putting data in thread scope and clearing up afterwards.
+ */
+
+public class ThreadScope implements Scope, DisposableBean {
+
+    /**
+     * Get bean for given name in the "ThreadScope".
+     */
+    public Object get(String name, ObjectFactory<?> factory) {
+        ThreadScopeContext context = ThreadScopeContextHolder.getContext();
+
+        Object result = context.getBean(name);
+        if (null == result) {
+            result = factory.getObject();
+            context.setBean(name, result);
+        }
+        return result;
+    }
+
+    /**
+     * Removes bean from scope.
+     */
+    public Object remove(String name) {
+        ThreadScopeContext context = ThreadScopeContextHolder.getContext();
+        return context.remove(name);
+    }
+
+    public void registerDestructionCallback(String name, Runnable callback) {
+        ThreadScopeContextHolder.getContext().registerDestructionCallback(name, callback);
+    }
+
+    /**
+     * Resolve the contextual object for the given key, if any. E.g. the HttpServletRequest object for key "request".
+     */
+    public Object resolveContextualObject(String key) {
+        return null;
+    }
+
+    /**
+     * Return the conversation ID for the current underlying scope, if any.
+     * <p/>
+     * In this case, it returns the thread name.
+     */
+    public String getConversationId() {
+        return Thread.currentThread().getName();
+    }
+
+    @Override
+    public void destroy() {
+        ThreadScopeContextHolder.clearContext();
+    }
+}
+
+
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadScopeBeanFactoryPostProcessor.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadScopeBeanFactoryPostProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..33ddea59efbc68b1f52d46b9f0ff577c83f075f2
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadScopeBeanFactoryPostProcessor.java
@@ -0,0 +1,26 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus.thread;
+
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+
+public class ThreadScopeBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
+
+    @Override
+    public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) {
+        factory.registerScope("ThreadScope", new ThreadScope());
+    }
+}
\ No newline at end of file
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadScopeContext.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadScopeContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..74acaebec47dacb75517075842092a40d2d74a07
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadScopeContext.java
@@ -0,0 +1,109 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus.thread;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ThreadScopeContext {
+
+    protected final Map<String, Bean> beans = new HashMap<>();
+
+    /**
+     * Get a bean value from the context.
+     *
+     * @param name bean name
+     * @return bean value or null
+     */
+    public Object getBean(String name) {
+        Bean bean = beans.get(name);
+        if (null == bean) {
+            return null;
+        }
+        return bean.object;
+    }
+
+    /**
+     * Set a bean in the context.
+     *
+     * @param name bean name
+     * @param object bean value
+     */
+    public void setBean(String name, Object object) {
+
+        Bean bean = beans.computeIfAbsent(name,k-> new Bean());
+        bean.object = object;
+    }
+
+    /**
+     * Remove a bean from the context, calling the destruction callback if any.
+     *
+     * @param name bean name
+     * @return previous value
+     */
+    public Object remove(String name) {
+        Bean bean = beans.get(name);
+        if (null != bean) {
+            beans.remove(name);
+            bean.destructionCallback.run();
+            return bean.object;
+        }
+        return null;
+    }
+
+    /**
+     * Register the given callback as to be executed after request completion.
+     *
+     * @param name The name of the bean.
+     * @param callback The callback of the bean to be executed for destruction.
+     */
+    public void registerDestructionCallback(String name, Runnable callback) {
+        Bean bean = beans.computeIfAbsent(name,k->new Bean());
+        bean.destructionCallback = callback;
+    }
+
+    /** Clear all beans and call the destruction callback. */
+    public void clear() {
+        for (Bean bean : beans.values()) {
+            if (null != bean.destructionCallback) {
+                bean.destructionCallback.run();
+            }
+        }
+        beans.clear();
+    }
+
+    /** Private class storing bean name and destructor callback. */
+    private class Bean {
+
+        private Object object;
+        private Runnable destructionCallback;
+
+        public Object getObject() {
+            return object;
+        }
+
+        public void setObject(Object object) {
+            this.object = object;
+        }
+
+        public Runnable getDestructionCallback() {
+            return destructionCallback;
+        }
+
+        public void setDestructionCallback(Runnable destructionCallback) {
+            this.destructionCallback = destructionCallback;
+        }
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadScopeContextHolder.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadScopeContextHolder.java
new file mode 100644
index 0000000000000000000000000000000000000000..54c43f6f7dc945659873378f70338c5f97d097b3
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadScopeContextHolder.java
@@ -0,0 +1,47 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus.thread;
+
+public final class ThreadScopeContextHolder {
+
+    private static final ThreadLocal<ThreadScopeContext> CONTEXT_HOLDER = ThreadLocal
+            .withInitial(ThreadScopeContext::new);
+
+    private ThreadScopeContextHolder() {
+        // utility object, not allowed to create instances
+    }
+
+    /**
+     * Get the thread specific context.
+     *
+     * @return thread scoped context
+     */
+    public static ThreadScopeContext getContext() {
+        return CONTEXT_HOLDER.get();
+    }
+
+    /**
+     * Set the thread specific context.
+     *
+     * @param context thread scoped context
+     */
+    public static void setContext(ThreadScopeContext context) {
+        CONTEXT_HOLDER.set(context);
+    }
+
+    public static void clearContext() {
+        CONTEXT_HOLDER.remove();
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadSignatureService.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadSignatureService.java
new file mode 100644
index 0000000000000000000000000000000000000000..efadcda499e75ef2479aabcfa2d1034dfa1b7ad0
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/messageBus/thread/ThreadSignatureService.java
@@ -0,0 +1,142 @@
+package org.opengroup.osdu.notification.provider.azure.messageBus.thread;
+
+import com.google.common.base.Strings;
+import com.google.gson.Gson;
+import org.apache.commons.lang3.StringUtils;
+import org.opengroup.osdu.core.common.cryptographic.HmacData;
+import org.opengroup.osdu.core.common.cryptographic.ISignatureService;
+import org.opengroup.osdu.core.common.cryptographic.SignatureServiceException;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.context.annotation.Primary;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.ScopedProxyMode;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.bind.DatatypeConverter;
+import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
+import java.util.Base64;
+
+@Component
+@Scope(value = "ThreadScope", proxyMode = ScopedProxyMode.TARGET_CLASS)
+@ConditionalOnExpression("${azure.serviceBus.enabled:true} || ${azure.eventGridToServiceBus.enabled:true}")
+@Primary
+public class ThreadSignatureService implements ISignatureService {
+    private static final String HMAC_SHA_256 = "HmacSHA256";
+    private static final String DATA_FORMAT = "{\"expireMillisecond\": \"%s\",\"hashMechanism\": \"hmacSHA256\",\"endpointUrl\": \"%s\",\"nonce\": \"%s\"}";
+    private static final String NOTIFICATION_SERVICE = "de-notification-service";
+    private static final long EXPIRE_DURATION = 30000L;
+    private static final String INVALID_SIGNATURE = "Invalid signature";
+    private static final String ERROR_GENERATING_SIGNATURE = "Error generating the signature";
+    private static final String SIGNATURE_EXPIRED = "Signature is expired";
+    private static final String MISSING_HMAC_SIGNATURE = "HMAC signature should not be null or empty";
+    private static final String MISSING_SECRET_VALUE = "Secret should not be null or empty";
+    private static final String MISSING_ATTRIBUTES_IN_SIGNATURE = "Missing url or nonce or expire time in the signature";
+
+    public ThreadSignatureService() {
+    }
+
+    public String getSignedSignature(String url, String secret) throws SignatureServiceException {
+        if (!Strings.isNullOrEmpty(url) && !Strings.isNullOrEmpty(secret)) {
+            long currentTime = System.currentTimeMillis();
+            String expireTime = String.valueOf(currentTime + 30000L);
+            String timeStamp = String.valueOf(currentTime);
+
+            try {
+                String nonce = DatatypeConverter.printHexBinary(this.generateRandomBytes(16)).toLowerCase();
+                String data = String.format("{\"expireMillisecond\": \"%s\",\"hashMechanism\": \"hmacSHA256\",\"endpointUrl\": \"%s\",\"nonce\": \"%s\"}", expireTime, url, nonce);
+                byte[] signature = this.getSignature(secret, nonce, timeStamp, data);
+                byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
+                String dataBytesEncoded = Base64.getEncoder().encodeToString(dataBytes);
+                StringBuilder output = new StringBuilder();
+                output.append(dataBytesEncoded).append(".").append(DatatypeConverter.printHexBinary(signature).toLowerCase());
+                return output.toString();
+            } catch (Exception var13) {
+                throw new SignatureServiceException("Error generating the signature", var13);
+            }
+        } else {
+            throw new SignatureServiceException("Error generating the signature");
+        }
+    }
+
+    public String getSignedSignature(String url, String secret, String expireTime, String nonce) throws SignatureServiceException {
+        if (!Strings.isNullOrEmpty(url) && !Strings.isNullOrEmpty(secret) && StringUtils.isNumeric(expireTime)) {
+            long expiry = Long.parseLong(expireTime);
+            if (System.currentTimeMillis() > expiry) {
+                throw new SignatureServiceException("Signature is expired");
+            } else {
+                String timeStamp = String.valueOf(expiry - 30000L);
+                String data = String.format("{\"expireMillisecond\": \"%s\",\"hashMechanism\": \"hmacSHA256\",\"endpointUrl\": \"%s\",\"nonce\": \"%s\"}", expireTime, url, nonce);
+
+                try {
+                    byte[] signature = this.getSignature(secret, nonce, timeStamp, data);
+                    return DatatypeConverter.printHexBinary(signature).toLowerCase();
+                } catch (Exception var10) {
+                    throw new SignatureServiceException("Error generating the signature", var10);
+                }
+            }
+        } else {
+            throw new SignatureServiceException("Error generating the signature");
+        }
+    }
+
+    public void verifyHmacSignature(String hmac, String secret) throws SignatureServiceException {
+        if (Strings.isNullOrEmpty(hmac)) {
+            throw new SignatureServiceException("HMAC signature should not be null or empty");
+        } else if (Strings.isNullOrEmpty(secret)) {
+            throw new SignatureServiceException("Secret should not be null or empty");
+        } else {
+            String[] tokens = hmac.split("\\.");
+            if (tokens.length != 2) {
+                throw new SignatureServiceException("Invalid signature");
+            } else {
+                byte[] dataBytes = Base64.getDecoder().decode(tokens[0]);
+                String requestSignature = tokens[1];
+                String data = new String(dataBytes, StandardCharsets.UTF_8);
+                HmacData hmacData = (HmacData)(new Gson()).fromJson(data, HmacData.class);
+                String url = hmacData.getEndpointUrl();
+                String nonce = hmacData.getNonce();
+                String expireTime = hmacData.getExpireMillisecond();
+                if (!Strings.isNullOrEmpty(url) && !Strings.isNullOrEmpty(nonce) && !Strings.isNullOrEmpty(expireTime)) {
+                    String newSignature = this.getSignedSignature(url, secret, expireTime, nonce);
+                    if (!requestSignature.equalsIgnoreCase(newSignature)) {
+                        throw new SignatureServiceException("Invalid signature");
+                    }
+                } else {
+                    throw new SignatureServiceException("Missing url or nonce or expire time in the signature");
+                }
+            }
+        }
+    }
+
+    private byte[] getSignature(String secret, String nonce, String timeStamp, String data) throws Exception {
+        byte[] secretBytes = DatatypeConverter.parseHexBinary(secret);
+        byte[] nonceBytes = DatatypeConverter.parseHexBinary(nonce);
+        byte[] encryptedNonce = this.computeHmacSha256(nonceBytes, secretBytes);
+        byte[] encryptedTimestamp = this.computeHmacSha256(timeStamp, encryptedNonce);
+        byte[] signedKey = this.computeHmacSha256("de-notification-service", encryptedTimestamp);
+        byte[] signature = this.computeHmacSha256(data, signedKey);
+        return signature;
+    }
+
+    private byte[] computeHmacSha256(String data, byte[] key) throws Exception {
+        Mac mac = Mac.getInstance("HmacSHA256");
+        mac.init(new SecretKeySpec(key, "HmacSHA256"));
+        return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
+    }
+
+    private byte[] computeHmacSha256(byte[] data, byte[] key) throws Exception {
+        Mac mac = Mac.getInstance("HmacSHA256");
+        mac.init(new SecretKeySpec(key, "HmacSHA256"));
+        return mac.doFinal(data);
+    }
+
+    private byte[] generateRandomBytes(int size) {
+        byte[] key = new byte[size];
+        SecureRandom secureRandom = new SecureRandom();
+        secureRandom.nextBytes(key);
+        return key;
+    }
+}
\ No newline at end of file
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationContent.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationContent.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3edc232272b90b1e5ab30dcb89f672eacd49dab
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationContent.java
@@ -0,0 +1,40 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.models;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+@AllArgsConstructor
+@Builder
+public class NotificationContent {
+    String NotificationId;
+    String data;
+    Map<String, String> extractAttributes;
+    boolean isHandShakeRequest;
+
+    public static NotificationContent mapFrom(String notificationId, String pubSubData, Map<String, String> attributes, boolean isHandShake) {
+        NotificationContentBuilder notificationContentBuilder = NotificationContent.builder()
+                .NotificationId(notificationId)
+                .data(pubSubData)
+                .extractAttributes(attributes)
+                .isHandShakeRequest(isHandShake);
+        return notificationContentBuilder.build();
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationRequest.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationEventGridRequest.java
similarity index 95%
rename from provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationRequest.java
rename to provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationEventGridRequest.java
index 32236c6e234268a2e0a92d05aa423661819387ff..1e3445d1526f79ea674c4715e9bd7231256d3aea 100644
--- a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationRequest.java
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationEventGridRequest.java
@@ -23,7 +23,7 @@ import lombok.NoArgsConstructor;
 @Data
 @AllArgsConstructor
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
-public class NotificationRequest {
+public class NotificationEventGridRequest {
 
     private String id;
 
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationEventGridServiceBusRequest.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationEventGridServiceBusRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..da13b71ccb3cf94e804198eaff6b87fc70ab57d8
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationEventGridServiceBusRequest.java
@@ -0,0 +1,42 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.models;
+
+import com.google.gson.JsonObject;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class NotificationEventGridServiceBusRequest {
+    private String id;
+
+    private String eventType;
+
+    private String subject;
+
+    private JsonObject data;
+
+    private String dataVersion;
+
+    private String eventTime;
+
+    private String metadataVersion;
+
+    private String topic;
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationServiceBusRequest.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationServiceBusRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..02f559d11595915c0c4bb82e8c2d3040094b7f57
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/models/NotificationServiceBusRequest.java
@@ -0,0 +1,28 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.models;
+
+import com.google.gson.JsonObject;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class NotificationServiceBusRequest {
+    private JsonObject message;
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/pubsub/EventGridRequestBodyExtractor.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/pubsub/EventGridRequestBodyExtractor.java
index b3c4aeb6b55e27936af4e0be2d42d66b4e00cbd0..fb5ba29ef3892508a195680d253c989eea209219 100644
--- a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/pubsub/EventGridRequestBodyExtractor.java
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/pubsub/EventGridRequestBodyExtractor.java
@@ -22,14 +22,14 @@ import com.google.gson.JsonObject;
 import lombok.SneakyThrows;
 import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
 import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.notification.provider.azure.models.NotificationContent;
 import org.opengroup.osdu.notification.provider.azure.models.HandshakeRequestData;
 import org.opengroup.osdu.notification.provider.azure.models.NotificationRecordsChangedData;
-import org.opengroup.osdu.notification.provider.azure.models.NotificationRequest;
+import org.opengroup.osdu.notification.provider.azure.models.NotificationEventGridRequest;
 import org.opengroup.osdu.notification.provider.interfaces.IPubsubRequestBodyExtractor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.stereotype.Component;
-import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.context.annotation.RequestScope;
 
 import javax.servlet.http.HttpServletRequest;
@@ -56,10 +56,11 @@ public class EventGridRequestBodyExtractor implements IPubsubRequestBodyExtracto
     private final HttpServletRequest httpServletRequest;
     private final JaxRsDpsLog logger;
 
-    private final NotificationRequest notificationRequest;
+    private final NotificationEventGridRequest notificationRequest;
     private NotificationRecordsChangedData notificationRecordsChangedData;
     private HandshakeRequestData handshakeRequestData;
     private boolean isHandshakeRequest;
+    private NotificationContent notificationContent;
 
     @Autowired
     public EventGridRequestBodyExtractor(HttpServletRequest httpServletRequest, JaxRsDpsLog log) {
@@ -151,12 +152,12 @@ public class EventGridRequestBodyExtractor implements IPubsubRequestBodyExtracto
      */
     @SneakyThrows
     // TODO : @komakkar sanitize the exceptions to match the SpringExceptionMapper and throw ValidationException
-    private NotificationRequest extractNotificationRequestFromHttpRequest() {
-        NotificationRequest notificationRequest = null;
+    private NotificationEventGridRequest extractNotificationRequestFromHttpRequest() {
+        NotificationEventGridRequest notificationRequest = null;
         if (this.notificationRequest == null && this.httpServletRequest.getMethod().equalsIgnoreCase("post")) {
             try {
                 String requestBody = getBody(this.httpServletRequest);
-                NotificationRequest[] notificationRequestArray = GSON.fromJson(requestBody, NotificationRequest[].class);
+                NotificationEventGridRequest[] notificationRequestArray = GSON.fromJson(requestBody, NotificationEventGridRequest[].class);
                 notificationRequest = notificationRequestArray[0];
 
                 this.isHandshakeRequest = notificationRequest.getEventType().equals(EVENTGRID_VALIDATION_EVENT);
@@ -173,12 +174,12 @@ public class EventGridRequestBodyExtractor implements IPubsubRequestBodyExtracto
         return notificationRequest;
     }
 
-    private void extractHandshakeData(NotificationRequest notificationRequest) {
+    private void extractHandshakeData(NotificationEventGridRequest notificationRequest) {
         this.handshakeRequestData = GSON.fromJson(notificationRequest.getData(), HandshakeRequestData.class);
         Preconditions.checkNotNull(this.handshakeRequestData.getValidationCode(), "Request payload parsing error handshkae");
     }
 
-    private void extractNotificationData(NotificationRequest notificationRequest) {
+    private void extractNotificationData(NotificationEventGridRequest notificationRequest) {
         NotificationRecordsChangedData notificationRecordsChangedData = GSON.fromJson(notificationRequest.getData(), NotificationRecordsChangedData.class);
         verifyNotificationData(notificationRecordsChangedData);
         this.notificationRecordsChangedData = notificationRecordsChangedData;
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureCosmosProperties.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureCosmosProperties.java
index c606785dabc1d8730bc3426d76dc8c73dab4471a..7a9fef37308bba5e0b088ea09537d7d45280672e 100644
--- a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureCosmosProperties.java
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureCosmosProperties.java
@@ -12,6 +12,9 @@ public class AzureCosmosProperties {
   @Value("${tenantinfo.container.name}")
   private String tenantInfoContainerName;
 
+  @Value("${registerSubscription.container.name}")
+  private String registerSubscriptionContainerName;
+
   @Value("${azure.cosmosdb.database}")
   private String cosmosDBName;
 
@@ -21,6 +24,12 @@ public class AzureCosmosProperties {
     return tenantInfoContainerName;
   }
 
+  @Bean
+  @Named("COSMOS_CONTAINER_NAME")
+  public String registerSubscriptionContainerName() {
+    return registerSubscriptionContainerName;
+  }
+
   @Bean
   @Named("COSMOS_DB_NAME")
   public String cosmosDBName() {
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureServiceAccountValidatorImpl.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureServiceAccountValidatorImpl.java
index 7aaccda189813531f38703cca25ee74252cc3570..7fd42f301fd5022a2c058a068b3cf5dee73fceb6 100644
--- a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureServiceAccountValidatorImpl.java
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureServiceAccountValidatorImpl.java
@@ -44,7 +44,7 @@ public class AzureServiceAccountValidatorImpl implements IServiceAccountValidato
         String appIdClaim = jwt.getClaim(APP_ID_CLAIM).asString();
 
         if(appIdClaim!= null && appIdClaim.equals(userIdentity)) {
-            logger.info("PubSub authorized");
+            logger.debug("PubSub authorized");
             return true;
         }
         return false;
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureServiceBusConfig.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureServiceBusConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9df67e2e4f6aec63c1c7c8cbbd818fff2653d05
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/AzureServiceBusConfig.java
@@ -0,0 +1,53 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.util;
+
+import lombok.Getter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@Getter
+public class AzureServiceBusConfig {
+    @Value("${executor-n-threads}")
+    private String nThreads;
+
+    @Value("${max-concurrent-calls}")
+    private String maxConcurrentCalls;
+
+    @Value("${max-lock-renew}")
+    private String maxLockRenewDurationInSeconds;
+
+    @Value("${initial-subscription-manager-delay}")
+    private String initialSubscriptionManagerDelay;
+
+    @Value("${consecutive-subscription-manager-delay}")
+    private String consecutiveSubscriptionManagerDelay;
+
+    @Value("${service-bus-enabled}")
+    private String ServiceBusEnabled;
+
+    @Value("${event-grid-to-service-bus-enabled}")
+    private String EventGridToServiceBusEnabled;
+
+    @Bean
+    public MDCContextMap mdcContextMap() {
+        return new MDCContextMap();
+    }
+
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/MDCContextMap.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/MDCContextMap.java
new file mode 100644
index 0000000000000000000000000000000000000000..57c08cb18613784974dc7260041b3a44e693d6d2
--- /dev/null
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/MDCContextMap.java
@@ -0,0 +1,30 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.util;
+
+import org.opengroup.osdu.core.common.model.http.DpsHeaders;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MDCContextMap {
+
+    public Map<String, String> getContextMap(String correlationId, String dataPartitionId) {
+        final Map<String, String> contextMap = new HashMap<>();
+        contextMap.put(DpsHeaders.CORRELATION_ID, correlationId);
+        contextMap.put(DpsHeaders.DATA_PARTITION_ID, dataPartitionId);
+        return contextMap;
+    }
+}
diff --git a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/ServiceAccountJwtAzureClientImpl.java b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/ServiceAccountJwtAzureClientImpl.java
index 934dd8672caad9ed2ad945c1af2761d640d1b7b9..88d68e6cfc9dbc3070782945b9309e5a92650784 100644
--- a/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/ServiceAccountJwtAzureClientImpl.java
+++ b/provider/notification-azure/src/main/java/org/opengroup/osdu/notification/provider/azure/util/ServiceAccountJwtAzureClientImpl.java
@@ -14,82 +14,19 @@
 
 package org.opengroup.osdu.notification.provider.azure.util;
 
-import com.auth0.jwt.JWT;
-import com.microsoft.aad.adal4j.AuthenticationContext;
-import com.microsoft.aad.adal4j.AuthenticationResult;
-import com.microsoft.aad.adal4j.ClientCredential;
-import org.apache.http.HttpStatus;
-import org.opengroup.osdu.core.common.model.http.AppException;
-import org.opengroup.osdu.core.common.model.search.IdToken;
-import org.opengroup.osdu.core.common.provider.interfaces.IJwtCache;
+import org.opengroup.osdu.azure.util.AzureServicePrincipleTokenService;
 import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import java.net.MalformedURLException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-
 @Component
 public class ServiceAccountJwtAzureClientImpl implements IServiceAccountJwtClient {
 
     @Autowired
-    private AppProperties config;
-
-    @Autowired
-    private IJwtCache tenantJwtCache;
-
-    public String getIdToken(String tenantName) {
-        String ACCESS_TOKEN = "";
-        ExecutorService service = null;
-
-        try {
-            // TODO : Refactor to move ID token form Common.Core.model.search to Common.core
-            IdToken cachedToken = (IdToken) this.tenantJwtCache.get(tenantName);
-
-            if ((cachedToken != null) && !IdToken.refreshToken(cachedToken)) {
-                return "Bearer " + cachedToken.getTokenValue();
-            }
-
-            // TODO : Control the thread count via config and pool should be created once.
-            service = Executors.newFixedThreadPool(1);
-
-            ACCESS_TOKEN = getAccessToken(service);
-            IdToken idToken = IdToken.builder().tokenValue(ACCESS_TOKEN).expirationTimeMillis(JWT.decode(ACCESS_TOKEN).getExpiresAt().getTime()).build();
-            this.tenantJwtCache.put(tenantName, idToken);
-        }  finally {
-            if(service != null) {
-                service.shutdown();
-            }
-        }
-        return "Bearer " + ACCESS_TOKEN;
-    }
-
-    // TODO : Refactor for making it test-able.
-    // THIS METHOD IS PUBLIC ONLY TO ENABLE UNIT TESTING
-    public String getAccessToken(ExecutorService service) {
-        AuthenticationContext context = null;
-        ClientCredential credential = null;
-        String ACCESS_TOKEN = null;
-        try {
-            context = new AuthenticationContext(this.config.getAuthURL(), false, service);
-            credential = new ClientCredential(this.config.getAuthClientID(), this.config.getAuthClientSecret());
-
-            Future<AuthenticationResult> future = context.acquireToken(this.config.getAadClientID(), credential, null);
+    private AzureServicePrincipleTokenService tokenService;
 
-            if (future == null) {
-                throw new AppException(HttpStatus.SC_FORBIDDEN, "Token not generated", "The user is not authorized to obtain Token From AAD");
-            }
-            ACCESS_TOKEN = future.get().getAccessToken();
-        } catch (MalformedURLException malformedURLException) {
-            malformedURLException.printStackTrace();
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-        } catch (ExecutionException e) {
-            e.printStackTrace();
-        }
-        return ACCESS_TOKEN;
+    @Override
+    public String getIdToken(String partitionId){
+        return "Bearer " + this.tokenService.getAuthorizationToken();
     }
 }
diff --git a/provider/notification-azure/src/main/resources/application.properties b/provider/notification-azure/src/main/resources/application.properties
index 3864e3180e5b7a998f7fc6ce072003b0e7e71b60..8855e8376cd707cc0efbc4413111f0119f03cc50 100644
--- a/provider/notification-azure/src/main/resources/application.properties
+++ b/provider/notification-azure/src/main/resources/application.properties
@@ -1,4 +1,4 @@
-#  Copyright © Microsoft Corporation
+#  Copyright © Microsoft Corporation
 #
 #  Licensed under the Apache License, Version 2.0 (the "License");
 #  you may not use this file except in compliance with the License.
@@ -20,10 +20,15 @@ server.error.whitelabel.enabled=false
 
 # Logging configuration
 LOG_PREFIX=${LOG_PREFIX}
-logging.level.org.springframework.web=DEBUG
+logging.level.org.springframework.web=${notification_spring_logging_level:INFO}
 logging.transaction.enabled=true
 logging.slf4jlogger.enabled=true
 logging.mdccontext.enabled=false
+logging.ignore.servlet.paths=/swagger-ui.html
+
+# Need below two properties for Entitlements config bean initialization due to a primary bean added in core-lib-azure which takes precedence over EntitlementsClientFactory class in notification service
+AUTHORIZE_API=${entitlements_service_endpoint}
+AUTHORIZE_API_KEY=${entitlements_service_api_key}
 
 # Service settings
 PARTITION_API=${partition_service_endpoint}
@@ -51,4 +56,31 @@ azure.keyvault.url=${KEYVAULT_URI}
 
 #TenantFactory Configuration
 tenantFactoryImpl.required=true
-tenantInfo.container.name=TenantInfo
\ No newline at end of file
+tenantInfo.container.name=TenantInfo
+
+#RegisterSubscription Configuration
+registerSubscription.container.name=RegisterSubscription
+
+# Specifies the number of threads to be created on the thread pool
+executor-n-threads=${executor_n_threads}
+
+# Specifies the maximum number of concurrent calls to the callback the message pump should initiate
+max-concurrent-calls=${max_concurrent_calls}
+
+# Specifies the maximum duration in seconds within which the lock will be renewed automatically
+max-lock-renew=${max_lock_renew_duration_seconds}
+
+# Specifies the initial delay before calling subscribeNotificationsEvent
+initial-subscription-manager-delay=${initial_subscription_manager_delay_seconds}
+
+# Specifies the consecutive thread delay for subscribeNotificationsEvent
+consecutive-subscription-manager-delay=${consecutive_subscription_manager_delay_seconds}
+
+# Specifies if Service Bus is enabled
+azure.serviceBus.enabled=${service_bus_enabled}
+
+# Specifies if Event Grid To Service Bus is enabled
+azure.eventGridToServiceBus.enabled=${event_grid_to_service_bus_enabled}
+
+# Specifies if Event Grid is enabled. Used to override the non-request scoped beans
+requestScope.enabled=${event_grid_enabled}
diff --git a/provider/notification-azure/src/main/resources/migrationConfig.json b/provider/notification-azure/src/main/resources/migrationConfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..f7b6f574d5fb08592b31d53c1bb6663c9447f78a
--- /dev/null
+++ b/provider/notification-azure/src/main/resources/migrationConfig.json
@@ -0,0 +1,18 @@
+[
+  {
+    "ResourceGroupIdCosmos": "This is the subscription ID corresponding to a resource group having Cosmos DB",
+    "PartitionKeyCosmos": "This is used by Cosmos DB to distribute data among multiple partitions.Example -opendes",
+    "ReadWriteMasterKeyCosmosDb": "Cosmos read write keys are very sensitive ones and provide access to the administrative resources",
+    "CosmosDBEndPoint": "Cosmos endpoint URL",
+    "DatabaseName": "Cosmos Database name. Example - osdu-db",
+    "ContainerName": "Cosmos Container name. Example -RegisterSubscription",
+    "ResourceGroupNameServiceBus": "This is the resource group name of a resource group having Service bus",
+    "ResourceGroupIdServiceBus": "This is the subscription ID corresponding to a resource group having Service Bus.This can be same as ResourceGroupIdCosmos mentioned above",
+    "NamespaceNameServiceBus": "Service bus namespace name(not host name) under ResourceGroupNameServiceBus",
+    "ServiceBusTopicName": "Service bus topic name under ResourceGroupNameServiceBus",
+    "SubscriptionIdsCosmos": [
+      "Subs_Id1",
+      "Subs_Id2"
+    ]
+  }
+]
\ No newline at end of file
diff --git a/provider/notification-azure/src/main/resources/migrationSetup.ps1 b/provider/notification-azure/src/main/resources/migrationSetup.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..a9e08258953d15af730618487d06dd7af79bb8e1
--- /dev/null
+++ b/provider/notification-azure/src/main/resources/migrationSetup.ps1
@@ -0,0 +1,24 @@
+# This script provides the pre migration setup for subscriptions from event grid to service bus.
+
+param([Parameter(Mandatory = $true)][Boolean]$InstallAzModule)
+
+try
+{
+    # Set execution policy
+    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
+
+    # Installation of modules. This Can be ignored by $InstallAzModule if already installed.
+    if ($InstallAzModule)
+    {
+        Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force -ErrorAction Stop
+    }
+
+    # Azure login
+    Connect-AzAccount -ErrorAction Stop
+
+    Write-Output "Migration Setup Successful."
+}
+catch
+{
+    Write-Output "Migration Setup Failed" $_
+}
\ No newline at end of file
diff --git a/provider/notification-azure/src/main/resources/migrationToServiceBus.ps1 b/provider/notification-azure/src/main/resources/migrationToServiceBus.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..e42d68148d1d8df2be0065c6c1a087413f854faa
--- /dev/null
+++ b/provider/notification-azure/src/main/resources/migrationToServiceBus.ps1
@@ -0,0 +1,162 @@
+<# This script performs migration of event grid subscriptions to service bus subscriptions for a given configuration file.
+   migrationSetup.ps1 is the prerequistes for successful execution of this script.
+#>
+Param([Parameter(Mandatory = $true)][String]$migrationConfigFilePath)
+
+Add-Type -AssemblyName System.Web
+
+# Generates auth key for cosmos API
+Function GenerateAuthorizationSignature
+{
+    [CmdletBinding()]
+    Param
+    (
+        [Parameter(Mandatory = $true)][String]$method,
+        [Parameter(Mandatory = $true)][String]$resourceLink,
+        [Parameter(Mandatory = $true)][String]$resourceType,
+        [Parameter(Mandatory = $true)][String]$key,
+        [Parameter(Mandatory = $true)][String]$keyType,
+        [Parameter(Mandatory = $true)][String]$tokenVersion,
+        [Parameter(Mandatory = $true)][String]$dateTime
+    )
+    $hmacSha = New-Object System.Security.Cryptography.HMACSHA256
+    $hmacSha.Key = [System.Convert]::FromBase64String($key)
+
+    $payLoad = "$($method.ToLowerInvariant() )`n$($resourceType.ToLowerInvariant() )`n$resourceLink`n$($dateTime.ToLowerInvariant() )`n`n"
+    $hashPayLoad = $hmacSha.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($payLoad))
+    $signature = [System.Convert]::ToBase64String($hashPayLoad);
+
+    [System.Web.HttpUtility]::UrlEncode("type=$keyType&ver=$tokenVersion&sig=$signature")
+}
+
+# Fetch the subscription from cosmos db
+Function GetCosmosSubscription
+{
+    [CmdletBinding()]
+    Param(
+        [Parameter(Mandatory = $true)][String]$Partition,
+        [Parameter(Mandatory = $true)][String]$SubscriptionId,
+        [Parameter(Mandatory = $true)][String]$ReadWriteMasterKeyCosmosDb,
+        [Parameter(Mandatory = $true)][String]$CosmosDBEndPoint,
+        [Parameter(Mandatory = $true)][String]$DatabaseName,
+        [Parameter(Mandatory = $true)][String]$ContainerName
+    )
+
+    $resourceType = "docs";
+    $resourceLink = "dbs/$DatabaseName/colls/$ContainerName/docs/$SubscriptionId"
+    $partitionkey = "[""$( $Partition )""]"
+    $cosmosURI = "$CosmosDBEndPoint$resourceLink"
+    $dateTime = [DateTime]::UtcNow.ToString("r")
+
+    $authToken = GenerateAuthorizationSignature -method "GET" -resourceLink $resourceLink -resourceType $resourceType -key $ReadWriteMasterKeyCosmosDb -keyType "master" -tokenVersion "1.0" -dateTime $dateTime
+
+    $headers = @{ authorization = $authToken; "x-ms-version" = "2017-02-22"; "x-ms-documentdb-partitionkey" = $partitionkey; "x-ms-date" = $dateTime }
+
+    # Call cosmos API to get subscription
+    Invoke-RestMethod -Method "GET" -Uri $cosmosURI -headers $headers -Verbose
+
+}
+
+# Update the cosmos subscription
+Function UpdateCosmosSubscription
+{
+    [CmdletBinding()]
+    Param(
+        [Parameter(Mandatory = $true)][String]$JsonSubscription,
+        [Parameter(Mandatory = $true)][String]$Partition,
+        [Parameter(Mandatory = $true)][String]$SubscriptionId,
+        [Parameter(Mandatory = $true)][String]$ReadWriteMasterKeyCosmosDb,
+        [Parameter(Mandatory = $true)][String]$CosmosDBEndPoint,
+        [Parameter(Mandatory = $true)][String]$DatabaseName,
+        [Parameter(Mandatory = $true)][String]$ContainerName
+    )
+
+    $resourceType = "docs";
+    $resourceLink = "dbs/$DatabaseName/colls/$ContainerName/docs/$SubscriptionId"
+    $partitionkey = "[""$( $Partition )""]"
+    $contentType = "application/json"
+    $cosmosURI = "$CosmosDBEndPoint$resourceLink"
+    $dateTime = [DateTime]::UtcNow.ToString("r")
+
+    $authToken = GenerateAuthorizationSignature -method "PUT" -resourceLink $ResourceLink -resourceType $ResourceType -key $ReadWriteMasterKeyCosmosDb -keyType "master" -tokenVersion "1.0" -dateTime $dateTime
+
+    $headers = @{ authorization = $authToken; "x-ms-version" = "2017-02-22"; "x-ms-documentdb-partitionkey" = $partitionkey; "x-ms-date" = $dateTime }
+
+    # Call cosmos API to update subscription
+    Invoke-RestMethod -Method "PUT" -ContentType $contentType -Uri $cosmosURI -headers $headers -Body $JsonSubscription -Verbose
+
+}
+
+# Migration Execution
+try
+{
+    $configurations = Get-Content -Raw -Path $migrationConfigFilePath| ConvertFrom-Json
+
+    foreach ($config in $configurations)
+    {
+        try
+        {
+            $ResourceGroupIdCosmos = $config.ResourceGroupIdCosmos
+            $PartitionKeyCosmos = $config.PartitionKeyCosmos
+            $ReadWriteMasterKeyCosmosDb = $config.ReadWriteMasterKeyCosmosDb
+            $CosmosDBEndPoint = $config.CosmosDBEndPoint
+            $DatabaseName = $config.DatabaseName
+            $ContainerName = $config.ContainerName
+            $ResourceGroupNameServiceBus = $config.ResourceGroupNameServiceBus
+            $ResourceGroupIdServiceBus = $config.ResourceGroupIdServiceBus
+            $NamespaceNameServiceBus = $config.NamespaceNameServiceBus
+            $ServiceBusTopicName = $config.ServiceBusTopicName
+            $SubscriptionIds = $config.SubscriptionIdsCosmos
+
+            foreach ($SubscriptionId in $SubscriptionIds)
+            {
+                $Subscription = $null
+                $ServiceBusSubscription = $null
+                try
+                {
+                    # Set resource group susbscription for cosmos
+                    Select-AzSubscription -SubscriptionName $ResourceGroupIdCosmos -Verbose -ErrorAction Stop
+
+                    $Subscription = GetCosmosSubscription -Partition $PartitionKeyCosmos -SubscriptionId $SubscriptionId -ReadWriteMasterKeyCosmosDb $ReadWriteMasterKeyCosmosDb -CosmosDBEndPoint $CosmosDBEndPoint -DatabaseName $DatabaseName -ContainerName $ContainerName
+                    if ((!$Subscription) -or (!$Subscription.notificationId) -or (!$Subscription.topic))
+                    {
+                        throw "Subscription is not present/null/empty or NotificationId/Topic is not present/null/empty in subscription with ID - $SubscriptionId"
+                    }
+                    $NotificationId = $Subscription.notificationId
+
+                    # Set resource group susbscription for service bus
+                    Select-AzSubscription -SubscriptionName $ResourceGroupIdServiceBus -Verbose -ErrorAction Stop
+
+                    # Create service bus topic subscription
+                    $ServiceBusSubscription = New-AzServiceBusSubscription -ResourceGroupName $ResourceGroupNameServiceBus -Namespace $NamespaceNameServiceBus -Topic $ServiceBusTopicName -Name $NotificationId -Verbose
+
+                    if (!$ServiceBusSubscription)
+                    {
+                        throw "Unable to create service bus subscription with Id - $NotificationId and topic - $ServiceBusTopicName "
+                    }
+                    # Update subscription topic name
+                    $Subscription.topic = $ServiceBusTopicName
+                    $JsonSubscription = $Subscription| ConvertTo-Json
+
+                    # Update cosmos subscription
+                    $UpdatedSubscription = UpdateCosmosSubscription -JsonSubscription $JsonSubscription -Partition $PartitionKeyCosmos -SubscriptionId $SubscriptionId -ReadWriteMasterKeyCosmosDb $ReadWriteMasterKeyCosmosDb -CosmosDBEndPoint $CosmosDBEndPoint -DatabaseName $DatabaseName -ContainerName $ContainerName
+
+                    Write-Output "Migration to Service Bus is Successful for Subscription - $SubscriptionId `n"
+                }
+                catch
+                {
+                    Write-Output "Migration Failed for Subscription - $SubscriptionId." $_
+                }
+            }
+        }
+        catch
+        {
+            Write-Output "Unable to process configuration -$config.ResourceGroupName." $_
+        }
+    }
+
+}
+catch
+{
+    Write-Output "Unable to process configurations" $_
+}
\ No newline at end of file
diff --git a/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/messageBus/MessageHandlerTest.java b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/messageBus/MessageHandlerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c5ee287a6ff5158a0cc704a5f22ea5156e50c184
--- /dev/null
+++ b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/messageBus/MessageHandlerTest.java
@@ -0,0 +1,71 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.messageBus;
+
+import com.microsoft.azure.servicebus.Message;
+import com.microsoft.azure.servicebus.SubscriptionClient;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.opengroup.osdu.notification.provider.azure.messageBus.MessageHandler;
+import org.opengroup.osdu.notification.provider.azure.messageBus.ProcessNotification;
+
+import java.util.UUID;
+
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+public class MessageHandlerTest {
+
+    private static final UUID uuid = UUID.randomUUID();
+    private static final String subscriptionName = "TestSubscription";
+
+    @InjectMocks
+    private MessageHandler messageHandler;
+
+    @Mock
+    private ProcessNotification processNotification;
+
+    @Mock
+    private SubscriptionClient subscriptionClient;
+
+    @Mock
+    private Message message;
+
+    @BeforeEach
+    public void init() {
+        when(message.getLockToken()).thenReturn(uuid);
+        when(subscriptionClient.getSubscriptionName()).thenReturn(subscriptionName);
+    }
+
+    @Test
+    public void shouldInvokeCompleteAsync() throws Exception {
+        lenient().doNothing().when(processNotification).performNotification(message, subscriptionName);
+        messageHandler.onMessageAsync(message);
+        verify(subscriptionClient, times(1)).completeAsync(uuid);
+        verify(processNotification, times(1)).performNotification(message, subscriptionClient.getSubscriptionName());
+    }
+
+    @Test
+    public void shouldInvokeAbandonAsyncWhenProcessNotificationThrowsException() throws Exception {
+        doThrow(new Exception()).when(processNotification).performNotification(message, subscriptionName);
+        messageHandler.onMessageAsync(message);
+        verify(subscriptionClient, times(1)).abandonAsync(uuid);
+        verify(processNotification, times(1)).performNotification(message, subscriptionClient.getSubscriptionName());
+    }
+}
diff --git a/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/messageBus/ProcessNotificationTest.java b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/messageBus/ProcessNotificationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..927672d6d6d69985f3c459cb9557467d81a579c2
--- /dev/null
+++ b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/messageBus/ProcessNotificationTest.java
@@ -0,0 +1,119 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.messageBus;
+
+import com.microsoft.azure.servicebus.Message;
+import org.junit.Assert;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.opengroup.osdu.core.common.http.HttpResponse;
+import org.opengroup.osdu.core.common.model.http.DpsHeaders;
+import org.opengroup.osdu.notification.provider.azure.messageBus.ProcessNotification;
+import org.opengroup.osdu.notification.provider.azure.messageBus.extractor.RequestBodyAdapter;
+import org.opengroup.osdu.notification.provider.azure.messageBus.thread.ThreadDpsHeaders;
+import org.opengroup.osdu.notification.provider.azure.models.NotificationContent;
+import org.opengroup.osdu.notification.provider.azure.util.MDCContextMap;
+import org.opengroup.osdu.notification.service.NotificationHandler;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+public class ProcessNotificationTest {
+    private static final String dataPartitionId = "opendes";
+    private static final String correlationId = "908fcf8d-30c5-4c74-a0ae-ab47b48b7a85";
+    private static final String notificationData = "[{\"id\":\"opendes:doc:\",\"kind\":\"opendes:at:wellbore:1.0.0\",\"op\":\"create\"},{\"id\":\"opendes:doc:\",\"kind\":\"opendes:at:wellbore:1.0.0\",\"op\":\"create\"}]";
+    private static final String subscriptionName = "TestSubscription";
+    private static final String notificationId = "Notification-Test-Subscription";
+    private HttpResponse response = new HttpResponse();
+    private static final Map<String, String> requestAttributes = new HashMap();
+    private final String NOT_ACKNOWLEDGE = "message not acknowledged by client";
+    private final String EXCEPTION_NOT_THROWN = "Should Throw Exception";
+    @InjectMocks
+    private ProcessNotification processNotification;
+
+    @Mock
+    private NotificationHandler notificationHandler;
+    @Mock
+    private RequestBodyAdapter requestBodyAdapter;
+    @Mock
+    private Message message;
+    @Mock
+    private NotificationContent notificationContent;
+    @Mock
+    private MDCContextMap mdcContextMap;
+    @Spy
+    private ThreadDpsHeaders dpsHeaders;
+
+    @BeforeEach
+    public void init() {
+        requestAttributes.put(DpsHeaders.DATA_PARTITION_ID, dataPartitionId);
+        requestAttributes.put(DpsHeaders.CORRELATION_ID, correlationId);
+        lenient().doNothing().when(dpsHeaders).setThreadContext(dataPartitionId, correlationId);
+        lenient().when(mdcContextMap.getContextMap(dataPartitionId, correlationId)).thenReturn(new HashMap<>());
+        lenient().when(dpsHeaders.getHeaders()).thenReturn(requestAttributes);
+        when(notificationContent.getExtractAttributes()).thenReturn(requestAttributes);
+        when(notificationContent.getNotificationId()).thenReturn(notificationId);
+        when(notificationContent.getData()).thenReturn(notificationData);
+    }
+
+    @Test
+    public void shouldSuccessfullyPerformNotification() throws Exception {
+        response.setResponseCode(200);
+        when(requestBodyAdapter.extractNotificationContent(message, subscriptionName)).thenReturn(notificationContent);
+        when(notificationHandler.notifySubscriber(notificationId, notificationData, requestAttributes)).thenReturn(response);
+        processNotification.performNotification(message, subscriptionName);
+        verify(notificationHandler, times(1)).notifySubscriber(notificationId, notificationData, requestAttributes);
+        verify(requestBodyAdapter, times(1)).extractNotificationContent(message, subscriptionName);
+    }
+
+    @Test
+    public void shouldThrowExceptionWhenNotifySubscriberFails() throws Exception {
+        response.setResponseCode(400);
+        when(requestBodyAdapter.extractNotificationContent(message, subscriptionName)).thenReturn(notificationContent);
+        when(notificationHandler.notifySubscriber(notificationId, notificationData, requestAttributes)).thenReturn(response);
+        try {
+            processNotification.performNotification(message, subscriptionName);
+            fail(EXCEPTION_NOT_THROWN);
+        } catch (Exception e) {
+            verify(notificationHandler, times(1)).notifySubscriber(notificationId, notificationData, requestAttributes);
+            verify(requestBodyAdapter, times(1)).extractNotificationContent(message, subscriptionName);
+            Assert.assertEquals(NOT_ACKNOWLEDGE, e.getMessage());
+        }
+    }
+
+    @Test
+    public void shouldThrowExceptionWhenNotifySubscriberThrowsException() throws Exception {
+        response.setResponseCode(400);
+        when(requestBodyAdapter.extractNotificationContent(message, subscriptionName)).thenReturn(notificationContent);
+        doThrow(new Exception()).when(notificationHandler).notifySubscriber(notificationId, notificationData, requestAttributes);
+        try {
+            processNotification.performNotification(message, subscriptionName);
+            fail(EXCEPTION_NOT_THROWN);
+        } catch (Exception e) {
+            verify(notificationHandler, times(1)).notifySubscriber(notificationId, notificationData, requestAttributes);
+            verify(requestBodyAdapter, times(1)).extractNotificationContent(message, subscriptionName);
+            Assert.assertNotNull(e);
+        }
+    }
+}
diff --git a/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/messageBus/SubscriptionClientFactoryTest.java b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/messageBus/SubscriptionClientFactoryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..dee2f7f0e5151cbabf538460eb1281d77e46e7a2
--- /dev/null
+++ b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/messageBus/SubscriptionClientFactoryTest.java
@@ -0,0 +1,71 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.messageBus;
+
+import com.microsoft.azure.servicebus.SubscriptionClient;
+import com.microsoft.azure.servicebus.primitives.ServiceBusException;
+import org.junit.Assert;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.opengroup.osdu.azure.servicebus.ISubscriptionClientFactory;
+import org.opengroup.osdu.notification.provider.azure.messageBus.SubscriptionClientFactImpl;
+
+import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class SubscriptionClientFactoryTest {
+    @InjectMocks
+    private SubscriptionClientFactImpl subsClientFactory;
+
+    @Mock
+    private SubscriptionClient subscriptionClient;
+
+    @Mock
+    private ISubscriptionClientFactory subscriptionClientFactory;
+
+    private static final String sbTopic = "testTopic";
+    private static final String sbSubscription = "testSubscription";
+    private static final String dataPartition = "testPartition";
+    private final String EXCEPTION_NOT_THROWN = "Should Throw Exception";
+    private final String SERVICE_BUS_EXCEPTION = "Unable to retrieve client info from Service Bus";
+
+    @Test
+    public void subscriptionClientShouldNotBeNull() throws ServiceBusException, InterruptedException {
+        when(subscriptionClientFactory.getClient(dataPartition, sbTopic, sbSubscription))
+                .thenReturn(subscriptionClient);
+        SubscriptionClient result = subsClientFactory.getSubscriptionClient(dataPartition, sbTopic, sbSubscription);
+        assertNotNull(result);
+        assertEquals(subscriptionClient, result);
+    }
+
+    @Test
+    public void shouldThrowExceptionWhenSubscriptionClientThrowsException() throws ServiceBusException, InterruptedException {
+        when(subscriptionClientFactory.getClient(dataPartition, sbTopic, sbSubscription))
+                .thenThrow(new ServiceBusException(false, SERVICE_BUS_EXCEPTION));
+        try {
+            subsClientFactory.getSubscriptionClient(dataPartition, sbTopic, sbSubscription);
+            fail(EXCEPTION_NOT_THROWN);
+        } catch (Exception e) {
+            Assert.assertNotNull(e);
+            Assert.assertEquals( SERVICE_BUS_EXCEPTION, e.getMessage());
+        }
+    }
+}
diff --git a/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/messageBus/SubscriptionManagerImplTest.java b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/messageBus/SubscriptionManagerImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1f6216898b1f660f7d8846322537ac83bcd35fc
--- /dev/null
+++ b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/messageBus/SubscriptionManagerImplTest.java
@@ -0,0 +1,182 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.messageBus;
+
+import com.microsoft.azure.servicebus.SubscriptionClient;
+import com.microsoft.azure.servicebus.primitives.ServiceBusException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.opengroup.osdu.azure.cosmosdb.CosmosStore;
+import org.opengroup.osdu.azure.partition.PartitionServiceClient;
+import org.opengroup.osdu.core.common.model.notification.HmacSecret;
+import org.opengroup.osdu.core.common.model.notification.Subscription;
+import org.opengroup.osdu.core.common.model.tenant.TenantInfo;
+import org.opengroup.osdu.core.common.notification.ISubscriptionFactory;
+import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory;
+import org.opengroup.osdu.notification.provider.azure.messageBus.ProcessNotification;
+import org.opengroup.osdu.notification.provider.azure.messageBus.SubscriptionClientFactImpl;
+import org.opengroup.osdu.notification.provider.azure.messageBus.SubscriptionManagerImpl;
+import org.opengroup.osdu.notification.provider.azure.messageBus.thread.ThreadDpsHeaders;
+import org.opengroup.osdu.notification.provider.azure.util.AzureServiceBusConfig;
+import org.opengroup.osdu.notification.provider.azure.util.AzureCosmosProperties;
+
+import java.util.Collections;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import static java.lang.Thread.sleep;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+public class SubscriptionManagerImplTest {
+
+    private static final String maxLockRenewDuration = "60";
+    private static final String maxConcurrentCalls = "1";
+    private static final String nThreads = "2";
+    private static final String errorMessage = "some-error";
+
+    @InjectMocks
+    private SubscriptionManagerImpl subscriptionManager;
+    @Mock
+    private SubscriptionClientFactImpl subscriptionClientFactory;
+    @Mock
+    private SubscriptionClient subscriptionClient;
+    @Mock
+    private ProcessNotification processNotification;
+    @Mock
+    private ITenantFactory tenantFactory;
+    @Mock
+    private ISubscriptionFactory subscriptionFactory;
+    @Mock
+    private ThreadDpsHeaders dpsHeaders;
+    @Mock
+    private PartitionServiceClient partitionService;
+    @Mock
+    private CosmosStore cosmosStore;
+    @Mock
+    private AzureCosmosProperties azureCosmosProperties;
+    @Mock
+    private AzureServiceBusConfig azureServiceBusConfig;
+
+    private static final String dataPartition = "testTenant";
+    private static final String cosmosDbName = "testDatabase";
+    private static final String registerContainerName = "testContainer";
+    private static final String sbTopic = "testTopic";
+    private static final String sbSubscription = "testSubscription";
+    private static final String initial_thread_delay = "0";
+    private static final String thread_delay = "1";
+
+    @BeforeEach
+    public void init() {
+        TenantInfo tenantInfo = new TenantInfo();
+        tenantInfo.setDataPartitionId(dataPartition);
+        lenient().when(azureServiceBusConfig.getMaxConcurrentCalls()).thenReturn(maxConcurrentCalls);
+        lenient().when(azureServiceBusConfig.getNThreads()).thenReturn(nThreads);
+        lenient().when(azureServiceBusConfig.getMaxLockRenewDurationInSeconds()).thenReturn(maxLockRenewDuration);
+        lenient().when(azureServiceBusConfig.getInitialSubscriptionManagerDelay()).thenReturn(initial_thread_delay);
+        lenient().when(azureServiceBusConfig.getConsecutiveSubscriptionManagerDelay()).thenReturn(thread_delay);
+        lenient().when(azureCosmosProperties.registerSubscriptionContainerName()).thenReturn(registerContainerName);
+        lenient().when(azureCosmosProperties.cosmosDBName()).thenReturn(cosmosDbName);
+        lenient().when(tenantFactory.listTenantInfo()).thenReturn(Collections.singletonList(tenantInfo));
+        lenient().when(cosmosStore.findAllItems(dataPartition, cosmosDbName, registerContainerName, Subscription.class)).
+                thenReturn(Collections.singletonList(getHmac_subscription()));
+    }
+
+    @Test
+    public void shouldSuccessfullyRegisterMessageHandler() throws ServiceBusException, InterruptedException {
+
+        when(subscriptionClientFactory.getSubscriptionClient(dataPartition, sbTopic, sbSubscription)).thenReturn(subscriptionClient);
+        doNothing().when(subscriptionClient).registerMessageHandler(any(), any(), any());
+        subscriptionManager.subscribeNotificationsEvent();
+
+        verify(azureServiceBusConfig, times(1)).getMaxConcurrentCalls();
+        verify(azureServiceBusConfig, times(1)).getNThreads();
+        verify(azureServiceBusConfig, times(1)).getMaxLockRenewDurationInSeconds();
+        verify(azureCosmosProperties, times(1)).registerSubscriptionContainerName();
+        verify(azureCosmosProperties, times(1)).cosmosDBName();
+        verify(subscriptionClientFactory, times(1)).getSubscriptionClient(dataPartition, sbTopic, sbSubscription);
+        verify(subscriptionClient, times(1)).registerMessageHandler(any(), any(), any());
+
+    }
+
+    @Test
+    public void shouldNotRegisterMessageHandlerWhenAlreadyRegisteredInPrevThread() throws ServiceBusException, InterruptedException {
+
+        when(subscriptionClientFactory.getSubscriptionClient(dataPartition, sbTopic, sbSubscription)).thenReturn(subscriptionClient);
+        doNothing().when(subscriptionClient).registerMessageHandler(any(), any(), any());
+        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(subscriptionManager, Integer.parseUnsignedInt(azureServiceBusConfig.getInitialSubscriptionManagerDelay()),
+                Integer.parseUnsignedInt(azureServiceBusConfig.getConsecutiveSubscriptionManagerDelay()), TimeUnit.SECONDS);
+        sleep(10000);
+        verify(azureServiceBusConfig, times(1)).getMaxConcurrentCalls();
+        verify(azureServiceBusConfig, atLeast(2)).getNThreads();
+        verify(azureServiceBusConfig, times(1)).getMaxLockRenewDurationInSeconds();
+        verify(azureCosmosProperties, atLeast(2)).registerSubscriptionContainerName();
+        verify(azureCosmosProperties, atLeast(2)).cosmosDBName();
+        verify(subscriptionClientFactory, times(1)).getSubscriptionClient(dataPartition, sbTopic, sbSubscription);
+        verify(subscriptionClient, times(1)).registerMessageHandler(any(), any(), any());
+
+    }
+
+    @Test
+    public void shouldNotRegisterMessageHandlerIfSSubscriptionClientThrowsException() throws ServiceBusException, InterruptedException {
+        lenient().doNothing().when(subscriptionClient).registerMessageHandler(any(), any(), any());
+        doThrow(new InterruptedException(errorMessage)).when(subscriptionClientFactory).getSubscriptionClient(dataPartition, sbTopic, sbSubscription);
+        subscriptionManager.subscribeNotificationsEvent();
+
+        verify(azureServiceBusConfig, times(0)).getMaxConcurrentCalls();
+        verify(azureServiceBusConfig, times(1)).getNThreads();
+        verify(azureServiceBusConfig, times(0)).getMaxLockRenewDurationInSeconds();
+        verify(azureCosmosProperties, times(1)).registerSubscriptionContainerName();
+        verify(azureCosmosProperties, times(1)).cosmosDBName();
+        verify(subscriptionClientFactory, times(1)).getSubscriptionClient(dataPartition, sbTopic, sbSubscription);
+        verify(subscriptionClient, times(0)).registerMessageHandler(any(), any(), any());
+    }
+
+    @Test
+    public void shouldThrowExceptionIfErrorWhileRegisteringMessageHandler() throws ServiceBusException, InterruptedException {
+
+        doThrow(new InterruptedException(errorMessage)).when(subscriptionClient).registerMessageHandler(any(), any(), any());
+        when(subscriptionClientFactory.getSubscriptionClient(dataPartition, sbTopic, sbSubscription)).thenReturn(subscriptionClient);
+        subscriptionManager.subscribeNotificationsEvent();
+
+        verify(azureServiceBusConfig, times(1)).getMaxConcurrentCalls();
+        verify(azureServiceBusConfig, times(1)).getNThreads();
+        verify(azureServiceBusConfig, times(1)).getMaxLockRenewDurationInSeconds();
+        verify(azureCosmosProperties, times(1)).registerSubscriptionContainerName();
+        verify(azureCosmosProperties, times(1)).cosmosDBName();
+        verify(subscriptionClientFactory, times(1)).getSubscriptionClient(dataPartition, sbTopic, sbSubscription);
+        verify(subscriptionClient, times(1)).registerMessageHandler(any(), any(), any());
+    }
+
+    private static Subscription getHmac_subscription() {
+        Subscription hmac_subscription = new Subscription();
+        hmac_subscription.setName("hamc_test_subscription");
+        hmac_subscription.setPushEndpoint("http://challenge");
+        hmac_subscription.setDescription("Description");
+        hmac_subscription.setTopic(sbTopic);
+        hmac_subscription.setNotificationId(sbSubscription);
+        hmac_subscription.setId("id_1");
+        hmac_subscription.setCreatedBy("test@test.com");
+        HmacSecret secret = new HmacSecret();
+        secret.setValue("testsecret");
+        hmac_subscription.setSecret(secret);
+        return hmac_subscription;
+    }
+}
diff --git a/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/provider/azure/messageBus/EventGridServiceBusRequestBodyExtractorTest.java b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/provider/azure/messageBus/EventGridServiceBusRequestBodyExtractorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..172cb1a1137012d28b307d4e6b30e918d1cac1db
--- /dev/null
+++ b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/provider/azure/messageBus/EventGridServiceBusRequestBodyExtractorTest.java
@@ -0,0 +1,119 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus;
+
+import com.microsoft.azure.servicebus.IMessage;
+import com.microsoft.azure.servicebus.Message;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.notification.provider.azure.messageBus.extractor.EventGridServiceBusRequestBodyExtractor;
+import org.springframework.http.HttpStatus;
+
+import java.util.Map;
+
+import static org.junit.Assert.fail;
+
+@RunWith(MockitoJUnitRunner.class)
+public class EventGridServiceBusRequestBodyExtractorTest {
+    @InjectMocks
+    private EventGridServiceBusRequestBodyExtractor sut;
+    private static final String inValidData = "[{\"invalidData\"}]";
+    private static final String validData = "[{\"id\":\"opendes:doc:\",\"kind\":\"opendes:at:wellbore:1.0.0\",\"op\":\"create\"},{\"id\":\"opendes:doc:\",\"kind\":\"opendes:at:wellbore:1.0.0\",\"op\":\"create\"}]";
+    private static final String dataPartitionId = "opendes";
+    private static final String correlationId = "908fcf8d-30c5-4c74-a0ae-ab47b48b7a85";
+    private static final String accountId = "ab47b48b7a85-30c5";
+
+    @Test
+    public void should_throwWhenAttributesAreMissing_extractDataFromRequestBody() {
+        IMessage message = getInvalidMessage();
+        try {
+            sut.InitializeExtractor(message);
+            fail("Should Throw Exception");
+        } catch (AppException appException) {
+            Assert.assertEquals(HttpStatus.BAD_REQUEST.value(), appException.getError().getCode());
+            Assert.assertEquals("Unable to parse request payload.", appException.getError().getMessage());
+        } catch (Exception exception) {
+            fail("Should Throw AppException");
+        }
+
+    }
+
+    @Test
+    public void shouldReturnNotificationDataAndAttributesWhenValidRequestBody() {
+        IMessage message = getValidMessage();
+        try {
+            sut.InitializeExtractor(message);
+            String notificationData = sut.extractDataFromRequestBody();
+            Assert.assertEquals(notificationData, validData);
+            Map<String, String> attributes = sut.extractAttributesFromRequestBody();
+            Assert.assertEquals(attributes.get("account-id"), accountId);
+            Assert.assertEquals(attributes.get("correlation-id"), correlationId);
+            Assert.assertEquals(attributes.get("data-partition-id"), dataPartitionId);
+
+        } catch (Exception exception) {
+            fail("Should not Throw AppException");
+        }
+
+    }
+
+    private Message getValidMessage() {
+
+        String body =
+                "[\n" +
+                        "    {\n" +
+                        "        \"id\": \"2425\",\n" +
+                        "        \"eventType\": \"recordInserted\",\n" +
+                        "        \"subject\": \"myapp/vehicles/motorcycles\",\n" +
+                        "        \"data\": {\n" +
+                        "            \"data\":" + validData + ",\n" +
+                        "            \"account-id\": \"" + accountId + "\",\n" +
+                        "            \"correlation-id\": \"" + correlationId + "\",\n" +
+                        "            \"data-partition-id\": \"" + dataPartitionId + "\"\n" +
+                        "        },\n" +
+                        "        \"dataVersion\": \"1.0\",\n" +
+                        "        \"metadataVersion\": \"1\",\n" +
+                        "        \"eventTime\": \"2020-08-14T18:04:06\",\n" +
+                        "        \"topic\": \"records-changed\"\n" +
+                        "    }\n" +
+                        "]";
+        return new Message(body);
+    }
+
+    private Message getInvalidMessage() {
+
+        String body =
+                "[\n" +
+                        "    {\n" +
+                        "        \"id\": \"2425\",\n" +
+                        "        \"eventType\": \"recordInserted\",\n" +
+                        "        \"subject\": \"myapp/vehicles/motorcycles\",\n" +
+                        "        \"data\": {\n" +
+                        "            \"data\":" + inValidData + ",\n" +
+                        "            \"data-partition-id\": \"" + dataPartitionId + "\"\n" +
+                        "        },\n" +
+                        "        \"dataVersion\": \"1.0\",\n" +
+                        "        \"metadataVersion\": \"1\",\n" +
+                        "        \"eventTime\": \"2020-08-14T18:04:12+00:00\",\n" +
+                        "        \"topic\": \"records-changed\"\n" +
+                        "    }\n" +
+                        "]";
+        Message message = new Message(body);
+        return message;
+    }
+}
diff --git a/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/provider/azure/messageBus/ServiceBusRequestBodyExtractorTest.java b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/provider/azure/messageBus/ServiceBusRequestBodyExtractorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f9729ecd25dabd2118d8adf33643928587e1c96
--- /dev/null
+++ b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/provider/azure/messageBus/ServiceBusRequestBodyExtractorTest.java
@@ -0,0 +1,101 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.provider.azure.messageBus;
+
+import com.microsoft.azure.servicebus.IMessage;
+import com.microsoft.azure.servicebus.Message;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.notification.provider.azure.messageBus.extractor.ServiceBusRequestBodyExtractor;
+import org.springframework.http.HttpStatus;
+
+import java.util.Map;
+
+import static org.junit.Assert.fail;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ServiceBusRequestBodyExtractorTest {
+    @InjectMocks
+    private ServiceBusRequestBodyExtractor sut;
+    private static final String inValidData = "[{\"invalidData\"}]";
+    private static final String validData = "[{\"id\":\"opendes:doc:\",\"kind\":\"opendes:at:wellbore:1.0.0\",\"op\":\"create\"},{\"id\":\"opendes:doc:\",\"kind\":\"opendes:at:wellbore:1.0.0\",\"op\":\"create\"}]";
+    private static final String dataPartitionId = "opendes";
+    private static final String correlationId = "908fcf8d-30c5-4c74-a0ae-ab47b48b7a85";
+    private static final String accountId = "ab47b48b7a85-30c5";
+
+    @Test
+    public void should_throwWhenAttributesAreMissing_extractDataFromRequestBody() {
+        IMessage message = getInvalidMessage();
+        try {
+            sut.InitializeExtractor(message);
+            fail("Should Throw Exception");
+        } catch (AppException appException) {
+            Assert.assertEquals(HttpStatus.BAD_REQUEST.value(), appException.getError().getCode());
+            Assert.assertEquals("Unable to parse request payload.", appException.getError().getMessage());
+        } catch (Exception exception) {
+            fail("Should Throw AppException");
+        }
+
+    }
+
+    @Test
+    public void shouldReturnNotificationDataAndAttributesWhenValidRequestBody() {
+        IMessage message = getValidMessage();
+        try {
+            sut.InitializeExtractor(message);
+            String notificationData = sut.extractDataFromRequestBody();
+            Assert.assertEquals(notificationData, validData);
+            Map<String, String> attributes = sut.extractAttributesFromRequestBody();
+            Assert.assertEquals(attributes.get("account-id"), accountId);
+            Assert.assertEquals(attributes.get("correlation-id"), correlationId);
+            Assert.assertEquals(attributes.get("data-partition-id"), dataPartitionId);
+
+        } catch (Exception exception) {
+            fail("Should not Throw AppException");
+        }
+
+    }
+
+    private Message getValidMessage() {
+
+        String body =
+                "    {\n" +
+                        "        \"message\": {\n" +
+                        "            \"data\":" + validData + ",\n" +
+                        "            \"account-id\": \"" + accountId + "\",\n" +
+                        "            \"correlation-id\": \"" + correlationId + "\",\n" +
+                        "            \"data-partition-id\": \"" + dataPartitionId + "\"\n" +
+                        "        }\n" +
+                        "    }";
+        return new Message(body);
+    }
+
+    private Message getInvalidMessage() {
+        String body =
+                "    {\n" +
+                        "        \"message\": {\n" +
+                        "            \"data\":" + inValidData + ",\n" +
+                        "            \"correlation-id\": \"" + correlationId + "\",\n" +
+                        "            \"data-partition-id\": \"" + dataPartitionId + "\"\n" +
+                        "        }\n" +
+                        "    }";
+        Message message = new Message(body);
+        return message;
+    }
+}
diff --git a/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/util/ServiceAccountClientImplTest.java b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/util/ServiceAccountClientImplTest.java
index e7caf1d3bf93c6e74b665570e48cb94a0d5c7f3d..59fbfb854e7e3bca9ea106a1706b387890f74e1b 100644
--- a/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/util/ServiceAccountClientImplTest.java
+++ b/provider/notification-azure/src/test/java/org/opengroup/osdu/notification/util/ServiceAccountClientImplTest.java
@@ -14,104 +14,56 @@
 
 package org.opengroup.osdu.notification.util;
 
-import org.apache.http.HttpStatus;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.mockito.Spy;
-import org.mockito.junit.MockitoJUnitRunner;
-import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.omg.CORBA.portable.ApplicationException;
+import org.opengroup.osdu.azure.util.AzureServicePrincipleTokenService;
 import org.opengroup.osdu.core.common.model.http.AppException;
-import org.opengroup.osdu.core.common.model.search.IdToken;
-import org.opengroup.osdu.notification.provider.azure.cache.JwtCache;
-import org.opengroup.osdu.notification.provider.azure.util.AppProperties;
 import org.opengroup.osdu.notification.provider.azure.util.ServiceAccountJwtAzureClientImpl;
 
-import java.util.concurrent.ExecutorService;
+import java.io.UnsupportedEncodingException;
 
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.when;
-import static org.mockito.MockitoAnnotations.initMocks;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.times;
 
-@RunWith(MockitoJUnitRunner.class)
+@ExtendWith(MockitoExtension.class)
 public class ServiceAccountClientImplTest {
 
-    final String tenantName = "Test Tenant";
-    final String validToken = "validToken";
-
-    @Mock
-    private IdToken idToken;
-
-    @Mock
-    private ExecutorService executorService;
-
-    @Mock
-    private AppProperties appProperties;
-
-    @Mock
-    private JwtCache tenantJwtCacheMock;
-
-    @Mock
-    private JaxRsDpsLog logger;
+    private static final  String tenantId = "tenantId";
+    private static final String token = "jwt-token";
 
     @InjectMocks
-    @Spy
-    private ServiceAccountJwtAzureClientImpl sut;
+    private ServiceAccountJwtAzureClientImpl serviceAccountJwtAzureClient;
 
-    @Before
-    public void setup() {
-        initMocks(this);
-        idToken = IdToken.builder().tokenValue(validToken).expirationTimeMillis(System.currentTimeMillis() + 10000000L).build();
-    }
+    @Mock
+    private AzureServicePrincipleTokenService azureServicePrincipleTokenService;
 
     @Test
-    public void should_getTokenFromCache_getIdTokenTest() {
-        // SetUp
-        when(tenantJwtCacheMock.get(any())).thenReturn(idToken);
-        String expectedToken = "Bearer " +idToken.getTokenValue();
+    public void shouldSuccessfullyGenerateToken() throws UnsupportedEncodingException, ApplicationException {
 
-        // Act
-        String returnedIdToken = sut.getIdToken(tenantName);
+        when(azureServicePrincipleTokenService.getAuthorizationToken()).thenReturn(token);
 
-        // Assert
-        Assert.assertEquals(expectedToken, returnedIdToken);
+        String result = serviceAccountJwtAzureClient.getIdToken(tenantId);
+
+        assertEquals("Bearer " + token, result);
+        verify(azureServicePrincipleTokenService, times(1)).getAuthorizationToken();
     }
 
     @Test
-    public void should_updateCache_getIdTokenTest() {
-        // Set up
-        when(tenantJwtCacheMock.get(any())).thenReturn(idToken);
-        String expectedToken = "Bearer " +idToken.getTokenValue();
+    public void shouldThrowAppException() throws UnsupportedEncodingException {
 
-        // Act
-        String returnedToken = this.sut.getIdToken(tenantName);
+        doThrow(AppException.class).when(azureServicePrincipleTokenService).getAuthorizationToken();
 
-        // Assert
-        Assert.assertEquals(expectedToken, returnedToken);
-    }
+        AppException exception = assertThrows(AppException.class, () -> {
+            serviceAccountJwtAzureClient.getIdToken(tenantId);
+        });
 
-    @Test
-    public void should_return403GivenInvalidApplicationProperties_getAccessToken() {
-        when(appProperties.getAuthURL()).thenReturn("https://login.microsoftonline.com/s/oauth2/token/");
-        when(appProperties.getAuthClientID()).thenReturn("testAuthClientID");
-        when(appProperties.getAuthClientSecret()).thenReturn("testAuthClientSecret");
-        when(appProperties.getAadClientID()).thenReturn("testAadClientID");
-
-        try {
-            // Act
-            sut.getAccessToken(executorService);
-
-            // Assert
-            fail("Should throw exception");
-        } catch (AppException appException) {
-            Assert.assertEquals(HttpStatus.SC_FORBIDDEN, appException.getError().getCode());
-        } catch (Exception e) {
-            fail("Should not throw this exception" + e.getMessage());
-        }
+        assertNotNull(exception);
+        verify(azureServicePrincipleTokenService, times(1)).getAuthorizationToken();
     }
 }
 
diff --git a/provider/notification-gcp/README.md b/provider/notification-gcp/README.md
index 28510ea1aa16804a313b26f988a32a49caa897b8..80a59b3287f04ee392f40d1e1d83fd8b0dc23384 100644
--- a/provider/notification-gcp/README.md
+++ b/provider/notification-gcp/README.md
@@ -31,6 +31,7 @@ In order to run the service locally or remotely, you will need to have the follo
 | `APP_REGISTER` | ex `https://register.com/api/register/v1` | Storage API endpoint | no | output of infrastructure deployment |
 | `APP_PROJECT` | ex `opendes` | Google Cloud Project Id | no | output of infrastructure deployment |
 | `APP_AUDIENCES` | ex `*****.apps.googleusercontent.com` | Client ID for getting access to cloud resources | yes | https://console.cloud.google.com/apis/credentials |
+| `PARTITION_API` | ex `http://localhost:8081/api/partition/v1` | Partition service endpoint | no | - |
 
 **System Environment required to run service**
 
@@ -135,7 +136,7 @@ After the service has started it should be accessible via a web browser by visit
 | `ENVIRONMENT` | `dev` OR `local` OR `dev_gke`| Local for running locally with services url's predefined as http://localhost , Dev & Dev_Gke is configurable environment | no | - |
 | `HMAC_SECRET` | ex`7a786376626e` | String in hex , must match pattern ^[a-zA-Z0-9]{8,30}+$ & be in register variable SUBSCRIBER_SECRET | yes | - |
 | `REGISTER_BASE_URL` | `http://localhost:8081/api/register/v1` | Register service url | no | - |
-| `NOTIFICATION_BASE_URL` | `http://localhost:8080/` | Notification service url  | no | - |
+| `NOTIFICATION_BASE_URL` | `http://localhost:8080/api/notification/v1/` | Notification service url  | no | - |
 | `INTEGRATION_TEST_AUDIENCE` | `********` | Client application ID | yes | https://console.cloud.google.com/apis/credentials |
 | `CLIENT_TENANT` | ex `opendes` | Client tenant | no | - |
 | `OSDU_TENANT` | ex `osdu` | Osdu tenant | no | - |
diff --git a/provider/notification-gcp/pom.xml b/provider/notification-gcp/pom.xml
index 399ab228ac2a2b3acaf702cb8b2316d6ce7db9da..a86b437ba4371a20cf5b1e3e9d70b00773d9f8bf 100644
--- a/provider/notification-gcp/pom.xml
+++ b/provider/notification-gcp/pom.xml
@@ -18,7 +18,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.opengroup.osdu</groupId>
     <artifactId>notification-gcp</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.12.0-SNAPSHOT</version>
     <name>notification-gcp</name>
     <description>GCP implementation for Notification service</description>
     <packaging>jar</packaging>
@@ -26,7 +26,7 @@
     <parent>
         <groupId>org.opengroup.osdu</groupId>
         <artifactId>os-notification</artifactId>
-        <version>0.9.0-SNAPSHOT</version>
+        <version>0.12.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 
@@ -44,13 +44,13 @@
         <dependency>
             <groupId>org.opengroup.osdu</groupId>
             <artifactId>core-lib-gcp</artifactId>
-            <version>0.7.0</version>
+            <version>0.11.0</version>
         </dependency>
 
         <dependency>
             <groupId>org.opengroup.osdu</groupId>
             <artifactId>notification-core</artifactId>
-            <version>0.9.0-SNAPSHOT</version>
+            <version>0.12.0-SNAPSHOT</version>
         </dependency>
 
         <dependency>
diff --git a/provider/notification-gcp/src/main/java/org/opengroup/osdu/notification/provider/gcp/di/ServiceAccountJwtClientFactory.java b/provider/notification-gcp/src/main/java/org/opengroup/osdu/notification/provider/gcp/di/ServiceAccountJwtClientFactory.java
index 403523702216a70169fdc77a96fef3d4490e3580..ad4a541f081362e8a46fdb84e5af5dcb6a13e381 100644
--- a/provider/notification-gcp/src/main/java/org/opengroup/osdu/notification/provider/gcp/di/ServiceAccountJwtClientFactory.java
+++ b/provider/notification-gcp/src/main/java/org/opengroup/osdu/notification/provider/gcp/di/ServiceAccountJwtClientFactory.java
@@ -20,9 +20,11 @@ import org.opengroup.osdu.notification.provider.gcp.util.AppProperties;
 import org.opengroup.osdu.notification.provider.gcp.util.ServiceAccountJwtGcpClientImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.config.AbstractFactoryBean;
+import org.springframework.context.annotation.Primary;
 import org.springframework.stereotype.Component;
 
 @Component
+@Primary
 public class ServiceAccountJwtClientFactory extends AbstractFactoryBean<IServiceAccountJwtClient> {
 
     @Autowired
diff --git a/provider/notification-gcp/src/main/resources/application.properties b/provider/notification-gcp/src/main/resources/application.properties
index fa6abe7faedd3e9971e6f725712c99e80a1788c8..c2f3bf7bea18040d814d894a14b5b50ec671e6ad 100644
--- a/provider/notification-gcp/src/main/resources/application.properties
+++ b/provider/notification-gcp/src/main/resources/application.properties
@@ -16,7 +16,10 @@
 
 LOG_PREFIX=notification
 logging.level.org.springframework.web=${LOG_LEVEL:DEBUG}
-server.servlet.contextPath=/
+server.servlet.contextPath=/api/notification/v1
 app.expireTime=300
 app.maxCacheSize=10
-server.error.whitelabel.enabled=false
\ No newline at end of file
+server.error.whitelabel.enabled=false
+
+google.audiences=${APP_AUDIENCES}
+partition.api=http://localhost:8081/api/partition/v1
\ No newline at end of file
diff --git a/provider/notification-ibm/pom.xml b/provider/notification-ibm/pom.xml
index ceb68a4d42a4752eade4204f1e41f856f514557e..089f6a66c5f698db00353a63f1e512779929c7e8 100644
--- a/provider/notification-ibm/pom.xml
+++ b/provider/notification-ibm/pom.xml
@@ -16,7 +16,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.opengroup.osdu</groupId>
     <artifactId>notification-ibm</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.12.0-SNAPSHOT</version>
     <name>notification-ibm</name>
     <description>IBM implementation for Notification service</description>
     <packaging>jar</packaging>
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.opengroup.osdu</groupId>
         <artifactId>os-notification</artifactId>
-        <version>0.9.0-SNAPSHOT</version>
+        <version>0.12.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
 
@@ -44,13 +44,13 @@
         <dependency>
             <groupId>org.opengroup.osdu</groupId>
             <artifactId>os-core-lib-ibm</artifactId>
-            <version>0.7.0</version>
+            <version>0.9.0</version>
         </dependency>
 
         <dependency>
             <groupId>org.opengroup.osdu</groupId>
             <artifactId>notification-core</artifactId>
-            <version>0.9.0-SNAPSHOT</version>
+            <version>0.12.0-SNAPSHOT</version>
         </dependency>
 
         <!-- unit test dependencies -->
diff --git a/provider/notification-ibm/src/main/java/org/opengroup/osdu/notification/provider/ibm/security/SecurityConfig.java b/provider/notification-ibm/src/main/java/org/opengroup/osdu/notification/provider/ibm/security/SecurityConfig.java
index 593efbbbf15e985a780b2a0cd568449d2372c0ae..bfa018bdf7ae35152d42b234aa2eb248280477fe 100644
--- a/provider/notification-ibm/src/main/java/org/opengroup/osdu/notification/provider/ibm/security/SecurityConfig.java
+++ b/provider/notification-ibm/src/main/java/org/opengroup/osdu/notification/provider/ibm/security/SecurityConfig.java
@@ -20,6 +20,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
 						"/swagger-resources/**",
 						"/configuration/security", 
 						"/swagger-ui.html", 
+						"/info",
 						"/webjars/**")
 				.permitAll().anyRequest().authenticated().and().oauth2ResourceServer().jwt();
 	}
diff --git a/provider/notification-reference/README.md b/provider/notification-reference/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6cfa317806a48ecb47185d38bcfd40a3fc7e70a3
--- /dev/null
+++ b/provider/notification-reference/README.md
@@ -0,0 +1,184 @@
+# Notification Service
+notification-reference is a [Spring Boot](https://spring.io/projects/spring-boot) service that allow for interested consumers to subscribe to data and metadata changes using a publish/subscriber pattern.
+This service could be used for OSDU hybrid cloud.
+
+## Getting Started
+These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
+
+### Requirements
+* Java 8
+* [Maven 3.6.0+](https://maven.apache.org/download.cgi)
+* GCloud command line tool
+* GCloud access to opendes project
+
+### General Tips
+
+**Environment Variable Management**
+The following tools make environment variable configuration simpler
+ - [direnv](https://direnv.net/) - for a shell/terminal environment
+ - [EnvFile](https://plugins.jetbrains.com/plugin/7861-envfile) - for [Intellij IDEA](https://www.jetbrains.com/idea/)
+
+**Lombok**
+This project uses [Lombok](https://projectlombok.org/) for code generation. You may need to configure your IDE to take advantage of this tool.
+ - [Intellij configuration](https://projectlombok.org/setup/intellij)
+ - [VSCode configuration](https://projectlombok.org/setup/vscode)
+
+### Installation
+In order to run the service locally or remotely, you will need to have the following environment variables defined.
+
+| name | value | description | sensitive? | source |
+| ---  | ---   | ---         | ---        | ---    |
+| `APP_ENTITLEMENTS` | ex `https://entitlements.com/entitlements/v1` | Entitlements API endpoint | no | output of infrastructure deployment |
+| `APP_REGISTER` | ex `https://register.com/api/register/v1` | Storage API endpoint | no | output of infrastructure deployment |
+| `APP_PROJECT` | ex `opendes` | Google Cloud Project Id | no | output of infrastructure deployment |
+| `APP_AUDIENCES` | ex `*****.apps.googleusercontent.com` | Client ID for getting access to cloud resources | yes | https://console.cloud.google.com/apis/credentials |
+| `PARTITION_API` | ex `http://localhost:8081/api/partition/v1` | Partition service endpoint | no | - |
+
+**System Environment required to run service**
+
+| name | value | description | sensitive? | source |
+| ---  | ---   | ---         | ---        | ---    |
+| `SPRING_PROFILES_ACTIVE` | `local` | spring active profile | no |
+
+### Run Locally
+Check that maven is installed:
+```bash
+$ mvn --version
+Apache Maven 3.6.0
+Maven home: /usr/share/maven
+Java version: 1.8.0_212, vendor: AdoptOpenJDK, runtime: /usr/lib/jvm/jdk8u212-b04/jre
+...
+```
+
+You will need to configure access to the remote maven repository that holds the OSDU dependencies. This file should live within `~/.m2/settings.xml`:
+
+```bash
+$ cat ~/.m2/settings.xml
+<?xml version="1.0" encoding="UTF-8"?>
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
+    <servers>
+        <server>
+            <id>os-core</id>
+            <username>slb-des-ext-collaboration</username>
+            <!-- Treat this auth token like a password. Do not share it with anyone, including Microsoft support. -->
+            <password>${VSTS_FEED_TOKEN}</password>
+        </server>
+    </servers>
+</settings>
+```
+
+* Update the Google cloud SDK to the latest version:
+
+```bash
+gcloud components update
+```
+* Set Google Project Id:
+
+```bash
+gcloud config set project <YOUR-PROJECT-ID>
+```
+
+* Perform a basic authentication in the selected project:
+
+```bash
+gcloud auth application-default login
+```
+
+* Navigate to notification service's root folder and run:
+
+```bash
+mvn jetty:run
+## Testing
+* Navigate to notification service's root folder and run:
+ 
+```bash
+mvn clean install   
+```
+
+* If you wish to see the coverage report then go to testing/target/site/jacoco-aggregate and open index.html
+
+* If you wish to build the project without running tests
+
+```bash
+mvn clean install -DskipTests
+```
+
+After configuring your environment as specified above, you can follow these steps to build and run the application. These steps should be invoked from the *repository root.*
+
+```bash
+cd provider/notification-reference/ && mvn spring-boot:run -Dspring-boot.run.profiles=local 
+```
+
+## Testing
+Navigate to notification service's root folder and run all the tests:
+
+```bash
+# build + test + install core service code
+$ (cd notification-core/ && mvn clean install)
+```
+
+## Test the application
+
+After the service has started it should be accessible via a web browser by visiting [http://localhost:8080/api/notification/v1/swagger-ui.html](http://localhost:8080/swagger-ui.html). If the request does not fail, you can then run the integration tests.
+
+### Dependencies needed to run the integration tests 
+* Java 8
+* Maven
+* Values for the following environment variables in Config.java
+  
+| name | value | description | sensitive? | source |
+| ---  | ---   | ---         | ---        | ---    |
+| `DE_OPS_TESTER` | `*****` | Service account base64 encoded string for API calls. Note: this user must have entitlements configured already, also **Private key id** of this account must be set in Register service variable SUBSCRIBER_PRIVATE_KEY_ID  | yes | https://console.cloud.google.com/iam-admin/serviceaccounts |
+| `DE_ADMIN_TESTER` | `*****` | Service account base64 encoded string for API calls. Note: this user must have entitlements configured already | yes | https://console.cloud.google.com/iam-admin/serviceaccounts |
+| `DE_EDITOR_TESTER` | `*****` | Service account base64 encoded string for API calls. Note: this user must have entitlements configured already  | yes | https://console.cloud.google.com/iam-admin/serviceaccounts |
+| `DE_NO_ACCESS_TESTER` | `*****` | Service account base64 encoded string for API calls. Note: this user must have entitlements configured already | yes | https://console.cloud.google.com/iam-admin/serviceaccounts |
+| `ENVIRONMENT` | `dev` OR `local` OR `dev_gke`| Local for running locally with services url's predefined as http://localhost , Dev & Dev_Gke is configurable environment | no | - |
+| `HMAC_SECRET` | ex`7a786376626e` | String in hex , must match pattern ^[a-zA-Z0-9]{8,30}+$ & be in register variable SUBSCRIBER_SECRET | yes | - |
+| `REGISTER_BASE_URL` | `http://localhost:8081/api/register/v1` | Register service url | no | - |
+| `NOTIFICATION_BASE_URL` | `http://localhost:8080/api/notification/v1/` | Notification service url  | no | - |
+| `INTEGRATION_TEST_AUDIENCE` | `********` | Client application ID | yes | https://console.cloud.google.com/apis/credentials |
+| `CLIENT_TENANT` | ex `opendes` | Client tenant | no | - |
+| `OSDU_TENANT` | ex `osdu` | Osdu tenant | no | - |
+| `TOPIC_ID` | ex `records-changed` | PubSub topic id | no | https://console.cloud.google.com/cloudpubsub/topic |
+| `REGISTER_CUSTOM_PUSH_URL_HMAC` | ex `http://localhost:8081/api/register/v1/test/challenge/hmac-integration-test` | Register testing push url | no | - |
+
+ **Entitlements configuration for integration accounts**
+ 
+ | DE_OPS_TESTER | DE_ADMIN_TESTER | DE_EDITOR_TESTER | DE_NO_ACCESS_TESTER | 
+ | ---  | ---   | ---  | ---   |
+ |notification.pubsub<br/>service.entitlements.user<br/>users<br/>users.datalake.ops</br>| service.entitlements.user<br/>users<br/>users.datalake.admins</br> | service.entitlements.user<br/>users<br/>users.datalake.editors</br> | service.entitlements.user<br/>users<br/>|
+
+Above variables should be configured in the release pipeline to run integration tests. You should also replace them with proper values if you wish to run tests locally.
+
+### Commands to run tests
+* Integration tests are refactored into two pieces: Core and Provider. Core contains business logic for tests and is a dependency for executing the tests from provider module. To build the core module, simply navigate to `notification-test-core` directory and run `mvn clean install`. This will build the core module
+* Next, to execute the integration tests, navigate to the provider module and execute `mvn test`
+```bash
+# (cd testing/notification-test-core/ && mvn clean install)
+# Note: this assumes that the environment variables for integration tests as outlined
+#       above are already exported in your environment.
+$ (cd testing/notification-test-gcp/ && mvn clean test)
+```
+
+## Deployment
+GKE Google Documentation: https://cloud.google.com/build/docs/deploying-builds/deploy-gke
+Anthos Google Documentation: https://cloud.google.com/anthos/multicluster-management/gateway/tutorials/cloud-build-integration
+
+## License
+Copyright © Google LLC
+
+Copyright © EPAM Systems
+ 
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+ 
+[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
+ 
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file
diff --git a/provider/notification-reference/kubernetes/deployments/deployment-os-notification-service.yml b/provider/notification-reference/kubernetes/deployments/deployment-os-notification-service.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ff445d3cdade8484695dd3f9e57ea88d66af7481
--- /dev/null
+++ b/provider/notification-reference/kubernetes/deployments/deployment-os-notification-service.yml
@@ -0,0 +1,81 @@
+apiVersion: v1
+data:
+  APP_ENTITLEMENTS: ${APP_ENTITLEMENTS}
+  APP_REGISTER: ${APP_REGISTER}
+  APP_PROJECT: ${APP_PROJECT}
+  APP_AUDIENCES: ${APP_AUDIENCES}
+  PARTITION_API: ${PARTITION_API}
+
+kind: ConfigMap
+metadata:
+  labels:
+    app: notification-reference
+  name: notification-config
+  namespace: default
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  generateName: notification-reference-anthos
+  labels:
+    app: notification-reference
+  name: notification-reference
+  namespace: default
+spec:
+  selector:
+    matchLabels:
+      app: notification-reference
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: notification-reference
+    spec:
+      containers:
+        -   env:
+              -   name: APP_ENTITLEMENTS
+                  valueFrom:
+                    configMapKeyRef:
+                      key: APP_ENTITLEMENTS
+                      name: notification-config
+              - name: APP_REGISTER
+                  valueFrom:
+                    configMapKeyRef:
+                      key: APP_REGISTER
+                      name: notification-config
+              - name: LOG_LEVEL
+                  valueFrom:
+                    configMapKeyRef:
+                      key: LOG_LEVEL
+                      name: notification-config
+              -   name: APP_PROJECT
+                  valueFrom:
+                    configMapKeyRef:
+                      key: APP_PROJECT
+                      name: notification-config
+              -   name: APP_AUDIENCES
+                  valueFrom:
+                    configMapKeyRef:
+                      key: APP_AUDIENCES
+                      name: notification-config
+              -   name: PARTITION_API
+                  valueFrom:
+                    configMapKeyRef:
+                      key: PARTITION_API
+                      name: notification-config
+            image: us.gcr.io/osdu-anthos-02/os-notification/anthos-notification-reference:9966597-dirty
+            name: notification-reference
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: notification-reference
+  namespace: default
+spec:
+  ports:
+    -   protocol: TCP
+        port: 80
+        targetPort: 8080
+  selector:
+    app: notification-reference
+  type: LoadBalancer
\ No newline at end of file
diff --git a/provider/notification-reference/pom.xml b/provider/notification-reference/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cd5610ffa7fdd0a6db36e08998ed93bdda91674d
--- /dev/null
+++ b/provider/notification-reference/pom.xml
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opengroup.osdu</groupId>
+    <artifactId>os-notification</artifactId>
+    <version>0.12.0-SNAPSHOT</version>
+    <relativePath>../../pom.xml</relativePath>
+  </parent>
+
+  <groupId>org.opengroup.osdu</groupId>
+  <artifactId>notification-reference</artifactId>
+  <version>0.12.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <properties>
+    <java.version>8</java.version>
+    <maven.compiler.target>${java.version}</maven.compiler.target>
+    <maven.compiler.source>${java.version}</maven.compiler.source>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opengroup.osdu</groupId>
+      <artifactId>core-lib-gcp</artifactId>
+      <version>0.11.0</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-amqp</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opengroup.osdu</groupId>
+      <artifactId>notification-core</artifactId>
+      <version>0.12.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.opengroup.osdu</groupId>
+      <artifactId>os-core-common</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>ch.qos.logback.contrib</groupId>
+      <artifactId>logback-json-classic</artifactId>
+      <version>0.1.5</version>
+    </dependency>
+
+    <!-- unit test dependencies -->
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito2</artifactId>
+      <version>2.0.2</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <version>2.0.2</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <version>2.0.2-beta</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.12</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <version>2.0.2</version>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
+        <configuration>
+          <profiles>
+            <profile>
+              <id>local</id>
+              <activation>
+                <activeByDefault>true</activeByDefault>
+              </activation>
+              <properties>
+                <spring.profiles.active>local</spring.profiles.active>
+              </properties>
+            </profile>
+            <profile>
+              <id>dev</id>
+              <properties>
+                <spring.profiles.active>dev</spring.profiles.active>
+              </properties>
+            </profile>
+          </profiles>
+        </configuration>
+        <executions>
+          <execution>
+            <goals>
+              <goal>repackage</goal>
+            </goals>
+            <configuration>
+              <classifier>spring-boot</classifier>
+              <mainClass>
+                org.opengroup.osdu.notification.provider.reference.Application
+              </mainClass>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>maven-war-plugin</artifactId>
+        <configuration>
+          <failOnMissingWebXml>false</failOnMissingWebXml>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.jacoco</groupId>
+        <artifactId>jacoco-maven-plugin</artifactId>
+        <version>0.7.7.201606060606</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>prepare-agent</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>report</id>
+            <phase>prepare-package</phase>
+            <goals>
+              <goal>report</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
\ No newline at end of file
diff --git a/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/Application.java b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/Application.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7639be09c10c143fd035434c5f62f9f53d2bcda
--- /dev/null
+++ b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/Application.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.provider.reference;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.FilterType;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+@SpringBootApplication
+@ComponentScan(value = {"org.opengroup.osdu"}, excludeFilters = {
+    @Filter(
+        type = FilterType.REGEX,
+        pattern = {"org.opengroup.osdu.core.gcp.multitenancy.StorageFactory"}
+    )
+})
+@EnableAsync
+public class Application {
+
+  public static void main(String[] args) {
+    SpringApplication.run(new Class[]{Application.class}, args);
+  }
+}
\ No newline at end of file
diff --git a/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/config/PropertiesConfiguration.java b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/config/PropertiesConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..c34830e3c279a9bcaca126ba82efae448752618a
--- /dev/null
+++ b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/config/PropertiesConfiguration.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.provider.reference.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConfigurationProperties
+@Data
+public class PropertiesConfiguration {
+
+  private String authorizeAPI;
+  private String registerAPI;
+  private String projectId;
+  private Integer expireTime = 300;
+  private Integer maxCacheSize = 10;
+
+  private String googleCloudProject;
+  private String googleCloudProjectRegion;
+  private String googleAudiences;
+}
diff --git a/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/pubsub/PubsubHandshakeHandler.java b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/pubsub/PubsubHandshakeHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..6e3d7e7dd1f9cfbf2a0f904b68653f089a66cb3c
--- /dev/null
+++ b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/pubsub/PubsubHandshakeHandler.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.provider.reference.pubsub;
+
+import org.opengroup.osdu.notification.provider.interfaces.IPubsubHandshakeHandler;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+@Component
+@Lazy
+public class PubsubHandshakeHandler implements IPubsubHandshakeHandler {
+
+  @Override
+  public String getHandshakeResponse() {
+    return null;
+  }
+}
\ No newline at end of file
diff --git a/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/pubsub/PubsubRequestBodyExtractor.java b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/pubsub/PubsubRequestBodyExtractor.java
new file mode 100644
index 0000000000000000000000000000000000000000..8928a72498717e86317789d054d95eecb65eca31
--- /dev/null
+++ b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/pubsub/PubsubRequestBodyExtractor.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.provider.reference.pubsub;
+
+import com.google.common.base.Strings;
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.servlet.http.HttpServletRequest;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.storage.MessageContent;
+import org.opengroup.osdu.notification.provider.interfaces.IPubsubRequestBodyExtractor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.annotation.RequestScope;
+
+@Component
+@RequestScope
+public class PubsubRequestBodyExtractor implements IPubsubRequestBodyExtractor {
+
+  private static final String INVALID_PUBSUB_MESSAGE = "Invalid pubsub message";
+  private static final Gson GSON = new Gson();
+  private MessageContent messageContent;
+  private JsonObject root = null;
+
+  @Autowired
+  private HttpServletRequest request;
+
+  @Autowired
+  private JaxRsDpsLog log;
+
+  public Map<String, String> extractAttributesFromRequestBody() {
+    if (this.messageContent == null) {
+      this.messageContent = this.extractPubsubMessageFromRequestBody();
+    }
+    return this.messageContent.getAttributes();
+  }
+
+  public String extractDataFromRequestBody() {
+    if (this.messageContent == null) {
+      this.messageContent = this.extractPubsubMessageFromRequestBody();
+    }
+    return this.messageContent.getData();
+  }
+
+  public String extractNotificationIdFromRequestBody() {
+    if (this.root == null) {
+      this.root = this.extractRootJsonElementFromRequestBody();
+    }
+    JsonElement subscription = this.root.get("subscription");
+    if (subscription == null) {
+      throw new AppException(HttpStatus.BAD_REQUEST.value(), INVALID_PUBSUB_MESSAGE,
+          "subscription object not found");
+    }
+
+    String[] fullNotificationId = subscription.getAsString().split("/");
+    return fullNotificationId[fullNotificationId.length - 1];
+  }
+
+  @Override
+  public boolean isHandshakeRequest() {
+    return false;
+  }
+
+  private MessageContent extractPubsubMessageFromRequestBody() {
+    if (this.root == null) {
+      this.root = this.extractRootJsonElementFromRequestBody();
+    }
+    JsonElement message = this.root.get("message");
+    if (message == null) {
+      throw new AppException(HttpStatus.BAD_REQUEST.value(), INVALID_PUBSUB_MESSAGE,
+          "message object not found");
+    }
+    MessageContent content = GSON.fromJson(message.toString(), MessageContent.class);
+
+    Map<String, String> attributes = content.getAttributes();
+    if (attributes == null || attributes.isEmpty()) {
+      log.error("Incorrect Message: " + message.toString());
+      throw new AppException(HttpStatus.BAD_REQUEST.value(), INVALID_PUBSUB_MESSAGE,
+          "attribute map not found");
+    }
+    String data = content.getData();
+    if (Strings.isNullOrEmpty(data)) {
+      throw new AppException(HttpStatus.BAD_REQUEST.value(), INVALID_PUBSUB_MESSAGE,
+          "data field not found");
+    }
+    Map<String, String> lowerCase = new HashMap<>();
+    attributes.forEach((key, value) -> lowerCase.put(key.toLowerCase(), value));
+    if (Strings.isNullOrEmpty(attributes.get("data-partition-id"))) {
+      throw new AppException(HttpStatus.BAD_REQUEST.value(), INVALID_PUBSUB_MESSAGE,
+          "No tenant information from pubsub message.");
+    }
+    content.setAttributes(lowerCase);
+
+    String decoded = new String(Base64.getDecoder().decode(data));
+    content.setData(decoded);
+
+    return content;
+  }
+
+  private JsonObject extractRootJsonElementFromRequestBody() {
+    try {
+      JsonParser jsonParser = new JsonParser();
+      BufferedReader reader = request.getReader();
+      Stream<String> lines = reader.lines();
+      String requestBody = lines.collect(Collectors.joining("\n"));
+      JsonElement rootElement = jsonParser.parse(requestBody);
+      if (!(rootElement instanceof JsonObject)) {
+        throw new AppException(HttpStatus.BAD_REQUEST.value(), "RequestBody is not JsonObject.",
+            "Request Body should be JsonObject to be processed.");
+      }
+      return rootElement.getAsJsonObject();
+    } catch (IOException e) {
+      throw new AppException(HttpStatus.INTERNAL_SERVER_ERROR.value(),
+          "Request payload parsing error",
+          "Unable to parse request payload.", e);
+    }
+  }
+}
diff --git a/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/security/SecurityConfig.java b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/security/SecurityConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..a60a619cdebadfddf4c31a9033587d9a93d5a5b8
--- /dev/null
+++ b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/security/SecurityConfig.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.provider.reference.security;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+  @Override
+  protected void configure(HttpSecurity httpSecurity) throws Exception {
+    httpSecurity
+        .httpBasic().disable()
+        .csrf().disable();
+  }
+}
\ No newline at end of file
diff --git a/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/AppProperties.java b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/AppProperties.java
new file mode 100644
index 0000000000000000000000000000000000000000..baaa243682eea04f7023ade9cc04c18ef393ccb2
--- /dev/null
+++ b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/AppProperties.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.provider.reference.util;
+
+import lombok.RequiredArgsConstructor;
+import org.opengroup.osdu.notification.provider.interfaces.IAppProperties;
+import org.opengroup.osdu.notification.provider.reference.config.PropertiesConfiguration;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class AppProperties implements IAppProperties {
+
+  private final PropertiesConfiguration propertiesConfiguration;
+
+  public String getAuthorizeAPI() {
+    return propertiesConfiguration.getAuthorizeAPI();
+  }
+
+  public String getRegisterAPI() {
+    return propertiesConfiguration.getRegisterAPI();
+  }
+
+  public String getPubSubServiceAccountEmail() {
+    return String.format("de-notification-service@%s.iam.gserviceaccount.com",
+        propertiesConfiguration.getProjectId());
+  }
+
+  public String getGoogleAudiences() {
+    return propertiesConfiguration.getGoogleAudiences();
+  }
+}
diff --git a/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/GoogleServiceAccountImpl.java b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/GoogleServiceAccountImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f511a67ed894418932f029b1b4037423042b9b2
--- /dev/null
+++ b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/GoogleServiceAccountImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.provider.reference.util;
+
+import lombok.SneakyThrows;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.opengroup.osdu.core.gcp.GoogleIdToken.IGoogleIdTokenFactory;
+import org.opengroup.osdu.notification.provider.interfaces.IGoogleServiceAccount;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class GoogleServiceAccountImpl implements IGoogleServiceAccount {
+
+  @Autowired
+  private IGoogleIdTokenFactory googleIdTokenFactory;
+  @Autowired
+  private CloseableHttpClient closeableHttpClient;
+
+  @SneakyThrows
+  @Override
+  public String getIdToken(String keyString, String audience) {
+    return this.googleIdTokenFactory.getGoogleIdToken(keyString, audience,
+        this.closeableHttpClient);
+  }
+}
\ No newline at end of file
diff --git a/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/GoogleServiceAccountValidatorGenerator.java b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/GoogleServiceAccountValidatorGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..462f9012c4ceee99a22bd7d5230bb51ee5a2abb6
--- /dev/null
+++ b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/GoogleServiceAccountValidatorGenerator.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.provider.reference.util;
+
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
+import com.google.api.client.http.javanet.NetHttpTransport;
+import com.google.api.client.json.jackson2.JacksonFactory;
+import java.util.Arrays;
+import org.springframework.stereotype.Component;
+
+@Component
+public class GoogleServiceAccountValidatorGenerator {
+
+  public GoogleIdTokenVerifier getVerifier(NetHttpTransport transport, JacksonFactory factory,
+      String... googleAudiences) {
+    GoogleIdTokenVerifier verifier;
+    if (googleAudiences == null || googleAudiences.length == 0) {
+      verifier = new GoogleIdTokenVerifier.Builder(transport, factory)
+          .build();
+    } else {
+      verifier = new GoogleIdTokenVerifier.Builder(transport, factory)
+          .setAudience(Arrays.asList(googleAudiences))
+          .build();
+    }
+    return verifier;
+  }
+}
diff --git a/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/GoogleServiceAccountValidatorImpl.java b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/GoogleServiceAccountValidatorImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..5841f8a7ea7f25eefacc0fda1bd5041fbb68a57a
--- /dev/null
+++ b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/GoogleServiceAccountValidatorImpl.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.provider.reference.util;
+
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
+import com.google.api.client.http.javanet.NetHttpTransport;
+import com.google.api.client.json.jackson2.JacksonFactory;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.notification.provider.interfaces.IServiceAccountValidator;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class GoogleServiceAccountValidatorImpl implements IServiceAccountValidator {
+
+  private final NetHttpTransport netHttpTransport = new NetHttpTransport();
+  private final JacksonFactory jacksonFactory = new JacksonFactory();
+
+  @Autowired
+  private JaxRsDpsLog log;
+  @Autowired
+  private AppProperties appConfig;
+  @Autowired
+  private GoogleServiceAccountValidatorGenerator verifierGenerator;
+
+  @Override
+  public boolean isValidPublisherServiceAccount(String jwt) {
+    return isValidServiceAccount(jwt, this.appConfig.getPubSubServiceAccountEmail());
+  }
+
+  @Override
+  public boolean isValidServiceAccount(String jwt, String userIdentity, String... googleAudiences) {
+    GoogleIdTokenVerifier verifier = this.verifierGenerator.getVerifier(this.netHttpTransport,
+        this.jacksonFactory, googleAudiences);
+    try {
+      GoogleIdToken idToken = verifier.verify(jwt);
+      if (idToken != null) {
+        GoogleIdToken.Payload payload = idToken.getPayload();
+
+        String email = payload.getEmail();
+        Boolean emailVerified = payload.getEmailVerified();
+
+        return (emailVerified && (email.equalsIgnoreCase(userIdentity)));
+      } else {
+        return false;
+      }
+    } catch (Exception e) {
+      this.log.error("Error when validating google id token", e);
+      return false;
+    }
+  }
+}
diff --git a/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/JwtValidity.java b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/JwtValidity.java
new file mode 100644
index 0000000000000000000000000000000000000000..282ad4c19c4aadae3306bb3c4db0b430aee6debe
--- /dev/null
+++ b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/JwtValidity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.provider.reference.util;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+public class JwtValidity {
+
+  String token;
+  long expiryTime;
+
+  JwtValidity(String jwt, long expiryTime) {
+    this.token = jwt;
+    this.expiryTime = expiryTime;
+  }
+}
diff --git a/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/ServiceAccountJwtGcpClientImpl.java b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/ServiceAccountJwtGcpClientImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..0bf66a94a46a2a85e3a98a5d799634364a96351f
--- /dev/null
+++ b/provider/notification-reference/src/main/java/org/opengroup/osdu/notification/provider/reference/util/ServiceAccountJwtGcpClientImpl.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.provider.reference.util;
+
+import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
+import com.google.api.client.http.HttpTransport;
+import com.google.api.client.json.JsonFactory;
+import com.google.api.client.json.jackson.JacksonFactory;
+import com.google.api.services.iam.v1.Iam;
+import com.google.api.services.iam.v1.IamScopes;
+import com.google.api.services.iam.v1.model.SignJwtRequest;
+import com.google.api.services.iam.v1.model.SignJwtResponse;
+import com.google.auth.http.HttpCredentialsAdapter;
+import com.google.auth.oauth2.GoogleCredentials;
+import com.google.common.base.Strings;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpStatus;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.tenant.TenantInfo;
+import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient;
+import org.opengroup.osdu.core.gcp.multitenancy.TenantFactory;
+
+public class ServiceAccountJwtGcpClientImpl implements IServiceAccountJwtClient {
+
+  private AppProperties config;
+  private static final String JWT_AUDIENCE = "https://www.googleapis.com/oauth2/v4/token";
+  private static final String SERVICE_ACCOUNT_NAME_FORMAT = "projects/%s/serviceAccounts/%s";
+  private static final JsonFactory JSON_FACTORY = new JacksonFactory();
+  static final String INVALID_INPUT = "Invalid inputs provided to getIdToken function";
+  static final String INVALID_DATA_PARTITION = "Invalid data partition id";
+
+  private static ConcurrentHashMap<String, JwtValidity> jwtCache = new ConcurrentHashMap<>();
+  private Iam iam;
+
+  public ServiceAccountJwtGcpClientImpl(AppProperties config) {
+    if (config == null) {
+      throw new IllegalArgumentException("AppProperties is null when initializing jwt client.");
+    } else {
+      this.config = config;
+    }
+  }
+
+  public String getIdToken(String dataPartitionId) {
+    String googleAudience = this.config.getGoogleAudiences();
+    String hostName = this.config.getRegisterAPI();
+    if (Strings.isNullOrEmpty(dataPartitionId) || Strings.isNullOrEmpty(googleAudience)
+        || Strings.isNullOrEmpty(hostName)) {
+      throw new AppException(HttpStatus.SC_BAD_REQUEST,
+          "data partition id, audiences or hostname are null", INVALID_INPUT);
+    }
+    try {
+      // Check if there is already a valid jwt
+      String key = dataPartitionId + googleAudience + hostName;
+      String jwt = checkAndGetJwtIfValid(key);
+        if (!Strings.isNullOrEmpty(jwt)) {
+            return jwt;
+        }
+
+      TenantInfo tenantInfo = new TenantFactory().getTenantInfo(dataPartitionId);
+      if (tenantInfo == null) {
+        throw new AppException(HttpStatus.SC_BAD_REQUEST, "data partition id is invalid",
+            INVALID_DATA_PARTITION);
+      }
+      long currentTime = System.currentTimeMillis() / 1000;
+      long expiryTime = currentTime + 3600;
+
+      // get signed JWT
+      Map<String, Object> signJwtPayload = this.getJwtCreationPayload(tenantInfo, googleAudience,
+          currentTime, expiryTime);
+
+      SignJwtRequest signJwtRequest = new SignJwtRequest();
+      signJwtRequest.setPayload(JSON_FACTORY.toString(signJwtPayload));
+
+      String serviceAccountName = String.format(SERVICE_ACCOUNT_NAME_FORMAT,
+          tenantInfo.getProjectId(),
+          tenantInfo.getServiceAccount());
+
+      Iam.Projects.ServiceAccounts.SignJwt signJwt = this.getIam(hostName).projects()
+          .serviceAccounts()
+          .signJwt(serviceAccountName, signJwtRequest);
+      SignJwtResponse signJwtResponse = signJwt.execute();
+      String signedJwt = signJwtResponse.getSignedJwt();
+
+      // get id token
+      List<NameValuePair> postParameters = new ArrayList<>();
+      postParameters.add(
+          new BasicNameValuePair("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"));
+      postParameters.add(new BasicNameValuePair("assertion", signedJwt));
+
+      HttpPost post = new HttpPost(JWT_AUDIENCE);
+      post.setHeader(HttpHeaders.CONTENT_TYPE,
+          ContentType.APPLICATION_FORM_URLENCODED.getMimeType());
+      post.setEntity(new UrlEncodedFormEntity(postParameters, "UTF-8"));
+
+      try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+        CloseableHttpResponse httpResponse = httpClient.execute(post);
+
+        JsonObject jsonContent = new JsonParser().parse(
+                EntityUtils.toString(httpResponse.getEntity()))
+            .getAsJsonObject();
+
+        if (!jsonContent.has("id_token")) {
+          throw new AppException(HttpStatus.SC_UNAUTHORIZED,
+              "User is not authorized to perform this operation.",
+              "Unauthorized to generate token");
+        }
+
+        String token = "Bearer " + jsonContent.get("id_token").getAsString();
+        jwtCache.put(key, new JwtValidity(token, expiryTime));
+        return token;
+      }
+    } catch (Exception e) {
+      throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR,
+          "Error happens when generating sauth token", "Error generating token", e);
+    }
+
+  }
+
+  Iam getIam(String hostName) throws GeneralSecurityException, IOException {
+    if (this.iam == null) {
+      HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
+
+      GoogleCredentials credential = GoogleCredentials.getApplicationDefault();
+      if (credential.createScopedRequired()) {
+        List<String> scopes = new ArrayList<>();
+        scopes.add(IamScopes.CLOUD_PLATFORM);
+        credential = credential.createScoped(scopes);
+      }
+
+      this.iam = new Iam.Builder(httpTransport, JSON_FACTORY,
+          new HttpCredentialsAdapter(credential))
+          .setApplicationName(hostName).build();
+    }
+
+    return this.iam;
+  }
+
+  // THIS METHOD IS ONLY TO ENABLE UNIT TESTING
+  boolean reduceTenantExpiry(String dataPartitionId, String googleAudience, String hostName,
+      long keepDifference) {
+    JwtValidity jwtValidity = jwtCache.get(dataPartitionId + googleAudience + hostName);
+      if (jwtValidity == null) {
+          return false;
+      }
+
+    long currentTime = System.currentTimeMillis() / 1000;
+    jwtValidity.expiryTime = currentTime + keepDifference;
+    return true;
+  }
+
+  // THIS METHOD IS ONLY TO ENABLE UNIT TESTING
+  void clearCache() {
+    jwtCache.clear();
+  }
+
+  private String checkAndGetJwtIfValid(String key) {
+    JwtValidity jwtValidity = jwtCache.get(key);
+      if (jwtValidity == null) {
+          return null;
+      }
+
+    // get current time
+    long currentTime = System.currentTimeMillis() / 1000;
+
+    // If exipring in less than 5 minutes then need to renew the token
+    if (jwtValidity.expiryTime - 300 < currentTime) {
+      jwtCache.remove(key);
+      return null;
+    }
+
+    return jwtValidity.token;
+  }
+
+
+  private Map<String, Object> getJwtCreationPayload(TenantInfo tenantInfo, String googleAudience,
+      long currentTime, long expiryTime) {
+    if (googleAudience.contains(",")) {
+      googleAudience = googleAudience.split(",")[0];
+    }
+    Map<String, Object> payload = new HashMap<>();
+    payload.put("target_audience", googleAudience);
+    payload.put("aud", JWT_AUDIENCE);
+    payload.put("exp", expiryTime);
+    payload.put("iat", currentTime);
+    payload.put("iss", tenantInfo.getServiceAccount());
+    return payload;
+  }
+}
+
+
diff --git a/provider/notification-reference/src/main/resources/application.properties b/provider/notification-reference/src/main/resources/application.properties
new file mode 100644
index 0000000000000000000000000000000000000000..f16a36215afb5b0e96810040ffcfe01e8eee60ca
--- /dev/null
+++ b/provider/notification-reference/src/main/resources/application.properties
@@ -0,0 +1,33 @@
+#
+#   Copyright 2017-2020, Schlumberger
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+
+LOG_PREFIX=notification
+logging.level.org.springframework.web=${LOG_LEVEL:DEBUG}
+server.servlet.contextPath=/api/notification/v1
+app.expireTime=300
+app.maxCacheSize=10
+server.error.whitelabel.enabled=false
+
+authorize-api=${APP_ENTITLEMENTS}
+register-api=${APP_REGISTER}
+project-api=${APP_PROJECT}
+expire-time=${APP_EXPIRE_TIME:300}
+max-cache-size=${APP_MAX_CACHE_SIZE:10}
+
+
+GOOGLE_AUDIENCES=${APP_AUDIENCES}
+google-audiences=${APP_AUDIENCES}
+partition-api=${PARTITION_API:http://localhost:8081/api/partition/v1}
\ No newline at end of file
diff --git a/provider/notification-reference/src/main/resources/logback.xml b/provider/notification-reference/src/main/resources/logback.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cbd32dfed70fc29a19a7876f0bb7deacc8daf3cb
--- /dev/null
+++ b/provider/notification-reference/src/main/resources/logback.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+  <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
+  <property resource="application.properties"/>
+  <logger name="org.opengroup.osdu" level="${LOG_LEVEL}"/>
+  <springProfile name="local">
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+      <encoder>
+        <pattern>%yellow([%thread]) %highlight(| %-5level |) %green(%d) %cyan(| %logger{15} |)
+          %highlight(%msg) %n
+        </pattern>
+        <charset>utf8</charset>
+      </encoder>
+    </appender>
+    <root level="info">
+      <appender-ref ref="CONSOLE"/>
+    </root>
+  </springProfile>
+
+  <springProfile name="!local">
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+      <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
+        <layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
+          <timestampFormat>yyyy-MM-dd HH:mm:ss.SSS</timestampFormat>
+          <timestampFormatTimezoneId>Etc/UTC</timestampFormatTimezoneId>
+          <appendLineSeparator>true</appendLineSeparator>
+
+          <jsonFormatter class="org.opengroup.osdu.core.gcp.logging.formatter.GoogleJsonFormatter">
+            <prettyPrint>false</prettyPrint>
+          </jsonFormatter>
+        </layout>
+      </encoder>
+    </appender>
+    -->
+
+    <root level="info">
+      <appender-ref ref="stdout"/>
+    </root>
+  </springProfile>
+
+</configuration>
\ No newline at end of file
diff --git a/provider/notification-reference/src/main/test/java/org/opengroup/osdu/notification/util/GoogleServiceAccountValidatorGeneratorTest.java b/provider/notification-reference/src/main/test/java/org/opengroup/osdu/notification/util/GoogleServiceAccountValidatorGeneratorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..73f2011d0c27363e4e0da89635b9f487e277e98d
--- /dev/null
+++ b/provider/notification-reference/src/main/test/java/org/opengroup/osdu/notification/util/GoogleServiceAccountValidatorGeneratorTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.util;
+
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
+import com.google.api.client.http.javanet.NetHttpTransport;
+import com.google.api.client.json.jackson2.JacksonFactory;
+import java.util.Collection;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.opengroup.osdu.notification.provider.reference.util.GoogleServiceAccountValidatorGenerator;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@RunWith(PowerMockRunner.class)
+public class GoogleServiceAccountValidatorGeneratorTest {
+
+  private final NetHttpTransport netHttpTransport = new NetHttpTransport();
+  private final JacksonFactory jacksonFactory = new JacksonFactory();
+  private static final String AUDIENCE_1 = "aud1";
+  private static final String AUDIENCE_2 = "aud2";
+
+  @InjectMocks
+  private GoogleServiceAccountValidatorGenerator sut;
+
+  @Test
+  public void should_returnVerifierWithoutAudiences_when_noAudiencesProvided() {
+    GoogleIdTokenVerifier verifier = this.sut.getVerifier(netHttpTransport, jacksonFactory);
+    Assert.assertNull(verifier.getAudience());
+  }
+
+  @Test
+  public void should_returnVerifierWithAudiences_when_AudiencesProvided() {
+    GoogleIdTokenVerifier verifier = this.sut.getVerifier(netHttpTransport, jacksonFactory,
+        AUDIENCE_1, AUDIENCE_2);
+    Collection<String> audiences = verifier.getAudience();
+    Assert.assertTrue(audiences.contains(AUDIENCE_1));
+    Assert.assertTrue(audiences.contains(AUDIENCE_2));
+  }
+}
diff --git a/provider/notification-reference/src/main/test/java/org/opengroup/osdu/notification/util/GoogleServiceAccountValidatorImplTests.java b/provider/notification-reference/src/main/test/java/org/opengroup/osdu/notification/util/GoogleServiceAccountValidatorImplTests.java
new file mode 100644
index 0000000000000000000000000000000000000000..22f9497bfcfbdcbc5d92b5801d193f661f1d0557
--- /dev/null
+++ b/provider/notification-reference/src/main/test/java/org/opengroup/osdu/notification/util/GoogleServiceAccountValidatorImplTests.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2021 Google LLC
+ * Copyright 2021 EPAM Systems, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opengroup.osdu.notification.util;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
+import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
+import java.io.IOException;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.notification.provider.reference.util.GoogleServiceAccountValidatorGenerator;
+import org.opengroup.osdu.notification.provider.reference.util.GoogleServiceAccountValidatorImpl;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@RunWith(PowerMockRunner.class)
+public class GoogleServiceAccountValidatorImplTests {
+
+  private static final String TEST_JWT = "testjwt";
+  private static final String TEST_USER_IDENTITY = "testidentity";
+
+  @Mock
+  private JaxRsDpsLog log;
+  @Mock
+  private GoogleServiceAccountValidatorGenerator verifierGenerator;
+  @Mock
+  private GoogleIdTokenVerifier verifier;
+  @Mock
+  private GoogleIdToken idToken;
+  @Mock
+  private GoogleIdToken.Payload payload;
+  @InjectMocks
+  private GoogleServiceAccountValidatorImpl sut;
+
+  @Test
+  public void should_returnTrue_when_tokenValidAndUserIdentityCorrect() throws Exception {
+    when(this.verifierGenerator.getVerifier(any(), any())).thenReturn(this.verifier);
+    when(this.verifier.verify(TEST_JWT)).thenReturn(this.idToken);
+    when(this.idToken.getPayload()).thenReturn(this.payload);
+    when(this.payload.getEmail()).thenReturn(TEST_USER_IDENTITY);
+    when(this.payload.getEmailVerified()).thenReturn(Boolean.TRUE);
+    Assert.assertTrue(this.sut.isValidServiceAccount(TEST_JWT, TEST_USER_IDENTITY));
+  }
+
+  @Test
+  public void should_returnFalse_when_tokenInvalid() throws Exception {
+    when(this.verifierGenerator.getVerifier(any(), any())).thenReturn(this.verifier);
+    when(this.verifier.verify(TEST_JWT)).thenReturn(null);
+    Assert.assertFalse(this.sut.isValidServiceAccount(TEST_JWT, TEST_USER_IDENTITY));
+  }
+
+  @Test
+  public void should_returnFalse_when_tokenValidAndUserIdentityIncorrect() throws Exception {
+    when(this.verifierGenerator.getVerifier(any(), any())).thenReturn(this.verifier);
+    when(this.verifier.verify(TEST_JWT)).thenReturn(this.idToken);
+    when(this.idToken.getPayload()).thenReturn(this.payload);
+    when(this.payload.getEmail()).thenReturn("wrongIdentity");
+    when(this.payload.getEmailVerified()).thenReturn(Boolean.TRUE);
+    Assert.assertFalse(this.sut.isValidServiceAccount(TEST_JWT, TEST_USER_IDENTITY));
+  }
+
+  @Test
+  public void should_returnFalse_when_tokenValidAndUserIdentityCorrect_butEmailNotVerified()
+      throws Exception {
+    when(this.verifierGenerator.getVerifier(any(), any())).thenReturn(this.verifier);
+    when(this.verifier.verify(TEST_JWT)).thenReturn(this.idToken);
+    when(this.idToken.getPayload()).thenReturn(this.payload);
+    when(this.payload.getEmail()).thenReturn(TEST_USER_IDENTITY);
+    when(this.payload.getEmailVerified()).thenReturn(Boolean.FALSE);
+    Assert.assertFalse(this.sut.isValidServiceAccount(TEST_JWT, TEST_USER_IDENTITY));
+  }
+
+  @Test
+  public void should_logExceptionAndReturnFalse_when_tokenValidationThrowsException()
+      throws Exception {
+    when(this.verifierGenerator.getVerifier(any(), any())).thenReturn(this.verifier);
+    IOException e = new IOException("invalid token");
+    when(this.verifier.verify(TEST_JWT)).thenThrow(e);
+    Assert.assertFalse(this.sut.isValidServiceAccount(TEST_JWT, TEST_USER_IDENTITY));
+    verify(this.log, times(1)).error("Error when validating google id token", e);
+  }
+}
diff --git a/testing/notification-test-aws/pom.xml b/testing/notification-test-aws/pom.xml
index c508099548475c07c59c0623051d8ae9fe44246e..c3336063beba95b562f28997ac649e3b8da0cfb6 100644
--- a/testing/notification-test-aws/pom.xml
+++ b/testing/notification-test-aws/pom.xml
@@ -21,13 +21,13 @@
     <parent>
         <groupId>org.opengroup.osdu</groupId>
         <artifactId>os-notification-testing</artifactId>
-        <version>0.9.0-SNAPSHOT</version>
+        <version>0.12.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
     <groupId>org.opengroup.osdu</groupId>
     <artifactId>notification-test-aws</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.12.0-SNAPSHOT</version>
     <name>notification-test-aws</name>
     <description>AWS Integration tests for Notification Service</description>
     <packaging>jar</packaging>
@@ -52,7 +52,7 @@
         <dependency>
             <groupId>org.opengroup.osdu.notification</groupId>
             <artifactId>notification-test-core</artifactId>
-            <version>0.9.0-SNAPSHOT</version>
+            <version>0.12.0-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.opengroup.osdu</groupId>
diff --git a/testing/notification-test-aws/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java b/testing/notification-test-aws/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
index f55ddb2c1550366a7db59d9f64b3417b8cdc9a46..15bce5ba911fe77c558a75f3dc4a29868d56d0f8 100644
--- a/testing/notification-test-aws/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
+++ b/testing/notification-test-aws/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
@@ -50,13 +50,6 @@ public class TestPubsubEndpointHMAC extends PubsubEndpointHMACTests {
         this.testUtils = null;
     }
 
-    @Test
-    @Override
-    public void should_return400_when_makingHttpRequestWithoutToken() throws Exception {
-        ClientResponse response =  descriptor.run(getArg(), "");
-        assertEquals(error(response.getEntity(String.class)), 403, response.getStatus());
-    }
-
     @Test
     @Override
     public void should_return401_when_noAccessOnCustomerTenant() throws Exception {
diff --git a/testing/notification-test-azure/pom.xml b/testing/notification-test-azure/pom.xml
index 28532c66c3047b77f5cc8dd7d2b63a63df830f6c..e206e2afba65d158c5af18936ceb106669981bce 100644
--- a/testing/notification-test-azure/pom.xml
+++ b/testing/notification-test-azure/pom.xml
@@ -21,13 +21,13 @@
     <parent>
         <groupId>org.opengroup.osdu</groupId>
         <artifactId>os-notification-testing</artifactId>
-        <version>0.9.0-SNAPSHOT</version>
+        <version>0.12.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
     <groupId>org.opengroup.osdu</groupId>
     <artifactId>notification-test-azure</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.12.0-SNAPSHOT</version>
     <name>notification-test-azure</name>
     <description>Integration tests Azure for notification</description>
     <packaging>jar</packaging>
@@ -42,7 +42,7 @@
         <dependency>
             <groupId>org.opengroup.osdu.notification</groupId>
             <artifactId>notification-test-core</artifactId>
-            <version>0.9.0-SNAPSHOT</version>
+            <version>0.12.0-SNAPSHOT</version>
         </dependency>
 
         <dependency>
@@ -54,6 +54,10 @@
                     <groupId>io.projectreactor</groupId>
                     <artifactId>reactor-core</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>com.azure</groupId>
+                    <artifactId>azure-storage-blob</artifactId>
+                </exclusion>
                 <exclusion>
                     <groupId>io.projectreactor.netty</groupId>
                     <artifactId>reactor-netty</artifactId>
diff --git a/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/StorageIntegrationDescriptor.java b/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/StorageIntegrationDescriptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..3dee5339b926db66dd40bd43d06b3e82400e3c11
--- /dev/null
+++ b/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/StorageIntegrationDescriptor.java
@@ -0,0 +1,86 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.api;
+
+import org.opengroup.osdu.notification.util.Config;
+import org.opengroup.osdu.notification.util.RestDescriptor;
+import org.opengroup.osdu.notification.util.TestUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class StorageIntegrationDescriptor extends RestDescriptor {
+
+    protected static final String LEGAL_TAG = TestUtils.getOsduTenant() + "-test-tag";
+
+    @Override
+    public String getPath() {
+        return "records";
+    }
+
+    @Override
+    public String getHttpMethod() {
+        return "PUT";
+    }
+
+    @Override
+    public String getValidBody() {
+        return "[\n" +
+                "  {\n" +
+                "      \"data\":{\n" +
+                "            \"Spuddate\":\"atspud\",\n" +
+                "            \"UWI\":\"atuwi\",\n" +
+                "            \"dlLatLongWGS84latitude\":\"latitude\",\n" +
+                "            \"dlLatLongWGS84longitude\":\"longitude\"},\n" +
+                "      \"version\":1591087431362345,\n" +
+                "      \"kind\":\"opendes:at:wellbore:1.0.0\",\n" +
+                "      \"acl\":{\n" +
+                "            \"viewers\":[\n" +
+                "                 \"data.test1@opendes.contoso.com\"],\n" +
+                "            \"owners\":[\n" +
+                "                 \"data.test1@opendes.contoso.com\"]},\n" +
+                "      \"legal\":{\n" +
+                "            \"legaltags\":[\n" +
+                "                 \"" + LEGAL_TAG + "\"],\n" +
+                "            \"otherRelevantDataCountries\":[\n" +
+                "                 \"BR\"],\n" +
+                "            \"status\":\"compliant\"},\n" +
+                "      \"createUser\":\"integrationtest@opendes.iam.gserviceaccount.com\",\n" +
+                "      \"createTime\":\"2020-06-01T18:32:52.054Z\",\n" +
+                "      \"modifyUser\":\"integrationtest@opendes.iam.gserviceaccount.com\",\n" +
+                "      \"modifyTime\":\"2020-06-02T08:43:51.553Z\"\n" +
+                "  }\n" +
+                "]";
+    }
+
+    @Override
+    public Map<String, String> getOsduTenantHeaders() {
+        Map<String, String> headers = new HashMap<>();
+        headers.put("data-partition-id", Config.Instance().OsduTenant);
+        headers.put("correlation-id", "storage-notification-it");
+        return headers;
+    }
+
+    // Customer Tenant headers is not required by the current Storage -Notification
+    // Integration Test scenario.It might be useful in upcoming test scenarios/cases
+    @Override
+    public Map<String, String> getCustomerTenantHeaders() {
+        Map<String, String> headers = new HashMap<>();
+        headers.put("data-partition-id", Config.Instance().ClientTenant);
+        headers.put("correlation-id", "storage-notification-it");
+        return headers;
+    }
+}
\ No newline at end of file
diff --git a/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java b/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
index 3f429752e1bbd58ecb5b69bfb2c6e6fbab9bc9cf..501e113e44f7d097dd9661f4e5a7f01ba4641603 100644
--- a/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
+++ b/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
@@ -98,7 +98,7 @@ public class TestPubsubEndpointHMAC extends PubsubEndpointHMACTests {
             ClientResponse response = descriptor.run(this.getArg(), this.testUtils.getOpsToken());
             Assert.assertEquals(this.error(response.getStatus() == 204 ? "" : (String)response.getEntity(String.class)), (long)this.expectedOkResponseCode(), (long)response.getStatus());
             Assert.assertEquals("GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH", response.getHeaders().getFirst("Access-Control-Allow-Methods"));
-            Assert.assertEquals("origin, content-type, accept, authorization, data-partition-id, correlation-id, appkey", response.getHeaders().getFirst("Access-Control-Allow-Headers"));
+            Assert.assertEquals("access-control-allow-origin, origin, content-type, accept, authorization, data-partition-id, correlation-id, appkey", response.getHeaders().getFirst("Access-Control-Allow-Headers"));
             Assert.assertEquals("*", response.getHeaders().getFirst("Access-Control-Allow-Origin"));
             Assert.assertEquals("true", response.getHeaders().getFirst("Access-Control-Allow-Credentials"));
             Assert.assertEquals("DENY", response.getHeaders().getFirst("X-Frame-Options"));
diff --git a/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/TestStorageIntegration.java b/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/TestStorageIntegration.java
new file mode 100644
index 0000000000000000000000000000000000000000..e25791aa146f8aa61a61c8213d24bed27bf89b58
--- /dev/null
+++ b/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/api/TestStorageIntegration.java
@@ -0,0 +1,241 @@
+// Copyright © Microsoft Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.api;
+
+import com.sun.jersey.api.client.ClientResponse;
+import org.apache.catalina.connector.Response;
+import org.apache.commons.lang3.time.StopWatch;
+import org.asynchttpclient.util.Assertions;
+import org.junit.*;
+import org.opengroup.osdu.core.common.model.http.DpsHeaders;
+import org.opengroup.osdu.core.common.model.notification.HmacSecret;
+import org.opengroup.osdu.core.common.model.notification.Subscription;
+import org.opengroup.osdu.core.common.model.notification.SubscriptionInfo;
+import org.opengroup.osdu.core.common.notification.ISubscriptionService;
+import org.opengroup.osdu.core.common.notification.SubscriptionAPIConfig;
+import org.opengroup.osdu.core.common.notification.SubscriptionException;
+import org.opengroup.osdu.core.common.notification.SubscriptionFactory;
+import org.opengroup.osdu.notification.util.*;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class TestStorageIntegration extends BaseTestTemplate {
+
+    private String subscriptionId = null;
+    private String notificationId = null;
+    private final String ackSubscriptionId = "AckSubscription";
+    private final String ackNotificationId = "testingAcknowledgement";
+    private ISubscriptionService subscriptionService;
+    private static SubscriptionFactory factory;
+    protected static final String LEGAL_TAG = TestUtils.getOsduTenant() + "-test-tag";
+
+    @BeforeClass
+    public static void classSetup() throws Exception {
+        descriptor = new StorageIntegrationDescriptor();
+        //Configure Register Service Client Library
+        SubscriptionAPIConfig config = SubscriptionAPIConfig.builder().rootUrl(Config.Instance().RegisterServicePath).build();
+        factory = new SubscriptionFactory(config);
+    }
+
+    @AfterClass
+    public static void classTearDown() throws Exception {
+    }
+
+    @Before
+    @Override
+    public void setup() throws Exception {
+        this.testUtils = new AzureTestUtils();
+    }
+
+    @Override
+    protected void deleteResource() throws Exception {
+        subscriptionService.delete(subscriptionId);
+    }
+
+    @After
+    @Override
+    public void tearDown() throws Exception {
+        this.testUtils = null;
+    }
+
+    @Override
+    protected void createResource() throws Exception {
+        createResourceInPartition(TestUtils.getOsduTenant());
+    }
+
+    private void createResourceInPartition(String partitionId) throws Exception {
+        Map<String, String> headers = new HashMap<>();
+        headers.put(DpsHeaders.DATA_PARTITION_ID, partitionId);
+        headers.put(DpsHeaders.AUTHORIZATION, testUtils.getOpsToken());
+        DpsHeaders dpsHeaders = DpsHeaders.createFromMap(headers);
+        subscriptionService = factory.create(dpsHeaders);
+
+        // Create a new subscription
+        Subscription subscription = new Subscription();
+        subscription.setName("storage-integration-test-hmac");
+        subscription.setDescription("Subscription created for Storage Integration Tests");
+        subscription.setTopic(Config.Instance().Topic);
+        subscription.setPushEndpoint(Config.Instance().HMACPushUrl);
+        HmacSecret secret = new HmacSecret();
+        secret.setValue(Config.Instance().hmacSecretValue);
+        subscription.setSecret(secret);
+        try {
+            Subscription subscriptionCreated = subscriptionService.create(subscription);
+            notificationId = subscriptionCreated.getNotificationId();
+            subscriptionId = subscriptionCreated.getId();
+            Config.Instance().NotificationId = notificationId;
+        } catch (SubscriptionException e) {
+            System.out.println("Subscription exception inner response : " + e.getHttpResponse());
+            throw e;
+        }
+    }
+
+    private void deleteAckSubscription() throws SubscriptionException {
+        try {
+            subscriptionService.delete(ackSubscriptionId);
+        } catch (SubscriptionException e) {
+            if (e.getHttpResponse().getResponseCode() == Response.SC_NOT_FOUND) {
+                System.out.println("Test Ack Subscription Not Found for deletion.");
+                return;
+            }
+            Assert.fail("Unable to delete Test Ack Subscription. Deletion Failed." + e);
+            throw e;
+        }
+    }
+
+    @Override
+    protected String getArg() {
+        return null;
+    }
+
+    @Override
+    protected String getInvalidArg() {
+        return null;
+    }
+
+    @Override
+    protected int expectedOkResponseCode() {
+        return 200;
+    }
+
+    @Test
+    @Override
+    public void should_return20XResponseCode_when_makingValidHttpsRequest() throws Exception {
+        try {
+            // Creates an actual subscription with a test endpoint i.e REGISTER_CUSTOM_PUSH_URL_HMAC
+            this.createResource();
+            // Delay to get the above subscription registered by Notification Service
+            TimeUnit.SECONDS.sleep(60);
+            
+            // Delete the Test Ack subscription if there exists any as a part of cleanup.
+            // The Test Ack Subscription gets created if the the test endpoint of actual subscription
+            // created above receives notification from Notification Service.
+            this.deleteAckSubscription();
+
+            //  Create legal tag used in storage record
+            LegalTagUtils.create(LEGAL_TAG, this.testUtils.getAdminToken());
+
+            // Insert a storage Record.This will send a notification to  the event grid/service bus topic
+            // subscriptions.From there it goes to the Notification Service.Finally from there it goes to the
+            // test endpoint i.e REGISTER_CUSTOM_PUSH_URL_HMAC which creates the Test ack Subscription.
+            String URL = Config.Instance().StorageServicePath;
+            ClientResponse response = descriptor.run(URL, "", this.testUtils.getAdminToken());
+            assertEquals(error(response.getEntity(String.class)), 201, response.getStatus());
+
+            // Verification of Test Ack Subscription creation from the above process.
+            StopWatch stopWatch = new StopWatch();
+            stopWatch.start();
+            // Retrieval of test ack subscription from Cosmos-DB.
+            long retryCount = Long.parseLong(Config.Instance().RetryCount);
+            long timeOut = Long.parseLong(Config.Instance().TimeOutSeconds);
+            SubscriptionInfo ackSubscription = subscriptionService.get(ackSubscriptionId);
+            while (ackSubscription == null && retryCount > 0) {
+                TimeUnit.SECONDS.sleep(timeOut);
+                ackSubscription = subscriptionService.get(ackSubscriptionId);
+                retryCount--;
+            }
+            Assertions.assertNotNull(ackSubscription, "Unable to retrieve test ack subscription. Elapsed time in minutes : " + (stopWatch.getTime(TimeUnit.MINUTES)));
+            if (ackSubscription != null) {
+                assertEquals("Unexpected Test Ack Subscription.", ackNotificationId, ackSubscription.getNotificationId());
+            }
+            stopWatch.stop();
+        } catch (Exception e) {
+            fail("An exception occurred :" + e);
+        } finally {
+            // Delete Actual Subscription
+            this.deleteResource();
+            // Deletion of Test Ack Subscription
+            this.deleteAckSubscription();
+            //  Delete legal tag
+            LegalTagUtils.delete(LEGAL_TAG, this.testUtils.getAdminToken());
+
+        }
+    }
+
+    /* Keeping the No-op test cases implementation as ignored as the Storage-Notification Integration
+    Test scenario does not involves them. */
+    @Test
+    @Override
+    @Ignore
+    public void should_return400_when_makingHttpRequestWithoutToken() throws Exception {
+    }
+
+    @Test
+    @Override
+    @Ignore
+    public void should_return307_when_makingHttpRequest() throws Exception {
+    }
+
+    @Test
+    @Override
+    @Ignore
+    public void should_return401_when_accessingWithNoAccessCredentials() throws Exception {
+    }
+
+    @Test
+    @Override
+    @Ignore
+    public void should_return401_when_noAccessOnCustomerTenant() throws Exception {
+    }
+
+    @Test
+    @Override
+    @Ignore
+    public void should_return401_when_accessingWithEditorCredentials() throws Exception {
+    }
+
+    @Test
+    @Override
+    @Ignore
+    public void should_return401_when_accessingWithAdminCredentials() throws Exception {
+    }
+
+    @Test
+    @Override
+    @Ignore
+    public void should_return20X_when_usingCredentialsWithOpsPermission() throws Exception {
+    }
+
+    @Test
+    @Override
+    @Ignore
+    public void should_returnOk_when_makingHttpOptionsRequest() throws Exception {
+    }
+}
\ No newline at end of file
diff --git a/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/util/LegalTagUtils.java b/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/util/LegalTagUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..c9f1eb14acdb95412a073c6b4316b4f682a07990
--- /dev/null
+++ b/testing/notification-test-azure/src/test/java/org/opengroup/osdu/notification/util/LegalTagUtils.java
@@ -0,0 +1,75 @@
+// Copyright 2017-2019, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.notification.util;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.sun.jersey.api.client.ClientResponse;
+import org.apache.http.HttpStatus;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class LegalTagUtils {
+    public static ClientResponse create(String legalTagName, String token) throws Exception {
+        return create("US", legalTagName, "2099-01-25", "Public Domain Data", token);
+    }
+
+    protected static ClientResponse create(String countryOfOrigin, String name, String expDate, String dataType, String token)
+            throws Exception {
+        String body = getBody(countryOfOrigin, name, expDate, dataType);
+        Map<String, String> headers = new HashMap<>();
+        headers.put("Data-Partition-Id", TestUtils.getOsduTenant());
+        ClientResponse response = TestUtils.send(getLegalUrl(), "legaltags", "POST", token, body, "", headers, false);
+        assertEquals(HttpStatus.SC_CREATED, response.getStatus());
+        Thread.sleep(100);
+        return response;
+    }
+
+    public static ClientResponse delete(String legalTagName, String token) throws Exception {
+        Map<String, String> headers = new HashMap<>();
+        headers.put("Data-Partition-Id", TestUtils.getOsduTenant());
+        return TestUtils.send(getLegalUrl(), "legaltags/" + legalTagName, "DELETE", token, "", "", headers, false);
+    }
+
+    protected static String getLegalUrl() {
+        return Config.Instance().LegalServicePath;
+    }
+
+    protected static String getBody(String countryOfOrigin, String name, String expDate, String dataType) {
+
+        JsonArray coo = new JsonArray();
+        coo.add(countryOfOrigin);
+
+        JsonObject properties = new JsonObject();
+        properties.add("countryOfOrigin", coo);
+        properties.addProperty("contractId", "A1234");
+        properties.addProperty("expirationDate", expDate);
+        properties.addProperty("dataType", dataType);
+        properties.addProperty("originator", "MyCompany");
+        properties.addProperty("securityClassification", "Public");
+        properties.addProperty("exportClassification", "EAR99");
+        properties.addProperty("personalData", "No Personal Data");
+
+        JsonObject tag = new JsonObject();
+        tag.addProperty("name", name);
+        tag.addProperty("description", "test for " + name);
+        tag.add("properties", properties);
+
+        return tag.toString();
+    }
+}
diff --git a/testing/notification-test-core/pom.xml b/testing/notification-test-core/pom.xml
index 9a12fe414bdacee481914f218b8a6cc5f821f682..02b337ba0c84b7c175fa568cb40fe05ab4697eb9 100644
--- a/testing/notification-test-core/pom.xml
+++ b/testing/notification-test-core/pom.xml
@@ -21,13 +21,13 @@
     <parent>
         <groupId>org.opengroup.osdu</groupId>
         <artifactId>os-notification-testing</artifactId>
-        <version>0.9.0-SNAPSHOT</version>
+        <version>0.12.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
     <groupId>org.opengroup.osdu.notification</groupId>
     <artifactId>notification-test-core</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.12.0-SNAPSHOT</version>
     <name>notification-test-core</name>
     <description>Integration tests core for notification</description>
     <packaging>jar</packaging>
@@ -113,7 +113,7 @@
         <dependency>
             <groupId>com.google.auth</groupId>
             <artifactId>google-auth-library-oauth2-http</artifactId>
-            <version>0.9.0</version>
+            <version>0.11.0</version>
         </dependency>
         <dependency>
             <groupId>io.jsonwebtoken</groupId>
diff --git a/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/BaseTestTemplate.java b/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/BaseTestTemplate.java
index 8792991c580a08210a61326e527cbfca5c61459a..01a0be5de9ef90263eb40f6efd729e3919b72ddb 100644
--- a/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/BaseTestTemplate.java
+++ b/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/BaseTestTemplate.java
@@ -89,7 +89,7 @@ public abstract class BaseTestTemplate extends TestBase {
 
 			assertEquals(error(response.getStatus() == 204 ? "" : response.getEntity(String.class)), expectedOkResponseCode(), response.getStatus());
 			assertEquals("GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH", response.getHeaders().getFirst("Access-Control-Allow-Methods"));
-			assertEquals("origin, content-type, accept, authorization, data-partition-id, correlation-id, appkey", response.getHeaders().getFirst("Access-Control-Allow-Headers"));
+			assertEquals("access-control-allow-origin, origin, content-type, accept, authorization, data-partition-id, correlation-id, appkey", response.getHeaders().getFirst("Access-Control-Allow-Headers"));
 			assertEquals("*", response.getHeaders().getFirst("Access-Control-Allow-Origin"));
 			assertEquals("true", response.getHeaders().getFirst("Access-Control-Allow-Credentials"));
 			assertEquals("DENY", response.getHeaders().getFirst("X-Frame-Options"));
diff --git a/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/Config.java b/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/Config.java
index 0d126cd2cd08d10993df45dd83c61bc62984ea07..8f7655b27ddf731230131e91fedad90b67809763 100644
--- a/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/Config.java
+++ b/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/Config.java
@@ -24,55 +24,61 @@ public class Config {
     public String GSAPushUrl;
     public String HMACPushUrl;
     public String RegisterServicePath;
+    public String StorageServicePath;
+    public String LegalServicePath;
     public String Topic;
     public String hmacSecretValue;
     public String NotificationId;
     public String DE_OPS_TESTER = System.getProperty("DE_OPS_TESTER", System.getenv("DE_OPS_TESTER"));
-
+    public String RetryCount;
+    public String TimeOutSeconds;
     private static Config config = new Config();
 
     public static Config Instance() {
         String env = getEnvironment();
-        config.ClientTenant = getEnvironmentVariableOrDefaultValue("CLIENT_TENANT","nonexistenttenant");
-        config.IntegrationAudience =  getEnvironmentVariableOrDefaultValue("INTEGRATION_TEST_AUDIENCE","245464679631-ktfdfpl147m1mjpbutl00b3cmffissgq.apps.googleusercontent.com");
-        config.OsduTenant = getEnvironmentVariableOrDefaultValue("OSDU_TENANT","opendes");
-        config.Topic = getEnvironmentVariableOrDefaultValue("TOPIC_ID","records-changed");
-
+        config.ClientTenant = getEnvironmentVariableOrDefaultValue("CLIENT_TENANT", "nonexistenttenant");
+        config.IntegrationAudience = getEnvironmentVariableOrDefaultValue("INTEGRATION_TEST_AUDIENCE", "245464679631-ktfdfpl147m1mjpbutl00b3cmffissgq.apps.googleusercontent.com");
+        config.OsduTenant = getEnvironmentVariableOrDefaultValue("OSDU_TENANT", "opendes");
+        config.Topic = getEnvironmentVariableOrDefaultValue("TOPIC_ID", "records-changed");
+        config.TimeOutSeconds = getEnvironmentVariableOrDefaultValue("TIME_OUT_SECONDS", "60");
+        config.RetryCount = getEnvironmentVariableOrDefaultValue("RETRY_COUNT", "3");
         config.hmacSecretValue = System.getProperty("HMAC_SECRET", System.getenv("HMAC_SECRET"));
         if (env.equalsIgnoreCase("LOCAL")) {
             //make sure to run register service on a different port. You can also choose to point to Register service that is running in cloud
             String registerUrl = "http://localhost:8081/api/register/v1";
-
             //must have notification and register services running on different ports
             config.HostUrl = "http://localhost:8080/";
 
-            config.GSAPushUrl = registerUrl+"/test/gsa-challenge/";
-            config.HMACPushUrl = registerUrl+"/test/challenge/";
+            config.GSAPushUrl = registerUrl + "/test/gsa-challenge/";
+            config.HMACPushUrl = registerUrl + "/test/challenge/";
             config.RegisterServicePath = registerUrl;
+            config.StorageServicePath = "http://localhost:8085/api/storage/v2/";
+            config.LegalServicePath = "http://localhost:8087/api/legal/v1/";
+
         } else if (env.equalsIgnoreCase("DEV") || isGke() || env.equalsIgnoreCase("CLOUD")) {
             String registerUrl = System.getProperty("REGISTER_BASE_URL", System.getenv("REGISTER_BASE_URL"));
             config.HostUrl = System.getProperty("NOTIFICATION_BASE_URL", System.getenv("NOTIFICATION_BASE_URL"));
-            config.GSAPushUrl = registerUrl+"/test/gsa-challenge/";
+            config.GSAPushUrl = registerUrl + "/test/gsa-challenge/";
             //Adding this so CPs can point to custom HMAC push endpoints
-            config.HMACPushUrl = getEnvironmentVariableOrDefaultValue("REGISTER_CUSTOM_PUSH_URL_HMAC",registerUrl+"/test/challenge/");
+            config.HMACPushUrl = getEnvironmentVariableOrDefaultValue("REGISTER_CUSTOM_PUSH_URL_HMAC", registerUrl + "/test/challenge/");
             //Adding a new variable NOTIFICATION_REGISTER_BASE_URL since REGISTER_BASE_URL is used by Register integration tests which needs a trailing \
-             String regUrl= getEnvironmentVariable("NOTIFICATION_REGISTER_BASE_URL");
-             if(regUrl==null)
-             {
-                 config.RegisterServicePath = registerUrl;
-             }
-             else
-             {
-                 config.RegisterServicePath = regUrl+"/api/register/v1";
-             }
+            String regUrl = getEnvironmentVariable("NOTIFICATION_REGISTER_BASE_URL");
+            config.StorageServicePath = getEnvironmentVariable("STORAGE_HOST");
+            config.LegalServicePath = System.getProperty("LEGAL_URL", System.getenv("LEGAL_URL"));
+            if (regUrl == null) {
+                config.RegisterServicePath = registerUrl;
+            } else {
+                config.RegisterServicePath = regUrl + "/api/register/v1";
+            }
 
-        }else
+        } else
             throw new RuntimeException("$ENVIRONMENT environment variable not provided");
 
-        System.out.println("HostUrl="+config.HostUrl);
-        System.out.println("config.Topic="+ config.Topic);
-        System.out.println("config.HMACPushUrl="+ config.HMACPushUrl);
-        System.out.println("config.RegisterServicePath="+ config.RegisterServicePath);
+        System.out.println("HostUrl=" + config.HostUrl);
+        System.out.println("config.Topic=" + config.Topic);
+        System.out.println("config.HMACPushUrl=" + config.HMACPushUrl);
+        System.out.println("config.RegisterServicePath=" + config.RegisterServicePath);
+        System.out.println("config.StorageServicePath=" + config.StorageServicePath);
         return config;
     }
 
diff --git a/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/RestDescriptor.java b/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/RestDescriptor.java
index 38690fc885965e34570151a04883230632f48c86..08bab7e551b06c5f172aead358a159d99801257b 100644
--- a/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/RestDescriptor.java
+++ b/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/RestDescriptor.java
@@ -22,34 +22,51 @@ import java.util.Map;
 
 public abstract class RestDescriptor {
 
-	public RestDescriptor() {
-	}
-
-	private String arg = "";
-	public String arg(){
-		return arg;
-	}
-	public abstract String getPath();
-	public abstract String getHttpMethod();
-	public abstract String getValidBody();
-	public abstract Map<String,String> getOsduTenantHeaders();
-	public abstract Map<String,String> getCustomerTenantHeaders();
-	public String getQuery() { return ""; }
-
-	public ClientResponse runHttp(String arg, String token) throws Exception{
-		this.arg = arg;
-		return TestUtils.send(getPath(), getHttpMethod(), token, getValidBody(), getQuery(), getOsduTenantHeaders(),true);
-	}
-	public ClientResponse run(String arg, String token) throws Exception{
-		this.arg = arg;
-		return TestUtils.send(getPath(), getHttpMethod(), token, getValidBody(), getQuery(),  getOsduTenantHeaders(),false);
-	}
-	public ClientResponse runOnCustomerTenant(String arg, String token) throws Exception{
-		this.arg = arg;
-		return TestUtils.send(getPath(), getHttpMethod(), token, getValidBody(), getQuery(), getCustomerTenantHeaders(), false);
-	}
-	public ClientResponse runOptions(String arg, String token) throws Exception{
-		this.arg = arg;
-		return TestUtils.send(getPath(), "OPTIONS", token, "", "",  getOsduTenantHeaders(),false);
-	}
+    public RestDescriptor() {
+    }
+
+    private String arg = "";
+
+    public String arg() {
+        return arg;
+    }
+
+    public abstract String getPath();
+
+    public abstract String getHttpMethod();
+
+    public abstract String getValidBody();
+
+    public abstract Map<String, String> getOsduTenantHeaders();
+
+    public abstract Map<String, String> getCustomerTenantHeaders();
+
+    public String getQuery() {
+        return "";
+    }
+
+    public ClientResponse runHttp(String arg, String token) throws Exception {
+        this.arg = arg;
+        return TestUtils.send(getPath(), getHttpMethod(), token, getValidBody(), getQuery(), getOsduTenantHeaders(), true);
+    }
+
+    public ClientResponse run(String arg, String token) throws Exception {
+        this.arg = arg;
+        return TestUtils.send(getPath(), getHttpMethod(), token, getValidBody(), getQuery(), getOsduTenantHeaders(), false);
+    }
+
+    public ClientResponse runOnCustomerTenant(String arg, String token) throws Exception {
+        this.arg = arg;
+        return TestUtils.send(getPath(), getHttpMethod(), token, getValidBody(), getQuery(), getCustomerTenantHeaders(), false);
+    }
+
+    public ClientResponse runOptions(String arg, String token) throws Exception {
+        this.arg = arg;
+        return TestUtils.send(getPath(), "OPTIONS", token, "", "", getOsduTenantHeaders(), false);
+    }
+
+    public ClientResponse run(String url, String arg, String token) throws Exception {
+        this.arg = arg;
+        return TestUtils.send(url, getPath(), getHttpMethod(), token, getValidBody(), getQuery(), getOsduTenantHeaders(), false);
+    }
 }
\ No newline at end of file
diff --git a/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/TestUtils.java b/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/TestUtils.java
index 393089845fdad198817e00950eb9e7300dd7ff84..17d5d90b5ded8ad2a87658a3aebde2022ae8b1d0 100644
--- a/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/TestUtils.java
+++ b/testing/notification-test-core/src/main/java/org/opengroup/osdu/notification/util/TestUtils.java
@@ -35,46 +35,56 @@ import com.sun.jersey.api.client.ClientResponse;
 import com.sun.jersey.api.client.WebResource;
 
 public abstract class TestUtils {
-	protected String serviceAccountFile;
-	protected static String opsToken = null;
-	protected static String adminToken = null;
-	protected static String editorToken = null;
-	protected static String noAccessToken = null;
-
-	public static String getApiPath(String api, boolean enforceHttp) throws Exception {
-		String baseUrl = Config.Instance().HostUrl;
-		if(enforceHttp)
-			baseUrl = baseUrl.replaceFirst("https", "http");
-		URL mergedURL = new URL(baseUrl + api);
-		return mergedURL.toString();
-	}
-
-	public static String getOsduTenant(){
-		return Config.Instance().OsduTenant;
-	}
-
-	public static String getCustomerTenant(){
-		return Config.Instance().ClientTenant;
-	}
-
-	public abstract String getOpsToken() throws Exception;
-	public abstract String getAdminToken() throws Exception;
-	public abstract String getEditorToken() throws Exception;
-	public abstract String getNoAccessToken() throws Exception;
+    protected String serviceAccountFile;
+    protected static String opsToken = null;
+    protected static String adminToken = null;
+    protected static String editorToken = null;
+    protected static String noAccessToken = null;
+
+    public static String getApiPath(String api, boolean enforceHttp) throws Exception {
+        String baseUrl = Config.Instance().HostUrl;
+        if (enforceHttp)
+            baseUrl = baseUrl.replaceFirst("https", "http");
+        URL mergedURL = new URL(baseUrl + api);
+        return mergedURL.toString();
+    }
+
+    public static String getApiPath(String baseUrl, String api, boolean enforceHttp) throws Exception {
+        if (enforceHttp)
+            baseUrl = baseUrl.replaceFirst("https", "http");
+        URL mergedURL = new URL(baseUrl + api);
+        return mergedURL.toString();
+    }
+
+    public static String getOsduTenant() {
+        return Config.Instance().OsduTenant;
+    }
+
+    public static String getCustomerTenant() {
+        return Config.Instance().ClientTenant;
+    }
+
+    public abstract String getOpsToken() throws Exception;
+
+    public abstract String getAdminToken() throws Exception;
+
+    public abstract String getEditorToken() throws Exception;
+
+    public abstract String getNoAccessToken() throws Exception;
 
     public static ClientResponse send(String path, String httpMethod, String token, String requestBody, String query,
-                               Map<String,String> headers, boolean enforceHttp)
+                                      Map<String, String> headers, boolean enforceHttp)
             throws Exception {
 
         Client client = getClient();
-		client.setConnectTimeout(15000);
-		client.setReadTimeout(15000);
+        client.setConnectTimeout(50000);
+        client.setReadTimeout(50000);
         client.setFollowRedirects(false);
         String url = getApiPath(path + query, enforceHttp);
         System.out.println(url);
-		System.out.println(httpMethod);
-		System.out.println(requestBody);
-		System.out.println(headers);
+        System.out.println(httpMethod);
+        System.out.println(requestBody);
+        System.out.println(headers);
 
         WebResource webResource = client.resource(url);
         final WebResource.Builder builder = webResource.type(MediaType.APPLICATION_JSON)
@@ -85,47 +95,72 @@ public abstract class TestUtils {
         return response;
     }
 
-	@SuppressWarnings("unchecked")
-	public <T> T getResult(ClientResponse response, int exepectedStatus, Class<T> classOfT) {
-		String json = response.getEntity(String.class);
-
-		assertEquals(exepectedStatus, response.getStatus());
-		if (exepectedStatus == 204) {
-			return null;
-		}
-
-		assertEquals(MediaType.APPLICATION_JSON, response.getType().toString());
-		if (classOfT == String.class) {
-			return (T) json;
-		}
-
-		Gson gson = new Gson();
-		return gson.fromJson(json, classOfT);
-	}
-
-	public static Client getClient() {
-		TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
-			@Override
-			public X509Certificate[] getAcceptedIssuers() {
-				return null;
-			}
-
-			@Override
-			public void checkClientTrusted(X509Certificate[] certs, String authType) {
-			}
-
-			@Override
-			public void checkServerTrusted(X509Certificate[] certs, String authType) {
-			}
-		} };
-
-		try {
-			SSLContext sc = SSLContext.getInstance("TLS");
-			sc.init(null, trustAllCerts, new SecureRandom());
-			HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
-		} catch (Exception e) {
-		}
-
-		return Client.create();
-	}
+    public static ClientResponse send(String url, String path, String httpMethod, String token, String requestBody,
+                                      String query, Map<String, String> headers, boolean enforceHttp)
+            throws Exception {
+
+        Client client = getClient();
+        client.setConnectTimeout(50000);
+        client.setReadTimeout(50000);
+        client.setFollowRedirects(false);
+        String URL = getApiPath(url, path + query, enforceHttp);
+        System.out.println(url + path);
+        System.out.println(httpMethod);
+        System.out.println(requestBody);
+        System.out.println(headers);
+        WebResource webResource = client.resource(URL);
+        final WebResource.Builder builder = webResource.type(MediaType.APPLICATION_JSON);
+        if (!token.isEmpty()) {
+            builder.header("Authorization", token);
+        }
+        headers.forEach((k, v) -> builder.header(k, v));
+        ClientResponse response = builder.method(httpMethod, ClientResponse.class, requestBody);
+
+        return response;
+
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T getResult(ClientResponse response, int exepectedStatus, Class<T> classOfT) {
+        String json = response.getEntity(String.class);
+
+        assertEquals(exepectedStatus, response.getStatus());
+        if (exepectedStatus == 204) {
+            return null;
+        }
+
+        assertEquals(MediaType.APPLICATION_JSON, response.getType().toString());
+        if (classOfT == String.class) {
+            return (T) json;
+        }
+
+        Gson gson = new Gson();
+        return gson.fromJson(json, classOfT);
+    }
+
+    public static Client getClient() {
+        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
+            @Override
+            public X509Certificate[] getAcceptedIssuers() {
+                return null;
+            }
+
+            @Override
+            public void checkClientTrusted(X509Certificate[] certs, String authType) {
+            }
+
+            @Override
+            public void checkServerTrusted(X509Certificate[] certs, String authType) {
+            }
+        }};
+
+        try {
+            SSLContext sc = SSLContext.getInstance("TLS");
+            sc.init(null, trustAllCerts, new SecureRandom());
+            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+        } catch (Exception e) {
+        }
+
+        return Client.create();
+    }
 }
\ No newline at end of file
diff --git a/testing/notification-test-gcp/pom.xml b/testing/notification-test-gcp/pom.xml
index 9ae43b5892daff41afe2f7b3e42809f2945e78ac..e22afb311f41d015a0f9a30f1cc19660ec8b7ef6 100644
--- a/testing/notification-test-gcp/pom.xml
+++ b/testing/notification-test-gcp/pom.xml
@@ -21,12 +21,12 @@
     <parent>
         <groupId>org.opengroup.osdu</groupId>
         <artifactId>os-notification-testing</artifactId>
-        <version>0.9.0-SNAPSHOT</version>
+        <version>0.12.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
     <artifactId>notification-test-gcp</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.12.0-SNAPSHOT</version>
     <name>notification-test-gcp</name>
     <description>Integration tests GCP for notification</description>
     <packaging>jar</packaging>
@@ -41,7 +41,7 @@
         <dependency>
             <groupId>org.opengroup.osdu.notification</groupId>
             <artifactId>notification-test-core</artifactId>
-            <version>0.9.0-SNAPSHOT</version>
+            <version>0.12.0-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.opengroup.osdu</groupId>
diff --git a/testing/notification-test-gcp/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointGSA.java b/testing/notification-test-gcp/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointGSA.java
index 0aa5c1c3cfa70e87ecc0ea8d0bf4d306192b673e..a743915e56c34ee0919d4213dbf74727a9b5b0b1 100644
--- a/testing/notification-test-gcp/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointGSA.java
+++ b/testing/notification-test-gcp/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointGSA.java
@@ -1,36 +1,72 @@
 package org.opengroup.osdu.notification.api;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.sun.jersey.api.client.ClientResponse;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.opengroup.osdu.notification.util.Config;
+import org.junit.Test;
 import org.opengroup.osdu.notification.util.GCPTestUtils;
-import org.opengroup.osdu.notification.util.RestDescriptor;
 
 public class TestPubsubEndpointGSA extends PubsubEndpointGSATests {
 
-    private static final GCPTestUtils gcpTestUtils = new GCPTestUtils();
+  private static final GCPTestUtils gcpTestUtils = new GCPTestUtils();
 
 
-    @BeforeClass
-    public static void classSetup() throws Exception {
-        PubsubEndpointGSATests.classSetup(gcpTestUtils.getOpsToken());
-    }
+  @BeforeClass
+  public static void classSetup() throws Exception {
+    PubsubEndpointGSATests.classSetup(gcpTestUtils.getOpsToken());
+  }
 
-    @AfterClass
-    public static void classTearDown() throws Exception {
-    }
+  @AfterClass
+  public static void classTearDown() throws Exception {
+  }
 
-    @Before
-    @Override
-    public void setup() throws Exception {
-        this.testUtils = new GCPTestUtils();
-    }
+  @Before
+  @Override
+  public void setup() throws Exception {
+    this.testUtils = new GCPTestUtils();
+  }
+
+  @After
+  @Override
+  public void tearDown() throws Exception {
+    this.testUtils = null;
+  }
+
+  @Override
+  @Test
+  public void should_return20X_when_usingCredentialsWithOpsPermission() throws Exception {
+    createResource();
+
+    try {
+      ClientResponse response = descriptor.run(getArg(), testUtils.getOpsToken());
 
-    @After
-    @Override
-    public void tearDown() throws Exception {
-        this.testUtils = null;
+      assertEquals(error(response.getStatus() == 204 ? "" : response.getEntity(String.class)),
+          expectedOkResponseCode(), response.getStatus());
+      assertEquals("GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH",
+          response.getHeaders().getFirst("Access-Control-Allow-Methods"));
+      assertEquals(
+          "access-control-allow-origin, origin, content-type, accept, authorization, data-partition-id, correlation-id, appkey",
+          response.getHeaders().getFirst("Access-Control-Allow-Headers"));
+      assertEquals("*", response.getHeaders().getFirst("Access-Control-Allow-Origin"));
+      assertEquals("true", response.getHeaders().getFirst("Access-Control-Allow-Credentials"));
+      assertEquals("DENY", response.getHeaders().getFirst("X-Frame-Options"));
+      assertEquals("1; mode=block", response.getHeaders().getFirst("X-XSS-Protection"));
+      assertEquals("nosniff", response.getHeaders().getFirst("X-Content-Type-Options"));
+      assertEquals("no-cache, no-store, must-revalidate",
+          response.getHeaders().getFirst("Cache-Control"));
+      assertEquals("default-src 'self'", response.getHeaders().getFirst("Content-Security-Policy"));
+      assertTrue(response.getHeaders().get("Strict-Transport-Security").get(0)
+          .contains("max-age=31536000"));
+      assertTrue(response.getHeaders().get("Strict-Transport-Security").get(0)
+          .contains("includeSubDomains"));
+      assertEquals("0", response.getHeaders().getFirst("Expires"));
+    } finally {
+      deleteResource();
     }
+  }
 }
\ No newline at end of file
diff --git a/testing/notification-test-gcp/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java b/testing/notification-test-gcp/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
index af7b1fba71692e4e40bb78ba9ef5679eaea2af6e..5ba744d1eb3c15eebab7d0c71bdcb0a1a02d0b00 100644
--- a/testing/notification-test-gcp/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
+++ b/testing/notification-test-gcp/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
@@ -1,34 +1,69 @@
 package org.opengroup.osdu.notification.api;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.sun.jersey.api.client.ClientResponse;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.opengroup.osdu.notification.util.Config;
+import org.junit.Test;
 import org.opengroup.osdu.notification.util.GCPTestUtils;
-import org.opengroup.osdu.notification.util.RestDescriptor;
-import org.opengroup.osdu.notification.util.TestUtils;
 
 public class TestPubsubEndpointHMAC extends PubsubEndpointHMACTests {
 
-    @BeforeClass
-    public static void classSetup() throws Exception {
-        PubsubEndpointHMACTests.classSetup();
-    }
+  @BeforeClass
+  public static void classSetup() throws Exception {
+    PubsubEndpointHMACTests.classSetup();
+  }
 
-    @AfterClass
-    public static void classTearDown() throws Exception {
-    }
+  @AfterClass
+  public static void classTearDown() throws Exception {
+  }
 
-    @Before
-    @Override
-    public void setup() throws Exception {
-        this.testUtils = new GCPTestUtils();
-    }
+  @Before
+  @Override
+  public void setup() throws Exception {
+    this.testUtils = new GCPTestUtils();
+  }
+
+  @After
+  @Override
+  public void tearDown() throws Exception {
+    this.testUtils = null;
+  }
+
+  @Override
+  @Test
+  public void should_return20X_when_usingCredentialsWithOpsPermission() throws Exception {
+    createResource();
+
+    try {
+      ClientResponse response = descriptor.run(getArg(), testUtils.getOpsToken());
 
-    @After
-    @Override
-    public void tearDown() throws Exception {
-        this.testUtils = null;
+      assertEquals(error(response.getStatus() == 204 ? "" : response.getEntity(String.class)),
+          expectedOkResponseCode(), response.getStatus());
+      assertEquals("GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH",
+          response.getHeaders().getFirst("Access-Control-Allow-Methods"));
+      assertEquals(
+          "access-control-allow-origin, origin, content-type, accept, authorization, data-partition-id, correlation-id, appkey",
+          response.getHeaders().getFirst("Access-Control-Allow-Headers"));
+      assertEquals("*", response.getHeaders().getFirst("Access-Control-Allow-Origin"));
+      assertEquals("true", response.getHeaders().getFirst("Access-Control-Allow-Credentials"));
+      assertEquals("DENY", response.getHeaders().getFirst("X-Frame-Options"));
+      assertEquals("1; mode=block", response.getHeaders().getFirst("X-XSS-Protection"));
+      assertEquals("nosniff", response.getHeaders().getFirst("X-Content-Type-Options"));
+      assertEquals("no-cache, no-store, must-revalidate",
+          response.getHeaders().getFirst("Cache-Control"));
+      assertEquals("default-src 'self'", response.getHeaders().getFirst("Content-Security-Policy"));
+      assertTrue(response.getHeaders().get("Strict-Transport-Security").get(0)
+          .contains("max-age=31536000"));
+      assertTrue(response.getHeaders().get("Strict-Transport-Security").get(0)
+          .contains("includeSubDomains"));
+      assertEquals("0", response.getHeaders().getFirst("Expires"));
+    } finally {
+      deleteResource();
     }
+  }
 }
\ No newline at end of file
diff --git a/testing/notification-test-ibm/pom.xml b/testing/notification-test-ibm/pom.xml
index b374c02678e26207220d304ee42d872dc1710bd9..9f52e4f684bcf892861219a9c6d0ab5277caf0e0 100644
--- a/testing/notification-test-ibm/pom.xml
+++ b/testing/notification-test-ibm/pom.xml
@@ -18,13 +18,13 @@
     <parent>
         <groupId>org.opengroup.osdu</groupId>
         <artifactId>os-notification-testing</artifactId>
-        <version>0.9.0-SNAPSHOT</version>
+        <version>0.12.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
     <groupId>org.opengroup.osdu</groupId>
     <artifactId>notification-test-ibm</artifactId>
-    <version>0.9.0-SNAPSHOT</version>
+    <version>0.12.0-SNAPSHOT</version>
     <name>notification-test-ibm</name>
     <description>Integration tests IBM for notification</description>
     <packaging>jar</packaging>
@@ -45,7 +45,7 @@
         <dependency>
             <groupId>org.opengroup.osdu.notification</groupId>
             <artifactId>notification-test-core</artifactId>
-            <version>0.9.0-SNAPSHOT</version>
+            <version>0.12.0-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>org.opengroup.osdu</groupId>
diff --git a/testing/notification-test-ibm/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java b/testing/notification-test-ibm/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
index 9a1f59c5a4d8f9d51cfb3175be4ddbc103554d5b..e01b1c888f7f1f79f9707246c3ebb3ed26d56380 100644
--- a/testing/notification-test-ibm/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
+++ b/testing/notification-test-ibm/src/test/java/org/opengroup/osdu/notification/api/TestPubsubEndpointHMAC.java
@@ -56,6 +56,14 @@ public class TestPubsubEndpointHMAC extends PubsubEndpointHMACTests {
 		// TODO getting SubscriptionException only on ci-cd env
 		super.should_return20XResponseCode_when_makingValidHttpsRequest();
 	}
+	
+	//running against tenant - 'nonexistenttenant' and entitlement throws 403 for invalid teanant
+	@Override
+	@Test
+	public void should_return401_when_noAccessOnCustomerTenant() throws Exception {
+		ClientResponse response = descriptor.runOnCustomerTenant(getArg(), getOsduTenantAdminCredentials());
+		assertEquals(error(	response.getEntity(String.class)),403, response.getStatus());
+	}
     
     
 }
\ No newline at end of file
diff --git a/testing/pom.xml b/testing/pom.xml
index e19233259c1057a20955126716a59fa71dd85f04..92724d716d54f21bd1aa70cfcacc6aed42992a86 100644
--- a/testing/pom.xml
+++ b/testing/pom.xml
@@ -18,7 +18,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>org.opengroup.osdu</groupId>
 	<artifactId>os-notification-testing</artifactId>
-	<version>0.9.0-SNAPSHOT</version>
+	<version>0.12.0-SNAPSHOT</version>
 	<description>Root Notification Service project</description>
 	<packaging>pom</packaging>