diff --git a/README.md b/README.md
index 985714e..d858a4e 100755
--- a/README.md
+++ b/README.md
@@ -30,6 +30,9 @@ The following config parameters are supported, they are defined in `config/defau
 | PARTITION                  | the kafka partition            |  0|
 | KAFKA_OPTIONS                  | the connection option for kafka            |  see below about KAFKA options                  |
 |TC_DEV_ENV| the flag whether to use topcoder development api or production| false|
+| TC_AUTHN_URL | the Topcoder authentication url | https://topcoder-dev.auth0.com/oauth/ro |
+| TC_AUTHN_REQUEST_BODY | the Topcoder authentication request body. This makes use of some environment variables: `TC_USERNAME`, `TC_PASSWORD`, `TC_CLIENT_ID`, `CLIENT_V2CONNECTION` | see `default.js` |
+| TC_AUTHZ_URL | the Topcoder authorization url | https://api.topcoder-dev.com/v3/authorizations |
 | NEW_CHALLENGE_TEMPLATE | the body template for new challenge request. You can change the subTrack, reviewTypes, technologies, .. here | see `default.js` |
 | NEW_CHALLENGE_DURATION_IN_DAYS | the duration of new challenge | 5 |
 |TC_URL| the base URL of topcoder to get the challenge URL| defaults to `https://www.topcoder-dev.com`|
diff --git a/config/default.js b/config/default.js
index 33832fe..c1a1e75 100644
--- a/config/default.js
+++ b/config/default.js
@@ -26,6 +26,19 @@ module.exports = {
     }
   },
   TC_DEV_ENV: process.env.NODE_ENV === 'production' ? false : true,
