diff --git a/.gitignore b/.gitignore
index 558f3c2..f225f4a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ node_modules
 env.sh
 .nyc_output
 coverage
+.tern-port
diff --git a/README.md b/README.md
index 603c8eb..55f1bd0 100644
--- a/README.md
+++ b/README.md
@@ -14,14 +14,13 @@ Wrapper library for Topcoder Submission API
 
     ```javascript
     const submissionApi = require('topcoder-submission-api-wrapper')
-    const submissionApiClient = submissionApi(_.pick(config,
+    const submissionApiM2MClient = submissionApi(_.pick(config,
           ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
             'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
             'AUTH0_PROXY_SERVER_URL']))
     ```
 
-    **Configuration / Environment variables:**
-
+    **M2M Authentication Configuration:**
     - AUTH0_URL - the auth0 url
     - AUTH0_AUDIENCE - the auth0 audience
     - TOKEN_CACHE_TIME - (optional) the token cache time
@@ -33,6 +32,29 @@ Wrapper library for Topcoder Submission API
     - PER_PAGE - the page size
     - MAX_PAGE_SIZE - the max number of page size
 
+    ```javascript
+    const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+          ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+           'TC_CLIENT_V2CONNECTION', 'SUBMISSION_API_URL']))
+    ```
+
+    **User Credentials Authentication Configuration:**
+    - USERNAME - Topcoder handle
+    - PASSWORD - Topcoder password
+    - TC_AUTHN_URL - OAUTH2 token URL, e.g. `https://topcoder.auth0.com/oauth/ro` or for dev `https://topcoder-dev.auth0.com/oauth/ro`
+    - TC_AUTHZ_URL - Topcoder API token URL, e.g. `https://api.topcoder.com/v3/authorizations` or for dev `https://api.topcoder-dev.com/v3/authorizations`
+    - TC_CLIENT_ID - OAUTH2 Client ID, e.g. `6ZwZEUo2ZK4c50aLPpgupeg5v2Ffxp9P` or for dev `JFDo7HMkf0q2CkVFHojy3zHWafziprhT`
+    - TC_CLIENT_V2CONNECTION - The OAUTH2 Client data source, e.g. `TC-User-Database`
+    - SUBMISSION_API_URL - Topcoder V5 Submission API URL. E.g. `https://api.topcoder.com/v5` or for dev `https://api.topcoder-dev.com/v5`
+
+    ```javascript
+    const submissionJwtMethodArgClient = submissionApi(_.pick(config,
+          ['SUBMISSION_API_URL']))
+    ```
+
+    **JWT Method Argument Authentication Configuration:**
+    - SUBMISSION_API_URL - Topcoder V5 Submission API URL. E.g. `https://api.topcoder.com/v5` or for dev `https://api.topcoder-dev.com/v5`
+
 3. Every function in this wrapper will return a promise, Handling promises is at the caller end. Call the functions with appropriate arguments
 
 E.g.
@@ -126,6 +148,13 @@ Following environment variables need to be set up before running the tests
 - TEST_AUTH0_CLIENT_ID
 - TEST_AUTH0_CLIENT_SECRET
 - TEST_SUBMISSION_API_URL
+- TEST_JWT
+- TEST_USERNAME
+- TEST_PASSWORD
+- TEST_TC_AUTHN_URL
+- TEST_TC_AUTHZ_URL
+- TEST_TC_CLIENT_ID
+- TEST_TC_CLIENT_V2CONNECTION
 ```
 
 Refer to Step # 2 in [this section](#how-to-use-this-wrapper) to learn more about the configuration variables.
diff --git a/Verification.md b/Verification.md
index e1bf986..757cd63 100644
--- a/Verification.md
+++ b/Verification.md
@@ -8,17 +8,19 @@
 
 ## Test Coverage Report
 
-  226 passing (5m)
+668 passing
 
-File                                        |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s
---------------------------------------------|----------|----------|----------|----------|-------------------
-All files                                   |    99.42 |       90 |      100 |    99.42 |
- topcoder-submission-api-wrapper            |      100 |      100 |      100 |      100 |
-  index.js                                  |      100 |      100 |      100 |      100 |
- topcoder-submission-api-wrapper/src        |      100 |      100 |      100 |      100 |
-  ReviewSummationsApi.js                    |      100 |      100 |      100 |      100 |
-  ReviewTypesApi.js                         |      100 |      100 |      100 |      100 |
-  ReviewsApi.js                             |      100 |      100 |      100 |      100 |
-  SubmissionsApi.js                         |      100 |      100 |      100 |      100 |
- topcoder-submission-api-wrapper/src/common |    97.56 |    88.89 |      100 |    97.56 |
-  helper.js                                 |    97.56 |    88.89 |      100 |    97.56 |                63
+
+File                                        |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+--------------------------------------------|----------|----------|----------|----------|-------------------|
+All files                                   |     99.5 |    95.52 |      100 |     99.5 |                   |
+ topcoder-submission-api-wrapper            |      100 |      100 |      100 |      100 |                   |
+  index.js                                  |      100 |      100 |      100 |      100 |                   |
+ topcoder-submission-api-wrapper/src        |      100 |      100 |      100 |      100 |                   |
+  ReviewSummationsApi.js                    |      100 |      100 |      100 |      100 |                   |
+  ReviewTypesApi.js                         |      100 |      100 |      100 |      100 |                   |
+  ReviewsApi.js                             |      100 |      100 |      100 |      100 |                   |
+  SubmissionsApi.js                         |      100 |      100 |      100 |      100 |                   |
+ topcoder-submission-api-wrapper/src/common |    98.25 |       88 |      100 |    98.25 |                   |
+  constants.js                              |      100 |      100 |      100 |      100 |                   |
+  helper.js                                 |    98.21 |       88 |      100 |    98.21 |               134 |
diff --git a/docs/ReviewSummationsApi.md b/docs/ReviewSummationsApi.md
index 649b5d5..e022e8f 100644
--- a/docs/ReviewSummationsApi.md
+++ b/docs/ReviewSummationsApi.md
@@ -22,11 +22,17 @@ Search review summations. Link headers are sent back and they have rel set to pr
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reqQuery = {
   page: 1,
   perPage: 3,
@@ -37,13 +43,27 @@ const reqQuery = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .searchReviewSummations(reqQuery)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .searchReviewSummations(reqQuery)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .searchReviewSummations(reqQuery, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // async / await model
-await submissionApiClient.searchReviewSummations(reqQuery)
+await submissionApiM2MClient.searchReviewSummations(reqQuery)
+
+await submissionApiUserCredentialsClient.searchReviewSummations(reqQuery)
+
+await submissionApiJwtMethodArgClient.searchReviewSummations(reqQuery, config.JWT)
 ```
 
 ### Parameters
