diff --git a/package.json b/package.json
index b0b388b..aed6a92 100644
--- a/package.json
+++ b/package.json
@@ -36,6 +36,7 @@
         "angular-touch": "~1.7.4",
         "angular-ui-bootstrap": "~2.5.0",
         "angular-ui-router": "~1.0.23",
+        "angularjs-datepicker": "^2.1.23",
         "auth0-angular": "~4.0.4",
         "auth0-js": "^9.11.3",
         "auth0-lock": "^11.17.2",
diff --git a/src/controllers/GitlabController.js b/src/controllers/GitlabController.js
index 3575005..a1ed04a 100644
--- a/src/controllers/GitlabController.js
+++ b/src/controllers/GitlabController.js
@@ -115,7 +115,11 @@ async function getGroupRegistrationUrl(req) {
   if (!user || !user.accessToken) {
     throw new errors.UnauthorizedError('You have not setup for Gitlab.');
   }
-  return await GitlabService.getGroupRegistrationUrl(user.username, req.params.id, req.params.accessLevel);
+  return await GitlabService.getGroupRegistrationUrl(
+    user.username,
+    req.params.id,
+    req.params.accessLevel,
+    req.params.expiredAt);
 }
 
 /**
@@ -193,7 +197,12 @@ async function addUserToGroupCallback(req, res) {
   });
 
   // add user to group
-  const gitlabUser = await GitlabService.addGroupMember(group.groupId, ownerUser.accessToken, token, group.accessLevel);
+  const gitlabUser = await GitlabService.addGroupMember(
+    group.groupId,
+    ownerUser.accessToken,
+    token,
+    group.accessLevel,
+    group.expiredAt);
   // associate gitlab username with TC username
   const mapping = await dbHelper.scanOne(UserMapping, {
     topcoderUsername: {eq: req.session.tcUsername},
diff --git a/src/front/src/app/app.js b/src/front/src/app/app.js
index 33f89c9..c3e6911 100644
--- a/src/front/src/app/app.js
+++ b/src/front/src/app/app.js
@@ -12,7 +12,8 @@ angular.module('topcoderX', [
   'ui.router',
   'ui.bootstrap',
   'angular-clipboard',
-  'angular-jwt'])
+  'angular-jwt',
+  '720kb.datepicker'])
   // In the run phase of your Angular application
   .run(['AuthService', function (AuthService) {
     // init AuthService, it has to be done once, when app starts
diff --git a/src/front/src/app/git-access-control/access-control.service.js b/src/front/src/app/git-access-control/access-control.service.js
index dadf140..fcc9eec 100644
--- a/src/front/src/app/git-access-control/access-control.service.js
+++ b/src/front/src/app/git-access-control/access-control.service.js
@@ -24,7 +24,12 @@ angular.module('topcoderX')
          * get gitlab shareable link
          *
          */
