diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b69987c6c1f252ebf824bd2a39bfe891fc4bedc6..3bd9ce007392a0dfe31ca6b87ebd268b3d516ede 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -19,28 +19,16 @@ variables:
   P_NAME: "app.access-token-provider"
   P_APP_TYPE: "java"
   P_CODE_SRC_PATH: "."
+  P_MAVEN_IMAGE_TAG: "3.6.3"
 
 
 # Define jobs
 code:
   stage: build
   extends:
-    - .codeForJava
-  variables:
-    P_MAVEN_IMAGE_TAG: "3.6.3"
+    - .buildCodeForJava
 
 quality:
   stage: tests
   extends:
-    - .sonarqubeForJava
-  variables:
-    P_MAVEN_IMAGE_TAG: "3.6.3"
-    P_CODE_BINARIES: "target/classes/"
-    P_CODE_JACOCO_REPORT_PATH: "target/jacoco.exec"
-    P_CODE_JUNIT_REPORTS_PATH: "target/surefire-reports"
-    P_CODE_DYNAMIC_ANALYSIS: "reuseReports"
-    P_CODE_COVERAGE_PLUGIN: "jacoco"
-    P_CODE_SOURCE_ENCODING: "UTF-8"
-    P_CODE_LANGUAGE: "java"
-    P_CODE_DEVELOPER_EDITION: "true"
-
+    - .testQualityForJavaWithSonarqube
\ No newline at end of file
diff --git a/access-token-provider-api/pom.xml b/access-token-provider-api/pom.xml
index 14535327c1b9cbc66ec5cb0519b429eff66fd508..7248359cacc10259112d61b47af4a584057aa782 100644
--- a/access-token-provider-api/pom.xml
+++ b/access-token-provider-api/pom.xml
@@ -11,8 +11,22 @@
     </parent>
 
     <groupId>net.ihe.gazelle</groupId>
-    <artifactId>lib.access-token-provider-api</artifactId>
+    <artifactId>app.access-token-provider-api</artifactId>
     <name>Access Token Provider Api</name>
     <version>1.0.0-SNAPSHOT</version>
 