@@ -51,6 +71,7 @@ await submissionApiClient.searchReviewSummations(reqQuery)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reqQuery** | [**SearchReviewSummationsCriteria**](SearchReviewSummationsCriteria.md) | the search review summations criteria
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -75,11 +96,17 @@ Same to search review summations, but only response status and headers informati
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reqQuery = {
   page: 1,
   perPage: 3,
@@ -90,13 +117,27 @@ const reqQuery = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .headReviewSummations(reqQuery)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .headReviewSummations(reqQuery)
   .then(result => console.log(result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .headReviewSummations(reqQuery, config.JWT)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.headReviewSummations(reqQuery)
+await submissionApiM2MClient.headReviewSummations(reqQuery)
+
+await submissionApiUserCredentialsClient.headReviewSummations(reqQuery)
+
+await submissionApiJwtMethodArgClient.headReviewSummations(reqQuery, config.JWT)
 ```
 
 ### Parameters
@@ -104,6 +145,7 @@ await submissionApiClient.headReviewSummations(reqQuery)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reqQuery** | [**SearchReviewSummationsCriteria**](SearchReviewSummationsCriteria.md) | the search reviews criteria
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -128,11 +170,17 @@ Create a review summation.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reqBody = {
   submissionId: 'a3d891ef-4002-48fc-ae35-e8623e6bd4b9',
   aggregateScore: 87.5,
@@ -142,13 +190,27 @@ const reqBody = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .createReviewSummation(reqBody)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .createReviewSummation(reqBody)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .createReviewSummation(reqBody, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // async / await model
-await submissionApiClient.createReviewSummation(reqBody)
+await submissionApiM2MClient.createReviewSummation(reqBody)
+
+await submissionApiUserCredentialsClient.createReviewSummation(reqBody)
+
+await submissionApiJwtMethodArgClient.createReviewSummation(reqBody, config.JWT)
 ```
 
 ### Parameters
@@ -156,6 +218,7 @@ await submissionApiClient.createReviewSummation(reqBody)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reqBody** | [**ReviewSummationData**](ReviewSummationData.md) | the review summation data
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -180,27 +243,48 @@ Get the review summation by id.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewSummationId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .getReviewSummation(reviewSummationId)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .getReviewSummation(reviewSummationId)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .getReviewSummation(reviewSummationId, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // async / await model
-await submissionApiClient.getReviewSummation(reviewSummationId)
+await submissionApiM2MClient.getReviewSummation(reviewSummationId)
+
+await submissionApiUserCredentialsClient.getReviewSummation(reviewSummationId)
+
+await submissionApiJwtMethodArgClient.getReviewSummation(reviewSummationId, config.JWT)
 ```
 ### Parameters
 
 Name | Type | Description
 ------------- | ------------- | -------------
  **reviewSummationId** | String | the review summation id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -225,21 +309,41 @@ Same to get review summation, but only response status and headers information r
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewSummationId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .headReviewSummation(reviewSummationId)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .headReviewSummation(reviewSummationId)
   .then(result => console.log(result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .headReviewSummation(reviewSummationId, config.JWT)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
 // async / await model
-await submissionApiClient.headReviewSummation(reviewId)
+await submissionApiM2MClient.headReviewSummation(reviewId)
+
+await submissionApiUserCredentialsClient.headReviewSummation(reviewId)
+
+await submissionApiJwtMethodArgClient.headReviewSummation(reviewId, config.JWT)
 ```
 
 ### Parameters
@@ -247,6 +351,7 @@ await submissionApiClient.headReviewSummation(reviewId)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reviewSummationId** | String | the review summation id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -271,11 +376,17 @@ Fully update review summation.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewSummationId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 const reqBody = {
   submissionId: 'a3d891ef-4002-48fc-ae35-e8623e6bd4b9',
@@ -286,13 +397,27 @@ const reqBody = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .updateReviewSummation(reviewSummationId, reqBody)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .updateReviewSummation(reviewSummationId, reqBody)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .updateReviewSummation(reviewSummationId, reqBody, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // async / await model
-await submissionApiClient.updateReviewSummation(reviewSummationId, reqBody)
+await submissionApiM2MClient.updateReviewSummation(reviewSummationId, reqBody)
+
+await submissionApiUserCredentialsClient.updateReviewSummation(reviewSummationId, reqBody)
+
+await submissionApiJwtMethodArgClient.updateReviewSummation(reviewSummationId, reqBody, config.JWT)
 ```
 
 ### Parameters
@@ -301,6 +426,7 @@ Name | Type | Description
 ------------- | ------------- | -------------
  **reviewSummationId** | String | the review summation id
  **reqBody** | [**ReviewSummationData**](ReviewSummationData.md) | the review summation data
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -325,11 +451,17 @@ Partially update review summation.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewSummationId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 const reqBody = {
   aggregateScore: 99,
@@ -337,13 +469,27 @@ const reqBody = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .patchReviewSummation(reviewSummationId, reqBody)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .patchReviewSummation(reviewSummationId, reqBody)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .patchReviewSummation(reviewSummationId, reqBody, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // async / await model
-await submissionApiClient.patchReviewSummation(reviewSummationId, reqBody)
+await submissionApiM2MClient.patchReviewSummation(reviewSummationId, reqBody)
+
+await submissionApiUserCredentialsClient.patchReviewSummation(reviewSummationId, reqBody)
+
+await submissionApiJwtMethodArgClient.patchReviewSummation(reviewSummationId, reqBody, config.JWT)
 ```
 
 ### Parameters
@@ -352,6 +498,7 @@ Name | Type | Description
 ------------- | ------------- | -------------
  **reviewSummationId** | String | the review summation id
  **reqBody** | [**ReviewSummationData**](ReviewSummationData.md) | the review summation data
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -376,21 +523,41 @@ Delete review summation by id.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewSummationId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .deleteReviewSummation(reviewSummationId)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .deleteReviewSummation(reviewSummationId)
   .then(result => console.log(result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .deleteReviewSummation(reviewSummationId, config.JWT)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
 // async / await model
-await submissionApiClient.deleteReviewSummation(reviewSummationId)
+await submissionApiM2MClient.deleteReviewSummation(reviewSummationId)
+
+await submissionApiUserCredentialsClient.deleteReviewSummation(reviewSummationId)
+
+await submissionApiJwtMethodArgClient.deleteReviewSummation(reviewSummationId, config.JWT)
 ```
 
 ### Parameters
@@ -398,6 +565,7 @@ await submissionApiClient.deleteReviewSummation(reviewSummationId)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reviewSummationId** | String | the review summation id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
diff --git a/docs/ReviewTypesApi.md b/docs/ReviewTypesApi.md
index d167e12..0eeef86 100644
--- a/docs/ReviewTypesApi.md
+++ b/docs/ReviewTypesApi.md
@@ -22,11 +22,17 @@ Search review types. Link headers are sent back and they have rel set to prev, n
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reqQuery = {
   page: 1,
   perPage: 10,
@@ -35,13 +41,27 @@ const reqQuery = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .searchReviewTypes(reqQuery)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .searchReviewTypes(reqQuery)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .searchReviewTypes(reqQuery, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.searchReviewTypes(reqQuery)
+await submissionApiM2MClient.searchReviewTypes(reqQuery)
+
+await submissionApiUserCredentialsClient.searchReviewTypes(reqQuery)
+
+await submissionApiJwtMethodArgClient.searchReviewTypes(reqQuery, config.JWT)
 ```
 
 ### Parameters
@@ -49,6 +69,7 @@ await submissionApiClient.searchReviewTypes(reqQuery)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reqQuery** | [**Criteria**](Criteria.md)| the search criteria
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -72,11 +93,17 @@ Same to search review types, but only response status and headers information re
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reqQuery = {
   page: 1,
   perPage: 10,
@@ -85,13 +112,27 @@ const reqQuery = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .headReviewTypes(reqQuery)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .headReviewTypes(reqQuery)
   .then(result => console.log(result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .headReviewTypes(reqQuery, config.JWT)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.headReviewTypes(reqQuery)
+await submissionApiM2MClient.headReviewTypes(reqQuery)
+
+await submissionApiUserCredentialsClient.headReviewTypes(reqQuery)
+
+await submissionApiJwtMethodArgClient.headReviewTypes(reqQuery, config.JWT)
 ```
 
 ### Parameters
@@ -99,6 +140,7 @@ await submissionApiClient.headReviewTypes(reqQuery)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reqQuery** | [**Criteria**](Criteria.md)| the search criteria
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -122,24 +164,44 @@ Create a review type.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reqBody = {
   name: 'Review',
   isActive: true
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .createReviewType(reqBody)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .createReviewType(reqBody)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .createReviewType(reqBody, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.createReviewType(reqBody)
+await submissionApiM2MClient.createReviewType(reqBody)
+
+await submissionApiUserCredentialsClient.createReviewType(reqBody)
+
+await submissionApiJwtMethodArgClient.createReviewType(reqBody, config.JWT)
 ```
 
 ### Parameters
@@ -147,6 +209,7 @@ await submissionApiClient.createReviewType(reqBody)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reqBody** | [**ReviewTypeData**](ReviewTypeData.md)| the review type data
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -170,27 +233,48 @@ Get the review type by id.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewTypeId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .getReviewType(reviewTypeId)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .getReviewType(reviewTypeId)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .getReviewType(reviewTypeId, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.getReviewType(reviewTypeId)
+await submissionApiM2MClient.getReviewType(reviewTypeId)
+
+await submissionApiUserCredentialsClient.getReviewType(reviewTypeId)
+
+await submissionApiJwtMethodArgClient.getReviewType(reviewTypeId, config.JWT)
 ```
 ### Parameters
 
 Name | Type | Description
 ------------- | ------------- | -------------
  **reviewTypeId** | String | the review type id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -214,21 +298,41 @@ Same to get review type, but only response status and headers information return
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewTypeId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .headReviewType(reviewTypeId)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .headReviewType(reviewTypeId)
   .then(result => console.log(result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .headReviewType(reviewTypeId, config.JWT)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.headReviewType(reviewTypeId)
+await submissionApiM2MClient.headReviewType(reviewTypeId)
+
+await submissionApiUserCredentialsClient.headReviewType(reviewTypeId)
+
+await submissionApiJwtMethodArgClient.headReviewType(reviewTypeId, config.JWT)
 ```
 
 ### Parameters
@@ -236,6 +340,7 @@ await submissionApiClient.headReviewType(reviewTypeId)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reviewTypeId** | String | the review type id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -259,11 +364,17 @@ Fully update review type.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewTypeId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 const reqBody = {
   name: 'Review',
@@ -271,13 +382,27 @@ const reqBody = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .updateReviewType(reviewTypeId, reqBody)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .updateReviewType(reviewTypeId, reqBody)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .updateReviewType(reviewTypeId, reqBody, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.updateReviewType(reviewTypeId, reqBody)
+await submissionApiM2MClient.updateReviewType(reviewTypeId, reqBody)
+
+await submissionApiUserCredentialsClient.updateReviewType(reviewTypeId, reqBody)
+
+await submissionApiJwtMethodArgClient.updateReviewType(reviewTypeId, reqBody, config.JWT)
 ```
 
 ### Parameters
@@ -286,6 +411,7 @@ Name | Type | Description
 ------------- | ------------- | -------------
  **reviewTypeId** | String | the review type id
  **reqBody** | [**ReviewTypeData**](ReviewTypeData.md)| the review type data
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -309,11 +435,17 @@ Partially update review type.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewTypeId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 const reqBody = {
   name: 'Review',
@@ -321,13 +453,27 @@ const reqBody = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .patchReviewType(reviewTypeId, reqBody)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .patchReviewType(reviewTypeId, reqBody)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .patchReviewType(reviewTypeId, reqBody, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.patchReviewType(reviewTypeId, reqBody)
+await submissionApiM2MClient.patchReviewType(reviewTypeId, reqBody)
+
+await submissionApiUserCredentialsClient.patchReviewType(reviewTypeId, reqBody)
+
+await submissionApiJwtMethodArgClient.patchReviewType(reviewTypeId, reqBody, config.JWT)
 ```
 
 ### Parameters
@@ -336,6 +482,7 @@ Name | Type | Description
 ------------- | ------------- | -------------
  **reviewTypeId** | String | the review type id
  **reqBody** | [**ReviewTypeData**](ReviewTypeData.md)| the review type data
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -359,21 +506,41 @@ Delete review type by id.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewTypeId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .deleteReviewType(reviewTypeId)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .deleteReviewType(reviewTypeId)
   .then(result => console.log(result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .deleteReviewType(reviewTypeId, config.JWT)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.deleteReviewType(reviewTypeId)
+await submissionApiM2MClient.deleteReviewType(reviewTypeId)
+
+await submissionApiUserCredentialsClient.deleteReviewType(reviewTypeId)
+
+await submissionApiJwtMethodArgClient.deleteReviewType(reviewTypeId, config.JWT)
 ```
 
 ### Parameters
@@ -381,6 +548,7 @@ await submissionApiClient.deleteReviewType(reviewTypeId)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reviewTypeId** | String | the review type id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
diff --git a/docs/ReviewsApi.md b/docs/ReviewsApi.md
index 983f10a..25c6f83 100644
--- a/docs/ReviewsApi.md
+++ b/docs/ReviewsApi.md
@@ -22,11 +22,18 @@ Search reviews. Link headers are sent back and they have rel set to prev, next,
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config,
+      ['SUBMISSION_API_URL']))
+
 const reqQuery = {
   page: 1,
   perPage: 10,
@@ -34,13 +41,28 @@ const reqQuery = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .searchReviews(reqQuery)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .searchReviews(reqQuery)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+
+submissionApiJwtMethodArgClient
+  .searchReviews(reqQuery, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.searchReviews(reqQuery)
+await submissionApiM2MClient.searchReviews(reqQuery)
+
+await submissionApiUserCredentialsClient.searchReviews(reqQuery)
+
+await submissionApiJwtMethodArgClient.searchReviews(reqQuery, config.JWT)
 ```
 
 ### Parameters
@@ -48,6 +70,7 @@ await submissionApiClient.searchReviews(reqQuery)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reqQuery** | [**SearchReviewsCriteria**](SearchReviewsCriteria.md)| the search reviews criteria
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -71,11 +94,17 @@ Same to search reviews, but only response status and headers information return.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reqQuery = {
   page: 1,
   perPage: 10,
@@ -83,13 +112,27 @@ const reqQuery = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .headReviews(reqQuery)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .headReviews(reqQuery)
   .then(result => console.log(result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .headReviews(reqQuery, config.JWT)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.headReviews(reqQuery)
+await submissionApiM2MClient.headReviews(reqQuery)
+
+await submissionApiUserCredentialsClient.headReviews(reqQuery)
+
+await submissionApiJwtMethodArgClient.headReviews(reqQuery, config.JWT)
 ```
 
 ### Parameters
@@ -97,6 +140,7 @@ await submissionApiClient.headReviews(reqQuery)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reqQuery** | [**SearchReviewsCriteria**](SearchReviewsCriteria.md)| the search reviews criteria
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -120,11 +164,17 @@ Create a review.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reqBody = {
   score: 89,
   reviewerId: 'a3d891ef-4002-48fc-ae35-e8623e6bd4b9',
@@ -135,13 +185,27 @@ const reqBody = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .createReview(reqBody)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .createReview(reqBody)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .createReview(reqBody, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.createReview(reqBody)
+await submissionApiM2MClient.createReview(reqBody)
+
+await submissionApiUserCredentialsClient.createReview(reqBody)
+
+await submissionApiJwtMethodArgClient.createReview(reqBody, config.JWT)
 ```
 
 ### Parameters
@@ -149,6 +213,7 @@ await submissionApiClient.createReview(reqBody)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reqBody** | [**ReviewData**](ReviewData.md)| the review data
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -172,27 +237,49 @@ Get the review by id.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .getReview(reviewId)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .getReview(reviewId)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .getReview(reviewId, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.getReview(reviewId)
+await submissionApiM2MClient.getReview(reviewId)
+
+await submissionApiUserCredentialsClient.getReview(reviewId)
+
+await submissionApiJwtMethodArgClient.getReview(reviewId, config.JWT)
+
 ```
 ### Parameters
 
 Name | Type | Description
 ------------- | ------------- | -------------
  **reviewId** | String | the review id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -216,21 +303,41 @@ Same to get review, but only response status and headers information return.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .headReview(reviewId)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .headReview(reviewId)
   .then(result => console.log(result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .headReview(reviewId, config.JWT)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.headReview(reviewId)
+await submissionApiM2MClient.headReview(reviewId)
+
+await submissionApiUserCredentialsClient.headReview(reviewId)
+
+await submissionApiJwtMethodArgClient.headReview(reviewId, config.JWT)
 ```
 
 ### Parameters
@@ -238,6 +345,7 @@ await submissionApiClient.headReview(reviewId)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reviewId** | String | the review id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -261,11 +369,17 @@ Fully update review.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArg = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 const reqBody = {
   score: 100,
@@ -277,13 +391,27 @@ const reqBody = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .updateReview(reviewId, reqBody)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .updateReview(reviewId, reqBody)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .updateReview(reviewId, reqBody, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.updateReview(reviewId, reqBody)
+await submissionApiM2MClient.updateReview(reviewId, reqBody)
+
+await submissionApiUserCredentialsClient.updateReview(reviewId, reqBody)
+
+await submissionApiJwtMethodArgClient.updateReview(reviewId, reqBody, config.JWT)
 ```
 
 ### Parameters
@@ -292,6 +420,7 @@ Name | Type | Description
 ------------- | ------------- | -------------
  **reviewId** | String | the review id
  **reqBody** | [**ReviewData**](ReviewData.md)| the review data
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -315,11 +444,17 @@ Partially update review.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArg = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 const reqBody = {
   score: 99,
@@ -329,13 +464,27 @@ const reqBody = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .patchReview(reviewId, reqBody)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .patchReview(reviewId, reqBody)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .patchReview(reviewId, reqBody, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.patchReview(reviewId, reqBody)
+await submissionApiM2MClient.patchReview(reviewId, reqBody)
+
+await submissionApiUserCredentialsClient.patchReview(reviewId, reqBody)
+
+await submissionApiJwtMethodArgClient.patchReview(reviewId, reqBody, config.JWT)
 ```
 
 ### Parameters
@@ -344,6 +493,7 @@ Name | Type | Description
 ------------- | ------------- | -------------
  **reviewId** | String | the review id
  **reqBody** | [**ReviewData**](ReviewData.md)| the review data
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -367,21 +517,41 @@ Delete review by id.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArg = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reviewId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .deleteReview(reviewId)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .deleteReview(reviewId)
   .then(result => console.log(result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .deleteReview(reviewId, config.JWT)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.deleteReview(reviewId)
+await submissionApiM2MClient.deleteReview(reviewId)
+
+await submissionApiUserCredentialsClient.deleteReview(reviewId)
+
+await submissionApiJwtMethodArgClient.deleteReview(reviewId, config.JWT)
 ```
 
 ### Parameters
@@ -389,6 +559,7 @@ await submissionApiClient.deleteReview(reviewId)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reviewId** | String | the review id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
diff --git a/docs/SubmissionsApi.md b/docs/SubmissionsApi.md
index e40b8ed..9926975 100644
--- a/docs/SubmissionsApi.md
+++ b/docs/SubmissionsApi.md
@@ -26,11 +26,17 @@ Search submissions. Link headers are sent back and they have rel set to prev, ne
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reqQuery = {
   page: 1,
   perPage: 10,
@@ -38,13 +44,27 @@ const reqQuery = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
   .searchSubmissions(reqQuery)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiUserCredentialsClient
+  .searchSubmissions(reqQuery)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiJwtMethodArgClient
+  .searchSubmissions(reqQuery, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.searchSubmissions(reqQuery)
+await submissionApiM2MClient.searchSubmissions(reqQuery)
+
+await submissionApiUserCredentialsClient.searchSubmissions(reqQuery)
+
+await submissionApiJwtMethodArgClient.searchSubmissions(reqQuery, config.JWT)
 ```
 
 ### Parameters
@@ -52,6 +72,7 @@ await submissionApiClient.searchSubmissions(reqQuery)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reqQuery** | [**SearchSubmissionsCriteria**](SearchSubmissionsCriteria.md)| the search submissions criteria
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -75,11 +96,17 @@ Same to search submissions, but only response status and headers information ret
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reqQuery = {
   page: 1,
   perPage: 10,
@@ -87,13 +114,27 @@ const reqQuery = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .headSubmissions(reqQuery)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .headSubmissions(reqQuery)
   .then(result => console.log(result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .headSubmissions(reqQuery, config.JWT)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.headSubmissions(reqQuery)
+await submissionApiM2MClient.headSubmissions(reqQuery)
+
+await submissionApiUserCredentialsClient.headSubmissions(reqQuery)
+
+await submissionApiJwtMethodArgClient.headSubmissions(reqQuery, config.JWT)
 ```
 
 ### Parameters
@@ -101,6 +142,7 @@ await submissionApiClient.headSubmissions(reqQuery)
 Name | Type | Description
 ------------- | ------------- | -------------
  **reqQuery** | [**SearchSubmissionsCriteria**](SearchSubmissionsCriteria.md)| the search submissions criteria
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -127,11 +169,17 @@ const path = require('path')
 const fs = require('fs')
 const fileData = fs.readFileSync(path.resolve(__dirname, './data/fileToUpload.zip'))
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const reqFormData1 = {
   submission: {
     name: 'fileToUpload.zip',
@@ -150,13 +198,27 @@ const reqFormData2 = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .createSubmission(reqFormData1)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .createSubmission(reqFormData1)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .createSubmission(reqFormData1, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.createSubmission(reqFormData2)
+await submissionApiM2MClient.createSubmission(reqFormData2)
+
+await submissionApiUserCredentialsClient.createSubmission(reqFormData2)
+
+await submissionApiJwtMethodArgClient.createSubmission(reqFormData2, config.JWT)
 ```
 
 ### Demo
@@ -206,6 +268,7 @@ app.listen(app.get('port'), () => {
 Name | Type | Description
 ------------- | ------------- | -------------
  **reqFormData** | [**SubmissionData**](SubmissionData.md)| the submission data
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -229,27 +292,48 @@ Get submission by id.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const submissionId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
   .getSubmission(submissionId)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiUserCredentialsClient
+  .getSubmission(submissionId)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiJwtMethodArgClient
+  .getSubmission(submissionId, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.getSubmission(submissionId)
+await submissionApiM2MClient.getSubmission(submissionId)
+
+await submissionApiUserCredentialsClient.getSubmission(submissionId)
+
+await submissionApiJwtMethodArgClient.getSubmission(submissionId, config.JWT)
 ```
 ### Parameters
 
 Name | Type | Description
 ------------- | ------------- | -------------
  **submissionId** | String | the submission id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -273,21 +357,41 @@ Same to get submission, but only response status and headers information return.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const submissionId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .headSubmission(submissionId)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .headSubmission(submissionId)
   .then(result => console.log(result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .headSubmission(submissionId, config.JWT)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.headSubmission(submissionId)
+await submissionApiM2MClient.headSubmission(submissionId)
+
+await submissionApiUserCredentialsClient.headSubmission(submissionId)
+
+await submissionApiJwtMethodArgClient.headSubmission(submissionId, config.JWT)
 ```
 
 ### Parameters
@@ -295,6 +399,7 @@ await submissionApiClient.headSubmission(submissionId)
 Name | Type | Description
 ------------- | ------------- | -------------
  **submissionId** | String | the submission id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -318,11 +423,17 @@ Fully update submission.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const submissionId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 const reqBody = {
   url: 'https://tc-test-submission-scan.s3.amazonaws.com/good.zip',
@@ -332,13 +443,27 @@ const reqBody = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .updateSubmission(submissionId, reqBody)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .updateSubmission(submissionId, reqBody)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .updateSubmission(submissionId, reqBody, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.updateSubmission(submissionId, reqBody)
+await submissionApiM2MClient.updateSubmission(submissionId, reqBody)
+
+await submissionApiUserCredentialsClient.updateSubmission(submissionId, reqBody)
+
+await submissionApiJwtMethodArgClient.updateSubmission(submissionId, reqBody, config.JWT)
 ```
 
 ### Parameters
@@ -347,6 +472,7 @@ Name | Type | Description
 ------------- | ------------- | -------------
  **submissionId** | String | the submission id
  **reqBody** | [**SubmissionUpdataData**](SubmissionUpdataData.md)| the submission data
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -370,11 +496,17 @@ Partially update submission.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const submissionId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 const reqBody = {
   url: 'https://tc-test-submission-scan.s3.amazonaws.com/good.zip',
@@ -382,13 +514,27 @@ const reqBody = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
   .patchSubmission(submissionId, reqBody)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiUserCredentialsClient
+  .patchSubmission(submissionId, reqBody)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiJwtMethodArgClient
+  .patchSubmission(submissionId, reqBody, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.patchSubmission(submissionId, reqBody)
+await submissionApiM2MClient.patchSubmission(submissionId, reqBody)
+
+await submissionApiUserCredentialsClient.patchSubmission(submissionId, reqBody)
+
+await submissionApiJwtMethodArgClient.patchSubmission(submissionId, reqBody, config.JWT)
 ```
 
 ### Parameters
@@ -397,6 +543,7 @@ Name | Type | Description
 ------------- | ------------- | -------------
  **submissionId** | String | the submission id
  **reqBody** | [**SubmissionUpdataData**](SubmissionUpdataData.md)| the submission data
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -420,21 +567,41 @@ Delete submission by id.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const submissionId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .deleteSubmission(submissionId)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .deleteSubmission(submissionId)
   .then(result => console.log(result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .deleteSubmission(submissionId, config.JWT)
+  .then(result => console.log(result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.deleteSubmission(submissionId)
+await submissionApiM2MClient.deleteSubmission(submissionId)
+
+await submissionApiUserCredentialsClient.deleteSubmission(submissionId)
+
+await submissionApiJwtMethodArgClient.deleteSubmission(submissionId, config.JWT)
 ```
 
 ### Parameters
@@ -442,6 +609,7 @@ await submissionApiClient.deleteSubmission(submissionId)
 Name | Type | Description
 ------------- | ------------- | -------------
  **submissionId** | String | the submission id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -465,21 +633,41 @@ Download submission by id.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const submissionId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .downloadSubmission(submissionId)
+  .then(result => console.log(result.status, result.body))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .downloadSubmission(submissionId)
   .then(result => console.log(result.status, result.body))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .downloadSubmission(submissionId, config.JWT)
+  .then(result => console.log(result.status, result.body))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.downloadSubmission(submissionId)
+await submissionApiM2MClient.downloadSubmission(submissionId)
+
+await submissionApiUserCredentialsClient.downloadSubmission(submissionId)
+
+await submissionApiJwtMethodArgClient.downloadSubmission(submissionId, config.JWT)
 ```
 
 ### Demo
@@ -526,6 +714,7 @@ app.listen(app.get('port'), () => {
 Name | Type | Description
 ------------- | ------------- | -------------
  **submissionId** | String | the submission id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -552,11 +741,17 @@ const path = require('path')
 const fs = require('fs')
 const fileData = fs.readFileSync(path.resolve(__dirname, './data/fileToUpload.zip'))
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const submissionId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 const reqFormData = {
   artifact: {
@@ -567,13 +762,27 @@ const reqFormData = {
 }
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
   .createArtifact(submissionId, reqFormData)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiUserCredentialsClient
+  .createArtifact(submissionId, reqFormData)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiJwtMethodArgClient
+  .createArtifact(submissionId, reqFormData, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.createArtifact(submissionId, reqFormData)
+await submissionApiM2MClient.createArtifact(submissionId, reqFormData)
+
+await submissionApiUserCredentialsClient.createArtifact(submissionId, reqFormData)
+
+await submissionApiJwtMethodArgClient.createArtifact(submissionId, reqFormData, config.JWT)
 ```
 
 ### Demo
@@ -624,6 +833,7 @@ Name | Type | Description
 ------------- | ------------- | -------------
  **submissionId** | String | the submission id
  **reqFormData** | [**ArtifactData**](ArtifactData.md)| the artifact
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -647,21 +857,41 @@ List artifacts of specified submission
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const submissionId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .listArtifacts(submissionId)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .listArtifacts(submissionId)
   .then(result => console.log(result.body, result.status))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .listArtifacts(submissionId, config.JWT)
+  .then(result => console.log(result.body, result.status))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.listArtifacts(submissionId)
+await submissionApiM2MClient.listArtifacts(submissionId)
+
+await submissionApiUserCredentialsClient.listArtifacts(submissionId)
+
+await submissionApiJwtMethodArgClient.listArtifacts(submissionId, config.JWT)
 ```
 
 ### Parameters
@@ -669,6 +899,7 @@ await submissionApiClient.listArtifacts(submissionId)
 Name | Type | Description
 ------------- | ------------- | -------------
  **submissionId** | String | the submission id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
@@ -692,22 +923,42 @@ Download artifact using submission id and artifact id.
 ### Example
 ```javascript
 const submissionApi = require('topcoder-submission-api-wrapper')
-const submissionApiClient = submissionApi(_.pick(config,
+const submissionApiM2MClient = submissionApi(_.pick(config,
       ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
         'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL',
         'AUTH0_PROXY_SERVER_URL']))
 
+const submissionApiUserCredentialsClient = submissionApi(_.pick(config,
+      ['USERNAME', 'PASSWORD', 'TC_AUTHN_URL', 'TC_AUTHZ_URL', 'TC_CLIENT_ID',
+       'TC_CLIENT_V2_CONNECTION', 'SUBMISSION_API_URL']))
+
+const submissionApiJwtMethodArgClient = submissionApi(_.pick(config, 'SUBMISSION_API_URL'))
+
 const submissionId = '8f4e8b6a-0ad2-4ff6-ab19-afeb102ff3b4'
 const artifactId = 'c56a4180-65aa-42ec-a945-5fd21dec0503'
 
 // Promise model
-submissionApiClient
+submissionApiM2MClient
+  .downloadArtifact(submissionId, artifactId)
+  .then(result => console.log(result.status, result.body))
+  .catch(err => console.log(err))
+
+submissionApiUserCredentialsClient
   .downloadArtifact(submissionId, artifactId)
   .then(result => console.log(result.status, result.body))
   .catch(err => console.log(err))
 
+submissionApiJwtMethodArgClient
+  .downloadArtifact(submissionId, artifactId, config.JWT)
+  .then(result => console.log(result.status, result.body))
+  .catch(err => console.log(err))
+
 // Async / await model
-await submissionApiClient.downloadArtifact(submissionId, artifactId)
+await submissionApiM2MClient.downloadArtifact(submissionId, artifactId)
+
+await submissionApiUserCredentialsClient.downloadArtifact(submissionId, artifactId)
+
+await submissionApiJwtMethodArgClient.downloadArtifact(submissionId, artifactId, config.JWT)
 ```
 
 ### Demo
@@ -755,6 +1006,7 @@ Name | Type | Description
 ------------- | ------------- | -------------
  **submissionId** | String | the submission id
  **artifactId** | String | the artifact id
+ **jwt**      | String | the optional json web token
 
 ### Return type
 
diff --git a/index.js b/index.js
index 83e1e20..995f1cd 100644
--- a/index.js
+++ b/index.js
@@ -16,7 +16,7 @@ module.exports = (allConfig) => {
    * SUBMISSION_API_URL: the Topcoder v5 submission api base url.
    * AUTH0_PROXY_SERVER_URL: the auth0 proxy server url, it is optional field.
    */
-  const schema = joi.object().keys({
+  const m2mSchema = joi.object().keys({
     AUTH0_URL: joi.string().uri().trim().required(),
     AUTH0_AUDIENCE: joi.string().uri().trim().required(),
     TOKEN_CACHE_TIME: joi.number().integer().min(0),
@@ -26,14 +26,63 @@ module.exports = (allConfig) => {
     AUTH0_PROXY_SERVER_URL: joi.string()
   })
 
+  /**
+   * The user credentials schema.
+   * USERNAME: the username
+   * PASSWORD: the user password
+   * TC_AUTHN_URL: the tc authn url
+   * TC_AUTHZ_URL: the tc authz url
+   * TC_CLIENT_ID: the tc client id
+   * TC_CLIENT_V2CONNECTION: the tc client v2connection
+   */
+  const credentialsSchema = joi.object().keys({
+    USERNAME: joi.string().trim().required(),
+    PASSWORD: joi.string().trim().required(),
+    TC_AUTHN_URL: joi.string().trim().uri().required(),
+    TC_AUTHZ_URL: joi.string().trim().uri().required(),
+    TC_CLIENT_ID: joi.string().trim().required(),
+    TC_CLIENT_V2CONNECTION: joi.string().trim().required(),
+    SUBMISSION_API_URL: joi.string().uri().trim().required()
+  })
+
+  /**
+   * The JWT method argument config schema
+   */
+  const jwtMethodArgSchema = joi.object().keys({
+    SUBMISSION_API_URL: joi.string().uri().trim().required()
+  }).unknown(false)
+
+  let schema = jwtMethodArgSchema
+  let schemaType = 'JWT Method Argument'
+
   // Pick auth config
-  const config = _.pick(allConfig, ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
-    'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL', 'AUTH0_PROXY_SERVER_URL' ])
+  const config = _.pick(allConfig, [
+    'AUTH0_URL',
+    'AUTH0_AUDIENCE',
+    'TOKEN_CACHE_TIME',
+    'AUTH0_CLIENT_ID',
+    'AUTH0_CLIENT_SECRET',
+    'SUBMISSION_API_URL',
+    'AUTH0_PROXY_SERVER_URL',
+    'USERNAME',
+    'PASSWORD',
+    'TC_AUTHN_URL',
+    'TC_AUTHZ_URL',
+    'TC_CLIENT_ID',
+    'TC_CLIENT_V2CONNECTION'
+  ])
+  if (_.has(config, 'AUTH0_URL')) {
+    schema = m2mSchema
+    schemaType = 'M2M Configuration'
+  } else if (_.has(config, 'USERNAME')) {
+    schema = credentialsSchema
+    schemaType = 'User Credentials Configuration'
+  }
+
   // Validate the arguments
   const result = joi.validate(config, schema)
-
   if (result.error) {
-    throw new Error(result.error.details[0].message)
+    throw new Error(`[${schemaType}] ${result.error.details[0].message}`)
   }
 
   // Export functions
@@ -41,156 +90,156 @@ module.exports = (allConfig) => {
     // -- review type APIs --
 
     // Search review types
-    searchReviewTypes: async (reqQuery) => {
-      return require('./src/ReviewTypesApi').searchReviewTypes(config, reqQuery)
+    searchReviewTypes: (reqQuery, jwt) => {
+      return require('./src/ReviewTypesApi').searchReviewTypes(config, reqQuery, jwt)
     },
     // Head review types
-    headReviewTypes: async (reqQuery) => {
-      return require('./src/ReviewTypesApi').headReviewTypes(config, reqQuery)
+    headReviewTypes: (reqQuery, jwt) => {
+      return require('./src/ReviewTypesApi').headReviewTypes(config, reqQuery, jwt)
     },
     // Create review type
-    createReviewType: async (reqBody) => {
-      return require('./src/ReviewTypesApi').createReviewType(config, reqBody)
+    createReviewType: (reqBody, jwt) => {
+      return require('./src/ReviewTypesApi').createReviewType(config, reqBody, jwt)
     },
     // Get review type
-    getReviewType: async (reviewTypeId) => {
-      return require('./src/ReviewTypesApi').getReviewType(config, reviewTypeId)
+    getReviewType: (reviewTypeId, jwt) => {
+      return require('./src/ReviewTypesApi').getReviewType(config, reviewTypeId, jwt)
     },
     // Head review type
-    headReviewType: async (reviewTypeId) => {
-      return require('./src/ReviewTypesApi').headReviewType(config, reviewTypeId)
+    headReviewType: (reviewTypeId, jwt) => {
+      return require('./src/ReviewTypesApi').headReviewType(config, reviewTypeId, jwt)
     },
     // Fully update review type
-    updateReviewType: async (reviewTypeId, reqBody) => {
-      return require('./src/ReviewTypesApi').updateReviewType(config, reviewTypeId, reqBody)
+    updateReviewType: (reviewTypeId, reqBody, jwt) => {
+      return require('./src/ReviewTypesApi').updateReviewType(config, reviewTypeId, reqBody, jwt)
     },
     // Partially update review type
-    patchReviewType: async (reviewTypeId, reqBody) => {
-      return require('./src/ReviewTypesApi').patchReviewType(config, reviewTypeId, reqBody)
+    patchReviewType: (reviewTypeId, reqBody, jwt) => {
+      return require('./src/ReviewTypesApi').patchReviewType(config, reviewTypeId, reqBody, jwt)
     },
     // Delete review type
-    deleteReviewType: async (reviewTypeId) => {
-      return require('./src/ReviewTypesApi').deleteReviewType(config, reviewTypeId)
+    deleteReviewType: (reviewTypeId, jwt) => {
+      return require('./src/ReviewTypesApi').deleteReviewType(config, reviewTypeId, jwt)
     },
 
     // -- review APIs --
 
     // Search reviews
-    searchReviews: async (reqQuery) => {
-      return require('./src/ReviewsApi').searchReviews(config, reqQuery)
+    searchReviews: (reqQuery, jwt) => {
+      return require('./src/ReviewsApi').searchReviews(config, reqQuery, jwt)
     },
     // Head reviews
-    headReviews: async (reqQuery) => {
-      return require('./src/ReviewsApi').headReviews(config, reqQuery)
+    headReviews: (reqQuery, jwt) => {
+      return require('./src/ReviewsApi').headReviews(config, reqQuery, jwt)
     },
     // Create review
-    createReview: async (reqBody) => {
-      return require('./src/ReviewsApi').createReview(config, reqBody)
+    createReview: (reqBody, jwt) => {
+      return require('./src/ReviewsApi').createReview(config, reqBody, jwt)
     },
     // Get review
-    getReview: async (reviewId) => {
-      return require('./src/ReviewsApi').getReview(config, reviewId)
+    getReview: (reviewId, jwt) => {
+      return require('./src/ReviewsApi').getReview(config, reviewId, jwt)
     },
     // Head review
-    headReview: async (reviewId) => {
-      return require('./src/ReviewsApi').headReview(config, reviewId)
+    headReview: (reviewId, jwt) => {
+      return require('./src/ReviewsApi').headReview(config, reviewId, jwt)
     },
     // Fully update review
-    updateReview: async (reviewId, reqBody) => {
-      return require('./src/ReviewsApi').updateReview(config, reviewId, reqBody)
+    updateReview: (reviewId, reqBody, jwt) => {
+      return require('./src/ReviewsApi').updateReview(config, reviewId, reqBody, jwt)
     },
     // Partially update review
-    patchReview: async (reviewId, reqBody) => {
-      return require('./src/ReviewsApi').patchReview(config, reviewId, reqBody)
+    patchReview: (reviewId, reqBody, jwt) => {
+      return require('./src/ReviewsApi').patchReview(config, reviewId, reqBody, jwt)
     },
     // Delete review
-    deleteReview: async (reviewId) => {
-      return require('./src/ReviewsApi').deleteReview(config, reviewId)
+    deleteReview: (reviewId, jwt) => {
+      return require('./src/ReviewsApi').deleteReview(config, reviewId, jwt)
     },
 
     // -- review summation APIs --
 
     // Search review summations
-    searchReviewSummations: async (reqQuery) => {
-      return require('./src/ReviewSummationsApi').searchReviewSummations(config, reqQuery)
+    searchReviewSummations: (reqQuery, jwt) => {
+      return require('./src/ReviewSummationsApi').searchReviewSummations(config, reqQuery, jwt)
     },
     // Head review summations
-    headReviewSummations: async (reqQuery) => {
-      return require('./src/ReviewSummationsApi').headReviewSummations(config, reqQuery)
+    headReviewSummations: (reqQuery, jwt) => {
+      return require('./src/ReviewSummationsApi').headReviewSummations(config, reqQuery, jwt)
     },
     // Create review summation
-    createReviewSummation: async (reqBody) => {
-      return require('./src/ReviewSummationsApi').createReviewSummation(config, reqBody)
+    createReviewSummation: (reqBody, jwt) => {
+      return require('./src/ReviewSummationsApi').createReviewSummation(config, reqBody, jwt)
     },
     // Get review summation
-    getReviewSummation: async (reviewSummationId) => {
-      return require('./src/ReviewSummationsApi').getReviewSummation(config, reviewSummationId)
+    getReviewSummation: (reviewSummationId, jwt) => {
+      return require('./src/ReviewSummationsApi').getReviewSummation(config, reviewSummationId, jwt)
     },
     // Head review summation
-    headReviewSummation: async (reviewSummationId) => {
-      return require('./src/ReviewSummationsApi').headReviewSummation(config, reviewSummationId)
+    headReviewSummation: (reviewSummationId, jwt) => {
+      return require('./src/ReviewSummationsApi').headReviewSummation(config, reviewSummationId, jwt)
     },
     // Fully update review summation
-    updateReviewSummation: async (reviewSummationId, reqBody) => {
-      return require('./src/ReviewSummationsApi').updateReviewSummation(config, reviewSummationId, reqBody)
+    updateReviewSummation: (reviewSummationId, reqBody, jwt) => {
+      return require('./src/ReviewSummationsApi').updateReviewSummation(config, reviewSummationId, reqBody, jwt)
     },
     // Partially update review summation
-    patchReviewSummation: async (reviewSummationId, reqBody) => {
-      return require('./src/ReviewSummationsApi').patchReviewSummation(config, reviewSummationId, reqBody)
+    patchReviewSummation: (reviewSummationId, reqBody, jwt) => {
+      return require('./src/ReviewSummationsApi').patchReviewSummation(config, reviewSummationId, reqBody, jwt)
     },
     // Delete review summation
-    deleteReviewSummation: async (reviewSummationId) => {
-      return require('./src/ReviewSummationsApi').deleteReviewSummation(config, reviewSummationId)
+    deleteReviewSummation: (reviewSummationId, jwt) => {
+      return require('./src/ReviewSummationsApi').deleteReviewSummation(config, reviewSummationId, jwt)
     },
 
     // -- submission APIs --
     // Search submissions
-    searchSubmissions: async (reqQuery) => {
-      return require('./src/SubmissionsApi').searchSubmissions(config, reqQuery)
+    searchSubmissions: (reqQuery, jwt) => {
+      return require('./src/SubmissionsApi').searchSubmissions(config, reqQuery, jwt)
     },
     // Head submissions
-    headSubmissions: async (reqQuery) => {
-      return require('./src/SubmissionsApi').headSubmissions(config, reqQuery)
+    headSubmissions: (reqQuery, jwt) => {
+      return require('./src/SubmissionsApi').headSubmissions(config, reqQuery, jwt)
     },
     // Create submission
-    createSubmission: async (reqFormData) => {
-      return require('./src/SubmissionsApi').createSubmission(config, reqFormData)
+    createSubmission: (reqFormData, jwt) => {
+      return require('./src/SubmissionsApi').createSubmission(config, reqFormData, jwt)
     },
     // Get submission
-    getSubmission: async (submissionId) => {
-      return require('./src/SubmissionsApi').getSubmission(config, submissionId)
+    getSubmission: (submissionId, jwt) => {
+      return require('./src/SubmissionsApi').getSubmission(config, submissionId, jwt)
     },
     // Head submission
-    headSubmission: async (submissionId) => {
-      return require('./src/SubmissionsApi').headSubmission(config, submissionId)
+    headSubmission: (submissionId, jwt) => {
+      return require('./src/SubmissionsApi').headSubmission(config, submissionId, jwt)
     },
     // Fully update submission
-    updateSubmission: async (submissionId, reqBody) => {
-      return require('./src/SubmissionsApi').updateSubmission(config, submissionId, reqBody)
+    updateSubmission: (submissionId, reqBody, jwt) => {
+      return require('./src/SubmissionsApi').updateSubmission(config, submissionId, reqBody, jwt)
     },
     // Partially update submission
-    patchSubmission: async (submissionId, reqBody) => {
-      return require('./src/SubmissionsApi').patchSubmission(config, submissionId, reqBody)
+    patchSubmission: (submissionId, reqBody, jwt) => {
+      return require('./src/SubmissionsApi').patchSubmission(config, submissionId, reqBody, jwt)
     },
     // Delete review submission
-    deleteSubmission: async (submissionId) => {
-      return require('./src/SubmissionsApi').deleteSubmission(config, submissionId)
+    deleteSubmission: (submissionId, jwt) => {
+      return require('./src/SubmissionsApi').deleteSubmission(config, submissionId, jwt)
     },
     // Download submission
-    downloadSubmission: async (submissionId) => {
-      return require('./src/SubmissionsApi').downloadSubmission(config, submissionId)
+    downloadSubmission: (submissionId, jwt) => {
+      return require('./src/SubmissionsApi').downloadSubmission(config, submissionId, jwt)
     },
     // Create artifact for submission
-    createArtifact: async (submissionId, reqFormData) => {
-      return require('./src/SubmissionsApi').createArtifact(config, submissionId, reqFormData)
+    createArtifact: (submissionId, reqFormData, jwt) => {
+      return require('./src/SubmissionsApi').createArtifact(config, submissionId, reqFormData, jwt)
     },
     // List artifacts of specified submission
-    listArtifacts: async (submissionId) => {
-      return require('./src/SubmissionsApi').listArtifacts(config, submissionId)
+    listArtifacts: (submissionId, jwt) => {
+      return require('./src/SubmissionsApi').listArtifacts(config, submissionId, jwt)
     },
     // Download artifact
-    downloadArtifact: async (submissionId, artifactId) => {
-      return require('./src/SubmissionsApi').downloadArtifact(config, submissionId, artifactId)
+    downloadArtifact: (submissionId, artifactId, jwt) => {
+      return require('./src/SubmissionsApi').downloadArtifact(config, submissionId, artifactId, jwt)
     }
   }
 }
diff --git a/package-lock.json b/package-lock.json
index fc5355c..1b93c42 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2126,9 +2126,9 @@
       "integrity": "sha1-/sfervF+fDoKVeHaBCgD4l2RdF0="
     },
     "lodash": {
-      "version": "4.17.14",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
-      "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw=="
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
     },
     "lodash.flattendeep": {
       "version": "4.4.0",
diff --git a/package.json b/package.json
index 21d5b9d..0e778de 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
   },
   "dependencies": {
     "@hapi/joi": "^15.0.3",
-    "lodash": "^4.17.14",
+    "lodash": "^4.17.15",
     "superagent": "^3.8.3",
     "tc-core-library-js": "appirio-tech/tc-core-library-js.git"
   },
diff --git a/src/ReviewSummationsApi.js b/src/ReviewSummationsApi.js
index d5b1081..fe45c4f 100644
--- a/src/ReviewSummationsApi.js
+++ b/src/ReviewSummationsApi.js
@@ -10,11 +10,12 @@ const helper = require('./common/helper')
  * @param {Object} reqQuery the query object, including page(The page number, default value is 1.),
  *   perPage(The number of items to list per page, default value is 20.), submissionId(the submission id filter),
  *   aggregateScore(the aggregate score filter), scoreCardId(the score card id filter) and isPassing (the passing boolean flag filter)
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise} searched review summations
  */
-const searchReviewSummations = async (config, reqQuery) => {
+const searchReviewSummations = (config, reqQuery, jwt = null) => {
   const url = helper.buildURLwithParams(`${config.SUBMISSION_API_URL}/reviewSummations`, reqQuery)
-  return helper.reqToV5API(config, 'GET', url)
+  return helper.reqToV5API(config, jwt, 'GET', url)
 }
 
 /**
@@ -23,11 +24,12 @@ const searchReviewSummations = async (config, reqQuery) => {
  * @param {Object} reqQuery the query object, including page(The page number, default value is 1.),
  *   perPage(The number of items to list per page, default value is 20.), submissionId(the submission id filter),
  *   aggregateScore(the aggregate score filter), scoreCardId(the score card id filter) and isPassing (the passing boolean flag filter)
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise} searched review summations
  */
-const headReviewSummations = async (config, reqQuery) => {
+const headReviewSummations = (config, reqQuery, jwt = null) => {
   const url = helper.buildURLwithParams(`${config.SUBMISSION_API_URL}/reviewSummations`, reqQuery)
-  return helper.reqToV5API(config, 'HEAD', url)
+  return helper.reqToV5API(config, jwt, 'HEAD', url)
 }
 
 /**
@@ -35,30 +37,33 @@ const headReviewSummations = async (config, reqQuery) => {
  * @param {Object} config Configuration object
  * @param {Object} reqBody the request body object, including submissionId(submission id), aggregateScore(aggregate score),
  *   scoreCardId(scorecard id), isPassing(passing boolean flag) and metadata(related metadata) properties
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise} created review summation
  */
-const createReviewSummation = async (config, reqBody) => {
-  return helper.reqToV5API(config, 'POST', `${config.SUBMISSION_API_URL}/reviewSummations`, reqBody)
+const createReviewSummation = (config, reqBody, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'POST', `${config.SUBMISSION_API_URL}/reviewSummations`, reqBody)
 }
 
 /**
  * Function to get the review summation by id.
  * @param {Object} config Configuration object
  * @param {String} reviewSummationId the review summation id
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const getReviewSummation = async (config, reviewSummationId) => {
-  return helper.reqToV5API(config, 'GET', `${config.SUBMISSION_API_URL}/reviewSummations/${reviewSummationId}`)
+const getReviewSummation = (config, reviewSummationId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'GET', `${config.SUBMISSION_API_URL}/reviewSummations/${reviewSummationId}`)
 }
 
 /**
  * Function to HEAD review summation by id.
  * @param {Object} config Configuration object
  * @param {String} reviewSummationId the review summation id
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const headReviewSummation = async (config, reviewSummationId) => {
-  return helper.reqToV5API(config, 'HEAD', `${config.SUBMISSION_API_URL}/reviewSummations/${reviewSummationId}`)
+const headReviewSummation = (config, reviewSummationId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'HEAD', `${config.SUBMISSION_API_URL}/reviewSummations/${reviewSummationId}`)
 }
 
 /**
@@ -67,10 +72,11 @@ const headReviewSummation = async (config, reviewSummationId) => {
  * @param {String} reviewSummationId the review summation id
  * @param {Object} reqBody the request body object, including submissionId(submission id), aggregateScore(aggregate score),
  *   scoreCardId(scorecard id), isPassing(passing boolean flag) and metadata(related metadata) properties
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise} updated review summation
  */
-const updateReviewSummation = async (config, reviewSummationId, reqBody) => {
-  return helper.reqToV5API(config, 'PUT', `${config.SUBMISSION_API_URL}/reviewSummations/${reviewSummationId}`, reqBody)
+const updateReviewSummation = (config, reviewSummationId, reqBody, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'PUT', `${config.SUBMISSION_API_URL}/reviewSummations/${reviewSummationId}`, reqBody)
 }
 
 /**
@@ -79,20 +85,22 @@ const updateReviewSummation = async (config, reviewSummationId, reqBody) => {
  * @param {String} reviewSummationId the review summation id
  * @param {Object} reqBody the request body object, including submissionId(submission id), aggregateScore(aggregate score),
  *   scoreCardId(scorecard id), isPassing(passing boolean flag) and metadata(related metadata) properties
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise} updated review summation
  */
-const patchReviewSummation = async (config, reviewSummationId, reqBody) => {
-  return helper.reqToV5API(config, 'PATCH', `${config.SUBMISSION_API_URL}/reviewSummations/${reviewSummationId}`, reqBody)
+const patchReviewSummation = (config, reviewSummationId, reqBody, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'PATCH', `${config.SUBMISSION_API_URL}/reviewSummations/${reviewSummationId}`, reqBody)
 }
 
 /**
  * Function to delete review summation by id.
  * @param {Object} config Configuration object
  * @param {String} reviewSummationId the review summation id
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const deleteReviewSummation = async (config, reviewSummationId) => {
-  return helper.reqToV5API(config, 'DELETE', `${config.SUBMISSION_API_URL}/reviewSummations/${reviewSummationId}`)
+const deleteReviewSummation = (config, reviewSummationId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'DELETE', `${config.SUBMISSION_API_URL}/reviewSummations/${reviewSummationId}`)
 }
 
 module.exports = {
diff --git a/src/ReviewTypesApi.js b/src/ReviewTypesApi.js
index b8d178e..45c0517 100644
--- a/src/ReviewTypesApi.js
+++ b/src/ReviewTypesApi.js
@@ -10,11 +10,12 @@ const helper = require('./common/helper')
  * @param {Object} reqQuery the query object, include page(The page number, default value is 1.),
  *   perPage(The number of items to list per page, default value is 20.), name(The name filter for review types.)
  *   and isActive(The active boolean flag filter for review types.)
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const searchReviewTypes = async (config, reqQuery) => {
+const searchReviewTypes = (config, reqQuery, jwt = null) => {
   const url = helper.buildURLwithParams(`${config.SUBMISSION_API_URL}/reviewTypes`, reqQuery)
-  return helper.reqToV5API(config, 'GET', url)
+  return helper.reqToV5API(config, jwt, 'GET', url)
 }
 
 /**
@@ -23,41 +24,45 @@ const searchReviewTypes = async (config, reqQuery) => {
  * @param {Object} reqQuery the query object, include page(The page number, default value is 1.),
  *   perPage(The number of items to list per page, default value is 20.), name(The name filter for review types.)
  *   and isActive(The active boolean flag filter for review types.)
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const headReviewTypes = async (config, reqQuery) => {
+const headReviewTypes = (config, reqQuery, jwt = null) => {
   const url = helper.buildURLwithParams(`${config.SUBMISSION_API_URL}/reviewTypes`, reqQuery)
-  return helper.reqToV5API(config, 'HEAD', url)
+  return helper.reqToV5API(config, jwt, 'HEAD', url)
 }
 
 /**
  * Function to create the review type.
  * @param {Object} config Configuration object
  * @param {Object} reqBody the request body object, include name(review type name) and isActive(active flag) properties
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const createReviewType = async (config, reqBody) => {
-  return helper.reqToV5API(config, 'POST', `${config.SUBMISSION_API_URL}/reviewTypes`, reqBody)
+const createReviewType = (config, reqBody, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'POST', `${config.SUBMISSION_API_URL}/reviewTypes`, reqBody)
 }
 
 /**
  * Function to get the review type by id.
  * @param {Object} config Configuration object
  * @param {String} reviewTypeId the review type id
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const getReviewType = async (config, reviewTypeId) => {
-  return helper.reqToV5API(config, 'GET', `${config.SUBMISSION_API_URL}/reviewTypes/${reviewTypeId}`)
+const getReviewType = (config, reviewTypeId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'GET', `${config.SUBMISSION_API_URL}/reviewTypes/${reviewTypeId}`)
 }
 
 /**
  * Function to HEAD review type by id.
  * @param {Object} config Configuration object
  * @param {String} reviewTypeId the review type id
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const headReviewType = async (config, reviewTypeId) => {
-  return helper.reqToV5API(config, 'HEAD', `${config.SUBMISSION_API_URL}/reviewTypes/${reviewTypeId}`)
+const headReviewType = (config, reviewTypeId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'HEAD', `${config.SUBMISSION_API_URL}/reviewTypes/${reviewTypeId}`)
 }
 
 /**
@@ -65,10 +70,11 @@ const headReviewType = async (config, reviewTypeId) => {
  * @param {Object} config Configuration object
  * @param {String} reviewTypeId the review type id
  * @param {Object} reqBody the request body object, include name(review type name) and isActive(active flag) properties
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const updateReviewType = async (config, reviewTypeId, reqBody) => {
-  return helper.reqToV5API(config, 'PUT', `${config.SUBMISSION_API_URL}/reviewTypes/${reviewTypeId}`, reqBody)
+const updateReviewType = (config, reviewTypeId, reqBody, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'PUT', `${config.SUBMISSION_API_URL}/reviewTypes/${reviewTypeId}`, reqBody)
 }
 
 /**
@@ -76,20 +82,22 @@ const updateReviewType = async (config, reviewTypeId, reqBody) => {
  * @param {Object} config Configuration object
  * @param {String} reviewTypeId the review type id
  * @param {Object} reqBody the request body object, include name(review type name) and isActive(active flag) properties
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const patchReviewType = async (config, reviewTypeId, reqBody) => {
-  return helper.reqToV5API(config, 'PATCH', `${config.SUBMISSION_API_URL}/reviewTypes/${reviewTypeId}`, reqBody)
+const patchReviewType = (config, reviewTypeId, reqBody, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'PATCH', `${config.SUBMISSION_API_URL}/reviewTypes/${reviewTypeId}`, reqBody)
 }
 
 /**
  * Function to delete review type by id.
  * @param {Object} config Configuration object
  * @param {String} reviewTypeId the review type id
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const deleteReviewType = async (config, reviewTypeId) => {
-  return helper.reqToV5API(config, 'DELETE', `${config.SUBMISSION_API_URL}/reviewTypes/${reviewTypeId}`)
+const deleteReviewType = (config, reviewTypeId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'DELETE', `${config.SUBMISSION_API_URL}/reviewTypes/${reviewTypeId}`)
 }
 
 module.exports = {
diff --git a/src/ReviewsApi.js b/src/ReviewsApi.js
index 60a81ee..96f7144 100644
--- a/src/ReviewsApi.js
+++ b/src/ReviewsApi.js
@@ -11,11 +11,12 @@ const helper = require('./common/helper')
  *   perPage(The number of items to list per page, default value is 20.), score(The score filter for reviews.),
  *   typeId(the review type id filter), reviewerId(reviewer id filter), scoreCardId (scorecard id filter)
  *   and submissionId(submission id filter)
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise} searched reviews
  */
-const searchReviews = async (config, reqQuery) => {
+const searchReviews = (config, reqQuery, jwt = null) => {
   const url = helper.buildURLwithParams(`${config.SUBMISSION_API_URL}/reviews`, reqQuery)
-  return helper.reqToV5API(config, 'GET', url)
+  return helper.reqToV5API(config, jwt, 'GET', url)
 }
 
 /**
@@ -25,11 +26,12 @@ const searchReviews = async (config, reqQuery) => {
  *   perPage(The number of items to list per page, default value is 20.), score(The score filter for reviews.),
  *   typeId(the review type id filter), reviewerId(reviewer id filter), scoreCardId (scorecard id filter)
  *   and submissionId(submission id filter)
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise} searched reviews head
  */
-const headReviews = async (config, reqQuery) => {
+const headReviews = (config, reqQuery, jwt = null) => {
   const url = helper.buildURLwithParams(`${config.SUBMISSION_API_URL}/reviews`, reqQuery)
-  return helper.reqToV5API(config, 'HEAD', url)
+  return helper.reqToV5API(config, jwt, 'HEAD', url)
 }
 
 /**
@@ -37,30 +39,33 @@ const headReviews = async (config, reqQuery) => {
  * @param {Object} config Configuration object
  * @param {Object} reqBody the request body object, including score(review score), typeId (review type id),
  *   reviewerId(reviewer id), scoreCardId(scorecard id), submissionId(submission id) and metadata(related metadata) properties
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise} created review
  */
-const createReview = async (config, reqBody) => {
-  return helper.reqToV5API(config, 'POST', `${config.SUBMISSION_API_URL}/reviews`, reqBody)
+const createReview = (config, reqBody, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'POST', `${config.SUBMISSION_API_URL}/reviews`, reqBody)
 }
 
 /**
  * Function to get the review by id.
  * @param {Object} config Configuration object
  * @param {String} reviewId the review id
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const getReview = async (config, reviewId) => {
-  return helper.reqToV5API(config, 'GET', `${config.SUBMISSION_API_URL}/reviews/${reviewId}`)
+const getReview = (config, reviewId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'GET', `${config.SUBMISSION_API_URL}/reviews/${reviewId}`)
 }
 
 /**
  * Function to HEAD review by id.
  * @param {Object} config Configuration object
  * @param {String} reviewId the review id
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const headReview = async (config, reviewId) => {
-  return helper.reqToV5API(config, 'HEAD', `${config.SUBMISSION_API_URL}/reviews/${reviewId}`)
+const headReview = (config, reviewId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'HEAD', `${config.SUBMISSION_API_URL}/reviews/${reviewId}`)
 }
 
 /**
@@ -69,10 +74,11 @@ const headReview = async (config, reviewId) => {
  * @param {String} reviewId the review id
  * @param {Object} reqBody the request body object, including score(review score), typeId (review type id),
  *   reviewerId(reviewer id), scoreCardId(scorecard id), submissionId(submission id) and metadata(related metadata) properties
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise} updated review
  */
-const updateReview = async (config, reviewId, reqBody) => {
-  return helper.reqToV5API(config, 'PUT', `${config.SUBMISSION_API_URL}/reviews/${reviewId}`, reqBody)
+const updateReview = (config, reviewId, reqBody, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'PUT', `${config.SUBMISSION_API_URL}/reviews/${reviewId}`, reqBody)
 }
 
 /**
@@ -81,20 +87,22 @@ const updateReview = async (config, reviewId, reqBody) => {
  * @param {String} reviewId the review id
  * @param {Object} reqBody the request body object, including score(review score), typeId (review type id),
  *   reviewerId(reviewer id), scoreCardId(scorecard id), submissionId(submission id) and metadata(related metadata) properties
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise} updated review
  */
-const patchReview = async (config, reviewId, reqBody) => {
-  return helper.reqToV5API(config, 'PATCH', `${config.SUBMISSION_API_URL}/reviews/${reviewId}`, reqBody)
+const patchReview = (config, reviewId, reqBody, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'PATCH', `${config.SUBMISSION_API_URL}/reviews/${reviewId}`, reqBody)
 }
 
 /**
  * Function to delete review by id.
  * @param {Object} config Configuration object
  * @param {String} reviewId the review id
+ * @param {String} jwt The JWT to authenticate the request
  * @returns {Promise}
  */
-const deleteReview = async (config, reviewId) => {
-  return helper.reqToV5API(config, 'DELETE', `${config.SUBMISSION_API_URL}/reviews/${reviewId}`)
+const deleteReview = (config, reviewId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'DELETE', `${config.SUBMISSION_API_URL}/reviews/${reviewId}`)
 }
 
 module.exports = {
diff --git a/src/SubmissionsApi.js b/src/SubmissionsApi.js
index a12005c..dd8968d 100644
--- a/src/SubmissionsApi.js
+++ b/src/SubmissionsApi.js
@@ -17,9 +17,9 @@ const helper = require('./common/helper')
  *   reviewSummation.isPassing(The review summation is passing flag filter)
  * @returns {Promise} searched submissions
  */
-const searchSubmissions = async (config, reqQuery) => {
+const searchSubmissions = (config, reqQuery, jwt = null) => {
   const url = helper.buildURLwithParams(`${config.SUBMISSION_API_URL}/submissions`, reqQuery)
-  return helper.reqToV5API(config, 'GET', url)
+  return helper.reqToV5API(config, jwt, 'GET', url)
 }
 
 /**
@@ -35,9 +35,9 @@ const searchSubmissions = async (config, reqQuery) => {
  *   reviewSummation.isPassing(The review summation is passing flag filter)
  * @returns {Promise} searched submissions head
  */
-const headSubmissions = async (config, reqQuery) => {
+const headSubmissions = (config, reqQuery, jwt = null) => {
   const url = helper.buildURLwithParams(`${config.SUBMISSION_API_URL}/submissions`, reqQuery)
-  return helper.reqToV5API(config, 'HEAD', url)
+  return helper.reqToV5API(config, jwt, 'HEAD', url)
 }
 
 /**
@@ -50,8 +50,8 @@ const headSubmissions = async (config, reqQuery) => {
  *   submissionPhaseId(the submission phase id)
  * @returns {Promise} created submission
  */
-const createSubmission = async (config, reqFormData) => {
-  return helper.reqToV5APIWithFile(config, `${config.SUBMISSION_API_URL}/submissions`, reqFormData, 'submission')
+const createSubmission = (config, reqFormData, jwt = null) => {
+  return helper.reqToV5APIWithFile(config, jwt, `${config.SUBMISSION_API_URL}/submissions`, reqFormData, 'submission')
 }
 
 /**
@@ -60,8 +60,8 @@ const createSubmission = async (config, reqFormData) => {
  * @param {String} submissionId the submission id
  * @returns {Promise} the submission with given id
  */
-const getSubmission = async (config, submissionId) => {
-  return helper.reqToV5API(config, 'GET', `${config.SUBMISSION_API_URL}/submissions/${submissionId}`)
+const getSubmission = (config, submissionId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'GET', `${config.SUBMISSION_API_URL}/submissions/${submissionId}`)
 }
 
 /**
@@ -70,8 +70,8 @@ const getSubmission = async (config, submissionId) => {
  * @param {String} submissionId the submission id
  * @returns {Promise}
  */
-const headSubmission = async (config, submissionId) => {
-  return helper.reqToV5API(config, 'HEAD', `${config.SUBMISSION_API_URL}/submissions/${submissionId}`)
+const headSubmission = (config, submissionId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'HEAD', `${config.SUBMISSION_API_URL}/submissions/${submissionId}`)
 }
 
 /**
@@ -84,8 +84,8 @@ const headSubmission = async (config, submissionId) => {
  *   submissionPhaseId(the submission phase id)
  * @returns {Promise} updated submission
  */
-const updateSubmission = async (config, submissionId, reqBody) => {
-  return helper.reqToV5API(config, 'PUT', `${config.SUBMISSION_API_URL}/submissions/${submissionId}`, reqBody)
+const updateSubmission = (config, submissionId, reqBody, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'PUT', `${config.SUBMISSION_API_URL}/submissions/${submissionId}`, reqBody)
 }
 
 /**
@@ -98,8 +98,8 @@ const updateSubmission = async (config, submissionId, reqBody) => {
  *   submissionPhaseId(the submission phase id)
  * @returns {Promise} updated submission
  */
-const patchSubmission = async (config, submissionId, reqBody) => {
-  return helper.reqToV5API(config, 'PATCH', `${config.SUBMISSION_API_URL}/submissions/${submissionId}`, reqBody)
+const patchSubmission = (config, submissionId, reqBody, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'PATCH', `${config.SUBMISSION_API_URL}/submissions/${submissionId}`, reqBody)
 }
 
 /**
@@ -108,8 +108,8 @@ const patchSubmission = async (config, submissionId, reqBody) => {
  * @param {String} submissionId the submission id
  * @returns {Promise}
  */
-const deleteSubmission = async (config, submissionId) => {
-  return helper.reqToV5API(config, 'DELETE', `${config.SUBMISSION_API_URL}/submissions/${submissionId}`)
+const deleteSubmission = (config, submissionId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'DELETE', `${config.SUBMISSION_API_URL}/submissions/${submissionId}`)
 }
 
 /**
@@ -118,8 +118,8 @@ const deleteSubmission = async (config, submissionId) => {
  * @param {String} submissionId the submission id
  * @returns {Promise} the submission file content
  */
-const downloadSubmission = async (config, submissionId) => {
-  return helper.reqToV5APIDownload(config, `${config.SUBMISSION_API_URL}/submissions/${submissionId}/download`)
+const downloadSubmission = (config, submissionId, jwt = null) => {
+  return helper.reqToV5APIDownload(config, jwt, `${config.SUBMISSION_API_URL}/submissions/${submissionId}/download`)
 }
 
 /**
@@ -130,8 +130,8 @@ const downloadSubmission = async (config, submissionId) => {
  *   artifact(a File object, artifact.name indicate the file name, submission.data is a Buffer contain the file data)
  * @returns {Promise} the created artifact
  */
-const createArtifact = async (config, submissionId, reqFormData) => {
-  return helper.reqToV5APIWithFile(config, `${config.SUBMISSION_API_URL}/submissions/${submissionId}/artifacts`, reqFormData, 'artifact')
+const createArtifact = (config, submissionId, reqFormData, jwt = null) => {
+  return helper.reqToV5APIWithFile(config, jwt, `${config.SUBMISSION_API_URL}/submissions/${submissionId}/artifacts`, reqFormData, 'artifact')
 }
 
 /**
@@ -140,8 +140,8 @@ const createArtifact = async (config, submissionId, reqFormData) => {
  * @param {String} submissionId the submission id
  * @returns {Promise} the artifacts of submission
  */
-const listArtifacts = async (config, submissionId) => {
-  return helper.reqToV5API(config, 'GET', `${config.SUBMISSION_API_URL}/submissions/${submissionId}/artifacts`)
+const listArtifacts = (config, submissionId, jwt = null) => {
+  return helper.reqToV5API(config, jwt, 'GET', `${config.SUBMISSION_API_URL}/submissions/${submissionId}/artifacts`)
 }
 
 /**
@@ -151,8 +151,8 @@ const listArtifacts = async (config, submissionId) => {
  * @param {String} artifactId the artifact id
  * @returns {Promise} the artifact file content
  */
-const downloadArtifact = async (config, submissionId, artifactId) => {
-  return helper.reqToV5APIDownload(config, `${config.SUBMISSION_API_URL}/submissions/${submissionId}/artifacts/${artifactId}/download`)
+const downloadArtifact = (config, submissionId, artifactId, jwt = null) => {
+  return helper.reqToV5APIDownload(config, jwt, `${config.SUBMISSION_API_URL}/submissions/${submissionId}/artifacts/${artifactId}/download`)
 }
 
 module.exports = {
diff --git a/src/common/constants.js b/src/common/constants.js
new file mode 100644
index 0000000..9189da0
--- /dev/null
+++ b/src/common/constants.js
@@ -0,0 +1,13 @@
+module.exports = Object.freeze({
+  cacheControl: {
+    noCache: 'no-cache'
+  },
+  contentType: {
+    json: 'application/json'
+  },
+  sso: false,
+  scope: 'openid profile offline_access',
+  responseType: 'token',
+  grantType: 'password',
+  device: 'Browser'
+})
diff --git a/src/common/helper.js b/src/common/helper.js
index 1b61723..c8f35c7 100644
--- a/src/common/helper.js
+++ b/src/common/helper.js
@@ -1,6 +1,9 @@
 const m2mAuth = require('tc-core-library-js').auth.m2m
 const request = require('superagent')
 const _ = require('lodash')
+
+const constants = require('./constants')
+
 let m2m = null
 
 /*
@@ -14,67 +17,135 @@ const getM2Mtoken = async (config) => {
   return m2m.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET)
 }
 
+/**
+ * Create token from credentials.
+ *
+ * @param {String} username the TC login username
+ * @param {String} password the TC login password
+ * @returns {String} JWT token that can be used in fetching TC resources.
+ */
+const tokenFromCredentials = async (config) => {
+  let v2Token
+  v2Token = await request
+    .post(config.TC_AUTHN_URL)
+    .send({
+      username: config.USERNAME,
+      password: config.PASSWORD,
+      client_id: config.TC_CLIENT_ID,
+      sso: constants.sso,
+      scope: constants.scope,
+      response_type: constants.responseType,
+      connection: config.TC_CLIENT_V2CONNECTION,
+      grant_type: constants.grantType,
+      device: constants.device
+    })
+    .set('cache-control', constants.cacheControl.noCache)
+    .set('content-type', constants.contentType.json)
+  const token = _.get(await _tokenV3FromV2(config, v2Token.body), 'body.result.content.token')
+  return token
+}
+
+/**
+ * Fetch v3 token.
+ *
+ * @param {Object} v2Token the v2 token
+ * @returns {Object} response that contains v3 token
+ */
+const _tokenV3FromV2 = async (config, v2Token) => {
+  return request
+    .post(config.TC_AUTHZ_URL)
+    .set('cache-control', constants.cacheControl.noCache)
+    .set('authorization', `Bearer ${v2Token['id_token']}`)
+    .set('content-type', constants.contentType.json)
+    .send({
+      param: {
+        externalToken: v2Token['id_token'],
+        refreshToken: _.get(v2Token, 'refresh_token', '')
+      }
+    })
+}
+
+/**
+ * Get authentication token for config
+ * @param {Object} config The token configuration
+ * @param {String} jwt The JWT
+ * @returns {Promise} resolves to token or error if something went wrong
+ */
+const getToken = (config, jwt = null) => {
+  if (_.has(config, 'AUTH0_URL')) {
+    return getM2Mtoken(config)
+  }
+  if (_.has(config, 'USERNAME')) {
+    return tokenFromCredentials(config)
+  }
+  if (jwt !== null) {
+    return Promise.resolve(jwt)
+  }
+  return Promise.reject(new Error('Invalid configuration'))
+}
+
 /**
  * Function to send request to V5 API
  * @param {Object} config Configuration object
+ * @param {String} jwt The JWT
  * @param{String} reqType Type of the request POST / PATCH / PUT / GET / DELETE / HEAD
  * @param(String) path Complete path of the API URL
  * @param{Object} reqBody Body of the request
  * @returns {Promise}
  */
-const reqToV5API = async (config, reqType, path, reqBody) => {
-  return getM2Mtoken(config).then((token) => {
-    // Based on request type perform necessary action
-    switch (reqType) {
-      case 'GET':
-        return request
-          .get(path)
-          .set('Authorization', `Bearer ${token}`)
-          .set('Content-Type', 'application/json')
-      case 'HEAD':
-        return request
-          .head(path)
-          .set('Authorization', `Bearer ${token}`)
-          .set('Content-Type', 'application/json')
-      case 'POST':
-        return request
-          .post(path)
-          .set('Authorization', `Bearer ${token}`)
-          .set('Content-Type', 'application/json')
-          .send(reqBody)
-      case 'PUT':
-        return request
-          .put(path)
-          .set('Authorization', `Bearer ${token}`)
-          .set('Content-Type', 'application/json')
-          .send(reqBody)
-      case 'PATCH':
-        return request
-          .patch(path)
-          .set('Authorization', `Bearer ${token}`)
-          .set('Content-Type', 'application/json')
-          .send(reqBody)
-      case 'DELETE':
-        return request
-          .delete(path)
-          .set('Authorization', `Bearer ${token}`)
-          .set('Content-Type', 'application/json')
-      default:
-        throw new Error('Invalid request type')
-    }
-  })
+const reqToV5API = async (config, jwt, reqType, path, reqBody) => {
+  const token = await getToken(config, jwt)
+  // Based on request type perform necessary action
+  switch (reqType) {
+    case 'GET':
+      return request
+        .get(path)
+        .set('Authorization', `Bearer ${token}`)
+        .set('Content-Type', 'application/json')
+    case 'HEAD':
+      return request
+        .head(path)
+        .set('Authorization', `Bearer ${token}`)
+        .set('Content-Type', 'application/json')
+    case 'POST':
+      return request
+        .post(path)
+        .set('Authorization', `Bearer ${token}`)
+        .set('Content-Type', 'application/json')
+        .send(reqBody)
+    case 'PUT':
+      return request
+        .put(path)
+        .set('Authorization', `Bearer ${token}`)
+        .set('Content-Type', 'application/json')
+        .send(reqBody)
+    case 'PATCH':
+      return request
+        .patch(path)
+        .set('Authorization', `Bearer ${token}`)
+        .set('Content-Type', 'application/json')
+        .send(reqBody)
+    case 'DELETE':
+      return request
+        .delete(path)
+        .set('Authorization', `Bearer ${token}`)
+        .set('Content-Type', 'application/json')
+    default:
+      throw new Error('Invalid request type')
+  }
 }
 
 /**
  * Function to send request to V5 API with file
  * @param {Object} config Configuration object
+ * @param {String} jwt The JWT
  * @param (String) path Complete path of the API URL
  * @param {Object} formData multiple part form data
  * @param {String} the file field name in formData
  * @returns {Promise}
  */
-const reqToV5APIWithFile = async (config, path, formData, fileFieldName) => {
-  const token = await getM2Mtoken(config)
+const reqToV5APIWithFile = async (config, jwt, path, formData, fileFieldName) => {
+  const token = await getToken(config, jwt)
   if (formData[fileFieldName] && formData[fileFieldName].data && formData[fileFieldName].name) {
     return request
       .post(path)
@@ -92,11 +163,12 @@ const reqToV5APIWithFile = async (config, path, formData, fileFieldName) => {
 /**
  * Function to download file using V5 API
  * @param {Object} config Configuration object
+ * @param {String} jwt The JWT
  * @param (String) path Complete path of the API URL
  * @returns {Promise}
  */
-const reqToV5APIDownload = async (config, path) => {
-  const token = await getM2Mtoken(config)
+const reqToV5APIDownload = async (config, jwt, path) => {
+  const token = await getToken(config, jwt)
   return request
     .get(path)
     .set('Authorization', `Bearer ${token}`)
@@ -137,5 +209,6 @@ module.exports = {
   reqToV5API,
   buildURLwithParams,
   reqToV5APIWithFile,
-  reqToV5APIDownload
+  reqToV5APIDownload,
+  getToken
 }
diff --git a/test/ReviewApi.test.js b/test/ReviewApi.test.js
index bcdae67..9574e75 100644
--- a/test/ReviewApi.test.js
+++ b/test/ReviewApi.test.js
@@ -5,823 +5,836 @@
 const _ = require('lodash')
 const should = require('chai').should()
 const config = require('./testConfig')
+const userConfig = require('./userTestConfig')
 const api = require('../index')
+const { makeJwtClient } = require('./common/testHelper.js')
+
+const m2mClient = api(config)
+const m2mFailClient = api(_.assign(_.cloneDeep(config), { 'AUTH0_CLIENT_ID': 'invalid' }))
+const userClient = api(userConfig)
+const userFailClient = api(_.assign(_.cloneDeep(userConfig), { 'PASSWORD': 'invalid' }))
+const jwtClient = makeJwtClient(api(_.pick(userConfig, 'SUBMISSION_API_URL')), userConfig.JWT)
+const jwtFailClient = makeJwtClient(api(_.pick(userConfig, 'SUBMISSION_API_URL')), null)
 
-const client = api(config)
-const failClient = api(_.assign(_.cloneDeep(config), { 'AUTH0_CLIENT_ID': 'invalid' }))
 const notFoundId = 'e0a789ea-6144-4266-bfae-872f9a26e749'
 
-// data got from searched reviews
-let reviewId
-let score
-let typeId
-let reviewerId
-let scoreCardId
-let submissionId
-let metadata
-let typeId2
-let reviewerId2
-let scoreCardId2
-let submissionId2
-
-// review id created in test
-let createdReviewId
-
-describe('Review API Tests', () => {
-  describe('Test search reviews', () => {
-    it(`search reviews no criteria success`, async () => {
-      const res = await client.searchReviews({})
-      should.equal(res.status, 200)
-      should.equal('1', res.header['x-page'])
-      should.equal('20', res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-      for (const item of res.body) {
-        should.exist(item.id)
-        should.exist(item.typeId)
-        should.exist(item.submissionId)
-        should.exist(item.reviewerId)
-        should.exist(item.scoreCardId)
-        should.exist(item.score)
-      }
-
-      // set test data from searched reviews
-      reviewId = res.body[0].id
-      score = res.body[0].score
-      typeId = res.body[0].typeId
-      reviewerId = res.body[0].reviewerId
-      scoreCardId = res.body[0].scoreCardId
-      submissionId = res.body[0].submissionId
-      metadata = res.body[0].metadata || {}
-      for (const item of res.body) {
-        if (!typeId2 || typeId2 === typeId) {
-          typeId2 = item.typeId
-        }
-        if (!reviewerId2 || reviewerId2 === reviewerId) {
-          reviewerId2 = item.reviewerId
-        }
-        if (!scoreCardId2 || scoreCardId2 === scoreCardId) {
-          scoreCardId2 = item.scoreCardId
-        }
-        if (!submissionId2 || submissionId2 === submissionId) {
-          submissionId2 = item.submissionId
-        }
-      }
-    })
+for (const c of [ [ m2mClient, m2mFailClient, 'M2M' ],
+  [ userClient, userFailClient, 'User Credentials' ],
+  [ jwtClient, jwtFailClient, 'JWT argument' ]]) {
+  const [client, failClient, clientName] = c
+
+  // data got from searched reviews
+  let reviewId
+  let score
+  let typeId
+  let reviewerId
+  let scoreCardId
+  let submissionId
+  let metadata
+  let typeId2
+  let reviewerId2
+  let scoreCardId2
+  let submissionId2
+
+  // review id created in test
+  let createdReviewId
+
+  describe(`Review API Tests (${clientName})`, () => {
+    describe('Test search reviews', () => {
+      it(`search reviews no criteria success`, async () => {
+        const res = await client.searchReviews({})
+        should.equal(res.status, 200)
+        should.equal('1', res.header['x-page'])
+        should.equal('20', res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+        for (const item of res.body) {
+          should.exist(item.id)
+          should.exist(item.typeId)
+          should.exist(item.submissionId)
+          should.exist(item.reviewerId)
+          should.exist(item.scoreCardId)
+          should.exist(item.score)
+        }
 
-    it(`search reviews by criteria success`, async () => {
-      const res = await client.searchReviews({
-        page: 1,
-        perPage: 3,
-        score,
-        typeId,
-        reviewerId,
-        scoreCardId,
-        submissionId
-      })
-      should.equal(res.status, 200)
-      should.exist(res.header['x-page'])
-      should.exist(res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-      should.equal(true, res.body.length > 0)
-      for (const item of res.body) {
-        should.exist(item.id)
-        should.equal(item.typeId, typeId)
-        should.equal(item.submissionId, submissionId)
-        should.equal(item.reviewerId, reviewerId)
-        should.equal(item.scoreCardId, scoreCardId)
-        should.equal(item.score, score)
-      }
-    })
+        // set test data from searched reviews
+        reviewId = res.body[0].id
+        score = res.body[0].score
+        typeId = res.body[0].typeId
+        reviewerId = res.body[0].reviewerId
+        scoreCardId = res.body[0].scoreCardId
+        submissionId = res.body[0].submissionId
+        metadata = res.body[0].metadata || {}
+        for (const item of res.body) {
+          if (!typeId2 || typeId2 === typeId) {
+            typeId2 = item.typeId
+          }
+          if (!reviewerId2 || reviewerId2 === reviewerId) {
+            reviewerId2 = item.reviewerId
+          }
+          if (!scoreCardId2 || scoreCardId2 === scoreCardId) {
+            scoreCardId2 = item.scoreCardId
+          }
+          if (!submissionId2 || submissionId2 === submissionId) {
+            submissionId2 = item.submissionId
+          }
+        }
+      })
 
-    it(`failure - search reviews with invalid page`, async () => {
-      try {
-        await client.searchReviews({ page: -1 })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"page" must be larger than or equal to 1')
-      }
-    })
+      it(`search reviews by criteria success`, async () => {
+        const res = await client.searchReviews({
+          page: 1,
+          perPage: 3,
+          score,
+          typeId,
+          reviewerId,
+          scoreCardId,
+          submissionId
+        })
+        should.equal(res.status, 200)
+        should.exist(res.header['x-page'])
+        should.exist(res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+        should.equal(true, res.body.length > 0)
+        for (const item of res.body) {
+          should.exist(item.id)
+          should.equal(item.typeId, typeId)
+          should.equal(item.submissionId, submissionId)
+          should.equal(item.reviewerId, reviewerId)
+          should.equal(item.scoreCardId, scoreCardId)
+          should.equal(item.score, score)
+        }
+      })
 
-    it(`failure - search reviews with invalid perPage`, async () => {
-      try {
-        await client.searchReviews({ perPage: -1 })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"perPage" must be larger than or equal to 1')
-      }
-    })
+      it(`failure - search reviews with invalid page`, async () => {
+        try {
+          await client.searchReviews({ page: -1 })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"page" must be larger than or equal to 1')
+        }
+      })
 
-    it(`failure - search reviews with invalid score`, async () => {
-      try {
-        await client.searchReviews({ score: 'abc' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"score" must be a number')
-      }
-    })
+      it(`failure - search reviews with invalid perPage`, async () => {
+        try {
+          await client.searchReviews({ perPage: -1 })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"perPage" must be larger than or equal to 1')
+        }
+      })
 
-    it(`failure - search reviews with invalid typeId`, async () => {
-      try {
-        await client.searchReviews({ typeId: 'abc' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"typeId" must be a valid GUID')
-      }
-    })
+      it(`failure - search reviews with invalid score`, async () => {
+        try {
+          await client.searchReviews({ score: 'abc' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"score" must be a number')
+        }
+      })
 
-    it(`failure - search reviews with invalid reviewerId`, async () => {
-      try {
-        await client.searchReviews({ reviewerId: 'abc' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"reviewerId" must be a number')
-      }
-    })
+      it(`failure - search reviews with invalid typeId`, async () => {
+        try {
+          await client.searchReviews({ typeId: 'abc' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"typeId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - search reviews with invalid scoreCardId`, async () => {
-      try {
-        await client.searchReviews({ scoreCardId: 'abc' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"scoreCardId" must be a number')
-      }
-    })
+      it(`failure - search reviews with invalid reviewerId`, async () => {
+        try {
+          await client.searchReviews({ reviewerId: 'abc' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"reviewerId" must be a number')
+        }
+      })
 
-    it(`failure - search reviews with invalid submissionId`, async () => {
-      try {
-        await client.searchReviews({ submissionId: 'abc' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
-      }
-    })
+      it(`failure - search reviews with invalid scoreCardId`, async () => {
+        try {
+          await client.searchReviews({ scoreCardId: 'abc' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"scoreCardId" must be a number')
+        }
+      })
 
-    it(`failure - search reviews with invalid m2m credential`, async () => {
-      try {
-        await failClient.searchReviews({})
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+      it(`failure - search reviews with invalid submissionId`, async () => {
+        try {
+          await client.searchReviews({ submissionId: 'abc' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
+        }
+      })
 
-  describe('Test head reviews', () => {
-    it(`head reviews no criteria success`, async () => {
-      const res = await client.headReviews({})
-      should.equal(res.status, 200)
-      should.equal('1', res.header['x-page'])
-      should.equal('20', res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
+      it(`failure - search reviews with invalid credential`, async () => {
+        try {
+          await failClient.searchReviews({})
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`head reviews by criteria success`, async () => {
-      const res = await client.headReviews({
-        page: 1,
-        perPage: 3,
-        score,
-        typeId,
-        reviewerId,
-        scoreCardId,
-        submissionId
-      })
-      should.equal(res.status, 200)
-      should.exist(res.header['x-page'])
-      should.exist(res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-    })
+    describe('Test head reviews', () => {
+      it(`head reviews no criteria success`, async () => {
+        const res = await client.headReviews({})
+        should.equal(res.status, 200)
+        should.equal('1', res.header['x-page'])
+        should.equal('20', res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+      })
 
-    it(`failure - head reviews with invalid page`, async () => {
-      try {
-        await client.headReviews({ page: -1 })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+      it(`head reviews by criteria success`, async () => {
+        const res = await client.headReviews({
+          page: 1,
+          perPage: 3,
+          score,
+          typeId,
+          reviewerId,
+          scoreCardId,
+          submissionId
+        })
+        should.equal(res.status, 200)
+        should.exist(res.header['x-page'])
+        should.exist(res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+      })
 
-    it(`failure - head reviews with invalid perPage`, async () => {
-      try {
-        await client.headReviews({ perPage: -1 })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+      it(`failure - head reviews with invalid page`, async () => {
+        try {
+          await client.headReviews({ page: -1 })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-    it(`failure - head reviews with invalid score`, async () => {
-      try {
-        await client.headReviews({ score: 'abc' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+      it(`failure - head reviews with invalid perPage`, async () => {
+        try {
+          await client.headReviews({ perPage: -1 })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-    it(`failure - head reviews with invalid typeId`, async () => {
-      try {
-        await client.headReviews({ typeId: 'abc' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+      it(`failure - head reviews with invalid score`, async () => {
+        try {
+          await client.headReviews({ score: 'abc' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-    it(`failure - head reviews with invalid reviewerId`, async () => {
-      try {
-        await client.headReviews({ reviewerId: 'abc' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+      it(`failure - head reviews with invalid typeId`, async () => {
+        try {
+          await client.headReviews({ typeId: 'abc' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-    it(`failure - head reviews with invalid scoreCardId`, async () => {
-      try {
-        await client.headReviews({ scoreCardId: 'abc' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+      it(`failure - head reviews with invalid reviewerId`, async () => {
+        try {
+          await client.headReviews({ reviewerId: 'abc' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-    it(`failure - head reviews with invalid submissionId`, async () => {
-      try {
-        await client.headReviews({ submissionId: 'abc' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+      it(`failure - head reviews with invalid scoreCardId`, async () => {
+        try {
+          await client.headReviews({ scoreCardId: 'abc' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-    it(`failure - head reviews with invalid m2m credential`, async () => {
-      try {
-        await failClient.headReviews({})
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+      it(`failure - head reviews with invalid submissionId`, async () => {
+        try {
+          await client.headReviews({ submissionId: 'abc' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-  describe('Test create review', () => {
-    it(`Create review success`, async () => {
-      const res = await client.createReview({
-        score: 88,
-        typeId,
-        reviewerId: reviewerId2,
-        scoreCardId,
-        submissionId: submissionId2,
-        metadata: { abc: 'def' }
-      })
-      createdReviewId = res.body.id
-      should.equal(res.status, 200)
-      should.equal(res.body.score, 88)
-      should.equal(res.body.typeId, typeId)
-      should.equal(res.body.reviewerId, reviewerId2)
-      should.equal(res.body.scoreCardId, scoreCardId)
-      should.equal(res.body.submissionId, submissionId2)
-      should.equal(true, _.isEqual(res.body.metadata, { abc: 'def' }))
+      it(`failure - head reviews with invalid credential`, async () => {
+        try {
+          await failClient.headReviews({})
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`failure - Create review with invalid m2m credential`, async () => {
-      try {
-        await failClient.createReview({
-          score: 100,
+    describe('Test create review', () => {
+      it(`Create review success`, async () => {
+        const res = await client.createReview({
+          score: 88,
           typeId,
-          reviewerId,
+          reviewerId: reviewerId2,
           scoreCardId,
-          submissionId
+          submissionId: submissionId2,
+          metadata: { abc: 'def' }
         })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
+        createdReviewId = res.body.id
+        should.equal(res.status, 200)
+        should.equal(res.body.score, 88)
+        should.equal(res.body.typeId, typeId)
+        should.equal(res.body.reviewerId, reviewerId2)
+        should.equal(res.body.scoreCardId, scoreCardId)
+        should.equal(res.body.submissionId, submissionId2)
+        should.equal(true, _.isEqual(res.body.metadata, { abc: 'def' }))
+      })
 
-    it(`failure - Create review with invalid request body, invalid score`, async () => {
-      try {
-        await client.createReview({
-          score: 'abc',
-          typeId,
-          reviewerId,
-          scoreCardId,
-          submissionId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"score" must be a number')
-      }
-    })
+      it(`failure - Create review with invalid credential`, async () => {
+        try {
+          await failClient.createReview({
+            score: 100,
+            typeId,
+            reviewerId,
+            scoreCardId,
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
 
-    it(`failure - Create review with invalid request body, invalid typeId`, async () => {
-      try {
-        await client.createReview({
-          score: 88,
-          typeId: 'abc',
-          reviewerId,
-          scoreCardId,
-          submissionId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"typeId" must be a valid GUID')
-      }
-    })
+      it(`failure - Create review with invalid request body, invalid score`, async () => {
+        try {
+          await client.createReview({
+            score: 'abc',
+            typeId,
+            reviewerId,
+            scoreCardId,
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"score" must be a number')
+        }
+      })
 
-    it(`failure - Create review with invalid request body, null typeId`, async () => {
-      try {
-        await client.createReview({
-          score: 88,
-          typeId: null,
-          reviewerId,
-          scoreCardId,
-          submissionId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"typeId" must be a string')
-      }
-    })
+      it(`failure - Create review with invalid request body, invalid typeId`, async () => {
+        try {
+          await client.createReview({
+            score: 88,
+            typeId: 'abc',
+            reviewerId,
+            scoreCardId,
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"typeId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - Create review with invalid request body, invalid reviewerId`, async () => {
-      try {
-        await client.createReview({
-          score: 88,
-          typeId,
-          reviewerId: 'abc',
-          scoreCardId,
-          submissionId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"reviewerId" must be a number')
-      }
-    })
+      it(`failure - Create review with invalid request body, null typeId`, async () => {
+        try {
+          await client.createReview({
+            score: 88,
+            typeId: null,
+            reviewerId,
+            scoreCardId,
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"typeId" must be a string')
+        }
+      })
 
-    it(`failure - Create review with invalid request body, invalid scoreCardId`, async () => {
-      try {
-        await client.createReview({
-          score: 88,
-          typeId,
-          reviewerId,
-          scoreCardId: 'abc',
-          submissionId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"scoreCardId" must be a number')
-      }
-    })
+      it(`failure - Create review with invalid request body, invalid reviewerId`, async () => {
+        try {
+          await client.createReview({
+            score: 88,
+            typeId,
+            reviewerId: 'abc',
+            scoreCardId,
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"reviewerId" must be a number')
+        }
+      })
 
-    it(`failure - Create review with invalid request body, invalid submissionId`, async () => {
-      try {
-        await client.createReview({
-          score: 88,
-          typeId,
-          reviewerId,
-          scoreCardId,
-          submissionId: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
-      }
-    })
+      it(`failure - Create review with invalid request body, invalid scoreCardId`, async () => {
+        try {
+          await client.createReview({
+            score: 88,
+            typeId,
+            reviewerId,
+            scoreCardId: 'abc',
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"scoreCardId" must be a number')
+        }
+      })
 
-    it(`failure - Create review with invalid request body, empty submissionId`, async () => {
-      try {
-        await client.createReview({
-          score: 88,
-          typeId,
-          reviewerId,
-          scoreCardId,
-          submissionId: ''
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" is not allowed to be empty')
-      }
-    })
-  })
+      it(`failure - Create review with invalid request body, invalid submissionId`, async () => {
+        try {
+          await client.createReview({
+            score: 88,
+            typeId,
+            reviewerId,
+            scoreCardId,
+            submissionId: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
+        }
+      })
 
-  describe('Test get review by id', () => {
-    it(`Get review by id success`, async () => {
-      const res = await client.getReview(reviewId)
-      should.equal(res.status, 200)
-      should.equal(res.body.id, reviewId)
-      should.equal(res.body.score, score)
-      should.equal(res.body.typeId, typeId)
-      should.equal(res.body.reviewerId, reviewerId)
-      should.equal(res.body.scoreCardId, scoreCardId)
-      should.equal(res.body.submissionId, submissionId)
-      should.equal(true, _.isEqual(res.body.metadata || {}, metadata))
+      it(`failure - Create review with invalid request body, empty submissionId`, async () => {
+        try {
+          await client.createReview({
+            score: 88,
+            typeId,
+            reviewerId,
+            scoreCardId,
+            submissionId: ''
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" is not allowed to be empty')
+        }
+      })
     })
 
-    it(`failure - Get review with invalid m2m credential`, async () => {
-      try {
-        await failClient.getReview(reviewId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
+    describe('Test get review by id', () => {
+      it(`Get review by id success`, async () => {
+        const res = await client.getReview(reviewId)
+        should.equal(res.status, 200)
+        should.equal(res.body.id, reviewId)
+        should.equal(res.body.score, score)
+        should.equal(res.body.typeId, typeId)
+        should.equal(res.body.reviewerId, reviewerId)
+        should.equal(res.body.scoreCardId, scoreCardId)
+        should.equal(res.body.submissionId, submissionId)
+        should.equal(true, _.isEqual(res.body.metadata || {}, metadata))
+      })
 
-    it(`failure - Get review by id not found`, async () => {
-      try {
-        await client.getReview(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Review with ID = ${notFoundId} is not found`)
-      }
-    })
+      it(`failure - Get review with invalid credential`, async () => {
+        try {
+          await failClient.getReview(reviewId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
 
-    it(`failure - Get review by invalid id`, async () => {
-      try {
-        await client.getReview('abc')
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"reviewId" must be a valid GUID')
-      }
-    })
-  })
+      it(`failure - Get review by id not found`, async () => {
+        try {
+          await client.getReview(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Review with ID = ${notFoundId} is not found`)
+        }
+      })
 
-  describe('Test head review by id', () => {
-    it(`Head review by id success`, async () => {
-      const res = await client.headReview(reviewId)
-      should.equal(res.status, 200)
+      it(`failure - Get review by invalid id`, async () => {
+        try {
+          await client.getReview('abc')
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"reviewId" must be a valid GUID')
+        }
+      })
     })
 
-    it(`failure - Head review with invalid m2m credential`, async () => {
-      try {
-        await failClient.headReview(reviewId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
+    describe('Test head review by id', () => {
+      it(`Head review by id success`, async () => {
+        const res = await client.headReview(reviewId)
+        should.equal(res.status, 200)
+      })
 
-    it(`failure - Head review by id not found`, async () => {
-      try {
-        await client.headReview(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-      }
-    })
+      it(`failure - Head review with invalid credential`, async () => {
+        try {
+          await failClient.headReview(reviewId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
 
-    it(`failure - Head review by invalid id`, async () => {
-      try {
-        await client.headReview('abc')
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
-  })
+      it(`failure - Head review by id not found`, async () => {
+        try {
+          await client.headReview(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+        }
+      })
 
-  describe('Test put review by id', () => {
-    it(`Put review by id success`, async () => {
-      const res = await client.updateReview(createdReviewId, {
-        score: 99,
-        typeId: typeId2,
-        reviewerId,
-        scoreCardId: scoreCardId2,
-        submissionId,
-        metadata: { aa: 12 }
-      })
-      should.equal(res.status, 200)
-      should.equal(res.body.id, createdReviewId)
-      should.equal(res.body.score, 99)
-      should.equal(res.body.typeId, typeId2)
-      should.equal(res.body.reviewerId, reviewerId)
-      should.equal(res.body.scoreCardId, scoreCardId2)
-      should.equal(res.body.submissionId, submissionId)
-      should.equal(true, _.isEqual(res.body.metadata, { aa: 12 }))
+      it(`failure - Head review by invalid id`, async () => {
+        try {
+          await client.headReview('abc')
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
     })
 
-    it(`failure - Put review with invalid m2m credential`, async () => {
-      try {
-        await failClient.updateReview(createdReviewId, {
+    describe('Test put review by id', () => {
+      it(`Put review by id success`, async () => {
+        const res = await client.updateReview(createdReviewId, {
           score: 99,
-          typeId,
+          typeId: typeId2,
           reviewerId,
-          scoreCardId,
-          submissionId
+          scoreCardId: scoreCardId2,
+          submissionId,
+          metadata: { aa: 12 }
         })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
+        should.equal(res.status, 200)
+        should.equal(res.body.id, createdReviewId)
+        should.equal(res.body.score, 99)
+        should.equal(res.body.typeId, typeId2)
+        should.equal(res.body.reviewerId, reviewerId)
+        should.equal(res.body.scoreCardId, scoreCardId2)
+        should.equal(res.body.submissionId, submissionId)
+        should.equal(true, _.isEqual(res.body.metadata, { aa: 12 }))
+      })
 
-    it(`failure - Put review by invalid id`, async () => {
-      try {
-        await client.updateReview('abc', {
-          score: 99,
-          typeId,
-          reviewerId,
-          scoreCardId,
-          submissionId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"reviewId" must be a valid GUID')
-      }
-    })
+      it(`failure - Put review with invalid credential`, async () => {
+        try {
+          await failClient.updateReview(createdReviewId, {
+            score: 99,
+            typeId,
+            reviewerId,
+            scoreCardId,
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
 
-    it(`failure - Put review by id with invalid score`, async () => {
-      try {
-        await client.updateReview(createdReviewId, {
-          score: 'abc',
-          typeId,
-          reviewerId,
-          scoreCardId,
-          submissionId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"score" must be a number')
-      }
-    })
+      it(`failure - Put review by invalid id`, async () => {
+        try {
+          await client.updateReview('abc', {
+            score: 99,
+            typeId,
+            reviewerId,
+            scoreCardId,
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"reviewId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - Put review by id with invalid typeId`, async () => {
-      try {
-        await client.updateReview(createdReviewId, {
-          score: 99,
-          typeId: 'abc',
-          reviewerId,
-          scoreCardId,
-          submissionId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"typeId" must be a valid GUID')
-      }
-    })
+      it(`failure - Put review by id with invalid score`, async () => {
+        try {
+          await client.updateReview(createdReviewId, {
+            score: 'abc',
+            typeId,
+            reviewerId,
+            scoreCardId,
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"score" must be a number')
+        }
+      })
 
-    it(`failure - Put review by id with invalid reviewerId`, async () => {
-      try {
-        await client.updateReview(createdReviewId, {
-          score: 99,
-          typeId,
-          reviewerId: 'tt',
-          scoreCardId,
-          submissionId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"reviewerId" must be a number')
-      }
-    })
+      it(`failure - Put review by id with invalid typeId`, async () => {
+        try {
+          await client.updateReview(createdReviewId, {
+            score: 99,
+            typeId: 'abc',
+            reviewerId,
+            scoreCardId,
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"typeId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - Put review by id with invalid scoreCardId`, async () => {
-      try {
-        await client.updateReview(createdReviewId, {
-          score: 99,
-          typeId,
-          reviewerId,
-          scoreCardId: 'rr',
-          submissionId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"scoreCardId" must be a number')
-      }
+      it(`failure - Put review by id with invalid reviewerId`, async () => {
+        try {
+          await client.updateReview(createdReviewId, {
+            score: 99,
+            typeId,
+            reviewerId: 'tt',
+            scoreCardId,
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"reviewerId" must be a number')
+        }
+      })
+
+      it(`failure - Put review by id with invalid scoreCardId`, async () => {
+        try {
+          await client.updateReview(createdReviewId, {
+            score: 99,
+            typeId,
+            reviewerId,
+            scoreCardId: 'rr',
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"scoreCardId" must be a number')
+        }
+      })
+
+      it(`failure - Put review by id with invalid submissionId`, async () => {
+        try {
+          await client.updateReview(createdReviewId, {
+            score: 99,
+            typeId,
+            reviewerId,
+            scoreCardId,
+            submissionId: 'invalid'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
+        }
+      })
+
+      it(`failure - Put review by id not found`, async () => {
+        try {
+          await client.updateReview(notFoundId, {
+            score: 99,
+            typeId,
+            reviewerId,
+            scoreCardId,
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Review with ID = ${notFoundId} is not found`)
+        }
+      })
     })
 
-    it(`failure - Put review by id with invalid submissionId`, async () => {
-      try {
-        await client.updateReview(createdReviewId, {
-          score: 99,
-          typeId,
-          reviewerId,
-          scoreCardId,
-          submissionId: 'invalid'
+    describe('Test patch review by id', () => {
+      it(`Patch review by id success 1`, async () => {
+        const res = await client.patchReview(createdReviewId, {
+          score: 77,
+          reviewerId: reviewerId2,
+          submissionId: submissionId2,
+          metadata: { a: 1, b: 'c' }
         })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
-      }
-    })
+        should.equal(res.status, 200)
+        should.equal(res.body.id, createdReviewId)
+        should.equal(res.body.score, 77)
+        should.equal(res.body.typeId, typeId2)
+        should.equal(res.body.reviewerId, reviewerId2)
+        should.equal(res.body.scoreCardId, scoreCardId2)
+        should.equal(res.body.submissionId, submissionId2)
+        should.equal(true, _.isEqual(res.body.metadata, { a: 1, b: 'c' }))
+      })
 
-    it(`failure - Put review by id not found`, async () => {
-      try {
-        await client.updateReview(notFoundId, {
-          score: 99,
+      it(`Patch review by id success 2`, async () => {
+        const res = await client.patchReview(createdReviewId, {
+          score: 56,
           typeId,
           reviewerId,
           scoreCardId,
-          submissionId
+          submissionId,
+          metadata: { abc: 123 }
         })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Review with ID = ${notFoundId} is not found`)
-      }
-    })
-  })
-
-  describe('Test patch review by id', () => {
-    it(`Patch review by id success 1`, async () => {
-      const res = await client.patchReview(createdReviewId, {
-        score: 77,
-        reviewerId: reviewerId2,
-        submissionId: submissionId2,
-        metadata: { a: 1, b: 'c' }
-      })
-      should.equal(res.status, 200)
-      should.equal(res.body.id, createdReviewId)
-      should.equal(res.body.score, 77)
-      should.equal(res.body.typeId, typeId2)
-      should.equal(res.body.reviewerId, reviewerId2)
-      should.equal(res.body.scoreCardId, scoreCardId2)
-      should.equal(res.body.submissionId, submissionId2)
-      should.equal(true, _.isEqual(res.body.metadata, { a: 1, b: 'c' }))
-    })
-
-    it(`Patch review by id success 2`, async () => {
-      const res = await client.patchReview(createdReviewId, {
-        score: 56,
-        typeId,
-        reviewerId,
-        scoreCardId,
-        submissionId,
-        metadata: { abc: 123 }
-      })
-      should.equal(res.status, 200)
-      should.equal(res.body.id, createdReviewId)
-      should.equal(res.body.score, 56)
-      should.equal(res.body.typeId, typeId)
-      should.equal(res.body.reviewerId, reviewerId)
-      should.equal(res.body.scoreCardId, scoreCardId)
-      should.equal(res.body.submissionId, submissionId)
-      should.equal(true, _.isEqual(res.body.metadata, { abc: 123 }))
-    })
+        should.equal(res.status, 200)
+        should.equal(res.body.id, createdReviewId)
+        should.equal(res.body.score, 56)
+        should.equal(res.body.typeId, typeId)
+        should.equal(res.body.reviewerId, reviewerId)
+        should.equal(res.body.scoreCardId, scoreCardId)
+        should.equal(res.body.submissionId, submissionId)
+        should.equal(true, _.isEqual(res.body.metadata, { abc: 123 }))
+      })
 
-    it(`failure - Patch review with invalid m2m credential`, async () => {
-      try {
-        await failClient.patchReview(createdReviewId, {
-          score: 9
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
+      it(`failure - Patch review with invalid credential`, async () => {
+        try {
+          await failClient.patchReview(createdReviewId, {
+            score: 9
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
 
-    it(`failure - Patch review by invalid id`, async () => {
-      try {
-        await client.patchReview('abc', {
-          score: 9
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"reviewId" must be a valid GUID')
-      }
-    })
+      it(`failure - Patch review by invalid id`, async () => {
+        try {
+          await client.patchReview('abc', {
+            score: 9
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"reviewId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - Patch review by id with invalid score`, async () => {
-      try {
-        await client.patchReview(createdReviewId, {
-          score: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"score" must be a number')
-      }
-    })
+      it(`failure - Patch review by id with invalid score`, async () => {
+        try {
+          await client.patchReview(createdReviewId, {
+            score: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"score" must be a number')
+        }
+      })
 
-    it(`failure - Patch review by id with invalid typeId`, async () => {
-      try {
-        await client.patchReview(createdReviewId, {
-          typeId: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"typeId" must be a valid GUID')
-      }
-    })
+      it(`failure - Patch review by id with invalid typeId`, async () => {
+        try {
+          await client.patchReview(createdReviewId, {
+            typeId: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"typeId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - Patch review by id with invalid reviewerId`, async () => {
-      try {
-        await client.patchReview(createdReviewId, {
-          reviewerId: 'tt'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"reviewerId" must be a number')
-      }
-    })
+      it(`failure - Patch review by id with invalid reviewerId`, async () => {
+        try {
+          await client.patchReview(createdReviewId, {
+            reviewerId: 'tt'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"reviewerId" must be a number')
+        }
+      })
 
-    it(`failure - Patch review by id with invalid scoreCardId`, async () => {
-      try {
-        await client.patchReview(createdReviewId, {
-          scoreCardId: 'rr'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"scoreCardId" must be a number')
-      }
-    })
+      it(`failure - Patch review by id with invalid scoreCardId`, async () => {
+        try {
+          await client.patchReview(createdReviewId, {
+            scoreCardId: 'rr'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"scoreCardId" must be a number')
+        }
+      })
 
-    it(`failure - Patch review by id with invalid submissionId`, async () => {
-      try {
-        await client.patchReview(createdReviewId, {
-          score: 99,
-          typeId,
-          reviewerId,
-          scoreCardId,
-          submissionId: 'invalid'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
-      }
-    })
+      it(`failure - Patch review by id with invalid submissionId`, async () => {
+        try {
+          await client.patchReview(createdReviewId, {
+            score: 99,
+            typeId,
+            reviewerId,
+            scoreCardId,
+            submissionId: 'invalid'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - Patch review by id not found`, async () => {
-      try {
-        await client.patchReview(notFoundId, {
-          score: 99,
-          typeId,
-          reviewerId,
-          scoreCardId,
-          submissionId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Review with ID = ${notFoundId} is not found`)
-      }
+      it(`failure - Patch review by id not found`, async () => {
+        try {
+          await client.patchReview(notFoundId, {
+            score: 99,
+            typeId,
+            reviewerId,
+            scoreCardId,
+            submissionId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Review with ID = ${notFoundId} is not found`)
+        }
+      })
     })
-  })
 
-  describe('Test delete review by id', () => {
-    it(`Delete review by id success`, async () => {
-      const res = await client.deleteReview(createdReviewId)
-      should.equal(res.status, 204)
-    })
+    describe('Test delete review by id', () => {
+      it(`Delete review by id success`, async () => {
+        const res = await client.deleteReview(createdReviewId)
+        should.equal(res.status, 204)
+      })
 
-    it(`failure - Delete review with invalid m2m credential`, async () => {
-      try {
-        await failClient.deleteReview(reviewId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
+      it(`failure - Delete review with invalid credential`, async () => {
+        try {
+          await failClient.deleteReview(reviewId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
 
-    it(`failure - Delete review by id not found`, async () => {
-      try {
-        await client.deleteReview(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Review with ID = ${notFoundId} is not found`)
-      }
-    })
+      it(`failure - Delete review by id not found`, async () => {
+        try {
+          await client.deleteReview(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Review with ID = ${notFoundId} is not found`)
+        }
+      })
 
-    it(`failure - Delete review by invalid id`, async () => {
-      try {
-        await client.deleteReview('abc')
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"reviewId" must be a valid GUID')
-      }
+      it(`failure - Delete review by invalid id`, async () => {
+        try {
+          await client.deleteReview('abc')
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"reviewId" must be a valid GUID')
+        }
+      })
     })
   })
-})
+}
diff --git a/test/ReviewSummationApi.test.js b/test/ReviewSummationApi.test.js
index 7cebe38..8951d78 100644
--- a/test/ReviewSummationApi.test.js
+++ b/test/ReviewSummationApi.test.js
@@ -5,303 +5,292 @@
 const _ = require('lodash')
 const should = require('chai').should()
 const config = require('./testConfig')
+const userConfig = require('./userTestConfig')
 const api = require('../index')
-
-const client = api(config)
-const failClient = api(_.assign(_.cloneDeep(config), { 'AUTH0_CLIENT_ID': 'invalid' }))
+const { makeJwtClient } = require('./common/testHelper.js')
+
+const m2mClient = api(config)
+const m2mFailClient = api(_.assign(_.cloneDeep(config), { 'AUTH0_CLIENT_ID': 'invalid' }))
+const userClient = api(userConfig)
+const userFailClient = api(_.assign(_.cloneDeep(userConfig), { 'PASSWORD': 'invalid' }))
+const jwtClient = makeJwtClient(api(_.pick(userConfig, 'SUBMISSION_API_URL')), userConfig.JWT)
+const jwtFailClient = makeJwtClient(api(_.pick(userConfig, 'SUBMISSION_API_URL')), null)
 const notFoundId = 'ace32387-8b33-47f1-8b01-6578b817a188'
 
-let createdSummationId
-
-let summationId
-let submissionId
-let aggregateScore
-let scoreCardId
-let isPassing
-let metadata
-let submissionId2
-let aggregateScore2
-let scoreCardId2
-let isPassing2
-
-describe('Review Summation API Tests', () => {
-  describe('Test search review summations', () => {
-    it(`search review summations no criteria success`, async () => {
-      const res = await client.searchReviewSummations({})
-      should.equal(res.status, 200)
-      should.equal('1', res.header['x-page'])
-      should.equal('20', res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-      for (const item of res.body) {
-        should.exist(item.id)
-        should.exist(item.submissionId)
-        should.exist(item.aggregateScore)
-        should.exist(item.scoreCardId)
-        should.exist(item.isPassing)
-        should.exist(item.created)
-        should.exist(item.updated)
-        should.exist(item.createdBy)
-        should.exist(item.updatedBy)
-      }
-
-      // set test data from searched reviews
-      summationId = res.body[0].id
-      submissionId = res.body[0].submissionId
-      aggregateScore = res.body[0].aggregateScore
-      scoreCardId = res.body[0].scoreCardId
-      isPassing = res.body[0].isPassing
-      metadata = res.body[0].metadata || {}
-
-      for (const item of res.body) {
-        if (!submissionId2 || submissionId2 === submissionId) {
-          submissionId2 = item.submissionId
-        }
-        if (!aggregateScore2 || aggregateScore2 === aggregateScore) {
-          aggregateScore2 = item.aggregateScore
-        }
-        if (!scoreCardId2 || scoreCardId2 === scoreCardId) {
-          scoreCardId2 = item.scoreCardId
-        }
-        if (!isPassing2 || isPassing2 === isPassing) {
-          isPassing2 = item.isPassing
-        }
-      }
-    })
+for (const c of [ [ m2mClient, m2mFailClient, 'M2M' ],
+  [ userClient, userFailClient, 'User Credentials' ],
+  [ jwtClient, jwtFailClient, 'JWT argument' ]]) {
+  const [client, failClient, clientName] = c
+
+  let createdSummationId
+
+  let summationId
+  let submissionId
+  let aggregateScore
+  let scoreCardId
+  let isPassing
+  let metadata
+  let submissionId2
+  let aggregateScore2
+  let scoreCardId2
+  let isPassing2
+
+  describe(`Review Summation API Tests (${clientName})`, () => {
+    describe('Test search review summations', () => {
+      it(`search review summations no criteria success`, async () => {
+        const res = await client.searchReviewSummations({})
+        should.equal(res.status, 200)
+        should.equal('1', res.header['x-page'])
+        should.equal('20', res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+        for (const item of res.body) {
+          should.exist(item.id)
+          should.exist(item.submissionId)
+          should.exist(item.aggregateScore)
+          should.exist(item.scoreCardId)
+          should.exist(item.isPassing)
+          should.exist(item.created)
+          should.exist(item.updated)
+          should.exist(item.createdBy)
+          should.exist(item.updatedBy)
+        }
 
-    it('search review summations by criteria success', async () => {
-      const res = await client.searchReviewSummations({
-        page: 1,
-        perPage: 3,
-        submissionId,
-        aggregateScore,
-        scoreCardId,
-        isPassing
-      })
-      should.equal(res.status, 200)
-      should.equal('1', res.header['x-page'])
-      should.equal('3', res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-      should.equal(true, res.body.length > 0)
-      for (const item of res.body) {
-        should.exist(item.id)
-        should.equal(item.submissionId, submissionId)
-        should.equal(item.aggregateScore, aggregateScore)
-        should.equal(item.scoreCardId, scoreCardId)
-        should.equal(item.isPassing, isPassing)
-      }
-    })
+        // set test data from searched reviews
+        summationId = res.body[0].id
+        submissionId = res.body[0].submissionId
+        aggregateScore = res.body[0].aggregateScore
+        scoreCardId = res.body[0].scoreCardId
+        isPassing = res.body[0].isPassing
+        metadata = res.body[0].metadata || {}
+
+        for (const item of res.body) {
+          if (!submissionId2 || submissionId2 === submissionId) {
+            submissionId2 = item.submissionId
+          }
+          if (!aggregateScore2 || aggregateScore2 === aggregateScore) {
+            aggregateScore2 = item.aggregateScore
+          }
+          if (!scoreCardId2 || scoreCardId2 === scoreCardId) {
+            scoreCardId2 = item.scoreCardId
+          }
+          if (!isPassing2 || isPassing2 === isPassing) {
+            isPassing2 = item.isPassing
+          }
+        }
+      })
 
-    it('failure - search review summations with invalid page', async () => {
-      try {
-        await client.searchReviewSummations({
-          page: -1
+      it('search review summations by criteria success', async () => {
+        const res = await client.searchReviewSummations({
+          page: 1,
+          perPage: 3,
+          submissionId,
+          aggregateScore,
+          scoreCardId,
+          isPassing
         })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"page" must be larger than or equal to 1')
-      }
-    })
+        should.equal(res.status, 200)
+        should.equal('1', res.header['x-page'])
+        should.equal('3', res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+        should.equal(true, res.body.length > 0)
+        for (const item of res.body) {
+          should.exist(item.id)
+          should.equal(item.submissionId, submissionId)
+          should.equal(item.aggregateScore, aggregateScore)
+          should.equal(item.scoreCardId, scoreCardId)
+          should.equal(item.isPassing, isPassing)
+        }
+      })
 
-    it(`failure - search review summations with invalid perPage`, async () => {
-      try {
-        await client.searchReviewSummations({
-          perPage: -1
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"perPage" must be larger than or equal to 1')
-      }
-    })
+      it('failure - search review summations with invalid page', async () => {
+        try {
+          await client.searchReviewSummations({
+            page: -1
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"page" must be larger than or equal to 1')
+        }
+      })
 
-    it(`failure - search review summations with invalid submissionId`, async () => {
-      try {
-        await client.searchReviewSummations({
-          submissionId: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
-      }
-    })
+      it(`failure - search review summations with invalid perPage`, async () => {
+        try {
+          await client.searchReviewSummations({
+            perPage: -1
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"perPage" must be larger than or equal to 1')
+        }
+      })
 
-    it(`failure - search review summations with invalid aggregateScore`, async () => {
-      try {
-        await client.searchReviewSummations({
-          aggregateScore: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"aggregateScore" must be a number')
-      }
-    })
+      it(`failure - search review summations with invalid submissionId`, async () => {
+        try {
+          await client.searchReviewSummations({
+            submissionId: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - search review summations with invalid scoreCardId`, async () => {
-      try {
-        await client.searchReviewSummations({
-          scoreCardId: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"scoreCardId" must be a number')
-      }
-    })
+      it(`failure - search review summations with invalid aggregateScore`, async () => {
+        try {
+          await client.searchReviewSummations({
+            aggregateScore: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"aggregateScore" must be a number')
+        }
+      })
 
-    it(`failure - search review summations with invalid isPassing`, async () => {
-      try {
-        await client.searchReviewSummations({
-          isPassing: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"isPassing" must be a boolean')
-      }
-    })
+      it(`failure - search review summations with invalid scoreCardId`, async () => {
+        try {
+          await client.searchReviewSummations({
+            scoreCardId: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"scoreCardId" must be a number')
+        }
+      })
 
-    it(`failure - search review summations with invalid m2m credential`, async () => {
-      try {
-        await failClient.searchReviewSummations({})
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+      it(`failure - search review summations with invalid isPassing`, async () => {
+        try {
+          await client.searchReviewSummations({
+            isPassing: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"isPassing" must be a boolean')
+        }
+      })
 
-  describe('Test head review summations', () => {
-    it(`head review summations no criteria success`, async () => {
-      const res = await client.headReviewSummations({})
-      should.equal(res.status, 200)
-      should.equal('1', res.header['x-page'])
-      should.equal('20', res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
+      it(`failure - search review summations with invalid credential`, async () => {
+        try {
+          await failClient.searchReviewSummations({})
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`head review summations by criteria success`, async () => {
-      const res = await client.headReviewSummations({
-        page: 1,
-        perPage: 3,
-        submissionId,
-        aggregateScore,
-        scoreCardId,
-        isPassing
-      })
-      should.equal(res.status, 200)
-      should.equal('1', res.header['x-page'])
-      should.equal('3', res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-    })
+    describe('Test head review summations', () => {
+      it(`head review summations no criteria success`, async () => {
+        const res = await client.headReviewSummations({})
+        should.equal(res.status, 200)
+        should.equal('1', res.header['x-page'])
+        should.equal('20', res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+      })
 
-    it(`failure - head review summations with invalid page`, async () => {
-      try {
-        await client.headReviewSummations({
-          page: -1
+      it(`head review summations by criteria success`, async () => {
+        const res = await client.headReviewSummations({
+          page: 1,
+          perPage: 3,
+          submissionId,
+          aggregateScore,
+          scoreCardId,
+          isPassing
         })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+        should.equal(res.status, 200)
+        should.equal('1', res.header['x-page'])
+        should.equal('3', res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+      })
 
-    it(`failure - head review summations with invalid perPage`, async () => {
-      try {
-        await client.headReviewSummations({
-          perPage: -1
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+      it(`failure - head review summations with invalid page`, async () => {
+        try {
+          await client.headReviewSummations({
+            page: -1
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-    it(`failure - head review summations with invalid submissionId`, async () => {
-      try {
-        await client.headReviewSummations({
-          submissionId: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+      it(`failure - head review summations with invalid perPage`, async () => {
+        try {
+          await client.headReviewSummations({
+            perPage: -1
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-    it(`failure - head review summations with invalid aggregateScore`, async () => {
-      try {
-        await client.headReviewSummations({
-          aggregateScore: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+      it(`failure - head review summations with invalid submissionId`, async () => {
+        try {
+          await client.headReviewSummations({
+            submissionId: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-    it(`failure - head review summations with invalid scoreCardId`, async () => {
-      try {
-        await client.headReviewSummations({
-          scoreCardId: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+      it(`failure - head review summations with invalid aggregateScore`, async () => {
+        try {
+          await client.headReviewSummations({
+            aggregateScore: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-    it(`failure - head review summations with invalid isPassing`, async () => {
-      try {
-        await client.headReviewSummations({
-          isPassing: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
+      it(`failure - head review summations with invalid scoreCardId`, async () => {
+        try {
+          await client.headReviewSummations({
+            scoreCardId: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-    it(`failure - head review summations with invalid m2m credential`, async () => {
-      try {
-        await failClient.headReviewSummations({})
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+      it(`failure - head review summations with invalid isPassing`, async () => {
+        try {
+          await client.headReviewSummations({
+            isPassing: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-  describe('Test create review summation', () => {
-    it(`Create review summation success`, async () => {
-      const res = await client.createReviewSummation({
-        submissionId,
-        aggregateScore,
-        scoreCardId,
-        isPassing,
-        metadata: {
-          abc: 'def'
+      it(`failure - head review summations with invalid credential`, async () => {
+        try {
+          await failClient.headReviewSummations({})
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
         }
       })
-      createdSummationId = res.body.id
-      should.equal(res.status, 200)
-      should.equal(res.body.submissionId, submissionId)
-      should.equal(res.body.aggregateScore, aggregateScore)
-      should.equal(res.body.scoreCardId, scoreCardId)
-      should.equal(res.body.isPassing, isPassing)
-      should.equal(true, _.isEqual(res.body.metadata, {
-        abc: 'def'
-      }))
     })
 
-    it(`failure - Create review summation with invalid m2m credential`, async () => {
-      try {
-        await failClient.createReviewSummation({
+    describe('Test create review summation', () => {
+      it(`Create review summation success`, async () => {
+        const res = await client.createReviewSummation({
           submissionId,
           aggregateScore,
           scoreCardId,
@@ -310,631 +299,654 @@ describe('Review Summation API Tests', () => {
             abc: 'def'
           }
         })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-
-    it(`failure - Create review summation with invalid request body, invalid submissionId`, async () => {
-      try {
-        await client.createReviewSummation({
-          submissionId: 'abc',
-          aggregateScore,
-          scoreCardId,
-          isPassing
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
-      }
-    })
+        createdSummationId = res.body.id
+        should.equal(res.status, 200)
+        should.equal(res.body.submissionId, submissionId)
+        should.equal(res.body.aggregateScore, aggregateScore)
+        should.equal(res.body.scoreCardId, scoreCardId)
+        should.equal(res.body.isPassing, isPassing)
+        should.equal(true, _.isEqual(res.body.metadata, {
+          abc: 'def'
+        }))
+      })
 
-    it(`failure - Create review summation with invalid request body, empty submissionId`, async () => {
-      try {
-        await client.createReviewSummation({
-          submissionId: '',
-          aggregateScore,
-          scoreCardId,
-          isPassing
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" is not allowed to be empty')
-      }
-    })
+      it(`failure - Create review summation with invalid credential`, async () => {
+        try {
+          await failClient.createReviewSummation({
+            submissionId,
+            aggregateScore,
+            scoreCardId,
+            isPassing,
+            metadata: {
+              abc: 'def'
+            }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
 
-    it(`failure - Create review summation with invalid request body, missing submissionId`, async () => {
-      try {
-        await client.createReviewSummation({
-          aggregateScore,
-          scoreCardId,
-          isPassing
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" is required')
-      }
-    })
+      it(`failure - Create review summation with invalid request body, invalid submissionId`, async () => {
+        try {
+          await client.createReviewSummation({
+            submissionId: 'abc',
+            aggregateScore,
+            scoreCardId,
+            isPassing
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - Create review summation with invalid request body, invalid aggregateScore`, async () => {
-      try {
-        await client.createReviewSummation({
-          submissionId,
-          aggregateScore: 'abc',
-          scoreCardId,
-          isPassing
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"aggregateScore" must be a number')
-      }
-    })
+      it(`failure - Create review summation with invalid request body, empty submissionId`, async () => {
+        try {
+          await client.createReviewSummation({
+            submissionId: '',
+            aggregateScore,
+            scoreCardId,
+            isPassing
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" is not allowed to be empty')
+        }
+      })
 
-    it(`failure - Create review summation with invalid request body, missing aggregateScore`, async () => {
-      try {
-        await client.createReviewSummation({
-          submissionId,
-          scoreCardId,
-          isPassing
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"aggregateScore" is required')
-      }
-    })
+      it(`failure - Create review summation with invalid request body, missing submissionId`, async () => {
+        try {
+          await client.createReviewSummation({
+            aggregateScore,
+            scoreCardId,
+            isPassing
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" is required')
+        }
+      })
 
-    it(`failure - Create review summation with invalid request body, invalid scoreCardId`, async () => {
-      try {
-        await client.createReviewSummation({
-          submissionId,
-          aggregateScore,
-          scoreCardId: 'abc',
-          isPassing
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"scoreCardId" must be a number')
-      }
-    })
+      it(`failure - Create review summation with invalid request body, invalid aggregateScore`, async () => {
+        try {
+          await client.createReviewSummation({
+            submissionId,
+            aggregateScore: 'abc',
+            scoreCardId,
+            isPassing
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"aggregateScore" must be a number')
+        }
+      })
 
-    it(`failure - Create review summation with invalid request body, missing scoreCardId`, async () => {
-      try {
-        await client.createReviewSummation({
-          submissionId,
-          aggregateScore,
-          isPassing
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"scoreCardId" is required')
-      }
-    })
+      it(`failure - Create review summation with invalid request body, missing aggregateScore`, async () => {
+        try {
+          await client.createReviewSummation({
+            submissionId,
+            scoreCardId,
+            isPassing
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"aggregateScore" is required')
+        }
+      })
 
-    it(`failure - Create review summation with invalid request body, invalid isPassing`, async () => {
-      try {
-        await client.createReviewSummation({
-          submissionId,
-          aggregateScore,
-          scoreCardId,
-          isPassing: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"isPassing" must be a boolean')
-      }
-    })
+      it(`failure - Create review summation with invalid request body, invalid scoreCardId`, async () => {
+        try {
+          await client.createReviewSummation({
+            submissionId,
+            aggregateScore,
+            scoreCardId: 'abc',
+            isPassing
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"scoreCardId" must be a number')
+        }
+      })
 
-    it(`failure - Create review summation with invalid request body, missing isPassing`, async () => {
-      try {
-        await client.createReviewSummation({
-          submissionId,
-          aggregateScore,
-          scoreCardId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"isPassing" is required')
-      }
-    })
+      it(`failure - Create review summation with invalid request body, missing scoreCardId`, async () => {
+        try {
+          await client.createReviewSummation({
+            submissionId,
+            aggregateScore,
+            isPassing
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"scoreCardId" is required')
+        }
+      })
 
-    it(`failure - Create review summation with invalid request body, invalid metadata`, async () => {
-      try {
-        await client.createReviewSummation({
-          submissionId,
-          aggregateScore,
-          scoreCardId,
-          isPassing,
-          metadata: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"metadata" must be an object')
-      }
-    })
-  })
+      it(`failure - Create review summation with invalid request body, invalid isPassing`, async () => {
+        try {
+          await client.createReviewSummation({
+            submissionId,
+            aggregateScore,
+            scoreCardId,
+            isPassing: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"isPassing" must be a boolean')
+        }
+      })
 
-  describe('Test get review summation by id', () => {
-    it('Get review summation by id success', async () => {
-      const res = await client.getReviewSummation(summationId)
-      should.equal(res.status, 200)
-      should.equal(res.body.id, summationId)
-      should.equal(res.body.submissionId, submissionId)
-      should.equal(res.body.aggregateScore, aggregateScore)
-      should.equal(res.body.scoreCardId, scoreCardId)
-      should.equal(res.body.isPassing, isPassing)
-      should.equal(true, _.isEqual(res.body.metadata || {}, metadata))
-    })
+      it(`failure - Create review summation with invalid request body, missing isPassing`, async () => {
+        try {
+          await client.createReviewSummation({
+            submissionId,
+            aggregateScore,
+            scoreCardId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"isPassing" is required')
+        }
+      })
 
-    it(`failure - Get review summation with invalid m2m credential`, async () => {
-      try {
-        await failClient.getReviewSummation(summationId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
+      it(`failure - Create review summation with invalid request body, invalid metadata`, async () => {
+        try {
+          await client.createReviewSummation({
+            submissionId,
+            aggregateScore,
+            scoreCardId,
+            isPassing,
+            metadata: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"metadata" must be an object')
+        }
+      })
     })
 
-    it(`failure - Get review summation by id not found`, async () => {
-      try {
-        await client.getReviewSummation(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Review summation with ID = ${notFoundId} is not found`)
-      }
-    })
+    describe('Test get review summation by id', () => {
+      it('Get review summation by id success', async () => {
+        const res = await client.getReviewSummation(summationId)
+        should.equal(res.status, 200)
+        should.equal(res.body.id, summationId)
+        should.equal(res.body.submissionId, submissionId)
+        should.equal(res.body.aggregateScore, aggregateScore)
+        should.equal(res.body.scoreCardId, scoreCardId)
+        should.equal(res.body.isPassing, isPassing)
+        should.equal(true, _.isEqual(res.body.metadata || {}, metadata))
+      })
 
-    it(`failure - Get review summation by invalid id`, async () => {
-      try {
-        await client.getReviewSummation('abc')
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"reviewSummationId" must be a valid GUID')
-      }
-    })
-  })
+      it(`failure - Get review summation with invalid credential`, async () => {
+        try {
+          await failClient.getReviewSummation(summationId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
 
-  describe('Test head review summation by id', () => {
-    it(`Head review summation by id success`, async () => {
-      const res = await client.headReviewSummation(summationId)
-      should.equal(res.status, 200)
-    })
+      it(`failure - Get review summation by id not found`, async () => {
+        try {
+          await client.getReviewSummation(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Review summation with ID = ${notFoundId} is not found`)
+        }
+      })
 
-    it(`failure - Head review summation with invalid m2m credential`, async () => {
-      try {
-        await failClient.headReviewSummation(summationId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
+      it(`failure - Get review summation by invalid id`, async () => {
+        try {
+          await client.getReviewSummation('abc')
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"reviewSummationId" must be a valid GUID')
+        }
+      })
     })
 
-    it(`failure - Head review summation by id not found`, async () => {
-      try {
-        await client.headReviewSummation(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-      }
-    })
+    describe('Test head review summation by id', () => {
+      it(`Head review summation by id success`, async () => {
+        const res = await client.headReviewSummation(summationId)
+        should.equal(res.status, 200)
+      })
 
-    it(`failure - Head review summation by invalid id`, async () => {
-      try {
-        await client.headReviewSummation('abc')
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
-  })
+      it(`failure - Head review summation with invalid credential`, async () => {
+        try {
+          await failClient.headReviewSummation(summationId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
 
-  describe('Test put review summation by id', () => {
-    it(`Put review summation by id success`, async () => {
-      const res = await client.updateReviewSummation(createdSummationId, {
-        submissionId: submissionId2,
-        aggregateScore: aggregateScore2,
-        scoreCardId: scoreCardId2,
-        isPassing: isPassing2,
-        metadata: { aa: 12 }
-      })
-      should.equal(res.status, 200)
-      should.equal(res.body.submissionId, submissionId2)
-      should.equal(res.body.aggregateScore, aggregateScore2)
-      should.equal(res.body.scoreCardId, scoreCardId2)
-      should.equal(res.body.isPassing, isPassing2)
-      should.equal(true, _.isEqual(res.body.metadata, { aa: 12 }))
-    })
+      it(`failure - Head review summation by id not found`, async () => {
+        try {
+          await client.headReviewSummation(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+        }
+      })
 
-    it(`failure - Put review summation with invalid m2m credential`, async () => {
-      try {
-        await failClient.updateReviewSummation(createdSummationId, {
-          ubmissionId: submissionId2,
-          aggregateScore: aggregateScore2,
-          scoreCardId: scoreCardId2,
-          isPassing: isPassing2,
-          metadata: { aa: 12 }
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
+      it(`failure - Head review summation by invalid id`, async () => {
+        try {
+          await client.headReviewSummation('abc')
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
     })
 
-    it(`failure - Put review summation by invalid id`, async () => {
-      try {
-        await client.updateReviewSummation('abc', {
+    describe('Test put review summation by id', () => {
+      it(`Put review summation by id success`, async () => {
+        const res = await client.updateReviewSummation(createdSummationId, {
           submissionId: submissionId2,
           aggregateScore: aggregateScore2,
           scoreCardId: scoreCardId2,
           isPassing: isPassing2,
           metadata: { aa: 12 }
         })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"reviewSummationId" must be a valid GUID')
-      }
-    })
+        should.equal(res.status, 200)
+        should.equal(res.body.submissionId, submissionId2)
+        should.equal(res.body.aggregateScore, aggregateScore2)
+        should.equal(res.body.scoreCardId, scoreCardId2)
+        should.equal(res.body.isPassing, isPassing2)
+        should.equal(true, _.isEqual(res.body.metadata, { aa: 12 }))
+      })
 
-    it(`failure - Put review summation by id not found`, async () => {
-      try {
-        await client.updateReviewSummation(notFoundId, {
-          submissionId: submissionId2,
-          aggregateScore: aggregateScore2,
-          scoreCardId: scoreCardId2,
-          isPassing: isPassing2,
-          metadata: { aa: 12 }
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Review summation with ID = ${notFoundId} is not found`)
-      }
-    })
+      it(`failure - Put review summation with invalid credential`, async () => {
+        try {
+          await failClient.updateReviewSummation(createdSummationId, {
+            ubmissionId: submissionId2,
+            aggregateScore: aggregateScore2,
+            scoreCardId: scoreCardId2,
+            isPassing: isPassing2,
+            metadata: { aa: 12 }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
 
-    it(`failure - Put review summation by id with invalid submissionId`, async () => {
-      try {
-        await client.updateReviewSummation(createdSummationId, {
-          submissionId: 'abc',
-          aggregateScore: aggregateScore2,
-          scoreCardId: scoreCardId2,
-          isPassing: isPassing2,
-          metadata: { aa: 12 }
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
-      }
-    })
+      it(`failure - Put review summation by invalid id`, async () => {
+        try {
+          await client.updateReviewSummation('abc', {
+            submissionId: submissionId2,
+            aggregateScore: aggregateScore2,
+            scoreCardId: scoreCardId2,
+            isPassing: isPassing2,
+            metadata: { aa: 12 }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"reviewSummationId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - Put review summation by id with missing submissionId`, async () => {
-      try {
-        await client.updateReviewSummation(createdSummationId, {
-          aggregateScore: aggregateScore2,
-          scoreCardId: scoreCardId2,
-          isPassing: isPassing2,
-          metadata: { aa: 12 }
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" is required')
-      }
-    })
+      it(`failure - Put review summation by id not found`, async () => {
+        try {
+          await client.updateReviewSummation(notFoundId, {
+            submissionId: submissionId2,
+            aggregateScore: aggregateScore2,
+            scoreCardId: scoreCardId2,
+            isPassing: isPassing2,
+            metadata: { aa: 12 }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Review summation with ID = ${notFoundId} is not found`)
+        }
+      })
 
-    it(`failure - Put review summation by id with empty submissionId`, async () => {
-      try {
-        await client.updateReviewSummation(createdSummationId, {
-          submissionId: '',
-          aggregateScore: aggregateScore2,
-          scoreCardId: scoreCardId2,
-          isPassing: isPassing2,
-          metadata: { aa: 12 }
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" is not allowed to be empty')
-      }
-    })
+      it(`failure - Put review summation by id with invalid submissionId`, async () => {
+        try {
+          await client.updateReviewSummation(createdSummationId, {
+            submissionId: 'abc',
+            aggregateScore: aggregateScore2,
+            scoreCardId: scoreCardId2,
+            isPassing: isPassing2,
+            metadata: { aa: 12 }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - Put review summation by id with invalid aggregateScore`, async () => {
-      try {
-        await client.updateReviewSummation(createdSummationId, {
-          submissionId: submissionId2,
-          aggregateScore: 'abc',
-          scoreCardId: scoreCardId2,
-          isPassing: isPassing2,
-          metadata: { aa: 12 }
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"aggregateScore" must be a number')
-      }
-    })
+      it(`failure - Put review summation by id with missing submissionId`, async () => {
+        try {
+          await client.updateReviewSummation(createdSummationId, {
+            aggregateScore: aggregateScore2,
+            scoreCardId: scoreCardId2,
+            isPassing: isPassing2,
+            metadata: { aa: 12 }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" is required')
+        }
+      })
 
-    it(`failure - Put review summation by id with missing aggregateScore`, async () => {
-      try {
-        await client.updateReviewSummation(createdSummationId, {
-          submissionId: submissionId2,
-          scoreCardId: scoreCardId2,
-          isPassing: isPassing2,
-          metadata: { aa: 12 }
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"aggregateScore" is required')
-      }
-    })
+      it(`failure - Put review summation by id with empty submissionId`, async () => {
+        try {
+          await client.updateReviewSummation(createdSummationId, {
+            submissionId: '',
+            aggregateScore: aggregateScore2,
+            scoreCardId: scoreCardId2,
+            isPassing: isPassing2,
+            metadata: { aa: 12 }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" is not allowed to be empty')
+        }
+      })
 
-    it(`failure - Put review summation by id with invalid scoreCardId`, async () => {
-      try {
-        await client.updateReviewSummation(createdSummationId, {
-          submissionId: submissionId2,
-          aggregateScore: aggregateScore2,
-          scoreCardId: 'abc',
-          isPassing: isPassing2,
-          metadata: { aa: 12 }
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"scoreCardId" must be a number')
-      }
-    })
+      it(`failure - Put review summation by id with invalid aggregateScore`, async () => {
+        try {
+          await client.updateReviewSummation(createdSummationId, {
+            submissionId: submissionId2,
+            aggregateScore: 'abc',
+            scoreCardId: scoreCardId2,
+            isPassing: isPassing2,
+            metadata: { aa: 12 }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"aggregateScore" must be a number')
+        }
+      })
 
-    it(`failure - Put review summation by id with missing scoreCardId`, async () => {
-      try {
-        await client.updateReviewSummation(createdSummationId, {
-          submissionId: submissionId2,
-          aggregateScore: aggregateScore2,
-          isPassing: isPassing2,
-          metadata: { aa: 12 }
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"scoreCardId" is required')
-      }
-    })
+      it(`failure - Put review summation by id with missing aggregateScore`, async () => {
+        try {
+          await client.updateReviewSummation(createdSummationId, {
+            submissionId: submissionId2,
+            scoreCardId: scoreCardId2,
+            isPassing: isPassing2,
+            metadata: { aa: 12 }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"aggregateScore" is required')
+        }
+      })
 
-    it(`failure - Put review summation by id with invalid isPassing`, async () => {
-      try {
-        await client.updateReviewSummation(createdSummationId, {
-          submissionId: submissionId2,
-          aggregateScore: aggregateScore2,
-          scoreCardId: scoreCardId2,
-          isPassing: 'abc',
-          metadata: { aa: 12 }
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"isPassing" must be a boolean')
-      }
-    })
+      it(`failure - Put review summation by id with invalid scoreCardId`, async () => {
+        try {
+          await client.updateReviewSummation(createdSummationId, {
+            submissionId: submissionId2,
+            aggregateScore: aggregateScore2,
+            scoreCardId: 'abc',
+            isPassing: isPassing2,
+            metadata: { aa: 12 }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"scoreCardId" must be a number')
+        }
+      })
 
-    it(`failure - Put review summation by id with missing isPassing`, async () => {
-      try {
-        await client.updateReviewSummation(createdSummationId, {
-          submissionId: submissionId2,
-          aggregateScore: aggregateScore2,
-          scoreCardId: scoreCardId2,
-          metadata: { aa: 12 }
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"isPassing" is required')
-      }
-    })
+      it(`failure - Put review summation by id with missing scoreCardId`, async () => {
+        try {
+          await client.updateReviewSummation(createdSummationId, {
+            submissionId: submissionId2,
+            aggregateScore: aggregateScore2,
+            isPassing: isPassing2,
+            metadata: { aa: 12 }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"scoreCardId" is required')
+        }
+      })
 
-    it(`failure - Put review summation by id with invalid metadata`, async () => {
-      try {
-        await client.updateReviewSummation(createdSummationId, {
-          submissionId: submissionId2,
-          aggregateScore: aggregateScore2,
-          scoreCardId: scoreCardId2,
-          isPassing: isPassing2,
-          metadata: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"metadata" must be an object')
-      }
-    })
-  })
+      it(`failure - Put review summation by id with invalid isPassing`, async () => {
+        try {
+          await client.updateReviewSummation(createdSummationId, {
+            submissionId: submissionId2,
+            aggregateScore: aggregateScore2,
+            scoreCardId: scoreCardId2,
+            isPassing: 'abc',
+            metadata: { aa: 12 }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"isPassing" must be a boolean')
+        }
+      })
 
-  describe('Test patch review summation by id', () => {
-    it(`Patch review summation by id success 1`, async () => {
-      const res = await client.patchReviewSummation(createdSummationId, {
-        submissionId,
-        aggregateScore,
-        metadata: { a: 1, b: 'c' }
-      })
-      should.equal(res.status, 200)
-      should.equal(res.body.id, createdSummationId)
-      should.equal(res.body.submissionId, submissionId)
-      should.equal(res.body.aggregateScore, aggregateScore)
-      should.equal(res.body.scoreCardId, scoreCardId2)
-      should.equal(res.body.isPassing, isPassing2)
-      should.equal(true, _.isEqual(res.body.metadata, { a: 1, b: 'c' }))
-    })
+      it(`failure - Put review summation by id with missing isPassing`, async () => {
+        try {
+          await client.updateReviewSummation(createdSummationId, {
+            submissionId: submissionId2,
+            aggregateScore: aggregateScore2,
+            scoreCardId: scoreCardId2,
+            metadata: { aa: 12 }
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"isPassing" is required')
+        }
+      })
 
-    it(`Patch review summation by id success 2`, async () => {
-      const res = await client.patchReviewSummation(createdSummationId, {
-        submissionId: submissionId2,
-        aggregateScore: aggregateScore2,
-        scoreCardId,
-        isPassing,
-        metadata: { abc: 123 }
-      })
-      should.equal(res.status, 200)
-      should.equal(res.body.id, createdSummationId)
-      should.equal(res.body.submissionId, submissionId2)
-      should.equal(res.body.aggregateScore, aggregateScore2)
-      should.equal(res.body.scoreCardId, scoreCardId)
-      should.equal(res.body.isPassing, isPassing)
-      should.equal(true, _.isEqual(res.body.metadata, { abc: 123 }))
+      it(`failure - Put review summation by id with invalid metadata`, async () => {
+        try {
+          await client.updateReviewSummation(createdSummationId, {
+            submissionId: submissionId2,
+            aggregateScore: aggregateScore2,
+            scoreCardId: scoreCardId2,
+            isPassing: isPassing2,
+            metadata: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"metadata" must be an object')
+        }
+      })
     })
 
-    it(`failure - Patch review summation with invalid m2m credential`, async () => {
-      try {
-        await failClient.patchReviewSummation(createdSummationId, {
-          aggregateScore: 90.5
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
+    describe('Test patch review summation by id', () => {
+      it(`Patch review summation by id success 1`, async () => {
+        const res = await client.patchReviewSummation(createdSummationId, {
+          submissionId,
+          aggregateScore,
+          metadata: { a: 1, b: 'c' }
+        })
+        should.equal(res.status, 200)
+        should.equal(res.body.id, createdSummationId)
+        should.equal(res.body.submissionId, submissionId)
+        should.equal(res.body.aggregateScore, aggregateScore)
+        should.equal(res.body.scoreCardId, scoreCardId2)
+        should.equal(res.body.isPassing, isPassing2)
+        should.equal(true, _.isEqual(res.body.metadata, { a: 1, b: 'c' }))
+      })
 
-    it(`failure - Patch review summation by invalid id`, async () => {
-      try {
-        await client.patchReviewSummation('abc', {
-          aggregateScore: 90.5
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"reviewSummationId" must be a valid GUID')
-      }
-    })
+      it(`Patch review summation by id success 2`, async () => {
+        const res = await client.patchReviewSummation(createdSummationId, {
+          submissionId: submissionId2,
+          aggregateScore: aggregateScore2,
+          scoreCardId,
+          isPassing,
+          metadata: { abc: 123 }
+        })
+        should.equal(res.status, 200)
+        should.equal(res.body.id, createdSummationId)
+        should.equal(res.body.submissionId, submissionId2)
+        should.equal(res.body.aggregateScore, aggregateScore2)
+        should.equal(res.body.scoreCardId, scoreCardId)
+        should.equal(res.body.isPassing, isPassing)
+        should.equal(true, _.isEqual(res.body.metadata, { abc: 123 }))
+      })
 
-    it(`failure - Patch review summation by id not found`, async () => {
-      try {
-        await client.patchReviewSummation(notFoundId, {
-          aggregateScore: 90.5
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Review summation with ID = ${notFoundId} is not found`)
-      }
-    })
+      it(`failure - Patch review summation with invalid credential`, async () => {
+        try {
+          await failClient.patchReviewSummation(createdSummationId, {
+            aggregateScore: 90.5
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
 
-    it(`failure - Patch review summation by id with invalid submissionId`, async () => {
-      try {
-        await client.patchReviewSummation(createdSummationId, {
-          submissionId: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
-      }
-    })
+      it(`failure - Patch review summation by invalid id`, async () => {
+        try {
+          await client.patchReviewSummation('abc', {
+            aggregateScore: 90.5
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"reviewSummationId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - Patch review summation by id with empty submissionId`, async () => {
-      try {
-        await client.patchReviewSummation(createdSummationId, {
-          submissionId: ''
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"submissionId" is not allowed to be empty')
-      }
-    })
+      it(`failure - Patch review summation by id not found`, async () => {
+        try {
+          await client.patchReviewSummation(notFoundId, {
+            aggregateScore: 90.5
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Review summation with ID = ${notFoundId} is not found`)
+        }
+      })
 
-    it(`failure - Patch review summation by id with invalid aggregateScore`, async () => {
-      try {
-        await client.patchReviewSummation(createdSummationId, {
-          aggregateScore: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"aggregateScore" must be a number')
-      }
-    })
+      it(`failure - Patch review summation by id with invalid submissionId`, async () => {
+        try {
+          await client.patchReviewSummation(createdSummationId, {
+            submissionId: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" must be a valid GUID')
+        }
+      })
 
-    it(`failure - Patch review summation by id with invalid scoreCardId`, async () => {
-      try {
-        await client.patchReviewSummation(createdSummationId, {
-          scoreCardId: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"scoreCardId" must be a number')
-      }
-    })
+      it(`failure - Patch review summation by id with empty submissionId`, async () => {
+        try {
+          await client.patchReviewSummation(createdSummationId, {
+            submissionId: ''
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"submissionId" is not allowed to be empty')
+        }
+      })
 
-    it(`failure - Patch review summation by id with invalid isPassing`, async () => {
-      try {
-        await client.patchReviewSummation(createdSummationId, {
-          isPassing: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"isPassing" must be a boolean')
-      }
-    })
+      it(`failure - Patch review summation by id with invalid aggregateScore`, async () => {
+        try {
+          await client.patchReviewSummation(createdSummationId, {
+            aggregateScore: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"aggregateScore" must be a number')
+        }
+      })
 
-    it(`failure - Patch review summation by id with invalid metadata`, async () => {
-      try {
-        await client.patchReviewSummation(createdSummationId, {
-          metadata: 'abc'
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"metadata" must be an object')
-      }
-    })
-  })
+      it(`failure - Patch review summation by id with invalid scoreCardId`, async () => {
+        try {
+          await client.patchReviewSummation(createdSummationId, {
+            scoreCardId: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"scoreCardId" must be a number')
+        }
+      })
 
-  describe('Test delete review summation by id', () => {
-    it(`Delete review summation by id success`, async () => {
-      const res = await client.deleteReviewSummation(createdSummationId)
-      should.equal(res.status, 204)
-    })
+      it(`failure - Patch review summation by id with invalid isPassing`, async () => {
+        try {
+          await client.patchReviewSummation(createdSummationId, {
+            isPassing: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"isPassing" must be a boolean')
+        }
+      })
 
-    it(`failure - Delete review summation with invalid m2m credential`, async () => {
-      try {
-        await failClient.deleteReviewSummation(summationId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
+      it(`failure - Patch review summation by id with invalid metadata`, async () => {
+        try {
+          await client.patchReviewSummation(createdSummationId, {
+            metadata: 'abc'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"metadata" must be an object')
+        }
+      })
     })
 
-    it(`failure - Delete review summation by id not found`, async () => {
-      try {
-        await client.deleteReviewSummation(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Review summation with ID = ${notFoundId} is not found`)
-      }
-    })
+    describe('Test delete review summation by id', () => {
+      it(`Delete review summation by id success`, async () => {
+        const res = await client.deleteReviewSummation(createdSummationId)
+        should.equal(res.status, 204)
+      })
+
+      it(`failure - Delete review summation with invalid credential`, async () => {
+        try {
+          await failClient.deleteReviewSummation(summationId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
 
-    it(`failure - Delete review summation by invalid id`, async () => {
-      try {
-        await client.deleteReviewSummation('abc')
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"reviewSummationId" must be a valid GUID')
-      }
+      it(`failure - Delete review summation by id not found`, async () => {
+        try {
+          await client.deleteReviewSummation(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Review summation with ID = ${notFoundId} is not found`)
+        }
+      })
+
+      it(`failure - Delete review summation by invalid id`, async () => {
+        try {
+          await client.deleteReviewSummation('abc')
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"reviewSummationId" must be a valid GUID')
+        }
+      })
     })
   })
-})
+}
diff --git a/test/ReviewTypeApi.test.js b/test/ReviewTypeApi.test.js
index c71d758..b9b8ebe 100644
--- a/test/ReviewTypeApi.test.js
+++ b/test/ReviewTypeApi.test.js
@@ -5,313 +5,326 @@
 const _ = require('lodash')
 const should = require('chai').should()
 const config = require('./testConfig')
+const userConfig = require('./userTestConfig')
 const api = require('../index')
+const { makeJwtClient } = require('./common/testHelper.js')
 
-const client = api(config)
-const failClient = api(_.assign(_.cloneDeep(config), { 'AUTH0_CLIENT_ID': 'invalid' }))
-let reviewTypeId
-const notFoundId = 'e0a789ea-6144-4266-bfae-872f9a26e749'
-
-describe('Review Type API Tests', () => {
-  describe('Test search review types', () => {
-    it(`search review types by criteria success`, async () => {
-      const res = await client.searchReviewTypes({ page: 1, perPage: 3, name: 'Iterative Review', isActive: true })
-      should.equal(res.status, 200)
-      should.exist(res.header['x-page'])
-      should.exist(res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-      for (let i = 0; i < 3; i++) {
-        should.equal('Iterative Review', res.body[i].name)
-        should.exist(res.body[i].id)
-        should.equal(true, res.body[i].isActive)
-      }
-    })
-
-    it(`search review types no criteria success`, async () => {
-      const res = await client.searchReviewTypes({})
-      should.equal(res.status, 200)
-      should.equal('1', res.header['x-page'])
-      should.equal('20', res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-      for (let i = 0; i < 20; i++) {
-        should.exist(res.body[i].name)
-        should.exist(res.body[i].id)
-        should.exist(res.body[i].isActive)
-      }
-    })
-
-    it(`failure - search review types with invalid criteria`, async () => {
-      try {
-        await client.searchReviewTypes({ isActive: 'invalid' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"isActive" must be a boolean')
-      }
-    })
-
-    it(`failure - search review types with invalid m2m credential`, async () => {
-      try {
-        await failClient.searchReviewTypes({})
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
-
-  describe('Test head review types', () => {
-    it(`Head review types by criteria success`, async () => {
-      const res = await client.headReviewTypes({ page: 1, perPage: 3, name: 'Iterative Review', isActive: true })
-      should.equal(res.status, 200)
-      should.exist(res.header['x-page'])
-      should.exist(res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-    })
-
-    it(`Head review types no criteria success`, async () => {
-      const res = await client.headReviewTypes({})
-      should.equal(res.status, 200)
-      should.equal('1', res.header['x-page'])
-      should.equal('20', res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-    })
-
-    it(`failure - head review types with invalid criteria`, async () => {
-      try {
-        await client.headReviewTypes({ isActive: 'invalid' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
-    })
-
-    it(`failure - head review types with invalid m2m credential`, async () => {
-      try {
-        await failClient.headReviewTypes({})
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
-
-  describe('Test create review type', () => {
-    it(`Create review type success`, async () => {
-      const res = await client.createReviewType({ name: 'test-for-create', isActive: true })
-      reviewTypeId = res.body.id
-      should.equal(res.body.name, 'test-for-create')
-      should.equal(res.body.isActive, true)
-    })
-
-    it(`failure - Create review with invalid m2m credential`, async () => {
-      try {
-        await failClient.createReviewType({ name: 'test-for-create', isActive: true })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-
-    it(`failure - Create review type with invalid request body, name is wrong`, async () => {
-      try {
-        await client.createReviewType({ name: 123, isActive: true })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `"name" must be a string`)
-      }
-    })
-
-    it(`failure - Create review type with invalid request body, name is missing`, async () => {
-      try {
-        await client.createReviewType({ isActive: true })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `"name" is required`)
-      }
-    })
+const m2mClient = api(config)
+const m2mFailClient = api(_.assign(_.cloneDeep(config), { 'AUTH0_CLIENT_ID': 'invalid' }))
+const userClient = api(userConfig)
+const userFailClient = api(_.assign(_.cloneDeep(userConfig), { 'PASSWORD': 'invalid' }))
+const jwtClient = makeJwtClient(api(_.pick(userConfig, 'SUBMISSION_API_URL')), userConfig.JWT)
+const jwtFailClient = makeJwtClient(api(_.pick(userConfig, 'SUBMISSION_API_URL')), null)
 
-    it(`failure - Create review type with invalid request body, isActive is wrong`, async () => {
-      try {
-        await client.createReviewType({ name: 'test-for-create', isActive: 123 })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `"isActive" must be a boolean`)
-      }
-    })
-
-    it(`failure - Create review type with invalid request body, isActive is missing`, async () => {
-      try {
-        await client.createReviewType({ name: 'test-for-create' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `"isActive" is required`)
-      }
-    })
-  })
-
-  describe('Test get review type by id', () => {
-    it(`Get review type by id success`, async () => {
-      const res = await client.getReviewType(reviewTypeId)
-      should.exist(res.body.id)
-      should.equal(res.body.name, 'test-for-create')
-      should.equal(res.body.isActive, true)
-    })
-
-    it(`failure - Get review type with invalid m2m credential`, async () => {
-      try {
-        await failClient.getReviewType(reviewTypeId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-
-    it(`failure - Get review type by id not found`, async () => {
-      try {
-        await client.getReviewType(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Review type with ID = ${notFoundId} is not found`)
-      }
-    })
-  })
-
-  describe('Test head review type by id', () => {
-    it(`Head review type by id success`, async () => {
-      const res = await client.headReviewType(reviewTypeId)
-      should.equal(res.status, 200)
-    })
-
-    it(`failure - Head review type with invalid m2m credential`, async () => {
-      try {
-        await failClient.headReviewType(reviewTypeId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-
-    it(`failure - Head review type by id not found`, async () => {
-      try {
-        await client.headReviewType(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-      }
-    })
-  })
-
-  describe('Test put review type by id', () => {
-    it(`Put review type by id success`, async () => {
-      const res = await client.updateReviewType(reviewTypeId, { name: 'test-for-put', isActive: false })
-      should.equal(res.status, 200)
-      should.exist(res.body.id)
-      should.equal(res.body.name, 'test-for-put')
-      should.equal(res.body.isActive, false)
-    })
-
-    it(`failure - Put review type with invalid m2m credential`, async () => {
-      try {
-        await failClient.updateReviewType(reviewTypeId, { name: 'test-for-put', isActive: false })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-
-    it(`failure - Put review type by id with invalid request body`, async () => {
-      try {
-        await client.updateReviewType(reviewTypeId, { name: 123, isActive: true })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `"name" must be a string`)
-      }
-    })
+const notFoundId = 'e0a789ea-6144-4266-bfae-872f9a26e749'
 
-    it(`failure - Put review type by id not found`, async () => {
-      try {
-        await client.updateReviewType(notFoundId, { name: 'test-for-put', isActive: false })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Review type with ID = ${notFoundId} is not found`)
-      }
+for (const c of [ [ m2mClient, m2mFailClient, 'M2M' ],
+  [ userClient, userFailClient, 'User Credentials' ],
+  [ jwtClient, jwtFailClient, 'JWT argument' ]]) {
+  const [client, failClient, clientName] = c
+  let reviewTypeId
+
+  describe(`Review Type API Tests (${clientName})`, () => {
+    describe('Test search review types', () => {
+      it(`search review types by criteria success`, async () => {
+        const res = await client.searchReviewTypes({ page: 1, perPage: 3, name: 'Iterative Review', isActive: true })
+        should.equal(res.status, 200)
+        should.exist(res.header['x-page'])
+        should.exist(res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+        for (let i = 0; i < 3; i++) {
+          should.equal('Iterative Review', res.body[i].name)
+          should.exist(res.body[i].id)
+          should.equal(true, res.body[i].isActive)
+        }
+      })
+
+      it(`search review types no criteria success`, async () => {
+        const res = await client.searchReviewTypes({})
+        should.equal(res.status, 200)
+        should.equal('1', res.header['x-page'])
+        should.equal('20', res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+        for (let i = 0; i < 20; i++) {
+          should.exist(res.body[i].name)
+          should.exist(res.body[i].id)
+          should.exist(res.body[i].isActive)
+        }
+      })
+
+      it(`failure - search review types with invalid criteria`, async () => {
+        try {
+          await client.searchReviewTypes({ isActive: 'invalid' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"isActive" must be a boolean')
+        }
+      })
+
+      it(`failure - search review types with invalid credential`, async () => {
+        try {
+          await failClient.searchReviewTypes({})
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
-  })
 
-  describe('Test patch review type by id', () => {
-    it(`Patch review type by id success`, async () => {
-      const res = await client.patchReviewType(reviewTypeId, { name: 'test-for-patch' })
-      should.equal(res.status, 200)
-      should.exist(res.body.id)
-      should.equal(res.body.name, 'test-for-patch')
-      should.equal(res.body.isActive, false)
+    describe('Test head review types', () => {
+      it(`Head review types by criteria success`, async () => {
+        const res = await client.headReviewTypes({ page: 1, perPage: 3, name: 'Iterative Review', isActive: true })
+        should.equal(res.status, 200)
+        should.exist(res.header['x-page'])
+        should.exist(res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+      })
+
+      it(`Head review types no criteria success`, async () => {
+        const res = await client.headReviewTypes({})
+        should.equal(res.status, 200)
+        should.equal('1', res.header['x-page'])
+        should.equal('20', res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+      })
+
+      it(`failure - head review types with invalid criteria`, async () => {
+        try {
+          await client.headReviewTypes({ isActive: 'invalid' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
+
+      it(`failure - head review types with invalid credential`, async () => {
+        try {
+          await failClient.headReviewTypes({})
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`failure - Patch review type with invalid m2m credential`, async () => {
-      try {
-        await failClient.patchReviewType(reviewTypeId, { name: 'test-for-patch' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
+    describe('Test create review type', () => {
+      it(`Create review type success`, async () => {
+        const res = await client.createReviewType({ name: 'test-for-create', isActive: true })
+        reviewTypeId = res.body.id
+        should.equal(res.body.name, 'test-for-create')
+        should.equal(res.body.isActive, true)
+      })
+
+      it(`failure - Create review with invalid credential`, async () => {
+        try {
+          await failClient.createReviewType({ name: 'test-for-create', isActive: true })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
+
+      it(`failure - Create review type with invalid request body, name is wrong`, async () => {
+        try {
+          await client.createReviewType({ name: 123, isActive: true })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `"name" must be a string`)
+        }
+      })
+
+      it(`failure - Create review type with invalid request body, name is missing`, async () => {
+        try {
+          await client.createReviewType({ isActive: true })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `"name" is required`)
+        }
+      })
+
+      it(`failure - Create review type with invalid request body, isActive is wrong`, async () => {
+        try {
+          await client.createReviewType({ name: 'test-for-create', isActive: 123 })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `"isActive" must be a boolean`)
+        }
+      })
+
+      it(`failure - Create review type with invalid request body, isActive is missing`, async () => {
+        try {
+          await client.createReviewType({ name: 'test-for-create' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `"isActive" is required`)
+        }
+      })
     })
 
-    it(`failure - Patch review type by id with invalid request body`, async () => {
-      try {
-        await client.patchReviewType(reviewTypeId, { name: 123 })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `"name" must be a string`)
-      }
+    describe('Test get review type by id', () => {
+      it(`Get review type by id success`, async () => {
+        const res = await client.getReviewType(reviewTypeId)
+        should.exist(res.body.id)
+        should.equal(res.body.name, 'test-for-create')
+        should.equal(res.body.isActive, true)
+      })
+
+      it(`failure - Get review type with invalid credential`, async () => {
+        try {
+          await failClient.getReviewType(reviewTypeId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
+
+      it(`failure - Get review type by id not found`, async () => {
+        try {
+          await client.getReviewType(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Review type with ID = ${notFoundId} is not found`)
+        }
+      })
     })
 
-    it(`failure - Patch review type by id not found`, async () => {
-      try {
-        await client.patchReviewType(notFoundId, { name: 'test-for-patch' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Review type with ID = ${notFoundId} is not found`)
-      }
+    describe('Test head review type by id', () => {
+      it(`Head review type by id success`, async () => {
+        const res = await client.headReviewType(reviewTypeId)
+        should.equal(res.status, 200)
+      })
+
+      it(`failure - Head review type with invalid credential`, async () => {
+        try {
+          await failClient.headReviewType(reviewTypeId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
+
+      it(`failure - Head review type by id not found`, async () => {
+        try {
+          await client.headReviewType(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+        }
+      })
     })
-  })
 
-  describe('Test delete review type by id', () => {
-    it(`Delete review type by id success`, async () => {
-      const res = await client.deleteReviewType(reviewTypeId)
-      should.equal(res.status, 204)
+    describe('Test put review type by id', () => {
+      it(`Put review type by id success`, async () => {
+        const res = await client.updateReviewType(reviewTypeId, { name: 'test-for-put', isActive: false })
+        should.equal(res.status, 200)
+        should.exist(res.body.id)
+        should.equal(res.body.name, 'test-for-put')
+        should.equal(res.body.isActive, false)
+      })
+
+      it(`failure - Put review type with invalid credential`, async () => {
+        try {
+          await failClient.updateReviewType(reviewTypeId, { name: 'test-for-put', isActive: false })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
+
+      it(`failure - Put review type by id with invalid request body`, async () => {
+        try {
+          await client.updateReviewType(reviewTypeId, { name: 123, isActive: true })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `"name" must be a string`)
+        }
+      })
+
+      it(`failure - Put review type by id not found`, async () => {
+        try {
+          await client.updateReviewType(notFoundId, { name: 'test-for-put', isActive: false })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Review type with ID = ${notFoundId} is not found`)
+        }
+      })
     })
 
-    it(`failure - Delete review type with invalid m2m credential`, async () => {
-      try {
-        await failClient.deleteReviewType(reviewTypeId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
+    describe('Test patch review type by id', () => {
+      it(`Patch review type by id success`, async () => {
+        const res = await client.patchReviewType(reviewTypeId, { name: 'test-for-patch' })
+        should.equal(res.status, 200)
+        should.exist(res.body.id)
+        should.equal(res.body.name, 'test-for-patch')
+        should.equal(res.body.isActive, false)
+      })
+
+      it(`failure - Patch review type with invalid credential`, async () => {
+        try {
+          await failClient.patchReviewType(reviewTypeId, { name: 'test-for-patch' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
+
+      it(`failure - Patch review type by id with invalid request body`, async () => {
+        try {
+          await client.patchReviewType(reviewTypeId, { name: 123 })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `"name" must be a string`)
+        }
+      })
+
+      it(`failure - Patch review type by id not found`, async () => {
+        try {
+          await client.patchReviewType(notFoundId, { name: 'test-for-patch' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Review type with ID = ${notFoundId} is not found`)
+        }
+      })
     })
 
-    it(`failure - Delete review type by id not found`, async () => {
-      try {
-        await client.deleteReviewType(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Review type with ID = ${notFoundId} is not found`)
-      }
+    describe('Test delete review type by id', () => {
+      it(`Delete review type by id success`, async () => {
+        const res = await client.deleteReviewType(reviewTypeId)
+        should.equal(res.status, 204)
+      })
+
+      it(`failure - Delete review type with invalid credential`, async () => {
+        try {
+          await failClient.deleteReviewType(reviewTypeId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
+
+      it(`failure - Delete review type by id not found`, async () => {
+        try {
+          await client.deleteReviewType(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Review type with ID = ${notFoundId} is not found`)
+        }
+      })
     })
   })
-})
+}
diff --git a/test/SubmissionApi.test.js b/test/SubmissionApi.test.js
index ccb4259..9f8ac59 100644
--- a/test/SubmissionApi.test.js
+++ b/test/SubmissionApi.test.js
@@ -5,12 +5,19 @@
 const _ = require('lodash')
 const should = require('chai').should()
 const config = require('./testConfig')
+const userConfig = require('./userTestConfig')
 const api = require('../index')
+const { makeJwtClient } = require('./common/testHelper.js')
 const path = require('path')
 const fs = require('fs')
-
-const client = api(config)
-const failClient = api(_.assign(_.cloneDeep(config), { 'AUTH0_CLIENT_ID': 'invalid' }))
+const store = require('./common/store')
+
+const m2mClient = api(config)
+const m2mFailClient = api(_.assign(_.cloneDeep(config), { 'AUTH0_CLIENT_ID': 'invalid' }))
+const userClient = api(userConfig)
+const userFailClient = api(_.assign(_.cloneDeep(userConfig), { 'PASSWORD': 'invalid' }))
+const jwtClient = makeJwtClient(api(_.pick(userConfig, 'SUBMISSION_API_URL')), userConfig.JWT)
+const jwtFailClient = makeJwtClient(api(_.pick(userConfig, 'SUBMISSION_API_URL')), null)
 const fileData1 = fs.readFileSync(path.resolve(__dirname, './data/fileToUpload.zip'))
 const fileData2 = fs.readFileSync(path.resolve(__dirname, './data/good.zip'))
 const notFoundId = 'e0a789ea-6144-4266-bfae-872f9a26e749'
@@ -24,620 +31,630 @@ const submission = {
 }
 const artifactId = 'c56a4180-65aa-42ec-a945-5fd21dec0503'
 
-// submission id created in test
-let createdSubmissionId1
-let createdSubmissionId2
-
-describe('Submission API Tests', () => {
-  describe('Test create submission', () => {
-    it(`Create submission with file upload success`, async () => {
-      const res = await client.createSubmission({
-        type,
-        memberId,
-        challengeId,
-        submission
-      })
-      createdSubmissionId1 = res.body.id
-      should.equal(res.status, 200)
-      should.equal(res.body.type, type)
-      should.equal(res.body.memberId, memberId)
-      should.equal(res.body.challengeId, challengeId)
-      should.equal(res.body.fileType, 'zip')
-      should.exist(res.body.url)
-    })
+for (const c of [ [ m2mClient, m2mFailClient, 'M2M' ],
+  [ userClient, userFailClient, 'User Credentials' ],
+  [ jwtClient, jwtFailClient, 'JWT argument' ]]) {
+  const [client, failClient, clientName] = c
 
-    it(`Create submission with url success`, async () => {
-      const res = await client.createSubmission({
-        type,
-        memberId,
-        challengeId,
-        url
-      })
-      createdSubmissionId2 = res.body.id
-      should.equal(res.status, 200)
-      should.equal(res.body.type, type)
-      should.equal(res.body.memberId, memberId)
-      should.equal(res.body.challengeId, challengeId)
-      should.equal(res.body.fileType, 'zip')
-      should.equal(res.body.url, url)
-    })
+  // submission id created in test
+  let createdSubmissionId1
+  let createdSubmissionId2
 
-    it(`failure - Create submission with both file upload and url`, async () => {
-      try {
-        await client.createSubmission({
+  describe(`Submission API Tests (${clientName})`, () => {
+    describe('Test create submission', () => {
+      it(`Create submission with file upload success`, async () => {
+        const res = await client.createSubmission({
           type,
           memberId,
           challengeId,
-          submission,
-          url
+          submission
         })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, 'Either file to be uploaded or URL should be present')
-      }
-    })
+        createdSubmissionId1 = res.body.id
+        should.equal(res.status, 200)
+        should.equal(res.body.type, type)
+        should.equal(res.body.memberId, memberId)
+        should.equal(res.body.challengeId, challengeId)
+        should.equal(res.body.fileType, 'zip')
+        should.exist(res.body.url)
+      })
 
-    it(`failure - Create submission without file upload and url`, async () => {
-      try {
-        await client.createSubmission({
+      it(`Create submission with url success`, async () => {
+        const res = await client.createSubmission({
           type,
           memberId,
-          challengeId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, 'Either file to be uploaded or URL should be present')
-      }
-    })
-
-    it(`failure - Create submission with invalid memberId`, async () => {
-      try {
-        await client.createSubmission({
-          type,
-          memberId: 'invalid',
           challengeId,
           url
         })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, '"memberId" must be a number')
-      }
-    })
+        createdSubmissionId2 = res.body.id
+        should.equal(res.status, 200)
+        should.equal(res.body.type, type)
+        should.equal(res.body.memberId, memberId)
+        should.equal(res.body.challengeId, challengeId)
+        should.equal(res.body.fileType, 'zip')
+        should.equal(res.body.url, url)
+      })
 
-    it(`failure - Create submission with invalid m2m credential`, async () => {
-      try {
-        await failClient.createSubmission({
-          type,
-          memberId,
-          challengeId,
-          submission,
-          url
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+      it(`failure - Create submission with both file upload and url`, async () => {
+        try {
+          await client.createSubmission({
+            type,
+            memberId,
+            challengeId,
+            submission,
+            url
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, 'Either file to be uploaded or URL should be present')
+        }
+      })
 
-  describe('Test download submission', () => {
-    it(`Download submission 1 success`, async () => {
-      const res = await client.downloadSubmission(createdSubmissionId1)
-      should.equal(Buffer.compare(res.body, fileData1), 0)
-    })
+      it(`failure - Create submission without file upload and url`, async () => {
+        try {
+          await client.createSubmission({
+            type,
+            memberId,
+            challengeId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, 'Either file to be uploaded or URL should be present')
+        }
+      })
 
-    it(`Download submission 2 success`, async () => {
-      const res = await client.downloadSubmission(createdSubmissionId2)
-      should.equal(Buffer.compare(res.body, fileData2), 0)
-    })
+      it(`failure - Create submission with invalid memberId`, async () => {
+        try {
+          await client.createSubmission({
+            type,
+            memberId: 'invalid',
+            challengeId,
+            url
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, '"memberId" must be a number')
+        }
+      })
 
-    it(`failure - Download submission with not found id`, async () => {
-      try {
-        await client.downloadSubmission(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Submission with ID = ${notFoundId} is not found`)
-      }
+      it(`failure - Create submission with invalid credential`, async () => {
+        try {
+          await failClient.createSubmission({
+            type,
+            memberId,
+            challengeId,
+            submission,
+            url
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`failure - Download submission with invalid m2m credential`, async () => {
-      try {
-        await failClient.downloadSubmission(createdSubmissionId2)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+    describe('Test download submission', () => {
+      it(`Download submission 1 success`, async () => {
+        const res = await client.downloadSubmission(createdSubmissionId1)
+        should.equal(Buffer.compare(res.body, fileData1), 0)
+      })
 
-  describe('Test search submissions', () => {
-    it(`Search submissions 1 success`, async () => {
-      const res = await client.searchSubmissions({})
-      should.equal(res.status, 200)
-      should.equal('1', res.header['x-page'])
-      should.equal('20', res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-      for (const item of res.body) {
-        should.exist(item.id)
-        should.exist(item.type)
-        should.exist(item.memberId)
-        should.exist(item.challengeId)
-        should.exist(item.url)
-      }
-    })
+      it(`Download submission 2 success`, async () => {
+        const res = await client.downloadSubmission(createdSubmissionId2)
+        should.equal(Buffer.compare(res.body, fileData2), 0)
+      })
 
-    it(`Search submissions 2 success`, async () => {
-      const res = await client.searchSubmissions({
-        page: 1,
-        perPage: 3,
-        challengeId,
-        memberId
-      })
-      should.equal(res.status, 200)
-      should.equal('1', res.header['x-page'])
-      should.equal('3', res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-      for (const item of res.body) {
-        should.exist(item.id)
-        should.exist(item.type)
-        should.equal(item.memberId, memberId)
-        should.equal(item.challengeId, challengeId)
-        should.exist(item.fileType)
-        should.exist(item.url)
-      }
-    })
+      it(`failure - Download submission with not found id`, async () => {
+        try {
+          await client.downloadSubmission(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Submission with ID = ${notFoundId} is not found`)
+        }
+      })
 
-    it(`failure - Search submissions with invalid parameter challengeId`, async () => {
-      try {
-        await client.searchSubmissions({ challengeId: 'abc' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `"challengeId" must be a number`)
-      }
+      it(`failure - Download submission with invalid credential`, async () => {
+        try {
+          await failClient.downloadSubmission(createdSubmissionId2)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`failure - Search submissions with invalid m2m credential`, async () => {
-      try {
-        await failClient.searchSubmissions({})
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+    describe('Test search submissions', () => {
+      it(`Search submissions 1 success`, async () => {
+        const res = await client.searchSubmissions({})
+        should.equal(res.status, 200)
+        should.equal('1', res.header['x-page'])
+        should.equal('20', res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+        for (const item of res.body) {
+          should.exist(item.id)
+          should.exist(item.type)
+          should.exist(item.memberId)
+          should.exist(item.challengeId)
+          should.exist(item.url)
+        }
+      })
 
-  describe('Test head submissions', () => {
-    it(`Head submissions 1 success`, async () => {
-      const res = await client.headSubmissions({})
-      should.equal(res.status, 200)
-      should.equal('1', res.header['x-page'])
-      should.equal('20', res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-    })
+      it(`Search submissions 2 success`, async () => {
+        const res = await client.searchSubmissions({
+          page: 1,
+          perPage: 3,
+          challengeId,
+          memberId
+        })
+        should.equal(res.status, 200)
+        should.equal('1', res.header['x-page'])
+        should.equal('3', res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+        for (const item of res.body) {
+          should.exist(item.id)
+          should.exist(item.type)
+          should.equal(item.memberId, memberId)
+          should.equal(item.challengeId, challengeId)
+          should.exist(item.fileType)
+          should.exist(item.url)
+        }
+      })
 
-    it(`Head submissions 2 success`, async () => {
-      const res = await client.searchSubmissions({
-        page: 1,
-        perPage: 3,
-        challengeId,
-        memberId
-      })
-      should.equal(res.status, 200)
-      should.equal('1', res.header['x-page'])
-      should.equal('3', res.header['x-per-page'])
-      should.exist(res.header['x-total'])
-      should.exist(res.header['x-total-pages'])
-    })
+      it(`failure - Search submissions with invalid parameter challengeId`, async () => {
+        try {
+          await client.searchSubmissions({ challengeId: 'abc' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `"challengeId" must be a number`)
+        }
+      })
 
-    it(`failure - Head submissions with invalid parameter challengeId`, async () => {
-      try {
-        await client.headSubmissions({ challengeId: 'abc' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-      }
+      it(`failure - Search submissions with invalid credential`, async () => {
+        try {
+          await failClient.searchSubmissions({})
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`failure - Head submissions with invalid m2m credential`, async () => {
-      try {
-        await failClient.searchSubmissions({})
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+    describe('Test head submissions', () => {
+      it(`Head submissions 1 success`, async () => {
+        const res = await client.headSubmissions({})
+        should.equal(res.status, 200)
+        should.equal('1', res.header['x-page'])
+        should.equal('20', res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+      })
 
-  describe('Test get submission', () => {
-    it(`Get submission 1 success`, async () => {
-      const res = await client.getSubmission(createdSubmissionId1)
-      should.equal(res.status, 200)
-      should.equal(res.body.type, type)
-      should.equal(res.body.memberId, memberId)
-      should.equal(res.body.challengeId, challengeId)
-      should.equal(res.body.fileType, 'zip')
-      should.exist(res.body.url)
-    })
+      it(`Head submissions 2 success`, async () => {
+        const res = await client.searchSubmissions({
+          page: 1,
+          perPage: 3,
+          challengeId,
+          memberId
+        })
+        should.equal(res.status, 200)
+        should.equal('1', res.header['x-page'])
+        should.equal('3', res.header['x-per-page'])
+        should.exist(res.header['x-total'])
+        should.exist(res.header['x-total-pages'])
+      })
 
-    it(`Get submission 2 success`, async () => {
-      const res = await client.getSubmission(createdSubmissionId2)
-      should.equal(res.status, 200)
-      should.equal(res.body.type, type)
-      should.equal(res.body.memberId, memberId)
-      should.equal(res.body.challengeId, challengeId)
-      should.equal(res.body.fileType, 'zip')
-      // should.equal(res.body.url, url) Can't test if url matches because url changes after AV processor is done with its task
-      should.exist(res.body.url)
-    })
+      it(`failure - Head submissions with invalid parameter challengeId`, async () => {
+        try {
+          await client.headSubmissions({ challengeId: 'abc' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+        }
+      })
 
-    it(`failure - Get submission with not found id`, async () => {
-      try {
-        await client.getSubmission(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Submission with ID = ${notFoundId} is not found`)
-      }
+      it(`failure - Head submissions with invalid credential`, async () => {
+        try {
+          await failClient.searchSubmissions({})
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`failure - Get submission with invalid m2m credential`, async () => {
-      try {
-        await failClient.getSubmission(createdSubmissionId2)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+    describe('Test get submission', () => {
+      it(`Get submission 1 success`, async () => {
+        const res = await client.getSubmission(createdSubmissionId1)
+        should.equal(res.status, 200)
+        should.equal(res.body.type, type)
+        should.equal(res.body.memberId, memberId)
+        should.equal(res.body.challengeId, challengeId)
+        should.equal(res.body.fileType, 'zip')
+        should.exist(res.body.url)
+      })
 
-  describe('Test head submission', () => {
-    it(`Head submission 1 success`, async () => {
-      const res = await client.headSubmission(createdSubmissionId1)
-      should.equal(res.status, 200)
-    })
+      it(`Get submission 2 success`, async () => {
+        const res = await client.getSubmission(createdSubmissionId2)
+        should.equal(res.status, 200)
+        should.equal(res.body.type, type)
+        should.equal(res.body.memberId, memberId)
+        should.equal(res.body.challengeId, challengeId)
+        should.equal(res.body.fileType, 'zip')
+        // should.equal(res.body.url, url) Can't test if url matches because url changes after AV processor is done with its task
+        should.exist(res.body.url)
+      })
 
-    it(`Head submission 2 success`, async () => {
-      const res = await client.headSubmission(createdSubmissionId2)
-      should.equal(res.status, 200)
-    })
+      it(`failure - Get submission with not found id`, async () => {
+        try {
+          await client.getSubmission(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Submission with ID = ${notFoundId} is not found`)
+        }
+      })
 
-    it(`failure - Head submission with not found id`, async () => {
-      try {
-        await client.headSubmission(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-      }
+      it(`failure - Get submission with invalid credential`, async () => {
+        try {
+          await failClient.getSubmission(createdSubmissionId2)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`failure - Head submission with invalid m2m credential`, async () => {
-      try {
-        await failClient.headSubmission(createdSubmissionId2)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+    describe('Test head submission', () => {
+      it(`Head submission 1 success`, async () => {
+        const res = await client.headSubmission(createdSubmissionId1)
+        should.equal(res.status, 200)
+      })
+
+      it(`Head submission 2 success`, async () => {
+        const res = await client.headSubmission(createdSubmissionId2)
+        should.equal(res.status, 200)
+      })
 
-  describe('Test put submission', () => {
-    it(`Put submission success`, async () => {
-      const res = await client.updateSubmission(createdSubmissionId2, {
-        type: 'challenge submission',
-        memberId,
-        challengeId,
-        url,
-        legacySubmissionId: 30003000
-      })
-      should.equal(res.status, 200)
-      should.equal(res.body.id, createdSubmissionId2)
-      should.equal(res.body.type, 'challenge submission')
-      should.equal(res.body.memberId, memberId)
-      should.equal(res.body.challengeId, challengeId)
-      should.equal(res.body.url, url)
-      should.equal(res.body.legacySubmissionId, 30003000)
+      it(`failure - Head submission with not found id`, async () => {
+        try {
+          await client.headSubmission(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+        }
+      })
+
+      it(`failure - Head submission with invalid credential`, async () => {
+        try {
+          await failClient.headSubmission(createdSubmissionId2)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`failure - Put submission with invalid legacySubmissionId parameter`, async () => {
-      try {
-        await client.updateSubmission(createdSubmissionId1, {
-          type,
+    describe('Test put submission', () => {
+      it(`Put submission success`, async () => {
+        const res = await client.updateSubmission(createdSubmissionId2, {
+          type: 'challenge submission',
           memberId,
           challengeId,
           url,
-          legacySubmissionId: 'abcde'
+          legacySubmissionId: 30003000
         })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `"legacySubmissionId" must be a number`)
-      }
-    })
+        should.equal(res.status, 200)
+        should.equal(res.body.id, createdSubmissionId2)
+        should.equal(res.body.type, 'challenge submission')
+        should.equal(res.body.memberId, memberId)
+        should.equal(res.body.challengeId, challengeId)
+        should.equal(res.body.url, url)
+        should.equal(res.body.legacySubmissionId, 30003000)
+      })
 
-    it(`failure - Put submission not found`, async () => {
-      try {
-        await client.updateSubmission(notFoundId, {
-          type,
-          memberId,
-          challengeId,
-          url
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Submission with ID = ${notFoundId} is not found`)
-      }
-    })
+      it(`failure - Put submission with invalid legacySubmissionId parameter`, async () => {
+        try {
+          await client.updateSubmission(createdSubmissionId1, {
+            type,
+            memberId,
+            challengeId,
+            url,
+            legacySubmissionId: 'abcde'
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `"legacySubmissionId" must be a number`)
+        }
+      })
 
-    it(`failure - Put submission with invalid m2m credential`, async () => {
-      try {
-        await failClient.updateSubmission(createdSubmissionId1, {
-          type,
-          memberId,
-          challengeId,
-          url
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+      it(`failure - Put submission not found`, async () => {
+        try {
+          await client.updateSubmission(notFoundId, {
+            type,
+            memberId,
+            challengeId,
+            url
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Submission with ID = ${notFoundId} is not found`)
+        }
+      })
 
-  describe('Test patch submission', () => {
-    it(`Patch submission success`, async () => {
-      const res = await client.patchSubmission(createdSubmissionId2, {
-        type: 'Contest Submission',
-        legacyUploadId: 1000000
-      })
-      should.equal(res.status, 200)
-      should.equal(res.body.id, createdSubmissionId2)
-      should.equal(res.body.type, 'Contest Submission')
-      should.equal(res.body.memberId, memberId)
-      should.equal(res.body.challengeId, challengeId)
-      should.equal(res.body.url, url)
-      should.equal(res.body.legacySubmissionId, 30003000)
-      should.equal(res.body.legacyUploadId, 1000000)
+      it(`failure - Put submission with invalid credential`, async () => {
+        try {
+          await failClient.updateSubmission(createdSubmissionId1, {
+            type,
+            memberId,
+            challengeId,
+            url
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`failure - Patch submission with invalid submissionPhaseId parameter`, async () => {
-      try {
-        await client.patchSubmission(createdSubmissionId1, { submissionPhaseId: 'abcde' })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `"submissionPhaseId" must be a number`)
-      }
-    })
+    describe('Test patch submission', () => {
+      it(`Patch submission success`, async () => {
+        const res = await client.patchSubmission(createdSubmissionId2, {
+          type: 'Contest Submission',
+          legacyUploadId: 1000000
+        })
+        should.equal(res.status, 200)
+        should.equal(res.body.id, createdSubmissionId2)
+        should.equal(res.body.type, 'Contest Submission')
+        should.equal(res.body.memberId, memberId)
+        should.equal(res.body.challengeId, challengeId)
+        should.equal(res.body.url, url)
+        should.equal(res.body.legacySubmissionId, 30003000)
+        should.equal(res.body.legacyUploadId, 1000000)
+      })
 
-    it(`failure - Patch submission not found`, async () => {
-      try {
-        await client.patchSubmission(notFoundId, { type })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Submission with ID = ${notFoundId} is not found`)
-      }
-    })
+      it(`failure - Patch submission with invalid submissionPhaseId parameter`, async () => {
+        try {
+          await client.patchSubmission(createdSubmissionId1, { submissionPhaseId: 'abcde' })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `"submissionPhaseId" must be a number`)
+        }
+      })
 
-    it(`failure - Patch submission with invalid m2m credential`, async () => {
-      try {
-        await failClient.patchSubmission(createdSubmissionId1, { type })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+      it(`failure - Patch submission not found`, async () => {
+        try {
+          await client.patchSubmission(notFoundId, { type })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Submission with ID = ${notFoundId} is not found`)
+        }
+      })
 
-  describe('Test create artifact for submission', () => {
-    it(`Create artifact success`, async () => {
-      const res = await client.createArtifact(createdSubmissionId1, {
-        artifact: submission,
-        typeId: artifactId
+      it(`failure - Patch submission with invalid credential`, async () => {
+        try {
+          await failClient.patchSubmission(createdSubmissionId1, { type })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
       })
-      should.equal(res.status, 200)
-      should.equal(res.body.artifact, `${artifactId}.zip`)
     })
 
-    it(`failure - Create artifact already exist`, async () => {
-      try {
-        await client.createArtifact(createdSubmissionId1, {
+    describe('Test create artifact for submission', () => {
+      before(function (done) {
+        store.artifactData = null
+        done()
+      })
+      it(`Create artifact success`, async () => {
+        const res = await client.createArtifact(createdSubmissionId1, {
           artifact: submission,
           typeId: artifactId
         })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 409)
-        should.equal(err.response.body.message, `Artifact ${artifactId}.zip already exists for Submission ${createdSubmissionId1}`)
-      }
-    })
+        should.equal(res.status, 200)
+        should.equal(res.body.artifact, `${artifactId}.zip`)
+      })
 
-    it(`failure - Create artifact no file 1`, async () => {
-      try {
-        await client.createArtifact(createdSubmissionId1, {
-          typeId: artifactId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, 'Artifact is missing or not under attribute `artifact`')
-      }
-    })
+      it(`failure - Create artifact already exist`, async () => {
+        try {
+          await client.createArtifact(createdSubmissionId1, {
+            artifact: submission,
+            typeId: artifactId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 409)
+          should.equal(err.response.body.message, `Artifact ${artifactId}.zip already exists for Submission ${createdSubmissionId1}`)
+        }
+      })
 
-    it(`failure - Create artifact file data incomplete`, async () => {
-      try {
-        await client.createArtifact(createdSubmissionId1, {
-          artifact: { name: 'test' },
-          typeId: artifactId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, 'Artifact is missing or not under attribute `artifact`')
-      }
-    })
+      it(`failure - Create artifact no file 1`, async () => {
+        try {
+          await client.createArtifact(createdSubmissionId1, {
+            typeId: artifactId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, 'Artifact is missing or not under attribute `artifact`')
+        }
+      })
 
-    it(`failure - Create artifact file data incomplete`, async () => {
-      try {
-        await client.createArtifact(createdSubmissionId1, {
-          artifact: { data: fileData1 },
-          typeId: artifactId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, 'Artifact is missing or not under attribute `artifact`')
-      }
-    })
+      it(`failure - Create artifact file data incomplete`, async () => {
+        try {
+          await client.createArtifact(createdSubmissionId1, {
+            artifact: { name: 'test' },
+            typeId: artifactId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, 'Artifact is missing or not under attribute `artifact`')
+        }
+      })
 
-    it(`failure - Create artifact for submission not found`, async () => {
-      try {
-        await client.createArtifact(notFoundId, {
-          artifact: submission,
-          typeId: artifactId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `Submission with ID = ${notFoundId} does not exist`)
-      }
-    })
+      it(`failure - Create artifact file data incomplete`, async () => {
+        try {
+          await client.createArtifact(createdSubmissionId1, {
+            artifact: { data: fileData1 },
+            typeId: artifactId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, 'Artifact is missing or not under attribute `artifact`')
+        }
+      })
 
-    it(`failure - Create artifact with invalid m2m credential`, async () => {
-      try {
-        await failClient.createArtifact(createdSubmissionId1, {
-          artifact: submission,
-          typeId: artifactId
-        })
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+      it(`failure - Create artifact for submission not found`, async () => {
+        try {
+          await client.createArtifact(notFoundId, {
+            artifact: submission,
+            typeId: artifactId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `Submission with ID = ${notFoundId} does not exist`)
+        }
+      })
 
-  describe('Test download artifact for submission', () => {
-    it(`Download artifact success`, async () => {
-      const res = await client.downloadArtifact(createdSubmissionId1, artifactId)
-      should.equal(res.status, 200)
-      should.equal(Buffer.compare(res.body, fileData1), 0)
+      it(`failure - Create artifact with invalid credential`, async () => {
+        try {
+          await failClient.createArtifact(createdSubmissionId1, {
+            artifact: submission,
+            typeId: artifactId
+          })
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`failure - Download artifact invalid submissionId`, async () => {
-      try {
-        await client.downloadArtifact('invalid', artifactId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `"submissionId" must be a valid GUID`)
-      }
-    })
+    describe('Test download artifact for submission', () => {
+      it(`Download artifact success`, async () => {
+        const res = await client.downloadArtifact(createdSubmissionId1, artifactId)
+        should.equal(res.status, 200)
+        should.equal(Buffer.compare(res.body, fileData1), 0)
+      })
 
-    it(`failure - Download artifact submission not found`, async () => {
-      try {
-        await client.downloadArtifact(notFoundId, artifactId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `Submission with ID = ${notFoundId} does not exist`)
-      }
-    })
+      it(`failure - Download artifact invalid submissionId`, async () => {
+        try {
+          await client.downloadArtifact('invalid', artifactId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `"submissionId" must be a valid GUID`)
+        }
+      })
 
-    it(`failure - Download artifact artifact not found`, async () => {
-      try {
-        await client.downloadArtifact(createdSubmissionId1, notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `Artifact ${notFoundId} doesn't exist for ${createdSubmissionId1}`)
-      }
-    })
+      it(`failure - Download artifact submission not found`, async () => {
+        try {
+          await client.downloadArtifact(notFoundId, artifactId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `Submission with ID = ${notFoundId} does not exist`)
+        }
+      })
 
-    it(`failure - Download artifact with invalid m2m credential`, async () => {
-      try {
-        await failClient.downloadArtifact(createdSubmissionId1, artifactId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+      it(`failure - Download artifact artifact not found`, async () => {
+        try {
+          await client.downloadArtifact(createdSubmissionId1, notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `Artifact ${notFoundId} doesn't exist for ${createdSubmissionId1}`)
+        }
+      })
 
-  describe('Test list artifacts for submission', () => {
-    it(`List artifacts success`, async () => {
-      const res = await client.listArtifacts(createdSubmissionId1)
-      should.equal(res.status, 200)
-      should.equal(res.body.artifacts.length > 0, true)
-      should.equal(res.body.artifacts.includes(artifactId), true)
+      it(`failure - Download artifact with invalid credential`, async () => {
+        try {
+          await failClient.downloadArtifact(createdSubmissionId1, artifactId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`failure - List artifacts submission invalid submissionId`, async () => {
-      try {
-        await client.listArtifacts('invalid')
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `"submissionId" must be a valid GUID`)
-      }
-    })
+    describe('Test list artifacts for submission', () => {
+      it(`List artifacts success`, async () => {
+        const res = await client.listArtifacts(createdSubmissionId1)
+        should.equal(res.status, 200)
+        should.equal(res.body.artifacts.length > 0, true)
+        should.equal(res.body.artifacts.includes(artifactId), true)
+      })
 
-    it(`failure - List artifacts submission not found`, async () => {
-      try {
-        await client.listArtifacts(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 400)
-        should.equal(err.response.body.message, `Submission with ID = ${notFoundId} does not exist`)
-      }
-    })
+      it(`failure - List artifacts submission invalid submissionId`, async () => {
+        try {
+          await client.listArtifacts('invalid')
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `"submissionId" must be a valid GUID`)
+        }
+      })
 
-    it(`failure - List artifacts with invalid m2m credential`, async () => {
-      try {
-        await failClient.listArtifacts(createdSubmissionId1)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
-    })
-  })
+      it(`failure - List artifacts submission not found`, async () => {
+        try {
+          await client.listArtifacts(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 400)
+          should.equal(err.response.body.message, `Submission with ID = ${notFoundId} does not exist`)
+        }
+      })
 
-  describe('Test delete submission', () => {
-    it(`Delete submission 1 success`, async () => {
-      const res = await client.deleteSubmission(createdSubmissionId1)
-      should.equal(res.status, 204)
+      it(`failure - List artifacts with invalid credential`, async () => {
+        try {
+          await failClient.listArtifacts(createdSubmissionId1)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
 
-    it(`Delete submission 2 success`, async () => {
-      const res = await client.deleteSubmission(createdSubmissionId2)
-      should.equal(res.status, 204)
-    })
+    describe('Test delete submission', () => {
+      it(`Delete submission 1 success`, async () => {
+        const res = await client.deleteSubmission(createdSubmissionId1)
+        should.equal(res.status, 204)
+      })
 
-    it(`failure - Delete submission with not found id`, async () => {
-      try {
-        await client.deleteSubmission(notFoundId)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.status, 404)
-        should.equal(err.response.body.message, `Submission with ID = ${notFoundId} is not found`)
-      }
-    })
+      it(`Delete submission 2 success`, async () => {
+        const res = await client.deleteSubmission(createdSubmissionId2)
+        should.equal(res.status, 204)
+      })
 
-    it(`failure - Delete submission with invalid m2m credential`, async () => {
-      try {
-        await failClient.deleteSubmission(createdSubmissionId2)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, 'Unknown Error')
-      }
+      it(`failure - Delete submission with not found id`, async () => {
+        try {
+          await client.deleteSubmission(notFoundId)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.status, 404)
+          should.equal(err.response.body.message, `Submission with ID = ${notFoundId} is not found`)
+        }
+      })
+
+      it(`failure - Delete submission with invalid credential`, async () => {
+        try {
+          await failClient.deleteSubmission(createdSubmissionId2)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, 'should not throw error here')
+        }
+      })
     })
   })
-})
+}
diff --git a/test/WrapperInitialization.test.js b/test/WrapperInitialization.test.js
index 2722c88..f94d666 100644
--- a/test/WrapperInitialization.test.js
+++ b/test/WrapperInitialization.test.js
@@ -4,82 +4,131 @@
 
 const _ = require('lodash')
 const should = require('chai').should()
-const allConfig = require('./testConfig')
+const m2mConfig = require('./testConfig')
+const userConfig = require('./userTestConfig')
 const api = require('../index')
 
 // Pick auth config
-const config = _.pick(allConfig, ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
-  'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL', 'AUTH0_PROXY_SERVER_URL' ])
+const m2mDesc = {
+  name: 'M2M',
+  schemaType: '[M2M Configuration]',
+  config: _.pick(m2mConfig, ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME',
+    'AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'SUBMISSION_API_URL', 'AUTH0_PROXY_SERVER_URL' ]),
+  uriFields: ['AUTH0_URL', 'AUTH0_AUDIENCE', 'SUBMISSION_API_URL'],
+  stringFields: ['AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'AUTH0_PROXY_SERVER_URL'],
+  intervalFields: ['TOKEN_CACHE_TIME']
+}
 
-describe('Wrapper Initialization Tests', () => {
-  for (const key in config) {
-    it(`Configuration ${key} is missing`, () => {
-      const cfg = _.omit(_.cloneDeep(config), key)
-      try {
-        api(cfg)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, `"${key}" is required`)
-      }
-    })
-  }
+const userDesc = {
+  name: 'User Credentials',
+  schemaType: '[User Credentials Configuration]',
+  config: _.pick(userConfig, [
+    'USERNAME',
+    'PASSWORD',
+    'TC_AUTHN_URL',
+    'TC_AUTHZ_URL',
+    'TC_CLIENT_ID',
+    'TC_CLIENT_V2CONNECTION',
+    'SUBMISSION_API_URL'
+  ]),
+  uriFields: [
+    'TC_AUTHN_URL',
+    'TC_AUTHZ_URL'
+  ],
+  stringFields: [
+    'USERNAME',
+    'PASSWORD',
+    'TC_AUTHN_URL',
+    'TC_AUTHZ_URL',
+    'TC_CLIENT_ID',
+    'TC_CLIENT_V2CONNECTION'
+  ],
+  intervalFields: []
+}
 
-  for (const key of ['AUTH0_URL', 'AUTH0_AUDIENCE', 'SUBMISSION_API_URL']) {
-    it(`Configuration ${key} is invalid, it should be valid uri`, () => {
-      const cfg = _.cloneDeep(config)
-      cfg[key] = 'invalid'
-      try {
-        api(cfg)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, `"${key}" must be a valid uri`)
-      }
-    })
-  }
+const jwtDesc = {
+  name: 'JWT Method Argument',
+  schemaType: '[JWT Method Argument]',
+  config: _.pick(userConfig, 'SUBMISSION_API_URL'),
+  uriFields: ['SUBMISSION_API_URL'],
+  stringFields: ['SUBMISSION_API_URL'],
+  intervalFields: []
+}
 
-  for (const key of ['AUTH0_CLIENT_ID', 'AUTH0_CLIENT_SECRET', 'AUTH0_PROXY_SERVER_URL']) {
-    it(`Configuration ${key} is invalid, it should be valid uri`, () => {
-      const cfg = _.cloneDeep(config)
-      cfg[key] = true
-      try {
-        api(cfg)
-        throw new Error('should not throw error here')
-      } catch (err) {
-        should.equal(err.message, `"${key}" must be a string`)
-      }
-    })
-  }
+for (const c of [m2mDesc, userDesc, jwtDesc]) {
+  const { name, schemaType, config, uriFields, stringFields, intervalFields } = c
+  describe(`Wrapper Initialization Tests (${name})`, () => {
+    for (const key in config) {
+      it(`Configuration ${key} is missing`, () => {
+        const cfg = _.omit(_.cloneDeep(config), key)
+        try {
+          api(cfg)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.not.equal(err.message, `should not throw error here`)
+        }
+      })
+    }
 
-  it(`Configuration TOKEN_CACHE_TIME is invalid, it should be number`, () => {
-    const cfg = _.cloneDeep(config)
-    cfg['TOKEN_CACHE_TIME'] = 'invalid'
-    try {
-      api(cfg)
-      throw new Error('should not throw error here')
-    } catch (err) {
-      should.equal(err.message, `"TOKEN_CACHE_TIME" must be a number`)
+    for (const key of uriFields) {
+      it(`Configuration ${key} is invalid, it should be valid uri`, () => {
+        const cfg = _.cloneDeep(config)
+        cfg[key] = 'invalid'
+        try {
+          api(cfg)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.message, `${schemaType} "${key}" must be a valid uri`)
+        }
+      })
     }
-  })
 
-  it(`Configuration TOKEN_CACHE_TIME is invalid, it should be an integer`, () => {
-    const cfg = _.cloneDeep(config)
-    cfg['TOKEN_CACHE_TIME'] = 123.45
-    try {
-      api(cfg)
-      throw new Error('should not throw error here')
-    } catch (err) {
-      should.equal(err.message, `"TOKEN_CACHE_TIME" must be an integer`)
+    for (const key of stringFields) {
+      it(`Configuration ${key} is invalid, it should be valid string`, () => {
+        const cfg = _.cloneDeep(config)
+        cfg[key] = true
+        try {
+          api(cfg)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.message, `${schemaType} "${key}" must be a string`)
+        }
+      })
     }
-  })
 
-  it(`Configuration TOKEN_CACHE_TIME is invalid, it should not less than 0`, () => {
-    const cfg = _.cloneDeep(config)
-    cfg['TOKEN_CACHE_TIME'] = -1
-    try {
-      api(cfg)
-      throw new Error('should not throw error here')
-    } catch (err) {
-      should.equal(err.message, `"TOKEN_CACHE_TIME" must be larger than or equal to 0`)
+    for (const key of intervalFields) {
+      it(`Configuration ${key} is invalid, it should be number`, () => {
+        const cfg = _.cloneDeep(config)
+        cfg[key] = 'invalid'
+        try {
+          api(cfg)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.message, `${schemaType} "${key}" must be a number`)
+        }
+      })
+
+      it(`Configuration ${key} is invalid, it should be an integer`, () => {
+        const cfg = _.cloneDeep(config)
+        cfg[key] = 123.45
+        try {
+          api(cfg)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.message, `${schemaType} "${key}" must be an integer`)
+        }
+      })
+
+      it(`Configuration ${key} is invalid, it should not less than 0`, () => {
+        const cfg = _.cloneDeep(config)
+        cfg[key] = -1
+        try {
+          api(cfg)
+          throw new Error('should not throw error here')
+        } catch (err) {
+          should.equal(err.message, `${schemaType} "${key}" must be larger than or equal to 0`)
+        }
+      })
     }
   })
-})
+}
diff --git a/test/common/routes.js b/test/common/routes.js
index b8f6216..d34d1aa 100644
--- a/test/common/routes.js
+++ b/test/common/routes.js
@@ -216,7 +216,7 @@ module.exports = {
   },
   '/submissions': {
     post: {
-      id: [td.SUBMISSION_ID2, td.SUBMISSION_ID1],
+      id: [td.SUBMISSION_ID2, td.SUBMISSION_ID1, td.SUBMISSION_ID2, td.SUBMISSION_ID1, td.SUBMISSION_ID2, td.SUBMISSION_ID1],
       schema: {
         authUser: joi.object().required(),
         files: joi.any(),
diff --git a/test/common/store.js b/test/common/store.js
new file mode 100644
index 0000000..cd91fe4
--- /dev/null
+++ b/test/common/store.js
@@ -0,0 +1,5 @@
+/**
+ * Persist test data
+ */
+
+module.exports = {}
diff --git a/test/common/testData.js b/test/common/testData.js
index 8f76688..26ae021 100644
--- a/test/common/testData.js
+++ b/test/common/testData.js
@@ -5,6 +5,7 @@ const _ = require('lodash')
 const url = require('url')
 const uuid = require('uuid/v4')
 const config = require('../testConfig')
+const userConfig = require('../userTestConfig')
 
 const M2M_TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3RvcGNvZGVyLWRldi5hdXRoMC5jb20vIiwic3ViIjoiZW5qdzE4MTBlRHozWFR3U08yUm4yWTljUVRyc3BuM0JAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbTJtLnRvcGNvZGVyLWRldi5jb20vIiwiaWF0IjoxNTUyMTE5NDQ4LCJleHAiOjU1NjIyMDU4NDgsImF6cCI6ImVuancxODEwZUR6M1hUd1NPMlJuMlk5Y1FUcnNwbjNCIiwic2NvcGUiOiJhbGw6cmV2aWV3IGFsbDpyZXZpZXdfc3VtbWF0aW9uIGFsbDpyZXZpZXdfdHlwZSBhbGw6c3VibWlzc2lvbiIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.uJE97vctfpmzA0HrK9rcmrfWVHZNzERrI-qag3fm_lc'
 const M2M_USER = {
@@ -12,6 +13,13 @@ const M2M_USER = {
 }
 const API_VERSION = url.parse(_.get(config, 'SUBMISSION_API_URL')).pathname
 const AUTH_PATH = url.parse(_.get(config, 'AUTH0_URL')).pathname
+const AUTHN_PATH = url.parse(_.get(userConfig, 'TC_AUTHN_URL')).pathname
+const AUTHN_ID_TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuaWNrbmFtZSI6IlRvbnlKIiwiZW1haWwiOiJhamVmdHNAdG9wY29kZXIuY29tIiwibmFtZSI6ImFqZWZ0c0B0b3Bjb2Rlci5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvZjExODkyYzM4MTQwMzZjNjhjNzhmNGNlMGY2Yzg3NjE_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZhai5wbmciLCJyb2xlcyI6WyJ1c2VyIl0sImFwcF9tZXRhZGF0YSI6eyJyb2xlcyI6WyJ1c2VyIl19LCJjbGllbnRJRCI6IkpGRG83SE1rZjBxMkNrVkZIb2p5M3pIV2FmemlwcmhUIiwidXBkYXRlZF9hdCI6IjIwMTktMDctMjVUMTQ6MzY6NDkuNjQzWiIsInVzZXJfaWQiOiJhdXRoMHw4NTQ3ODk5IiwiaWRlbnRpdGllcyI6W3sidXNlcl9pZCI6Ijg1NDc4OTkiLCJwcm92aWRlciI6ImF1dGgwIiwiY29ubmVjdGlvbiI6IlRDLVVzZXItRGF0YWJhc2UiLCJpc1NvY2lhbCI6ZmFsc2V9XSwiY3JlYXRlZF9hdCI6IjIwMTctMDEtMDhUMTA6MzM6MzAuODQzWiIsImlzcyI6Imh0dHBzOi8vdG9wY29kZXItZGV2LmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw4NTQ3ODk5IiwiYXVkIjoiSkZEbzdITWtmMHEyQ2tWRkhvankzekhXYWZ6aXByaFQiLCJpYXQiOjE1NjQwNjU0MDksImV4cCI6MTkyNDA2NTQwOX0.RUk8nieOdRPj4dj-ZUhgFrdcAszU9EHW2fFlDul8RH0'
+const AUTHN_REFRESH_TOKEN = 'kpHUTupKo7z6dRNdGpPOeIZtaCQg3Se0wit0vQWaABsdS'
+const AUTHN_ACCESS_TOKEN = 'IU9HcR5jOrk7LmEzJe43ybE6m8AUZj4D'
+const AUTHN_TOKEN_TYPE = 'bearer'
+const AUTHZ_PATH = url.parse(_.get(userConfig, 'TC_AUTHZ_URL')).pathname
+const AUTHZ_TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyb2xlcyI6WyJUb3Bjb2RlciBVc2VyIiwiQ29ubmVjdCBTdXBwb3J0IiwiYWRtaW5pc3RyYXRvciIsInRlc3RSb2xlIiwiYWFhIiwidG9ueV90ZXN0XzEiLCJDb25uZWN0IE1hbmFnZXIiLCJDb25uZWN0IEFkbWluIiwiY29waWxvdCIsIkNvbm5lY3QgQ29waWxvdCBNYW5hZ2VyIl0sImlzcyI6Imh0dHBzOi8vYXBpLnRvcGNvZGVyLWRldi5jb20iLCJoYW5kbGUiOiJUb255SiIsImV4cCI6MTU2NDA2NjkzOCwidXNlcklkIjoiODU0Nzg5OSIsImlhdCI6MTU2NDA2NjMzOCwiZW1haWwiOiJhamVmdHNAdG9wY29kZXIuY29tIiwianRpIjoiMTRkNTliZjctMWI5Ny00Y2ZjLWE3OWUtZmY3NjI2YjI2MzRjIn0.Krh9nQY7M-mpQzbjwKrD_eTSDF7ra8GY-kSY-rstcEg'
 const REVIEW_TYPE_ID = uuid()
 const REVIEW_ID = uuid()
 const REVIEW_SUMMATION_ID = uuid()
@@ -38,6 +46,13 @@ module.exports = {
   M2M_USER,
   API_VERSION,
   AUTH_PATH,
+  AUTHN_PATH,
+  AUTHN_REFRESH_TOKEN,
+  AUTHN_ID_TOKEN,
+  AUTHN_ACCESS_TOKEN,
+  AUTHN_TOKEN_TYPE,
+  AUTHZ_PATH,
+  AUTHZ_TOKEN,
   REVIEW_TYPE_ID,
   REVIEW_ID,
   REVIEW_SUMMATION_ID,
diff --git a/test/common/testHelper.js b/test/common/testHelper.js
index 75b2f8e..ab13af1 100644
--- a/test/common/testHelper.js
+++ b/test/common/testHelper.js
@@ -333,6 +333,16 @@ const multiPartParse = (body, contentType) => {
   return partsByName
 }
 
+/**
+ * Make client that invokes the Wrapper methods with JWT argument
+ */
+function makeJwtClient (api, jwt) {
+  return Object.entries(api).reduce((acc, [key, fn]) => {
+    acc[key] = (...args) => fn(...args, jwt)
+    return acc
+  }, {})
+}
+
 module.exports = {
   resHeaders,
   hexToString,
@@ -343,5 +353,6 @@ module.exports = {
   get,
   put,
   patch,
-  remove
+  remove,
+  makeJwtClient
 }
diff --git a/test/prepare.js b/test/prepare.js
index 8dbedef..022527d 100644
--- a/test/prepare.js
+++ b/test/prepare.js
@@ -14,15 +14,20 @@ const th = require('./common/testHelper')
 const td = require('./common/testData')
 const Reviews = require('./data/Reviews.json')
 const ReviewSummations = require('./data/ReviewSummations.json')
+const store = require('./common/store')
 
 const AUTH_PATH = td.AUTH_PATH
+const AUTHN_PATH = td.AUTHN_PATH
+const AUTHN_REFRESH_TOKEN = td.AUTHN_REFRESH_TOKEN
+const AUTHN_ID_TOKEN = td.AUTHN_ID_TOKEN
+const AUTHN_ACCESS_TOKEN = td.AUTHN_ACCESS_TOKEN
+const AUTHN_TOKEN_TYPE = td.AUTHN_TOKEN_TYPE
+const AUTHZ_PATH = td.AUTHZ_PATH
+const AUTHZ_TOKEN = td.AUTHZ_TOKEN
+
 const API_VERSION = td.API_VERSION
 
-let reviewTypeData
-let reviewData
-let reviewSummationData
-let submissionData = {}
-let artifactData
+store.submissionData = {}
 const reviewForGet = Reviews[0]
 const reviewSummationForGet = ReviewSummations[0]
 
@@ -51,6 +56,22 @@ prepare(function (done) {
         }]
       }
     })
+    .post(AUTHN_PATH)
+    .reply((_uri, requestBody) => {
+      if (requestBody.password === 'invalid') {
+        return [401, {
+          message: 'Unknown Error'
+        }]
+      }
+      return [200, {
+        'id_token': AUTHN_ID_TOKEN,
+        'refresh_token': AUTHN_REFRESH_TOKEN,
+        'access_token': AUTHN_ACCESS_TOKEN,
+        'token_type': AUTHN_TOKEN_TYPE
+      }]
+    })
+    .post(AUTHZ_PATH)
+    .reply(() => [ 200, { result: { content: { token: AUTHZ_TOKEN } } } ])
     .post(`/reviewTypes`)
     .reply(function (uri, body) {
       const result = th.create({
@@ -59,7 +80,7 @@ prepare(function (done) {
         body
       })
       if (result[0] === td.CREATE_SUCCESS_STATUS) {
-        reviewTypeData = result[1]
+        store.reviewTypeData = result[1]
       }
       return result
     })
@@ -86,7 +107,7 @@ prepare(function (done) {
       return th.get({
         uri,
         method: this.method.toLowerCase(),
-        obj: reviewTypeData,
+        obj: store.reviewTypeData,
         notFound: td.NotFoundError.ReviewType
       })
     })
@@ -107,12 +128,12 @@ prepare(function (done) {
       const result = th.put({
         uri,
         method: this.method.toLowerCase(),
-        obj: reviewTypeData,
+        obj: store.reviewTypeData,
         body,
         notFound: td.NotFoundError.ReviewType
       })
       if (result[0] === td.SUCCESS_STATUS) {
-        reviewTypeData = result[1]
+        store.reviewTypeData = result[1]
       }
       return result
     })
@@ -122,12 +143,12 @@ prepare(function (done) {
       const result = th.put({
         uri,
         method: this.method.toLowerCase(),
-        obj: reviewTypeData,
+        obj: store.reviewTypeData,
         body,
         notFound: td.NotFoundError.ReviewType
       })
       if (result[0] === td.SUCCESS_STATUS) {
-        reviewTypeData = result[1]
+        store.reviewTypeData = result[1]
       }
       return result
     })
@@ -137,11 +158,11 @@ prepare(function (done) {
       const result = th.remove({
         uri,
         method: this.method.toLowerCase(),
-        obj: reviewTypeData,
+        obj: store.reviewTypeData,
         notFound: td.NotFoundError.ReviewType
       })
       if (result[0] === td.DELETE_SUCCESS_STATUS) {
-        reviewTypeData = null
+        store.reviewTypeData = null
       }
       return result
     })
@@ -154,7 +175,7 @@ prepare(function (done) {
         needUser: true
       })
       if (result[0] === td.CREATE_SUCCESS_STATUS) {
-        reviewData = result[1]
+        store.reviewData = result[1]
       }
       return result
     })
@@ -204,13 +225,13 @@ prepare(function (done) {
       const result = th.put({
         uri,
         method: this.method.toLowerCase(),
-        obj: reviewData,
+        obj: store.reviewData,
         body,
         needUser: true,
         notFound: td.NotFoundError.Review
       })
       if (result[0] === td.SUCCESS_STATUS) {
-        reviewData = result[1]
+        store.reviewData = result[1]
       }
       return result
     })
@@ -220,13 +241,13 @@ prepare(function (done) {
       const result = th.put({
         uri,
         method: this.method.toLowerCase(),
-        obj: reviewData,
+        obj: store.reviewData,
         body,
         needUser: true,
         notFound: td.NotFoundError.Review
       })
       if (result[0] === td.SUCCESS_STATUS) {
-        reviewData = result[1]
+        store.reviewData = result[1]
       }
       return result
     })
@@ -236,11 +257,11 @@ prepare(function (done) {
       const result = th.remove({
         uri,
         method: this.method.toLowerCase(),
-        obj: reviewData,
+        obj: store.reviewData,
         notFound: td.NotFoundError.Review
       })
       if (result[0] === td.DELETE_SUCCESS_STATUS) {
-        reviewData = null
+        store.reviewData = null
       }
       return result
     })
@@ -253,7 +274,7 @@ prepare(function (done) {
         needUser: true
       })
       if (result[0] === td.CREATE_SUCCESS_STATUS) {
-        reviewSummationData = result[1]
+        store.reviewSummationData = result[1]
       }
       return result
     })
@@ -303,14 +324,14 @@ prepare(function (done) {
       const result = th.put({
         uri,
         method: this.method.toLowerCase(),
-        obj: reviewSummationData,
+        obj: store.reviewSummationData,
         body,
         needUser: true,
         notFoundId: td.SUMMATION_NOTFOUND_ID,
         notFound: td.NotFoundError.ReviewSummation
       })
       if (result[0] === td.SUCCESS_STATUS) {
-        reviewSummationData = result[1]
+        store.reviewSummationData = result[1]
       }
       return result
     })
@@ -320,14 +341,14 @@ prepare(function (done) {
       const result = th.put({
         uri,
         method: this.method.toLowerCase(),
-        obj: reviewSummationData,
+        obj: store.reviewSummationData,
         body,
         needUser: true,
         notFoundId: td.SUMMATION_NOTFOUND_ID,
         notFound: td.NotFoundError.ReviewSummation
       })
       if (result[0] === td.SUCCESS_STATUS) {
-        reviewSummationData = result[1]
+        store.reviewSummationData = result[1]
       }
       return result
     })
@@ -337,12 +358,12 @@ prepare(function (done) {
       const result = th.remove({
         uri,
         method: this.method.toLowerCase(),
-        obj: reviewSummationData,
+        obj: store.reviewSummationData,
         notFoundId: td.SUMMATION_NOTFOUND_ID,
         notFound: td.NotFoundError.ReviewSummation
       })
       if (result[0] === td.DELETE_SUCCESS_STATUS) {
-        reviewSummationData = null
+        store.reviewSummationData = null
       }
       return result
     })
@@ -359,7 +380,7 @@ prepare(function (done) {
         isSubmission: true
       })
       if (result[0] === td.CREATE_SUCCESS_STATUS) {
-        submissionData[result[1].id] = result[1]
+        store.submissionData[result[1].id] = result[1]
       }
       return result
     })
@@ -406,7 +427,7 @@ prepare(function (done) {
     .get(`/submissions/${td.SUBMISSION_ID1}/artifacts`)
     .query(true)
     .reply(function (uri, body) {
-      return [td.SUCCESS_STATUS, { artifacts: [artifactData.artifact.split('.')[0]] }]
+      return [td.SUCCESS_STATUS, { artifacts: [store.artifactData.artifact.split('.')[0]] }]
     })
     .get(`/submissions/invalid/artifacts`)
     .query(true)
@@ -436,11 +457,11 @@ prepare(function (done) {
       if (result.error) {
         return [td.JOI_FAIL_STATUS, { message: result.error.details[0].message }]
       }
-      if (artifactData) {
+      if (store.artifactData) {
         return [409, { message: `Artifact ${route.id}.zip already exists for Submission ${td.SUBMISSION_ID1}` }]
       }
-      artifactData = { artifact: `${route.id}.zip` }
-      return [td.SUCCESS_STATUS, artifactData]
+      store.artifactData = { artifact: `${route.id}.zip` }
+      return [td.SUCCESS_STATUS, store.artifactData]
     })
     .get(`/submissions`)
     .query(true)
@@ -465,7 +486,7 @@ prepare(function (done) {
       return th.get({
         uri,
         method: this.method.toLowerCase(),
-        obj: submissionData,
+        obj: store.submissionData,
         isSubmission: true,
         needUser: true,
         notFound: td.NotFoundError.Submission
@@ -489,14 +510,14 @@ prepare(function (done) {
       const result = th.put({
         uri,
         method: this.method.toLowerCase(),
-        obj: submissionData,
+        obj: store.submissionData,
         isSubmission: true,
         body,
         needUser: true,
         notFound: td.NotFoundError.Submission
       })
       if (result[0] === td.SUCCESS_STATUS) {
-        submissionData[result[1].id] = result[1]
+        store.submissionData[result[1].id] = result[1]
       }
       return result
     })
@@ -506,14 +527,14 @@ prepare(function (done) {
       const result = th.put({
         uri,
         method: this.method.toLowerCase(),
-        obj: submissionData,
+        obj: store.submissionData,
         isSubmission: true,
         body,
         needUser: true,
         notFound: td.NotFoundError.Submission
       })
       if (result[0] === td.SUCCESS_STATUS) {
-        submissionData[result[1].id] = result[1]
+        store.submissionData[result[1].id] = result[1]
       }
       return result
     })
@@ -523,12 +544,12 @@ prepare(function (done) {
       const result = th.remove({
         uri,
         method: this.method.toLowerCase(),
-        obj: submissionData,
+        obj: store.submissionData,
         isSubmission: true,
         notFound: td.NotFoundError.Submission
       })
       if (result[0] === td.DELETE_SUCCESS_STATUS) {
-        submissionData[result[1]] = null
+        store.submissionData[result[1]] = null
         result[1] = null
       }
       return result
diff --git a/test/userTestConfig.js b/test/userTestConfig.js
new file mode 100644
index 0000000..36f9dcb
--- /dev/null
+++ b/test/userTestConfig.js
@@ -0,0 +1,19 @@
+/*
+ * Config for tests.
+ */
+
+const config = {
+  JWT: process.env.TEST_JWT,
+  USERNAME: process.env.TEST_USERNAME,
+  PASSWORD: process.env.TEST_PASSWORD,
+  TC_AUTHN_URL: process.env.TEST_TC_AUTHN_URL,
+  TC_AUTHZ_URL: process.env.TEST_TC_AUTHZ_URL,
+  TC_CLIENT_ID: process.env.TEST_TC_CLIENT_ID,
+  TC_CLIENT_V2CONNECTION: process.env.TEST_TC_CLIENT_V2CONNECTION,
+  SUBMISSION_API_URL: process.env.TEST_SUBMISSION_API_URL,
+  PAGE: process.env.PAGE || 1,
+  PER_PAGE: process.env.PER_PAGE || 20,
+  MAX_PAGE_SIZE: process.env.MAX_PAGE_SIZE || 100
+}
+
+module.exports = config