-        service.getGitlabShareableLink = function (groupId, accessLevel) {
+        service.getGitlabShareableLink = function (groupId, accessLevel, expiredAt) {
+            if (expiredAt) {
+                return $http.get(baseUrl + '/api/v1/gitlab/groups/' + groupId + '/registrationurl/' + accessLevel + '/' + expiredAt).then(function (response) {
+                    return response;
+                });
+            }
             return $http.get(baseUrl + '/api/v1/gitlab/groups/' + groupId + '/registrationurl/' + accessLevel).then(function (response) {
                 return response;
             });
diff --git a/src/front/src/app/git-access-control/git-access-dialog.controller.js b/src/front/src/app/git-access-control/git-access-dialog.controller.js
index 1823278..6838f17 100644
--- a/src/front/src/app/git-access-control/git-access-dialog.controller.js
+++ b/src/front/src/app/git-access-control/git-access-dialog.controller.js
@@ -12,10 +12,12 @@ angular.module('topcoderX').controller('GitAccessDialogController', [
   ) {
     $scope.provider = provider;
     $scope.accessLevel = '';
+    $scope.expiredAt = '';
     if ($scope.provider === 'github') {
       $scope.accessLevel = 'member';
     } else {
       $scope.accessLevel = '30';
+      $scope.dateLimit = new Date().toDateString();
     }
 
     /**
@@ -25,12 +27,20 @@ angular.module('topcoderX').controller('GitAccessDialogController', [
       $scope.accessLevel = accessLevel;
     };
 
+    /**
+     * Update the expired at params
+     */
+    $scope.updateExpired = function (expiredAt) {
+      $scope.expiredAt = expiredAt;
+    };
+
     /**
      * Set changes to father controller
      */
     $scope.setChanges = function () {
       $uibModalInstance.close({
         accessLevel: $scope.accessLevel,
+        expiredAt: $scope.expiredAt
       });
     };
 
diff --git a/src/front/src/app/git-access-control/git-access-dialog.html b/src/front/src/app/git-access-control/git-access-dialog.html
index d0794a6..570ec13 100644
--- a/src/front/src/app/git-access-control/git-access-dialog.html
+++ b/src/front/src/app/git-access-control/git-access-dialog.html
@@ -9,14 +9,21 @@ <h4 class="modal-title" id="reg-dialog-label">Configure Access Level and Valid P
         <div class="row">
             <label class="form-label">Access Level:</label>
             <select class="form-control" ng-if="provider === 'gitlab'" ng-model="accessLevel" ng-change="updateAccessLevel(accessLevel)" required>
-                <option value ="30">Developer</option>
+                <option value ="10">Guest</option>
                 <option value ="20">Reporter</option>
+                <option value ="30">Developer</option>
+                <option value ="40">Maintainer</option>
+                <option value ="50">Owner</option>
             </select>
             <select class="form-control" ng-if="provider === 'github'" ng-model="accessLevel" ng-change="updateAccessLevel(accessLevel)" required>
                 <option value ="member">Member</option>
                 <option value ="maintainer">Maintainer</option>
             </select>
             <br />
+            <label ng-if="provider === 'gitlab'" class="form-label">Expired At:</label>
+            <datepicker ng-if="provider === 'gitlab'" date-format="yyyy-MM-dd" date-min-limit="{{dateLimit}}">
+                <input class="form-control" ng-model="expiredAt" type="text" ng-change="updateExpired(expiredAt)"/>
+            </datepicker>
         </div>
     </div>
     <div class="modal-footer">
@@ -27,4 +34,4 @@ <h4 class="modal-title" id="reg-dialog-label">Configure Access Level and Valid P
             Cancel
         </button>
     </div>
-</div>
+</div>
\ No newline at end of file
diff --git a/src/front/src/app/git-access-control/gitAccessControl.controller.js b/src/front/src/app/git-access-control/gitAccessControl.controller.js
index ea615c3..5ce60ee 100644
--- a/src/front/src/app/git-access-control/gitAccessControl.controller.js
+++ b/src/front/src/app/git-access-control/gitAccessControl.controller.js
@@ -88,8 +88,13 @@ angular.module('topcoderX').controller('GitAccessController', ['currentUser', '$
                 function (data) {
                     if (data) {
                         const accessLevel = data.accessLevel;
+                        const expiredAt = data.expiredAt;
                         var config = $scope.tableConfig[provider];
-                        config.accessLinkMethod.apply(vm, [team.id, accessLevel]).then(function (response) {
+                        var params = [team.id, accessLevel];
+                        if (expiredAt) {
+                            params.push(expiredAt);
+                        }
+                        config.accessLinkMethod.apply(vm, params).then(function (response) {
                             team.accessLink = response.data.url;
                             team.showLink = true;
                             team.gettingLink = false;
diff --git a/src/front/src/index.css b/src/front/src/index.css
index 0d851b9..8b80263 100644
--- a/src/front/src/index.css
+++ b/src/front/src/index.css
@@ -1,4 +1,5 @@
 /*add css dependencies in node_modules here*/
 
 @import url("../../../node_modules/metismenu/dist/metisMenu.css");
-@import url("../../../node_modules/footable/css/footable.core.css");
\ No newline at end of file
+@import url("../../../node_modules/footable/css/footable.core.css");
+@import url("../../../node_modules/angularjs-datepicker/dist/angular-datepicker.min.css");
\ No newline at end of file
diff --git a/src/front/src/index.js b/src/front/src/index.js
index 4a1cc7f..95a2e5c 100644
--- a/src/front/src/index.js
+++ b/src/front/src/index.js
@@ -29,4 +29,5 @@ require('metismenu');
 require('pace-js');
 require('footable');
 require('jquery-ui-dist/jquery-ui');
+require('angularjs-datepicker');
 window.shortid = require('shortid')
\ No newline at end of file
diff --git a/src/models/OwnerUserGroup.js b/src/models/OwnerUserGroup.js
index 7c8662b..c3b729e 100644
--- a/src/models/OwnerUserGroup.js
+++ b/src/models/OwnerUserGroup.js
@@ -64,6 +64,10 @@ const schema = new Schema({
       name: 'AccessLevelIndex',
     },
   },
+  expiredAt: {
+    type: String,
+    required: false
+  }
 });
 
 
diff --git a/src/routes.js b/src/routes.js
index 168a5f9..b2649bb 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -86,6 +86,12 @@ module.exports = {
       method: 'getGroupRegistrationUrl',
     },
   },
+  '/gitlab/groups/:id/registrationurl/:accessLevel/:expiredAt': {
+    get: {
+      controller: 'GitlabController',
+      method: 'getGroupRegistrationUrl',
+    },
+  },
   '/gitlab/groups/:id/users': {
     delete: {
       controller: 'GitlabController',
diff --git a/src/services/GitlabService.js b/src/services/GitlabService.js
index 77edd8e..5e25524 100644
--- a/src/services/GitlabService.js
+++ b/src/services/GitlabService.js
@@ -145,9 +145,10 @@ listOwnerUserGroups.schema = Joi.object().keys({
  * @param {String} ownerUsername the owner user name
  * @param {String} groupId the group id
  * @param {String} accessLevel the group access level
+ * @param {String} expiredAt the expired at params to define how long user joined teams. can be null
  * @returns {Promise} the promise result
  */
-async function getGroupRegistrationUrl(ownerUsername, groupId, accessLevel) {
+async function getGroupRegistrationUrl(ownerUsername, groupId, accessLevel, expiredAt) {
   // generate identifier
   const identifier = helper.generateIdentifier();
 
@@ -159,6 +160,7 @@ async function getGroupRegistrationUrl(ownerUsername, groupId, accessLevel) {
     groupId,
     identifier,
     accessLevel,
+    expiredAt
   });
 
   // construct URL
@@ -170,6 +172,7 @@ getGroupRegistrationUrl.schema = Joi.object().keys({
   ownerUsername: Joi.string().required(),
   groupId: Joi.string().required(),
   accessLevel: Joi.string().required(),
+  expiredAt: Joi.string()
 });
 
 /**
@@ -178,9 +181,10 @@ getGroupRegistrationUrl.schema = Joi.object().keys({
  * @param {String} ownerUserToken the owner user token
  * @param {String} normalUserToken the normal user token
  * @param {String} accessLevel the access level
+ * @param {String} expiredAt the expired at params to define how long user joined teams. can be null
  * @returns {Promise} the promise result
  */
-async function addGroupMember(groupId, ownerUserToken, normalUserToken, accessLevel) {
+async function addGroupMember(groupId, ownerUserToken, normalUserToken, accessLevel, expiredAt) {
   let username;
   let userId;
   try {
@@ -195,11 +199,15 @@ async function addGroupMember(groupId, ownerUserToken, normalUserToken, accessLe
       throw new errors.UnauthorizedError('Can not get user id from the normal user access token.');
     }
 
+    let body = `user_id=${userId}&access_level=${accessLevel}`;
+    if (expiredAt) {
+      body = body + `&expires_at=${expiredAt} `;
+    }
     // add user to group
     await request
       .post(`${config.GITLAB_API_BASE_URL}/api/v4/groups/${groupId}/members`)
       .set('Authorization', `Bearer ${ownerUserToken}`)
-      .send(`user_id=${userId}&access_level=${accessLevel}`)
+      .send(body)
       .end();
     // return gitlab username
     return {
@@ -222,6 +230,7 @@ addGroupMember.schema = Joi.object().keys({
   ownerUserToken: Joi.string().required(),
   normalUserToken: Joi.string().required(),
   accessLevel: Joi.string().required(),
+  expiredAt: Joi.string()
 });
 
 /**