-</project>
\ No newline at end of file
+
+    <dependencies>
+        <dependency>
+            <groupId>net.ihe.gazelle</groupId>
+            <artifactId>lib.annotations</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>net.ihe.gazelle</groupId>
+            <artifactId>sb.iua-standard-block</artifactId>
+            <version>1.0.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/lib/net.ihe.gazelle.app.accesstokenproviderapi/adapter/README.txt b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/README.txt
similarity index 100%
rename from access-token-provider-api/src/main/java/net/ihe/gazelle/lib/net.ihe.gazelle.app.accesstokenproviderapi/adapter/README.txt
rename to access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/README.txt
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/webservice/AudienceRegistry.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/webservice/AudienceRegistry.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c41aa00159f149cf9f75b1069ab963a3508bce4
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/webservice/AudienceRegistry.java
@@ -0,0 +1,17 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.adapter.webservice;
+
+import net.ihe.gazelle.app.accesstokenproviderapi.business.Credential;
+
+/**
+ * Interface to interact with the audience registry where is store all known audience with their credential
+ */
+public interface AudienceRegistry {
+
+    /**
+     * Get credential's audience
+     * @param audienceId
+     * @return credential
+     */
+    Credential getAudienceCredentials(String audienceId);
+
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/webservice/DummyAuthzServer.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/webservice/DummyAuthzServer.java
new file mode 100644
index 0000000000000000000000000000000000000000..27f6de6fe11245f40135c2267f3e87bf140aea7f
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/webservice/DummyAuthzServer.java
@@ -0,0 +1,18 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.adapter.webservice;
+
+/**
+ * For SoapUI integration need, a simplified Authorization Server (or IDP) is required.
+ */
+public interface DummyAuthzServer {
+
+    /**
+     * get a dummy access token
+     * @param userId
+     * @param audienceId
+     * @param purposeOfUser
+     * @param resourceId
+     * @return an access token
+     */
+    byte[] getAccessToken(String userId, String audienceId, String purposeOfUser, String resourceId);
+
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/webservice/TestUserRegistry.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/webservice/TestUserRegistry.java
new file mode 100644
index 0000000000000000000000000000000000000000..3477a8885364822bcbf6b2953573e34ad925886d
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/webservice/TestUserRegistry.java
@@ -0,0 +1,16 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.adapter.webservice;
+
+import net.ihe.gazelle.app.accesstokenproviderapi.business.testuser.TestUser;
+
+/**
+ * Interface to interact with the test-users’ database for authentication step and token content
+ */
+public interface TestUserRegistry {
+
+    /**
+     * @param userId
+     * @return TestUser
+     */
+    TestUser getTestUser(String userId);
+
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/webservice/TokenGenerator.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/webservice/TokenGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..0be087f904facb15eb002cce87222927b6eb8f70
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/webservice/TokenGenerator.java
@@ -0,0 +1,18 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.adapter.webservice;
+
+import net.ihe.gazelle.app.accesstokenproviderapi.business.AccessTokenRequest;
+import net.ihe.gazelle.sb.iua.business.EncodedIUAToken;
+
+/**
+ * Interface to interact with the access token generator
+ */
+public interface TokenGenerator {
+
+    /**
+     * generate an access token from an access token request
+     * @param accessTokenRequest
+     * @return EncodedIUAToken
+     */
+    EncodedIUAToken generateAccessToken(AccessTokenRequest accessTokenRequest);
+
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/lib/net.ihe.gazelle.app.accesstokenproviderapi/application/README.txt b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/application/README.txt
similarity index 100%
rename from access-token-provider-api/src/main/java/net/ihe/gazelle/lib/net.ihe.gazelle.app.accesstokenproviderapi/application/README.txt
rename to access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/application/README.txt
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AccessTokenExtension.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AccessTokenExtension.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd92b50c67f8c55d80175dad59ebba560cb60c1e
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AccessTokenExtension.java
@@ -0,0 +1,256 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Extensions for the Access Token
+ */
+public class AccessTokenExtension {
+
+    private String subjectId;
+    private List<String> subjectOrganizations = new ArrayList<>();
+    private List<String> subjectOrganizationIds = new ArrayList<>();
+    private String homeCommunityId;
+    private String nationalProviderIdentifier;
+    private List<String> providerIds = new ArrayList<>();
+    private CodedValue subjectRole;
+    private CodedValue purposeOfUse;
+    private String resourceId;
+    private String onBehalfOf;
+
+    /**
+     * constructor
+     */
+    public AccessTokenExtension() {
+        // Constructor is empty because all variables are optionals.
+    }
+
+    /**
+     * get the subjectId
+     * @return subjectId
+     */
+    public String getSubjectId() {
+        return subjectId;
+    }
+
+    /**
+     * set the subjectId
+     * @param subjectId the subjectId
+     */
+    public void setSubjectId(String subjectId) {
+        this.subjectId = subjectId;
+    }
+
+    /**
+     * get subjectOrganizations list
+     * @return subjectOrganizations
+     */
+    public List<String> getSubjectOrganizations() {
+        return subjectOrganizations;
+    }
+
+    /**
+     * add a subjectOrganization in the subjectOrganizations list
+     * @param subjectOrganization a nationalProviderIdentifier
+     */
+    public void addSubjectOrganization(String subjectOrganization) {
+        this.subjectOrganizations.add(subjectOrganization);
+    }
+
+    /**
+     * remove a subjectOrganization from the subjectOrganizations list
+     * @param subjectOrganization a nationalProviderIdentifier
+     */
+    public void removeSubjectOrganization(String subjectOrganization) {
+        this.subjectOrganizations.remove(subjectOrganization);
+    }
+
+    /**
+     * get subjectOrganizationIds list
+     * @return subjectOrganizationIds
+     */
+    public List<String> getSubjectOrganizationIds() {
+        return subjectOrganizationIds;
+    }
+
+    /**
+     * add a subjectOrganizationId in the subjectOrganizationIds list
+     * @param subjectOrganizationId a subjectOrganizationId
+     */
+    public void addSubjectOrganizationId(String subjectOrganizationId) {
+        this.subjectOrganizationIds.add(subjectOrganizationId);
+    }
+
+    /**
+     * remove a subjectOrganizationId from the subjectOrganizationIds list
+     * @param subjectOrganizationId a subjectOrganizationId
+     */
+    public void removeSubjectOrganizationId(String subjectOrganizationId) {
+        this.subjectOrganizationIds.remove(subjectOrganizationId);
+    }
+
+    /**
+     * get the homeCommunityId
+     * @return homeCommunityId
+     */
+    public String getHomeCommunityId() {
+        return homeCommunityId;
+    }
+
+    /**
+     * set the homeCommunityId
+     * @param homeCommunityId the homeCommunityId
+     */
+    public void setHomeCommunityId(String homeCommunityId) {
+        this.homeCommunityId = homeCommunityId;
+    }
+
+    /**
+     * get the nationalProviderIdentifier
+     * @return nationalProviderIdentifier
+     */
+    public String getNationalProviderIdentifier() {
+        return nationalProviderIdentifier;
+    }
+
+    /**
+     * set the nationalProviderIdentifier
+     * @param nationalProviderIdentifier the nationalProviderIdentifier
+     */
+    public void setNationalProviderIdentifier(String nationalProviderIdentifier) {
+        this.nationalProviderIdentifier = nationalProviderIdentifier;
+    }
+
+    /**
+     * get providerIds list
+     * @return providerIds
+     */
+    public List<String> getProviderIds() {
+        return providerIds;
+    }
+
+    /**
+     * add a providerId in the providerIds list
+     * @param providerId a providerId
+     */
+    public void addProviderId(String providerId) {
+        this.providerIds.add(providerId);
+    }
+
+    /**
+     * remove a providerId in the providerIds list
+     * @param providerId a providerId
+     */
+    public void removeProviderId(String providerId) {
+        this.providerIds.remove(providerId);
+    }
+
+    /**
+     * get the subjectRole
+     * @return subjectRole
+     */
+    public CodedValue getSubjectRole() {
+        return subjectRole;
+    }
+
+    /**
+     * set the subjectRole
+     * @param subjectRole the subjectRole
+     */
+    public void setSubjectRole(CodedValue subjectRole) {
+        this.subjectRole = subjectRole;
+    }
+
+    /**
+     * get the purposeOfUse
+     * @return purposeOfUse
+     */
+    public CodedValue getPurposeOfUse() {
+        return purposeOfUse;
+    }
+
+    /**
+     * set the purposeOfUse
+     * @param purposeOfUse the purposeOfUse
+     */
+    public void setPurposeOfUse(CodedValue purposeOfUse) {
+        this.purposeOfUse = purposeOfUse;
+    }
+
+    /**
+     * get the resourceId
+     * @return resourceId
+     */
+    public String getResourceId() {
+        return resourceId;
+    }
+
+    /**
+     * set the resourceId
+     * @param resourceId the resourceId
+     */
+    public void setResourceId(String resourceId) {
+        this.resourceId = resourceId;
+    }
+
+    /**
+     * get the onBehalfOf
+     * @return onBehalfOf
+     */
+    public String getOnBehalfOf() {
+        return onBehalfOf;
+    }
+
+    /**
+     * set the onBehalfOf
+     * @param onBehalfOf the onBehalfOf
+     */
+    public void setOnBehalfOf(String onBehalfOf) {
+        this.onBehalfOf = onBehalfOf;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AccessTokenExtension that = (AccessTokenExtension) o;
+
+        if (subjectId != null ? !subjectId.equals(that.subjectId) : that.subjectId != null) return false;
+        if (subjectOrganizations != null ? !subjectOrganizations.equals(that.subjectOrganizations) : that.subjectOrganizations != null)
+            return false;
+        if (subjectOrganizationIds != null ? !subjectOrganizationIds.equals(that.subjectOrganizationIds) : that.subjectOrganizationIds != null)
+            return false;
+        if (homeCommunityId != null ? !homeCommunityId.equals(that.homeCommunityId) : that.homeCommunityId != null)
+            return false;
+        if (nationalProviderIdentifier != null ? !nationalProviderIdentifier.equals(that.nationalProviderIdentifier) : that.nationalProviderIdentifier != null)
+            return false;
+        if (providerIds != null ? !providerIds.equals(that.providerIds) : that.providerIds != null) return false;
+        if (subjectRole != null ? !subjectRole.equals(that.subjectRole) : that.subjectRole != null) return false;
+        if (purposeOfUse != null ? !purposeOfUse.equals(that.purposeOfUse) : that.purposeOfUse != null) return false;
+        if (resourceId != null ? !resourceId.equals(that.resourceId) : that.resourceId != null) return false;
+        return onBehalfOf != null ? onBehalfOf.equals(that.onBehalfOf) : that.onBehalfOf == null;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode() {
+        int result = subjectId != null ? subjectId.hashCode() : 0;
+        result = 31 * result + (subjectOrganizations != null ? subjectOrganizations.hashCode() : 0);
+        result = 31 * result + (subjectOrganizationIds != null ? subjectOrganizationIds.hashCode() : 0);
+        result = 31 * result + (homeCommunityId != null ? homeCommunityId.hashCode() : 0);
+        result = 31 * result + (nationalProviderIdentifier != null ? nationalProviderIdentifier.hashCode() : 0);
+        result = 31 * result + (providerIds != null ? providerIds.hashCode() : 0);
+        result = 31 * result + (subjectRole != null ? subjectRole.hashCode() : 0);
+        result = 31 * result + (purposeOfUse != null ? purposeOfUse.hashCode() : 0);
+        result = 31 * result + (resourceId != null ? resourceId.hashCode() : 0);
+        result = 31 * result + (onBehalfOf != null ? onBehalfOf.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AccessTokenRequest.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AccessTokenRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1dfad1ed718c4a314453a92814d3f0d84e246b3
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AccessTokenRequest.java
@@ -0,0 +1,145 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import net.ihe.gazelle.sb.iua.business.TokenType;
+
+import java.time.Duration;
+
+/**
+ * The Access Token request
+ */
+public class AccessTokenRequest {
+
+    private String issuer;
+    private String subject;
+    private String audience;
+    private Duration validityTime;
+    private TokenType tokenType;
+    private Signature signature;
+    private AccessTokenExtension extension;
+
+    /**
+     * constructor
+     */
+    public AccessTokenRequest(String issuer, String subject, String audience, Duration validityTime, TokenType tokenType) {
+        this.issuer = issuer;
+        this.subject = subject;
+        this.audience = audience;
+        this.validityTime = validityTime;
+        this.tokenType = tokenType;
+    }
+
+    /**
+     * get the issuer
+     *
+     * @return issuer
+     */
+    public String getIssuer() {
+        return issuer;
+    }
+
+    /**
+     * get the subject
+     *
+     * @return subject
+     */
+    public String getSubject() {
+        return subject;
+    }
+
+    /**
+     * get the audience
+     *
+     * @return audience
+     */
+    public String getAudience() {
+        return audience;
+    }
+
+    /**
+     * get the validityTime
+     *
+     * @return validityTime
+     */
+    public Duration getValidityTime() {
+        return validityTime;
+    }
+
+    /**
+     * get the tokenType
+     *
+     * @return tokenType
+     */
+    public TokenType getTokenType() {
+        return tokenType;
+    }
+
+    /**
+     * get the signature
+     *
+     * @return signature
+     */
+    public Signature getSignature() {
+        return signature;
+    }
+
+    /**
+     * set the signature
+     *
+     * @param signature the signature
+     */
+    public void setSignature(Signature signature) {
+        this.signature = signature;
+    }
+
+    /**
+     * get the extension
+     *
+     * @return extension
+     */
+    public AccessTokenExtension getExtension() {
+        return extension;
+    }
+
+    /**
+     * set the extension
+     *
+     * @param extension the extension
+     */
+    public void setExtension(AccessTokenExtension extension) {
+        this.extension = extension;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AccessTokenRequest that = (AccessTokenRequest) o;
+
+        if (!issuer.equals(that.issuer)) return false;
+        if (!subject.equals(that.subject)) return false;
+        if (!audience.equals(that.audience)) return false;
+        if (!validityTime.equals(that.validityTime)) return false;
+        if (tokenType != that.tokenType) return false;
+        if (signature != null ? !signature.equals(that.signature) : that.signature != null) return false;
+        return extension != null ? extension.equals(that.extension) : that.extension == null;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode() {
+        int result = issuer.hashCode();
+        result = 31 * result + subject.hashCode();
+        result = 31 * result + audience.hashCode();
+        result = 31 * result + validityTime.hashCode();
+        result = 31 * result + tokenType.hashCode();
+        result = 31 * result + (signature != null ? signature.hashCode() : 0);
+        result = 31 * result + (extension != null ? extension.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AsymmetricSignature.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AsymmetricSignature.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3f30203de4c1cf83289bcdfe54a85e6d096ea76
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AsymmetricSignature.java
@@ -0,0 +1,62 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import java.util.Arrays;
+
+/**
+ * Asymmetric signature information of the access token
+ */
+public class AsymmetricSignature extends Signature {
+
+    private byte[] privateKey;
+    private String privateKeyPassword;
+
+    /**
+     * constructor
+     */
+    public AsymmetricSignature(String algorithm, byte[] privateKey, String privateKeyPassword) {
+        super(algorithm);
+        this.privateKey = privateKey;
+        this.privateKeyPassword = privateKeyPassword;
+    }
+
+    /**
+     * get the privateKey
+     * @return privateKey
+     */
+    public byte[] getPrivateKey() {
+        return privateKey;
+    }
+
+    /**
+     * get the privateKeyPassword
+     * @return privateKeyPassword
+     */
+    public String getPrivateKeyPassword() {
+        return privateKeyPassword;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        if (!super.equals(o)) return false;
+
+        AsymmetricSignature that = (AsymmetricSignature) o;
+
+        if (!Arrays.equals(privateKey, that.privateKey)) return false;
+        return privateKeyPassword.equals(that.privateKeyPassword);
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode() {
+        int result = Arrays.hashCode(privateKey);
+        result = 31 * result + privateKeyPassword.hashCode();
+        return result;
+    }
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/CodedValue.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/CodedValue.java
new file mode 100644
index 0000000000000000000000000000000000000000..ebd7e365c497b4eab5b7444c4af6ff0fd195e9bc
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/CodedValue.java
@@ -0,0 +1,74 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+/**
+ * A Coded value
+ */
+public class CodedValue {
+
+    private String code;
+    private String codeSystem;
+    private String codeSystemName;
+    private String displayName;
+
+    /**
+     * constructor
+     */
+    public CodedValue(String code, String codeSystem) {
+        this.code = code;
+        this.codeSystem = codeSystem;
+    }
+
+    /**
+     * get the code
+     *
+     * @return code
+     */
+    public String getCode() {
+        return code;
+    }
+
+    /**
+     * get the codeSystem
+     *
+     * @return codeSystem
+     */
+    public String getCodeSystem() {
+        return codeSystem;
+    }
+
+    /**
+     * get the codeSystemName
+     *
+     * @return codeSystemName
+     */
+    public String getCodeSystemName() {
+        return codeSystemName;
+    }
+
+    /**
+     * set the codeSystemName
+     *
+     * @param codeSystemName the codeSystemName
+     */
+    public void setCodeSystemName(String codeSystemName) {
+        this.codeSystemName = codeSystemName;
+    }
+
+    /**
+     * get the displayName
+     *
+     * @return displayName
+     */
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    /**
+     * set the displayName
+     *
+     * @param displayName the displayName
+     */
+    public void setDisplayName(String displayName) {
+        this.displayName = displayName;
+    }
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/Credential.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/Credential.java
new file mode 100644
index 0000000000000000000000000000000000000000..cb7789cee54d0df2909d9073df1444858d5739f6
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/Credential.java
@@ -0,0 +1,7 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+/**
+ * Credential for an audience
+ */
+public abstract class Credential {
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/Password.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/Password.java
new file mode 100644
index 0000000000000000000000000000000000000000..7123a182d92aebecfc6f86fc9bd5f78b599c7656
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/Password.java
@@ -0,0 +1,47 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import java.util.Arrays;
+
+/**
+ * A password
+ */
+public class Password extends Credential {
+
+    private byte[] value;
+
+    /**
+     * constructor
+     */
+    public Password(byte[] value) {
+        this.value = value;
+    }
+
+    /**
+     * get the value
+     * @return value
+     */
+    public byte[] getValue() {
+        return value;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Password password = (Password) o;
+
+        return Arrays.equals(value, password.value);
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode() {
+        return Arrays.hashCode(value);
+    }
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/PublicKey.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/PublicKey.java
new file mode 100644
index 0000000000000000000000000000000000000000..2803b5b9cbe33305368cc87a7cb00e0ec4ff7bbe
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/PublicKey.java
@@ -0,0 +1,46 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import java.util.Arrays;
+
+/**
+ * A public key
+ */
+public class PublicKey extends Credential {
+    private byte[] key;
+
+    /**
+     * constructor
+     */
+    public PublicKey(byte[] key) {
+        this.key = key;
+    }
+
+    /**
+     * get the key
+     * @return key
+     */
+    public byte[] getKey() {
+        return key;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        PublicKey publicKey = (PublicKey) o;
+
+        return Arrays.equals(key, publicKey.key);
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode() {
+        return Arrays.hashCode(key);
+    }
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/lib/net.ihe.gazelle.app.accesstokenproviderapi/business/README.txt b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/README.txt
similarity index 100%
rename from access-token-provider-api/src/main/java/net/ihe/gazelle/lib/net.ihe.gazelle.app.accesstokenproviderapi/business/README.txt
rename to access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/README.txt
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/Signature.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/Signature.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec065fc59c883571956776052d626bda93d4663f
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/Signature.java
@@ -0,0 +1,46 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+
+/**
+ * Signature information of the access token
+ */
+public abstract class Signature {
+
+    private String algorithm;
+
+    /**
+     * constructor
+     */
+    public Signature(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * get the algorithm
+     * @return algorithm
+     */
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Signature signature = (Signature) o;
+
+        return algorithm.equals(signature.algorithm);
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode() {
+        return algorithm.hashCode();
+    }
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/SymmetricSignature.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/SymmetricSignature.java
new file mode 100644
index 0000000000000000000000000000000000000000..31628baae5de12ccbdcb0762a2f4e4f778af00db
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/SymmetricSignature.java
@@ -0,0 +1,47 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+/**
+ * Symmetric signature information of the access token
+ */
+public class SymmetricSignature extends Signature {
+
+    private String secret;
+
+    /**
+     * constructor
+     */
+    public SymmetricSignature(String algorithm, String secret) {
+        super(algorithm);
+        this.secret = secret;
+    }
+
+    /**
+     * get the secret
+     * @return secret
+     */
+    public String getSecret() {
+        return secret;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        if (!super.equals(o)) return false;
+
+        SymmetricSignature that = (SymmetricSignature) o;
+
+        return secret.equals(that.secret);
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode() {
+        return secret.hashCode();
+    }
+}
diff --git a/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/testuser/TestUser.java b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/testuser/TestUser.java
new file mode 100644
index 0000000000000000000000000000000000000000..321d4eada01514f6fd4fad131b567e52ca20d602
--- /dev/null
+++ b/access-token-provider-api/src/main/java/net/ihe/gazelle/app/accesstokenproviderapi/business/testuser/TestUser.java
@@ -0,0 +1,144 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business.testuser;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Test user used for authentication and token content
+ */
+public class TestUser {
+
+    private String userId;
+    private List<String> givenNames = new ArrayList<>();
+    private String lastName;
+    private Date birthDate; //fixme Date ?
+    private String gender; //fixme String ?
+    private Map<String, String> extensions = new HashMap<>();
+
+    /**
+     * Constructor
+     */
+    public TestUser(String userId, List<String> givenNames, String lastName) {
+        this.userId = userId;
+        this.givenNames = givenNames;
+        this.lastName = lastName;
+    }
+
+    /**
+     * get the userId
+     * @return userId
+     */
+    public String getUserId() {
+        return userId;
+    }
+
+    /**
+     * get the givenNames
+     * @return givenNames
+     */
+    public List<String> getGivenNames() {
+        return givenNames;
+    }
+
+    /**
+     * get the lastName
+     * @return lastName
+     */
+    public String getLastName() {
+        return lastName;
+    }
+
+    /**
+     * get the birthDate
+     * @return birthDate
+     */
+    public Date getBirthDate() {
+        return birthDate;
+    }
+
+    /**
+     * set the birthDate
+     *
+     * @param birthDate the birthDate
+     */
+    public void setBirthDate(Date birthDate) {
+        this.birthDate = birthDate;
+    }
+
+    /**
+     * get the gender
+     * @return gender
+     */
+    public String getGender() {
+        return gender;
+    }
+
+    /**
+     * set the gender
+     *
+     * @param gender the gender
+     */
+    public void setGender(String gender) {
+        this.gender = gender;
+    }
+
+    /**
+     * get the extensions
+     * @return extensions
+     */
+    public Map<String, String> getExtensions() {
+        return extensions;
+    }
+
+    /**
+     * add an extension in the extensions map
+     * @param key key of the extension
+     * @param value value of the extension
+     */
+    public void addExtension(String key, String value) {
+        extensions.put(key, value);
+    }
+
+    /**
+     * remove an extension in the extensions map
+     * @param key key of the extension
+     */
+    public void removeExtension(String key) {
+        extensions.remove(key);
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        TestUser testUser = (TestUser) o;
+
+        if (!userId.equals(testUser.userId)) return false;
+        if (!givenNames.equals(testUser.givenNames)) return false;
+        if (!lastName.equals(testUser.lastName)) return false;
+        if (birthDate != null ? !birthDate.equals(testUser.birthDate) : testUser.birthDate != null) return false;
+        if (gender != null ? !gender.equals(testUser.gender) : testUser.gender != null) return false;
+        return extensions != null ? extensions.equals(testUser.extensions) : testUser.extensions == null;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode() {
+        int result = userId.hashCode();
+        result = 31 * result + givenNames.hashCode();
+        result = 31 * result + lastName.hashCode();
+        result = 31 * result + (birthDate != null ? birthDate.hashCode() : 0);
+        result = 31 * result + (gender != null ? gender.hashCode() : 0);
+        result = 31 * result + (extensions != null ? extensions.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/access-token-provider-api/src/test/java/net/ihe/gazelle/lib/net.ihe.gazelle.app.accesstokenproviderapi/adapter/README.txt b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/README.txt
similarity index 100%
rename from access-token-provider-api/src/test/java/net/ihe/gazelle/lib/net.ihe.gazelle.app.accesstokenproviderapi/adapter/README.txt
rename to access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/adapter/README.txt
diff --git a/access-token-provider-api/src/test/java/net/ihe/gazelle/lib/net.ihe.gazelle.app.accesstokenproviderapi/application/README.txt b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/application/README.txt
similarity index 100%
rename from access-token-provider-api/src/test/java/net/ihe/gazelle/lib/net.ihe.gazelle.app.accesstokenproviderapi/application/README.txt
rename to access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/application/README.txt
diff --git a/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AccessTokenExtensionTest.java b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AccessTokenExtensionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c0bfb297bb2a588776d32b2456581d710afa704f
--- /dev/null
+++ b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AccessTokenExtensionTest.java
@@ -0,0 +1,305 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import net.ihe.gazelle.lib.annotations.Covers;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class AccessTokenExtensionTest {
+
+    /**
+     * Test subjectId getter and setter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-012")
+    void getSetSubjectId(){
+        String subjectId = "id";
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setSubjectId(subjectId);
+        assertEquals(subjectId, accessTokenExtension.getSubjectId(), "Getter shall return the value of subjectId !");
+    }
+
+    /**
+     * Test addSubjectOrganization and removeSubjectOrganization.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-013")
+    void subjectOrganization(){
+        String orga1 = "orga1";
+        String orga2 = "orga2";
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.addSubjectOrganization(orga1);
+        assertEquals(1, accessTokenExtension.getSubjectOrganizations().size());
+        accessTokenExtension.addSubjectOrganization(orga2);
+        assertEquals(2, accessTokenExtension.getSubjectOrganizations().size());
+        accessTokenExtension.removeSubjectOrganization(orga1);
+        assertEquals(1, accessTokenExtension.getSubjectOrganizations().size());
+        assertEquals(orga2, accessTokenExtension.getSubjectOrganizations().get(0));
+    }
+
+    /**
+     * Test addSubjectOrganizationId and removeSubjectOrganizationId.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-014")
+    void subjectOrganizationId(){
+        String orgaId1 = "orgaId1";
+        String orgaId2 = "orgaId2";
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.addSubjectOrganizationId(orgaId1);
+        assertEquals(1, accessTokenExtension.getSubjectOrganizationIds().size());
+        accessTokenExtension.addSubjectOrganizationId(orgaId2);
+        assertEquals(2, accessTokenExtension.getSubjectOrganizationIds().size());
+        accessTokenExtension.removeSubjectOrganizationId(orgaId1);
+        assertEquals(1, accessTokenExtension.getSubjectOrganizationIds().size());
+        assertEquals(orgaId2, accessTokenExtension.getSubjectOrganizationIds().get(0));
+    }
+
+    /**
+     * Test subjectId getter and setter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-015")
+    void homeCommunityId(){
+        String homeCommunityId = "id";
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setHomeCommunityId(homeCommunityId);
+        assertEquals(homeCommunityId, accessTokenExtension.getHomeCommunityId());
+    }
+
+    /**
+     * Test subjectId getter and setter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-016")
+    void nationalProviderIdentifier(){
+        String nationalProviderIdentifier = "id";
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setNationalProviderIdentifier(nationalProviderIdentifier);
+        assertEquals(nationalProviderIdentifier, accessTokenExtension.getNationalProviderIdentifier());
+    }
+
+    /**
+     * Test addProviderId and removeProviderId.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-017")
+    void providerId(){
+        String providerId1 = "provId1";
+        String providerId2 = "provId2";
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.addProviderId(providerId1);
+        assertEquals(1, accessTokenExtension.getProviderIds().size());
+        accessTokenExtension.addProviderId(providerId2);
+        assertEquals(2, accessTokenExtension.getProviderIds().size());
+        accessTokenExtension.removeProviderId(providerId1);
+        assertEquals(1, accessTokenExtension.getProviderIds().size());
+        assertEquals(providerId2, accessTokenExtension.getProviderIds().get(0));
+    }
+
+    /**
+     * Test subjectRole getter and setter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-018")
+    void subjectRole(){
+        CodedValue codedValue = new CodedValue("a", "b");
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setSubjectRole(codedValue);
+        assertEquals(codedValue, accessTokenExtension.getSubjectRole());
+    }
+
+    /**
+     * Test purposeOfUse getter and setter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-019")
+    void purposeOfUse(){
+        CodedValue codedValue = new CodedValue("a", "b");
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setPurposeOfUse(codedValue);
+        assertEquals(codedValue, accessTokenExtension.getPurposeOfUse());
+    }
+
+    /**
+     * Test resourceId getter and setter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-020")
+    void resourceId(){
+        String resourceId = "id";
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setResourceId(resourceId);
+        assertEquals(resourceId, accessTokenExtension.getResourceId());
+    }
+
+    /**
+     * Test onBehalfOf getter and setter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-021")
+    void onBehalfOf(){
+        String onBehalfOf = "toto";
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setOnBehalfOf(onBehalfOf);
+        assertEquals(onBehalfOf, accessTokenExtension.getOnBehalfOf());
+    }
+
+    /**
+     * Test equals with null.
+     */
+    @Test
+    void equalsNull() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        assertFalse(accessTokenExtension.equals(null), "Object shall not be equal to null !");
+    }
+
+    /**
+     * Test equals with itself.
+     */
+    @Test
+    void equalsItself() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        assertTrue(accessTokenExtension.equals(accessTokenExtension), "Object shall be equal to itself !");
+    }
+
+    /**
+     * Test equals with another class instance.
+     */
+    @Test
+    void equalsOtherClass() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        assertFalse(accessTokenExtension.equals(34), "Object shall not be equal to an instance of another class !");
+    }
+
+    /**
+     * Test equals with different subjectId
+     */
+    @Test
+    void equalsDifferentSubjectId() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setSubjectId("1");
+        AccessTokenExtension accessTokenExtension2 = new AccessTokenExtension();
+        accessTokenExtension.setSubjectId("2");
+        assertFalse(accessTokenExtension.equals(accessTokenExtension2), "Objects shall not be equal if they have different subjectId !");
+    }
+
+    /**
+     * Test equals with different subjectOrganization
+     */
+    @Test
+    void equalsDifferentSubjectOrganization() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.addSubjectOrganization("1");
+        AccessTokenExtension accessTokenExtension2 = new AccessTokenExtension();
+        accessTokenExtension.addSubjectOrganization("2");
+        assertFalse(accessTokenExtension.equals(accessTokenExtension2), "Objects shall not be equal if they have different subjectOrganization !");
+    }
+
+    /**
+     * Test equals with different subjectOrganizationId
+     */
+    @Test
+    void equalsDifferentSubjectOrganizationId() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.addSubjectOrganizationId("1");
+        AccessTokenExtension accessTokenExtension2 = new AccessTokenExtension();
+        accessTokenExtension.addSubjectOrganizationId("2");
+        assertFalse(accessTokenExtension.equals(accessTokenExtension2), "Objects shall not be equal if they have different subjectOrganizationId !");
+    }
+
+    /**
+     * Test equals with different homeCommunityId
+     */
+    @Test
+    void equalsDifferentHomeCommunityId() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setHomeCommunityId("1");
+        AccessTokenExtension accessTokenExtension2 = new AccessTokenExtension();
+        accessTokenExtension.setHomeCommunityId("2");
+        assertFalse(accessTokenExtension.equals(accessTokenExtension2), "Objects shall not be equal if they have different homeCommunityId !");
+    }
+
+    /**
+     * Test equals with different nationalProviderIdentifier
+     */
+    @Test
+    void equalsDifferentNationalProviderIdentifier() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setNationalProviderIdentifier("1");
+        AccessTokenExtension accessTokenExtension2 = new AccessTokenExtension();
+        accessTokenExtension.setNationalProviderIdentifier("2");
+        assertFalse(accessTokenExtension.equals(accessTokenExtension2), "Objects shall not be equal if they have different nationalProviderIdentifier !");
+    }
+
+    /**
+     * Test equals with different providerId
+     */
+    @Test
+    void equalsDifferentProviderId() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.addProviderId("1");
+        AccessTokenExtension accessTokenExtension2 = new AccessTokenExtension();
+        accessTokenExtension.addProviderId("2");
+        assertFalse(accessTokenExtension.equals(accessTokenExtension2), "Objects shall not be equal if they have different providerId !");
+    }
+
+    /**
+     * Test equals with different purposeOfUse
+     */
+    @Test
+    void equalsDifferentPurposeOfUse() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setPurposeOfUse(new CodedValue("1", "1"));
+        AccessTokenExtension accessTokenExtension2 = new AccessTokenExtension();
+        accessTokenExtension.setPurposeOfUse(new CodedValue("2", "2"));
+        assertFalse(accessTokenExtension.equals(accessTokenExtension2), "Objects shall not be equal if they have different purposeOfUse !");
+    }
+
+    /**
+     * Test equals with different subjectRole
+     */
+    @Test
+    void equalsDifferentSubjectRole() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setSubjectRole(new CodedValue("1", "1"));
+        AccessTokenExtension accessTokenExtension2 = new AccessTokenExtension();
+        accessTokenExtension.setSubjectRole(new CodedValue("2", "2"));
+        assertFalse(accessTokenExtension.equals(accessTokenExtension2), "Objects shall not be equal if they have different subjectRole !");
+    }
+
+    /**
+     * Test equals with different resourceId
+     */
+    @Test
+    void equalsDifferentResourceId() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setResourceId("1");
+        AccessTokenExtension accessTokenExtension2 = new AccessTokenExtension();
+        accessTokenExtension.setResourceId("2");
+        assertFalse(accessTokenExtension.equals(accessTokenExtension2), "Objects shall not be equal if they have different resourceId !");
+    }
+
+    /**
+     * Test equals with different onBehalfOf
+     */
+    @Test
+    void equalsDifferentOnBehalfOf() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        accessTokenExtension.setOnBehalfOf("1");
+        AccessTokenExtension accessTokenExtension2 = new AccessTokenExtension();
+        accessTokenExtension.setOnBehalfOf("2");
+        assertFalse(accessTokenExtension.equals(accessTokenExtension2), "Objects shall not be equal if they have different onBehalfOf !");
+    }
+
+    /**
+     * Test for the hashcode method
+     */
+    @Test
+    void testHashCode() {
+        AccessTokenExtension accessTokenExtension = new AccessTokenExtension();
+        assertNotNull(accessTokenExtension.hashCode(), "Generated hashCode shall not be null !");
+    }
+
+
+}
diff --git a/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AccessTokenRequestTest.java b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AccessTokenRequestTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7737a96d937f1941f9755de6cdc346646bd80188
--- /dev/null
+++ b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AccessTokenRequestTest.java
@@ -0,0 +1,206 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import net.ihe.gazelle.lib.annotations.Covers;
+import net.ihe.gazelle.sb.iua.business.TokenType;
+import org.junit.jupiter.api.Test;
+
+import java.time.Duration;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class AccessTokenRequestTest {
+
+    private static final String ISSUER = "issuer";
+    private static final String SUBJECT = "subject";
+    private static final String AUDIENCE = "audience";
+    private static final Duration DURATION = Duration.ofMinutes(1);
+    private static final TokenType TOKEN_TYPE = TokenType.JWT;
+    private static final SymmetricSignature SIGNATURE = new SymmetricSignature("RSALALA", "SECRET");
+    private static final AccessTokenExtension EXTENSION = new AccessTokenExtension();
+
+
+    /**
+     * Test issuer getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-001")
+    void getIssuer() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        assertEquals(ISSUER, accessTokenRequest.getIssuer(), "Getter shall return the value of issuer !");
+    }
+
+    /**
+     * Test subject getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-002")
+    void getSubject() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        assertEquals(SUBJECT, accessTokenRequest.getSubject(), "Getter shall return the value of subject !");
+    }
+
+    /**
+     * Test audience getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-003")
+    void getAudience() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        assertEquals(AUDIENCE, accessTokenRequest.getAudience(), "Getter shall return the value of audience !");
+    }
+
+    /**
+     * Test validityTime getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-004")
+    void getValidityTime() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        assertEquals(DURATION, accessTokenRequest.getValidityTime(), "Getter shall return the value of validityTime !");
+    }
+
+    /**
+     * Test tokenType getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-007")
+    void getTokenType() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        assertEquals(TOKEN_TYPE, accessTokenRequest.getTokenType(), "Getter shall return the value of tokenType !");
+    }
+
+    /**
+     * Test signature getter and setter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-005")
+    void signature() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        accessTokenRequest.setSignature(SIGNATURE);
+        assertEquals(SIGNATURE, accessTokenRequest.getSignature(), "Setter shall change the value of signature !");
+    }
+
+    /**
+     * Test extension getter and setter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-005")
+    void extension() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        accessTokenRequest.setExtension(EXTENSION);
+        assertEquals(EXTENSION, accessTokenRequest.getExtension(), "Setter shall change the value of extension !");
+    }
+
+    /**
+     * Test equals with null.
+     */
+    @Test
+    void equalsNull() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        assertFalse(accessTokenRequest.equals(null), "Object shall not be equal to null !");
+    }
+
+    /**
+     * Test equals with itself.
+     */
+    @Test
+    void equalsItself() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        assertTrue(accessTokenRequest.equals(accessTokenRequest), "Object shall be equal to itself !");
+    }
+
+    /**
+     * Test equals with another class instance.
+     */
+    @Test
+    void equalsOtherClass() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        assertFalse(accessTokenRequest.equals(34), "Object shall not be equal to an instance of another class !");
+    }
+
+    /**
+     * Test equals with different issuer
+     */
+    @Test
+    void equalsDifferentIssuer() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        AccessTokenRequest accessTokenRequest2 = new AccessTokenRequest("ISSUER2", SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        assertFalse(accessTokenRequest.equals(accessTokenRequest2), "Objects shall not be equal if they have different issuer !");
+    }
+
+    /**
+     * Test equals with different subject
+     */
+    @Test
+    void equalsDifferentSubject() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        AccessTokenRequest accessTokenRequest2 = new AccessTokenRequest(ISSUER, "SUBJECT2", AUDIENCE, DURATION, TOKEN_TYPE);
+        assertFalse(accessTokenRequest.equals(accessTokenRequest2), "Objects shall not be equal if they have different subject !");
+    }
+
+    /**
+     * Test equals with different audience
+     */
+    @Test
+    void equalsDifferentAudience() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        AccessTokenRequest accessTokenRequest2 = new AccessTokenRequest(ISSUER, SUBJECT, "AUDIENCE2", DURATION, TOKEN_TYPE);
+        assertFalse(accessTokenRequest.equals(accessTokenRequest2), "Objects shall not be equal if they have different audience !");
+    }
+
+    /**
+     * Test equals with different validityTime
+     */
+    @Test
+    void equalsDifferentValidityTime() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        AccessTokenRequest accessTokenRequest2 = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, Duration.ofDays(3), TOKEN_TYPE);
+        assertFalse(accessTokenRequest.equals(accessTokenRequest2), "Objects shall not be equal if they have different validityTime !");
+    }
+
+    /**
+     * Test equals with different tokenType
+     */
+    @Test
+    void equalsDifferentTokenType() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        AccessTokenRequest accessTokenRequest2 = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TokenType.SAML);
+        assertFalse(accessTokenRequest.equals(accessTokenRequest2), "Objects shall not be equal if they have different tokenType !");
+    }
+
+    /**
+     * Test equals with different signature
+     */
+    @Test
+    void equalsDifferentSignature() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        AccessTokenRequest accessTokenRequest2 = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        accessTokenRequest2.setSignature(new SymmetricSignature("RSA", "secret"));
+        assertFalse(accessTokenRequest.equals(accessTokenRequest2), "Objects shall not be equal if they have different signature !");
+    }
+
+    /**
+     * Test equals with different extension
+     */
+    @Test
+    void equalsDifferentExtension() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        AccessTokenRequest accessTokenRequest2 = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        accessTokenRequest2.setExtension(new AccessTokenExtension());
+        assertFalse(accessTokenRequest.equals(accessTokenRequest2), "Objects shall not be equal if they have different extension !");
+    }
+
+    /**
+     * Test for the hashcode method
+     */
+    @Test
+    void testHashCode() {
+        AccessTokenRequest accessTokenRequest = new AccessTokenRequest(ISSUER, SUBJECT, AUDIENCE, DURATION, TOKEN_TYPE);
+        assertNotNull(accessTokenRequest.hashCode(), "Generated hashCode shall not be null !");
+    }
+
+
+}
diff --git a/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AsymmetricSignatureTest.java b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AsymmetricSignatureTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b21389017d1ad63f2b8ee3168e26ef6cb159407
--- /dev/null
+++ b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/AsymmetricSignatureTest.java
@@ -0,0 +1,101 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import net.ihe.gazelle.lib.annotations.Covers;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class AsymmetricSignatureTest {
+
+    private static final byte[] KEY = "key".getBytes();
+    private static final String PASSWORD = "password";
+    private static final String ALGORITHM = "RSAPOUETPOUET";
+
+    /**
+     * Test privateKey getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-010")
+    void getPrivateKey(){
+        AsymmetricSignature signature = new AsymmetricSignature(ALGORITHM, KEY, PASSWORD);
+        assertEquals(KEY, signature.getPrivateKey(), "Getter shall return the value of privateKey !");
+    }
+
+    /**
+     * Test privateKeyPassword getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-011")
+    void getPrivateKeyPassword(){
+        AsymmetricSignature signature = new AsymmetricSignature(ALGORITHM, KEY, PASSWORD);
+        assertEquals(PASSWORD, signature.getPrivateKeyPassword(), "Getter shall return the value of privateKeyPassword !");
+    }
+
+    /**
+     * Test equals with null.
+     */
+    @Test
+    void equalsNull() {
+        AsymmetricSignature signature = new AsymmetricSignature(ALGORITHM, KEY, PASSWORD);
+        assertFalse(signature.equals(null), "Object shall not be equal to null !");
+    }
+
+    /**
+     * Test equals with itself.
+     */
+    @Test
+    void equalsItself() {
+        AsymmetricSignature signature = new AsymmetricSignature(ALGORITHM, KEY, PASSWORD);
+        assertTrue(signature.equals(signature), "Object shall be equal to itself !");
+    }
+
+    /**
+     * Test equals with another class instance.
+     */
+    @Test
+    void equalsOtherClass() {
+        AsymmetricSignature signature = new AsymmetricSignature(ALGORITHM, KEY, PASSWORD);
+        assertFalse(signature.equals(34), "Object shall not be equal to an instance of another class !");
+    }
+
+    /**
+     * Test equals with different algorithm
+     */
+    @Test
+    void equalsDifferentAlgorithm() {
+        AsymmetricSignature signature = new AsymmetricSignature(ALGORITHM, KEY, PASSWORD);
+        AsymmetricSignature signature2 = new AsymmetricSignature("ALGORITHM", KEY, PASSWORD);
+        assertFalse(signature.equals(signature2), "Objects shall not be equal if they have different algorithm !");
+    }
+
+    /**
+     * Test equals with different privateKey
+     */
+    @Test
+    void equalsDifferentPrivateKey() {
+        AsymmetricSignature signature = new AsymmetricSignature(ALGORITHM, KEY, PASSWORD);
+        AsymmetricSignature signature2 = new AsymmetricSignature(ALGORITHM, "KEY".getBytes(), PASSWORD);
+        assertFalse(signature.equals(signature2), "Objects shall not be equal if they have different privateKey !");
+    }
+
+    /**
+     * Test equals with different privateKeyPassword
+     */
+    @Test
+    void equalsDifferentPrivateKeyPassword() {
+        AsymmetricSignature signature = new AsymmetricSignature(ALGORITHM, KEY, PASSWORD);
+        AsymmetricSignature signature2 = new AsymmetricSignature(ALGORITHM, KEY, "PASSWORD");
+        assertFalse(signature.equals(signature2), "Objects shall not be equal if they have different privateKeyPassword !");
+    }
+
+    /**
+     * Test for the hashcode method
+     */
+    @Test
+    void testHashCode() {
+        AsymmetricSignature signature = new AsymmetricSignature(ALGORITHM, KEY, PASSWORD);
+        assertNotNull(signature.hashCode(), "Generated hashCode shall not be null !");
+    }
+
+
+}
diff --git a/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/CodedValueTest.java b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/CodedValueTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1125c461192b6d9bf167b0b3df242a2ccfa6c1bf
--- /dev/null
+++ b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/CodedValueTest.java
@@ -0,0 +1,52 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class CodedValueTest {
+
+    private static final String CODE = "100000007";
+    private static final String CODE_SYSTEM = "2.16.840.1.113883.3.3478.6.1";
+    private static final String CODE_SYSTEM_NAME = "ACC-Internal";
+    private static final String DISPLAY_NAME = "Hematoma Size";
+
+    /**
+     * Test code getter.
+     */
+    @Test
+    void getCode(){
+        CodedValue codedValue = new CodedValue(CODE, CODE_SYSTEM);
+        assertEquals(CODE, codedValue.getCode(), "Getter shall return the value of code !");
+    }
+
+    /**
+     * Test codeSystem getter.
+     */
+    @Test
+    void getCodeSystem(){
+        CodedValue codedValue = new CodedValue(CODE, CODE_SYSTEM);
+        assertEquals(CODE_SYSTEM, codedValue.getCodeSystem(), "Getter shall return the value of codeSystem !");
+    }
+
+    /**
+     * Test codeSystemName getter and setter.
+     */
+    @Test
+    void codeSystemName(){
+        CodedValue codedValue = new CodedValue(CODE, CODE_SYSTEM);
+        codedValue.setCodeSystemName(CODE_SYSTEM_NAME);
+        assertEquals(CODE_SYSTEM_NAME, codedValue.getCodeSystemName());
+    }
+
+    /**
+     * Test displayName getter and setter.
+     */
+    @Test
+    void codeDisplayName(){
+        CodedValue codedValue = new CodedValue(CODE, CODE_SYSTEM);
+        codedValue.setDisplayName(DISPLAY_NAME);
+        assertEquals(DISPLAY_NAME, codedValue.getDisplayName());
+    }
+
+}
diff --git a/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/PasswordTest.java b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/PasswordTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c01d384256209ffe33171526def6069691e67fad
--- /dev/null
+++ b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/PasswordTest.java
@@ -0,0 +1,68 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import net.ihe.gazelle.lib.annotations.Covers;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class PasswordTest {
+
+    private static final byte[] VALUE = "value".getBytes();
+
+    /**
+     * Test value getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-031")
+    void getKey() {
+        Password publicKey = new Password(VALUE);
+        assertEquals(VALUE, publicKey.getValue(), "Getter shall return the value of value !");
+    }
+
+    /**
+     * Test equals with null.
+     */
+    @Test
+    void equalsNull() {
+        Password publicKey = new Password(VALUE);
+        assertFalse(publicKey.equals(null), "Object shall not be equal to null !");
+    }
+
+    /**
+     * Test equals with itself.
+     */
+    @Test
+    void equalsItself() {
+        Password publicKey = new Password(VALUE);
+        assertTrue(publicKey.equals(publicKey), "Object shall be equal to itself !");
+    }
+
+    /**
+     * Test equals with another class instance.
+     */
+    @Test
+    void equalsOtherClass() {
+        Password publicKey = new Password(VALUE);
+        assertFalse(publicKey.equals(34), "Object shall not be equal to an instance of another class !");
+    }
+
+    /**
+     * Test equals with different issuer
+     */
+    @Test
+    void equalsDifferentIssuer() {
+        Password publicKey = new Password(VALUE);
+        Password publicKey2 = new Password("VALUE".getBytes());
+        assertFalse(publicKey.equals(publicKey2), "Objects shall not be equal if they have different issuer !");
+    }
+
+    /**
+     * Test for the hashcode method
+     */
+    @Test
+    void testHashCode() {
+        Password publicKey = new Password(VALUE);
+        assertNotNull(publicKey.hashCode(), "Generated hashCode shall not be null !");
+    }
+
+}
diff --git a/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/PublicKeyTest.java b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/PublicKeyTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..729212d1fd87d050cf29cb016ab7ab88e11b73c4
--- /dev/null
+++ b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/PublicKeyTest.java
@@ -0,0 +1,71 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import net.ihe.gazelle.lib.annotations.Covers;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class PublicKeyTest {
+
+    private static final byte[] KEY = "key".getBytes();
+
+    /**
+     * Test key getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-031")
+    void getKey() {
+        PublicKey publicKey = new PublicKey(KEY);
+        assertEquals(KEY, publicKey.getKey(), "Getter shall return the value of key !");
+    }
+
+    /**
+     * Test equals with null.
+     */
+    @Test
+    void equalsNull() {
+        PublicKey publicKey = new PublicKey(KEY);
+        assertFalse(publicKey.equals(null), "Object shall not be equal to null !");
+    }
+
+    /**
+     * Test equals with itself.
+     */
+    @Test
+    void equalsItself() {
+        PublicKey publicKey = new PublicKey(KEY);
+        assertTrue(publicKey.equals(publicKey), "Object shall be equal to itself !");
+    }
+
+    /**
+     * Test equals with another class instance.
+     */
+    @Test
+    void equalsOtherClass() {
+        PublicKey publicKey = new PublicKey(KEY);
+        assertFalse(publicKey.equals(34), "Object shall not be equal to an instance of another class !");
+    }
+
+    /**
+     * Test equals with different issuer
+     */
+    @Test
+    void equalsDifferentIssuer() {
+        PublicKey publicKey = new PublicKey(KEY);
+        PublicKey publicKey2 = new PublicKey("KEY".getBytes());
+        assertFalse(publicKey.equals(publicKey2), "Objects shall not be equal if they have different issuer !");
+    }
+
+    /**
+     * Test for the hashcode method
+     */
+    @Test
+    void testHashCode() {
+        PublicKey publicKey = new PublicKey(KEY);
+        assertNotNull(publicKey.hashCode(), "Generated hashCode shall not be null !");
+    }
+
+}
diff --git a/access-token-provider-api/src/test/java/net/ihe/gazelle/lib/net.ihe.gazelle.app.accesstokenproviderapi/business/README.txt b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/README.txt
similarity index 100%
rename from access-token-provider-api/src/test/java/net/ihe/gazelle/lib/net.ihe.gazelle.app.accesstokenproviderapi/business/README.txt
rename to access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/README.txt
diff --git a/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/SignatureTest.java b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/SignatureTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c69fe304d0f4b4d3bc252c020086b5c0632f964
--- /dev/null
+++ b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/SignatureTest.java
@@ -0,0 +1,31 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import net.ihe.gazelle.lib.annotations.Covers;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class SignatureTest {
+
+    private static final String ALGORITHM = "RSAPOUETPOUET";
+
+    /**
+     * Test algorithm getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-008")
+    void getAlgorithm(){
+        Signature signature = new Signature(ALGORITHM) {};
+        assertEquals(ALGORITHM, signature.getAlgorithm(), "Getter shall return the value of algorithm !");
+    }
+
+    /**
+     * Test for the hashcode method
+     */
+    @Test
+    void testHashCode() {
+        Signature signature = new Signature(ALGORITHM) {};
+        assertNotNull(signature.hashCode(), "Generated hashCode shall not be null !");
+    }
+
+}
diff --git a/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/SymmetricSignatureTest.java b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/SymmetricSignatureTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d42a0631d338bc7eb018cbe436fd4810dada4bb
--- /dev/null
+++ b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/SymmetricSignatureTest.java
@@ -0,0 +1,82 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business;
+
+import net.ihe.gazelle.lib.annotations.Covers;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class SymmetricSignatureTest {
+
+    private static final String ALGO = "RSAPOUETPOUET";
+    private static final String SECRET = "PSST";
+
+    /**
+     * Test privateKey getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-009")
+    void getPrivateKey() {
+        SymmetricSignature signature = new SymmetricSignature(ALGO, SECRET);
+        assertEquals(SECRET, signature.getSecret(), "Getter shall return the value of privateKey !");
+    }
+
+    /**
+     * Test equals with null.
+     */
+    @Test
+    void equalsNull() {
+        SymmetricSignature signature = new SymmetricSignature(ALGO, SECRET);
+        assertFalse(signature.equals(null), "Object shall not be equal to null !");
+    }
+
+    /**
+     * Test equals with itself.
+     */
+    @Test
+    void equalsItself() {
+        SymmetricSignature signature = new SymmetricSignature(ALGO, SECRET);
+        assertTrue(signature.equals(signature), "Object shall be equal to itself !");
+    }
+
+    /**
+     * Test equals with another class instance.
+     */
+    @Test
+    void equalsOtherClass() {
+        SymmetricSignature signature = new SymmetricSignature(ALGO, SECRET);
+        assertFalse(signature.equals(34), "Object shall not be equal to an instance of another class !");
+    }
+
+    /**
+     * Test equals with different algorithm
+     */
+    @Test
+    void equalsDifferentAlgorithm() {
+        SymmetricSignature signature = new SymmetricSignature(ALGO, SECRET);
+        SymmetricSignature signature2 = new SymmetricSignature("ALGO", SECRET);
+        assertFalse(signature.equals(signature2), "Objects shall not be equal if they have different algorithm !");
+    }
+
+    /**
+     * Test equals with different secret
+     */
+    @Test
+    void equalsDifferentSecret() {
+        SymmetricSignature signature = new SymmetricSignature(ALGO, SECRET);
+        SymmetricSignature signature2 = new SymmetricSignature(ALGO, "SECRET");
+        assertFalse(signature.equals(signature2), "Objects shall not be equal if they have different secret !");
+    }
+
+    /**
+     * Test for the hashcode method
+     */
+    @Test
+    void testHashCode() {
+        SymmetricSignature signature = new SymmetricSignature(ALGO, SECRET);
+        assertNotNull(signature.hashCode(), "Generated hashCode shall not be null !");
+    }
+
+}
diff --git a/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/testuser/TestUserTest.java b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/testuser/TestUserTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b4ee79d9a2a0383410c9b2c3977c172ca1550c3
--- /dev/null
+++ b/access-token-provider-api/src/test/java/net/ihe/gazelle/app/accesstokenproviderapi/business/testuser/TestUserTest.java
@@ -0,0 +1,229 @@
+package net.ihe.gazelle.app.accesstokenproviderapi.business.testuser;
+
+import net.ihe.gazelle.lib.annotations.Covers;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class TestUserTest {
+
+    private static final String USER_ID = "id";
+    private static final String GIVEN_NAME = "given";
+    private static final String LAST_NAME = "lastName";
+    private static final Date BIRTH_DATE = new Date();
+    private static final String GENDER = "gender";
+
+    /**
+     * Test userId getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-023")
+    void getUserId() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        assertEquals(USER_ID, testUser.getUserId(), "Getter shall return the value of userId !");
+    }
+
+    /**
+     * Test givenNames getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-024")
+    void getGivenNames() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        assertEquals(givenNames, testUser.getGivenNames(), "Getter shall return the value of givenNames !");
+    }
+
+    /**
+     * Test lastName getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-025")
+    void getlastName() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        assertEquals(LAST_NAME, testUser.getLastName(), "Getter shall return the value of lastName !");
+    }
+
+    /**
+     * Test birthDate getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-026")
+    void birthDate() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        testUser.setBirthDate(BIRTH_DATE);
+        assertEquals(BIRTH_DATE, testUser.getBirthDate(), "Getter shall return the value of birthDate !");
+    }
+
+    /**
+     * Test birthDate getter.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-027")
+    void gender() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        testUser.setGender(GENDER);
+        assertEquals(GENDER, testUser.getGender(), "Getter shall return the value of gender !");
+    }
+
+    /**
+     * Test addExtension and removeExtension.
+     */
+    @Test
+    @Covers(requirements = "TOKENPROV-028")
+    void addExtension() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        testUser.addExtension("key1", "value1");
+        assertEquals(1, testUser.getExtensions().size());
+        testUser.addExtension("key2", "value2");
+        assertEquals(2, testUser.getExtensions().size());
+        testUser.removeExtension("key1");
+        assertEquals(1, testUser.getExtensions().size());
+        assertEquals("value2", testUser.getExtensions().get("key2"));
+    }
+
+    /**
+     * Test equals with null.
+     */
+    @Test
+    void equalsNull() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        assertFalse(testUser.equals(null), "Object shall not be equal to null !");
+    }
+
+    /**
+     * Test equals with itself.
+     */
+    @Test
+    void equalsItself() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        assertTrue(testUser.equals(testUser), "Object shall be equal to itself !");
+    }
+
+    /**
+     * Test equals with another class instance.
+     */
+    @Test
+    void equalsOtherClass() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        assertFalse(testUser.equals(34), "Object shall not be equal to an instance of another class !");
+    }
+
+    /**
+     * Test equals with different issuerId
+     */
+    @Test
+    void equalsDifferentUserID() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        TestUser testUser2 = new TestUser("USER_ID", givenNames, LAST_NAME);
+        assertFalse(testUser.equals(testUser2), "Objects shall not be equal if they have different issuerId !");
+    }
+
+    /**
+     * Test equals with different givenNames
+     */
+    @Test
+    void equalsDifferentGivenNames() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        List<String> givenNames2 = new ArrayList<>();
+        givenNames2.add("given2");
+        TestUser testUser2 = new TestUser(USER_ID, givenNames2, LAST_NAME);
+        assertFalse(testUser.equals(testUser2), "Objects shall not be equal if they have different givenNames !");
+    }
+
+
+    /**
+     * Test equals with different lastName
+     */
+    @Test
+    void equalsDifferentLastName() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        TestUser testUser2 = new TestUser(USER_ID, givenNames, "LAST_NAME");
+        assertFalse(testUser.equals(testUser2), "Objects shall not be equal if they have different lastName !");
+    }
+
+    /**
+     * Test equals with different birthName
+     */
+    @Test
+    void equalsDifferentBirthName() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        testUser.setBirthDate(BIRTH_DATE);
+        TestUser testUser2 = new TestUser(USER_ID, givenNames, LAST_NAME);
+        testUser2.setBirthDate(new Date());
+        assertFalse(testUser.equals(testUser2), "Objects shall not be equal if they have different birthName !");
+    }
+
+    /**
+     * Test equals with different gender
+     */
+    @Test
+    void equalsDifferentGender() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        testUser.setGender(GENDER);
+        TestUser testUser2 = new TestUser(USER_ID, givenNames, LAST_NAME);
+        testUser.setGender("GENDER");
+        assertFalse(testUser.equals(testUser2), "Objects shall not be equal if they have different gender !");
+    }
+
+    /**
+     * Test equals with different extensions
+     */
+    @Test
+    void equalsDifferentExtensions() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        testUser.addExtension("1", "1");
+        TestUser testUser2 = new TestUser(USER_ID, givenNames, LAST_NAME);
+        testUser2.addExtension("1", "1");
+        testUser2.addExtension("2", "2");
+        assertFalse(testUser.equals(testUser2), "Objects shall not be equal if they have different extensions !");
+    }
+
+    /**
+     * Test for the hashcode method
+     */
+    @Test
+    void testHashCode() {
+        List<String> givenNames = new ArrayList<>();
+        givenNames.add(GIVEN_NAME);
+        TestUser testUser = new TestUser(USER_ID, givenNames, LAST_NAME);
+        assertNotNull(testUser.hashCode(), "Generated hashCode shall not be null !");
+    }
+
+}