+  TC_AUTHN_URL: process.env.TC_AUTHN_URL || 'https://topcoder-dev.auth0.com/oauth/ro',
+  TC_AUTHN_REQUEST_BODY: {
+    username: process.env.TC_USERNAME || 'mess',
+    password: process.env.TC_PASSWORD || 'appirio123',
+    client_id: process.env.TC_CLIENT_ID || 'JFDo7HMkf0q2CkVFHojy3zHWafziprhT',
+    sso: false,
+    scope: 'openid profile offline_access',
+    response_type: 'token',
+    connection: process.env.CLIENT_V2CONNECTION || 'TC-User-Database',
+    grant_type: 'password',
+    device: 'Browser'
+  },
+  TC_AUTHZ_URL: process.env.TC_AUTHZ_URL || 'https://api.topcoder-dev.com/v3/authorizations',
   NEW_CHALLENGE_TEMPLATE: process.env.NEW_CHALLENGE_TEMPLATE || {
     milestoneId: 1,
     subTrack: 'FIRST_2_FINISH',
diff --git a/configuration.md b/configuration.md
index cc1f595..03aa592 100644
--- a/configuration.md
+++ b/configuration.md
@@ -13,6 +13,9 @@ The following config parameters are supported, they are defined in `config/defau
 |KAFKA_CLIENT_CERT | The Kafka SSL certificate to use when connecting| Read from kafka_client.cer file, but this can be set as a string like it is on Heroku |
 |KAFKA_CLIENT_CERT_KEY | The Kafka SSL certificate key to use when connecting| Read from kafka_client.key file, but this can be set as a string like it is on Heroku|
 |TC_DEV_ENV| the flag whether to use topcoder development api or production| false|
+| TC_AUTHN_URL | the Topcoder authentication url | https://topcoder-dev.auth0.com/oauth/ro |
+| TC_AUTHN_REQUEST_BODY | the Topcoder authentication request body. This makes use of some environment variables: `TC_USERNAME`, `TC_PASSWORD`, `TC_CLIENT_ID`, `CLIENT_V2CONNECTION` | see `default.js` |
+| TC_AUTHZ_URL | the Topcoder authorization url | https://api.topcoder-dev.com/v3/authorizations |
 | NEW_CHALLENGE_TEMPLATE | the body template for new challenge request. You can change the subTrack, reviewTypes, technologies, .. here | see `default.js` |
 | NEW_CHALLENGE_DURATION_IN_DAYS | the duration of new challenge | 5 |
 |TC_URL| the base URL of topcoder to get the challenge URL| defaults to `https://www.topcoder-dev.com`|
diff --git a/package.json b/package.json
index b5904c2..db1c7a3 100644
--- a/package.json
+++ b/package.json
@@ -24,7 +24,6 @@
   },
   "homepage": "https://gitlab.com/luettich/processor#README",
   "dependencies": {
-    "@topcoder-platform/topcoder-api-challenges-v4-wrapper": "^1.0.5",
     "@topcoder-platform/topcoder-api-challenges-v4-wrapper-dev": "^1.0.5",
     "axios": "^0.19.0",
     "circular-json": "^0.5.7",
@@ -43,6 +42,7 @@
     "node-gitlab-api": "^2.2.8",
     "nodemailer": "^4.6.7",
     "tc-core-library-js": "appirio-tech/tc-core-library-js.git#v2.6.3",
+    "topcoder-api-challenges": "^1.0.6",
     "topcoder-api-projects": "^1.0.1",
     "topcoder-dev-api-projects": "^1.0.1",
     "topcoder-healthcheck-dropin": "^1.0.3",
diff --git a/services/IssueService.js b/services/IssueService.js
index 57dc6bc..bae4f1d 100755
--- a/services/IssueService.js
+++ b/services/IssueService.js
@@ -197,13 +197,13 @@ async function handleIssueAssignment(event, issue, force = false) {
       dbIssue = await ensureChallengeExists(event, issue);
 
       if (!dbIssue) {
-        const err = errors.internalDependencyError(`Can't find the issue in DB. It's not found or not accessible`);
+        const err = errors.internalDependencyError('Can\'t find the issue in DB. It\'s not found or not accessible');
         // The dbissue is not found, the db is not accessible, or the issue is still in creation process.
         // Handle it for rescheduling.
         await eventService.handleEventGracefully(event, issue, err);
         return;
       }
-  
+
       // Handle multiple assignees. TC-X allows only one assignee.
       if (event.data.issue.assignees && event.data.issue.assignees.length > 1) {
         const comment = 'Topcoder-X only supports a single assignee on a ticket to avoid issues with payment';
@@ -313,7 +313,7 @@ async function handleIssueUpdate(event, issue) {
     dbIssue = await ensureChallengeExists(event, issue, false);
 
     if (!dbIssue) {
-      const err = errors.internalDependencyError(`Can't find the issue in DB. It's not found or not accessible`);
+      const err = errors.internalDependencyError('Can\'t find the issue in DB. It\'s not found or not accessible');
       // The dbissue is not found, the db is not accessible, or the issue is still in creation process.
       // Handle it for rescheduling.
       await eventService.handleEventGracefully(event, issue, err);
@@ -363,9 +363,9 @@ async function handleIssueClose(event, issue) {
   let dbIssue;
   try {
     dbIssue = await ensureChallengeExists(event, issue);
-    
+
     if (!dbIssue) {
-      const err = errors.internalDependencyError(`Can't find the issue in DB. It's not found or not accessible`);
+      const err = errors.internalDependencyError('Can\'t find the issue in DB. It\'s not found or not accessible');
       // The dbissue is not found, the db is not accessible, or the issue is still in creation process.
       // Handle it for rescheduling.
       await eventService.handleEventGracefully(event, issue, err);
@@ -376,11 +376,11 @@ async function handleIssueClose(event, issue) {
 
     // if the issue has payment success or payment pending status, we'll ignore this process.
     if (dbIssue && dbIssue.status === 'challenge_payment_successful') {
-      logger.debug(`Ignoring close issue processing. The issue has challenge_payment_successful.`);
+      logger.debug('Ignoring close issue processing. The issue has challenge_payment_successful.');
       return;
     }
     if (dbIssue && dbIssue.status === 'challenge_payment_pending') {
-      logger.debug(`Ignoring close issue processing. The issue has challenge_payment_pending.`);
+      logger.debug('Ignoring close issue processing. The issue has challenge_payment_pending.');
       return;
     }
 
@@ -641,7 +641,7 @@ async function handleIssueLabelUpdated(event, issue) {
   // Sometimes Github send label updated event before issue created event.
   // This process will be ignored. The label will be processed (stored) at hanleIssueCreated.
   if (!dbIssue) {
-    logger.debug(`DB record not found. Issue label update ignored.`);
+    logger.debug('DB record not found. Issue label update ignored.');
     return;
   }
   await dbHelper.update(models.Issue, dbIssue.id, {
@@ -662,7 +662,7 @@ async function handleIssueUnAssignment(event, issue) {
     dbIssue = await ensureChallengeExists(event, issue);
 
     if (!dbIssue) {
-      const err = errors.internalDependencyError(`Can't find the issue in DB. It's not found or not accessible`);
+      const err = errors.internalDependencyError('Can\'t find the issue in DB. It\'s not found or not accessible');
       // The dbissue is not found, the db is not accessible, or the issue is still in creation process.
       // Handle it for rescheduling.
       await eventService.handleEventGracefully(event, issue, err);
diff --git a/utils/db-helper.js b/utils/db-helper.js
index 1d4db26..40fe1c5 100644
--- a/utils/db-helper.js
+++ b/utils/db-helper.js
@@ -81,7 +81,7 @@ async function updateMany(model, collection) {
         return reject(err);
       }
 
-      resolve(result);
+      return resolve(result);
     });
   });
 }
@@ -142,7 +142,7 @@ async function remove(Model, queryParams) {
           return reject(err);
         }
 
-        resolve(dbItem);
+        return resolve(dbItem);
       });
     }
   });
diff --git a/utils/logger.js b/utils/logger.js
index 272f94b..b2c90d8 100644
--- a/utils/logger.js
+++ b/utils/logger.js
@@ -9,8 +9,8 @@
  * @version 1.0
  */
 'use strict';
-const config = require('config');
 const util = require('util');
+const config = require('config');
 const _ = require('lodash');
 const winston = require('winston');
 const getParams = require('get-parameter-names');
diff --git a/utils/topcoder-api-helper.js b/utils/topcoder-api-helper.js
index 761e25d..c55b469 100644
--- a/utils/topcoder-api-helper.js
+++ b/utils/topcoder-api-helper.js
@@ -13,17 +13,18 @@
 'use strict';
 
 const config = require('config');
+const jwtDecode = require('jwt-decode');
 const axios = require('axios');
 const _ = require('lodash');
 const moment = require('moment');
 const circularJSON = require('circular-json');
 
-const m2mAuth = require('tc-core-library-js').auth.m2m;
+// const m2mAuth = require('tc-core-library-js').auth.m2m;
 
-const m2m = m2mAuth(_.pick(config, ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME', 'AUTH0_PROXY_SERVER_URL']));
+// const m2m = m2mAuth(_.pick(config, ['AUTH0_URL', 'AUTH0_AUDIENCE', 'TOKEN_CACHE_TIME', 'AUTH0_PROXY_SERVER_URL']));
 
 let topcoderApiProjects = require('topcoder-api-projects');
-let topcoderApiChallenges = require('@topcoder-platform/topcoder-api-challenges-v4-wrapper');
+let topcoderApiChallenges = require('topcoder-api-challenges');
 
 const topcoderDevApiProjects = require('topcoder-dev-api-projects');
 const topcoderDevApiChallenges = require('@topcoder-platform/topcoder-api-challenges-v4-wrapper-dev');
@@ -37,12 +38,16 @@ if (config.TC_DEV_ENV) {
   topcoderApiProjects = topcoderDevApiProjects;
   topcoderApiChallenges = topcoderDevApiChallenges;
 }
+
+// Cache the access token
+let cachedAccessToken;
+
 // Init the API instances
 const projectsClient = topcoderApiProjects.ApiClient.instance;
 const challengesClient = topcoderApiChallenges.ApiClient.instance;
 
-//Timeout increase to 5 minutes
-challengesClient.timeout=300000;
+// Timeout increase to 5 minutes
+challengesClient.timeout = 300000;
 
 const bearer = projectsClient.authentications.bearer;
 bearer.apiKeyPrefix = 'Bearer';
@@ -51,20 +56,66 @@ const projectsApiInstance = new topcoderApiProjects.DefaultApi();
 const challengesApiInstance = new topcoderApiChallenges.DefaultApi();
 
 /**
- * Function to get M2M token
- * @returns {Promise} The promised token
+ * Authenticate with Topcoder API and get the access token.
+ * @returns {String} the access token issued by Topcoder
+ * @private
  */
-async function getM2Mtoken() {
-  return await m2m.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET);
+async function getAccessToken() {
+  // Check the cached access token
+  if (cachedAccessToken) {
+    const decoded = jwtDecode(cachedAccessToken);
+    if (decoded.iat > new Date().getTime()) {
+      // Still not expired, just use it
+      return cachedAccessToken;
+    }
+  }
+
+  // Authenticate
+  const v2Response = await axios.post(config.TC_AUTHN_URL, config.TC_AUTHN_REQUEST_BODY);
+  const v2IdToken = _.get(v2Response, 'data.id_token');
+  const v2RefreshToken = _.get(v2Response, 'data.refresh_token');
+
+  if (!v2IdToken || !v2RefreshToken) {
+    throw new Error(`cannot authenticate with topcoder: ${config.TC_AUTHN_URL}`);
+  }
+
+  // Authorize
+  const v3Response = await axios.post(
+    config.TC_AUTHZ_URL, {
+      param: {
+        externalToken: v2IdToken,
+        refreshToken: v2RefreshToken
+      }
+    }, {
+      headers: {
+        authorization: `Bearer ${v2IdToken}`
+      }
+    });
+
+  cachedAccessToken = _.get(v3Response, 'data.result.content.token');
+
+  if (!cachedAccessToken) {
+    throw new Error(`cannot authorize with topcoder: ${config.TC_AUTHZ_URL}`);
+  }
+
+  return cachedAccessToken;
 }
 
+// /**
+//  * Function to get M2M token
+//  * @returns {Promise} The promised token
+//  */
+// async function getM2Mtoken() {
+//   return await m2m.getMachineToken(config.AUTH0_CLIENT_ID, config.AUTH0_CLIENT_SECRET);
+// }
+
 /**
  * Create a new project.
  * @param {String} projectName the project name
  * @returns {Number} the created project id
  */
 async function createProject(projectName) {
-  bearer.apiKey = await getM2Mtoken();
+  bearer.apiKey = await getAccessToken();
   // eslint-disable-next-line new-cap
   const projectBody = new topcoderApiProjects.ProjectRequestBody.constructFromObject({
     projectName
@@ -96,7 +147,7 @@ async function createProject(projectName) {
  * @returns {Number} the created challenge id
  */
 async function createChallenge(challenge) {
-  bearer.apiKey = await getM2Mtoken();
+  bearer.apiKey = await getAccessToken();
   const start = new Date();
   const startTime = moment(start).toISOString();
   const end = moment(start).add(config.NEW_CHALLENGE_DURATION_IN_DAYS, 'days').toISOString();
@@ -137,7 +188,7 @@ async function createChallenge(challenge) {
  * @param {Object} challenge the challenge to update
  */
 async function updateChallenge(id, challenge) {
-  bearer.apiKey = await getM2Mtoken();
+  bearer.apiKey = await getAccessToken();
   logger.debug(`Updating challenge ${id} with ${circularJSON.stringify(challenge)}`);
   // eslint-disable-next-line new-cap
   const challengeBody = new topcoderApiChallenges.UpdateChallengeBodyParam.constructFromObject({
@@ -175,7 +226,7 @@ async function updateChallenge(id, challenge) {
  * @param {Number} id the challenge id
  */
 async function activateChallenge(id) {
-  bearer.apiKey = await getM2Mtoken();
+  bearer.apiKey = await getAccessToken();
   logger.debug(`Activating challenge ${id}`);
   try {
     const response = await new Promise((resolve, reject) => {
@@ -215,7 +266,7 @@ async function getChallengeById(id) {
   if (!_.isNumber(id)) {
     throw new Error('The challenge id must valid number');
   }
-  const apiKey = await getM2Mtoken();
+  const apiKey = await getAccessToken();
   logger.debug('Getting topcoder challenge details');
   try {
     const response = await axios.get(`${challengesClient.basePath}/challenges/${id}`, {
@@ -246,7 +297,7 @@ async function getChallengeById(id) {
  * @param {Number} winnerId the winner id
  */
 async function closeChallenge(id, winnerId) {
-  const apiKey = await getM2Mtoken();
+  const apiKey = await getAccessToken();
   logger.debug(`Closing challenge ${id}`);
   try {
     const response = await axios.post(`${challengesClient.basePath}/challenges/${id}/close?winnerId=${winnerId}`, null, {
@@ -276,7 +327,7 @@ async function closeChallenge(id, winnerId) {
  * @returns {Number} the billing account id
  */
 async function getProjectBillingAccountId(id) {
-  const apiKey = await getM2Mtoken();
+  const apiKey = await getAccessToken();
   logger.debug(`Getting project billing detail ${id}`);
   try {
     const response = await axios.get(`${projectsClient.basePath}/direct/projects/${id}`, {
@@ -308,7 +359,7 @@ async function getProjectBillingAccountId(id) {
  * @returns {Number} the user id
  */
 async function getTopcoderMemberId(handle) {
-  bearer.apiKey = await getM2Mtoken();
+  bearer.apiKey = await getAccessToken();
   try {
     const response = await axios.get(`${projectsClient.basePath}/members/${handle}`);
     const statusCode = response ? response.status : null;
@@ -327,7 +378,7 @@ async function getTopcoderMemberId(handle) {
  * @param {Object} resource the resource resource to add
  */
 async function addResourceToChallenge(id, resource) {
-  bearer.apiKey = await getM2Mtoken();
+  bearer.apiKey = await getAccessToken();
   logger.debug(`adding resource to challenge ${id}`);
   try {
     const response = await new Promise((resolve, reject) => {
@@ -368,7 +419,7 @@ async function getResourcesFromChallenge(id) {
   if (!_.isNumber(id)) {
     throw new Error('The challenge id must valid number');
   }
-  const apiKey = await getM2Mtoken();
+  const apiKey = await getAccessToken();
   logger.debug(`fetch resource from challenge ${id}`);
   try {
     const response = await axios.get(`${challengesClient.basePath}/challenges/${id}/resources`, {
@@ -413,7 +464,7 @@ async function roleAlreadySet(id, role) {
  * @param {Object} resource the resource  resource to remove
  */
 async function unregisterUserFromChallenge(id) {
-  bearer.apiKey = await getM2Mtoken();
+  bearer.apiKey = await getAccessToken();
   logger.debug(`removing resource from challenge ${id}`);
   try {
     const response = await new Promise((resolve, reject) => {
@@ -450,7 +501,7 @@ async function unregisterUserFromChallenge(id) {
  * @param {Number} id the challenge id
  */
 async function cancelPrivateContent(id) {
-  bearer.apiKey = await getM2Mtoken();
+  bearer.apiKey = await getAccessToken();
   logger.debug(`Cancelling challenge ${id}`);
   try {
     const response = await new Promise((resolve, reject) => {
@@ -498,7 +549,7 @@ async function assignUserAsRegistrant(topcoderUserId, challengeId) {
  * @param {Object} resource the resource resource to remove
  */
 async function removeResourceToChallenge(id, resource) {
-  bearer.apiKey = await getM2Mtoken();
+  bearer.apiKey = await getAccessToken();
   logger.debug(`removing resource from challenge ${id}`);
   try {
     const response = await new Promise((resolve, reject) => {
@@ -528,7 +579,7 @@ async function removeResourceToChallenge(id, resource) {
  * @returns {Array} the resources of challenge
  */
 async function getChallengeResources(id) {
-  const apiKey = await getM2Mtoken();
+  const apiKey = await getAccessToken();
   logger.debug(`getting resource from challenge ${id}`);
   try {
     const response = await axios.get(`${challengesClient.basePath}/challenges/${id}/resources`, {