DLAB-000 fixed merge conflicts
diff --git a/README.md b/README.md
index 8a3db02..36b1075 100644
--- a/README.md
+++ b/README.md
@@ -61,6 +61,8 @@
 
         [Azure OAuth2 Authentication](#Azure_OAuth2_Authentication)
 
+        [DEX Authentication](#DEX_Authentication)
+
 ---------------
 # What is DLAB? <a name="What_is_DLAB"></a>
 
@@ -2519,3 +2521,31 @@
 - **permissionScope** - describes Azure resource where user should have any role to pass authentication. If user has no role in resource IAM he/she will not be logged in  
 - **managementApiAuthFile** - authentication file that is used to query Microsoft Graph API to check user roles in resource described in permissionScope  
 
+## DEX Authentication <a name="DEX_Authentication"></a>
+DLab supports DEX authentication that is configured automatically in Security Service and Self Service after DLab is deployed.
+Dex is an identity service that uses OpenID Connect to drive authentication for other apps.
+Please see explanation details about configuration parameters for Self Service and Security Service below.
+To enable dex authentication in DLab: 
+1. Update *self-service.yml* configuration property **dexIdentityProviderEnabled**:
+
+       dexIdentityProviderEnabled: true
+2. Update *security.yml* configuration for dex:
+
+       dexConfiguration:
+         url: <DEX_URL>
+         clientId: <DEX_CLIENT_ID>
+         clientSecret: <DEX_CLIENT_SECRET>
+         redirectUri: <DEX_REDIRECT_URI>
+         authorizationPath: <DEX_AUTH_PATH>
+         scope: <DEX_SCOPES>
+where: 
+- **url** - url where dex is up and running (e.g. **http://34.221.245.73:5556/dex**)
+- **clientId** - application client id (should be taken from dex config)
+- **clientSecret** - client secret (should be taken from dex config)
+- **redirectUri** - callback entry point of the app
+- **authorizationPath** - dex authorization path. By default is **/auth**
+- **scope** - [open id connect scopes](https://github.com/dexidp/dex/blob/master/Documentation/custom-scopes-claims-clients.md). E.g. **openid+email+groups**
+
+__NOTE: dex configuration itself is out of scope of that documentation. You can read more about DEX itself under the following link:__ 
+https://github.com/dexidp/dex        
+    
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/ssn/scripts/configure_mongo.py b/infrastructure-provisioning/src/ssn/scripts/configure_mongo.py
index 7d4eb01..c7bdad6 100644
--- a/infrastructure-provisioning/src/ssn/scripts/configure_mongo.py
+++ b/infrastructure-provisioning/src/ssn/scripts/configure_mongo.py
@@ -86,7 +86,7 @@
             json_data = json.load(data)
         for i in json_data:
             client.dlabdb.roles.insert_one(i)
-        client.dlabdb.security.create_index("expireAt", expireAfterSeconds=7200)
+        client.dlabdb.security.create_index("lastAccess", expireAfterSeconds=7200)
         if add_2_yml_config(path,'security','authorization','enabled'):
             command = ['service', 'mongod', 'restart']
             subprocess.call(command, shell=False)
diff --git a/services/dlab-auth-common/src/main/java/com/epam/dlab/auth/UserInfo.java b/services/dlab-auth-common/src/main/java/com/epam/dlab/auth/UserInfo.java
index abd9eb9..5ecbc0e 100644
--- a/services/dlab-auth-common/src/main/java/com/epam/dlab/auth/UserInfo.java
+++ b/services/dlab-auth-common/src/main/java/com/epam/dlab/auth/UserInfo.java
@@ -1,20 +1,19 @@
 /***************************************************************************
 
-Copyright (c) 2016, EPAM SYSTEMS INC
+ Copyright (c) 2016, EPAM SYSTEMS INC
 
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
 
-    http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
 
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-****************************************************************************/
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ****************************************************************************/
 
 package com.epam.dlab.auth;
 
@@ -29,79 +28,80 @@
 @JsonIgnoreProperties(ignoreUnknown = true)
 public class UserInfo implements Principal {
 
-    private final String username;
-    private final String accessToken;
-    private final Set<String> roles = new HashSet<>();
-    private final Map<String,String> keys = new HashMap<>();
+	private final String username;
+	private final String accessToken;
+	private final Set<String> roles = new HashSet<>();
+	private final Map<String, String> keys = new HashMap<>();
+	private Date expireAt;
 
-    @JsonProperty
-    private String firstName;
-    @JsonProperty
-    private String lastName;
-    @JsonProperty
-    private String remoteIp;
-    @JsonProperty
-    private boolean awsUser = false;
+	@JsonProperty
+	private String firstName;
+	@JsonProperty
+	private String lastName;
+	@JsonProperty
+	private String remoteIp;
+	@JsonProperty
+	private boolean awsUser = false;
 
-    @JsonCreator
-    public UserInfo(@JsonProperty("username") String username,
-    				@JsonProperty("access_token") String accessToken) {
-        this.username = (username == null ? null : username.toLowerCase());
-        this.accessToken = accessToken;
-    }
+	@JsonCreator
+	public UserInfo(@JsonProperty("username") String username,
+					@JsonProperty("access_token") String accessToken) {
+		this.username = (username == null ? null : username.toLowerCase());
+		this.accessToken = accessToken;
+	}
 
-    @Override
-    @JsonProperty("username")
-    public String getName() {
-        return username;
-    }
+	@Override
+	@JsonProperty("username")
+	public String getName() {
+		return username;
+	}
 
-    public String getSimpleName() {
-        return (username == null ? null : username.replaceAll("@.*", ""));
-    }
+	public String getSimpleName() {
+		return (username == null ? null : username.replaceAll("@.*", ""));
+	}
 
-    @JsonProperty("access_token")
-    public String getAccessToken() {
-        return accessToken;
-    }
+	@JsonProperty("access_token")
+	public String getAccessToken() {
+		return accessToken;
+	}
 
-    @JsonProperty("roles")
-    public Collection<String> getRoles() {
-        return roles;
-    }
+	@JsonProperty("roles")
+	public Collection<String> getRoles() {
+		return roles;
+	}
 
-    //@JsonSetter("roles")
-    public void addRoles(Collection<String> r) {
-        roles.addAll(r);
-    }
+	//@JsonSetter("roles")
+	public void addRoles(Collection<String> r) {
+		roles.addAll(r);
+	}
 
-    @JsonSetter("roles")
-    public void addRoles(String[] r) {
-        roles.addAll(Arrays.asList(r));
-    }
+	@JsonSetter("roles")
+	public void addRoles(String[] r) {
+		roles.addAll(Arrays.asList(r));
+	}
 
-    public void addRole(String role) {
-        roles.add(role);
-    }
+	public void addRole(String role) {
+		roles.add(role);
+	}
 
 
-    public String getFirstName() {
-        return firstName;
-    }
+	public String getFirstName() {
+		return firstName;
+	}
 
-    public void setFirstName(String firstName) {
-        this.firstName = firstName;
-    }
+	public void setFirstName(String firstName) {
+		this.firstName = firstName;
+	}
 
-    public String getLastName() {
-        return lastName;
-    }
+	public String getLastName() {
+		return lastName;
+	}
 
-    public void setLastName(String lastName) {
-        this.lastName = lastName;
-    }
+	public void setLastName(String lastName) {
+		this.lastName = lastName;
+	}
 
-    public String getRemoteIp() {
+	public String getRemoteIp() {
 		return remoteIp;
 	}
 
@@ -110,79 +110,87 @@
 	}
 
 	public UserInfo withToken(String token) {
-        UserInfo newInfo  = new UserInfo(username, token);
-        roles.forEach(newInfo::addRole);
-        newInfo.firstName = this.firstName;
-        newInfo.lastName  = this.lastName;
-        newInfo.remoteIp  = this.remoteIp;
-        newInfo.awsUser   = this.awsUser;
-        newInfo.setKeys(this.getKeys());
-        return newInfo;
-    }
+		UserInfo newInfo = new UserInfo(username, token);
+		roles.forEach(newInfo::addRole);
+		newInfo.firstName = this.firstName;
+		newInfo.lastName = this.lastName;
+		newInfo.remoteIp = this.remoteIp;
+		newInfo.awsUser = this.awsUser;
+		newInfo.setKeys(this.getKeys());
+		return newInfo;
+	}
 
-    public boolean isAwsUser() {
-        return awsUser;
-    }
+	public boolean isAwsUser() {
+		return awsUser;
+	}
 
-    public void setAwsUser(boolean awsUser) {
-        this.awsUser = awsUser;
-    }
+	public void setAwsUser(boolean awsUser) {
+		this.awsUser = awsUser;
+	}
 
-    public Map<String, String> getKeys() {
-        return keys;
-    }
+	public Map<String, String> getKeys() {
+		return keys;
+	}
 
-    public void addKey(String id, String status) {
-        keys.put(id,status);
-    }
+	public void addKey(String id, String status) {
+		keys.put(id, status);
+	}
 
-    @JsonSetter("keys")
-    public void setKeys(Map<String,String> awsKeys) {
-        awsKeys.forEach(keys::put);
-    }
+	@JsonSetter("keys")
+	public void setKeys(Map<String, String> awsKeys) {
+		awsKeys.forEach(keys::put);
+	}
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
+	public Date getExpireAt() {
+		return expireAt;
+	}
 
-        UserInfo userInfo = (UserInfo) o;
+	public void setExpireAt(Date expireAt) {
+		this.expireAt = expireAt;
+	}
 
-        if (awsUser != userInfo.awsUser) return false;
-        if (username != null ? !username.equals(userInfo.username) : userInfo.username != null) return false;
-        if (accessToken != null ? !accessToken.equals(userInfo.accessToken) : userInfo.accessToken != null)
-            return false;
-        if (!roles.equals(userInfo.roles)) return false;
-        if (!keys.equals(userInfo.keys)) return false;
-        if (firstName != null ? !firstName.equals(userInfo.firstName) : userInfo.firstName != null) return false;
-        if (lastName != null ? !lastName.equals(userInfo.lastName) : userInfo.lastName != null) return false;
-        return remoteIp != null ? remoteIp.equals(userInfo.remoteIp) : userInfo.remoteIp == null;
+	@Override
+	public boolean equals(Object o) {
+		if (this == o) return true;
+		if (o == null || getClass() != o.getClass()) return false;
 
-    }
+		UserInfo userInfo = (UserInfo) o;
 
-    @Override
-    public int hashCode() {
-        return Objects.hash(username,
-                accessToken,
-                roles,
-                keys,
-                firstName,
-                lastName,
-                remoteIp,
-                awsUser);
-    }
+		if (awsUser != userInfo.awsUser) return false;
+		if (username != null ? !username.equals(userInfo.username) : userInfo.username != null) return false;
+		if (accessToken != null ? !accessToken.equals(userInfo.accessToken) : userInfo.accessToken != null)
+			return false;
+		if (!roles.equals(userInfo.roles)) return false;
+		if (!keys.equals(userInfo.keys)) return false;
+		if (firstName != null ? !firstName.equals(userInfo.firstName) : userInfo.firstName != null) return false;
+		if (lastName != null ? !lastName.equals(userInfo.lastName) : userInfo.lastName != null) return false;
+		return remoteIp != null ? remoteIp.equals(userInfo.remoteIp) : userInfo.remoteIp == null;
 
-    @Override
-    public String toString() {
-        return "UserInfo{" +
-                "username='" + username + '\'' +
-                ", accessToken='" + accessToken + '\'' +
-                ", roles=" + roles +
-                ", keys=" + keys.keySet() +
-                ", firstName='" + firstName + '\'' +
-                ", lastName='" + lastName + '\'' +
-                ", remoteIp='" + remoteIp + '\'' +
-                ", awsUser=" + awsUser +
-                '}';
-    }
+	}
+
+	@Override
+	public int hashCode() {
+		return Objects.hash(username,
+				accessToken,
+				roles,
+				keys,
+				firstName,
+				lastName,
+				remoteIp,
+				awsUser);
+	}
+
+	@Override
+	public String toString() {
+		return "UserInfo{" +
+				"username='" + username + '\'' +
+				", accessToken='" + accessToken + '\'' +
+				", roles=" + roles +
+				", keys=" + keys.keySet() +
+				", firstName='" + firstName + '\'' +
+				", lastName='" + lastName + '\'' +
+				", remoteIp='" + remoteIp + '\'' +
+				", awsUser=" + awsUser +
+				'}';
+	}
 }
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/auth/AuthorizationCodeFlowResponse.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/auth/AuthorizationCodeFlowResponse.java
similarity index 97%
rename from services/dlab-model/src/main/java/com/epam/dlab/dto/azure/auth/AuthorizationCodeFlowResponse.java
rename to services/dlab-model/src/main/java/com/epam/dlab/dto/auth/AuthorizationCodeFlowResponse.java
index 3725cde..644ba42 100644
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/azure/auth/AuthorizationCodeFlowResponse.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/auth/AuthorizationCodeFlowResponse.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.epam.dlab.dto.azure.auth;
+package com.epam.dlab.dto.auth;
 
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java
index 9b67a5e..51f3869 100644
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java
@@ -104,11 +104,6 @@
 			}
 
 			@Override
-			public <T> T get(String path, Class<T> clazz) {
-				throw new UnsupportedOperationException(OPERATION_IS_NOT_SUPPORTED);
-			}
-
-			@Override
 			public <T> T get(String path, String accessToken, Class<T> clazz) {
 				throw new UnsupportedOperationException(OPERATION_IS_NOT_SUPPORTED);
 			}
diff --git a/services/security-azure/src/main/java/com/epam/dlab/auth/azure/AuthorizationCodeSupplier.java b/services/security-azure/src/main/java/com/epam/dlab/auth/azure/AuthorizationCodeSupplier.java
index 709bb46..7d5aafc 100644
--- a/services/security-azure/src/main/java/com/epam/dlab/auth/azure/AuthorizationCodeSupplier.java
+++ b/services/security-azure/src/main/java/com/epam/dlab/auth/azure/AuthorizationCodeSupplier.java
@@ -17,7 +17,7 @@
 package com.epam.dlab.auth.azure;
 
 import com.epam.dlab.auth.conf.AzureLoginConfiguration;
-import com.epam.dlab.dto.azure.auth.AuthorizationCodeFlowResponse;
+import com.epam.dlab.dto.auth.AuthorizationCodeFlowResponse;
 import com.microsoft.aad.adal4j.AuthenticationContext;
 import com.microsoft.aad.adal4j.AuthenticationResult;
 
diff --git a/services/security-azure/src/main/java/com/epam/dlab/auth/azure/AzureAuthenticationResource.java b/services/security-azure/src/main/java/com/epam/dlab/auth/azure/AzureAuthenticationResource.java
index db58e07..2ac0f44 100644
--- a/services/security-azure/src/main/java/com/epam/dlab/auth/azure/AzureAuthenticationResource.java
+++ b/services/security-azure/src/main/java/com/epam/dlab/auth/azure/AzureAuthenticationResource.java
@@ -23,7 +23,7 @@
 import com.epam.dlab.auth.contract.SecurityAPI;
 import com.epam.dlab.auth.dto.UserCredentialDTO;
 import com.epam.dlab.auth.rest.AbstractAuthenticationService;
-import com.epam.dlab.dto.azure.auth.AuthorizationCodeFlowResponse;
+import com.epam.dlab.dto.auth.AuthorizationCodeFlowResponse;
 import com.epam.dlab.rest.dto.ErrorDTO;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
diff --git a/services/security-azure/src/main/java/com/epam/dlab/auth/azure/AzureSecurityResource.java b/services/security-azure/src/main/java/com/epam/dlab/auth/azure/AzureSecurityResource.java
index 1d25243..4192daa 100644
--- a/services/security-azure/src/main/java/com/epam/dlab/auth/azure/AzureSecurityResource.java
+++ b/services/security-azure/src/main/java/com/epam/dlab/auth/azure/AzureSecurityResource.java
@@ -18,7 +18,7 @@
 
 import com.epam.dlab.auth.azure.service.AzureAuthorizationCodeService;
 import com.epam.dlab.auth.conf.AzureLoginConfiguration;
-import com.epam.dlab.dto.azure.auth.AuthorizationCodeFlowResponse;
+import com.epam.dlab.dto.auth.AuthorizationCodeFlowResponse;
 import com.epam.dlab.exceptions.DlabAuthenticationException;
 import com.epam.dlab.rest.dto.ErrorDTO;
 import com.google.common.cache.Cache;
diff --git a/services/security-service/security.yml b/services/security-service/security.yml
index aa294e3..c37eec4 100644
--- a/services/security-service/security.yml
+++ b/services/security-service/security.yml
@@ -195,6 +195,13 @@
     applicationName: DLAB-webapp
 </#if>
 
+dexConfiguration:
+  url: <DEX_URL>
+  clientId: <DEX_CLIENT_ID>
+  clientSecret: <DEX_CLIENT_SECRET>
+  redirectUri: <DEX_REDIRECT_URI>
+  authorizationPath: <DEX_AUTH_PATH>
+  scope: <DEX_SCOPES>
 
 logging:
   level: INFO
diff --git a/services/security-service/src/main/java/com/epam/dlab/auth/SecurityServiceApplication.java b/services/security-service/src/main/java/com/epam/dlab/auth/SecurityServiceApplication.java
index f0f7fa1..35bd95c 100644
--- a/services/security-service/src/main/java/com/epam/dlab/auth/SecurityServiceApplication.java
+++ b/services/security-service/src/main/java/com/epam/dlab/auth/SecurityServiceApplication.java
@@ -13,13 +13,13 @@
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-
  ****************************************************************************/
 
 package com.epam.dlab.auth;
 
 import com.epam.dlab.auth.modules.ModuleFactory;
 import com.epam.dlab.auth.modules.SecurityServiceModule;
+import com.epam.dlab.auth.resources.DexOauthResource;
 import com.epam.dlab.cloud.CloudModule;
 import com.epam.dlab.rest.mappers.AuthenticationExceptionMapper;
 import com.epam.dlab.util.ServiceUtils;
@@ -59,6 +59,7 @@
 		CloudModule cloudModule = ModuleFactory.getCloudProviderModule(conf);
 		Injector injector = Guice.createInjector(new SecurityServiceModule(conf, env), cloudModule);
 		env.jersey().register(new AuthenticationExceptionMapper());
+		env.jersey().register(injector.getInstance(DexOauthResource.class));
 		cloudModule.init(env, injector);
 	}
 }
diff --git a/services/security-service/src/main/java/com/epam/dlab/auth/SecurityServiceConfiguration.java b/services/security-service/src/main/java/com/epam/dlab/auth/SecurityServiceConfiguration.java
index 5593978..3ced16e 100644
--- a/services/security-service/src/main/java/com/epam/dlab/auth/SecurityServiceConfiguration.java
+++ b/services/security-service/src/main/java/com/epam/dlab/auth/SecurityServiceConfiguration.java
@@ -20,6 +20,7 @@
 import com.epam.dlab.ServiceConfiguration;
 import com.epam.dlab.auth.conf.AzureLoginConfiguration;
 import com.epam.dlab.auth.dao.Request;
+import com.epam.dlab.auth.dex.DexConfiguration;
 import com.epam.dlab.config.gcp.GcpLoginConfiguration;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import org.apache.directory.ldap.client.api.LdapConnectionConfig;
@@ -55,6 +56,8 @@
 	private AzureLoginConfiguration azureLoginConfiguration;
 	@JsonProperty
 	private GcpLoginConfiguration gcpLoginConfiguration;
+	@JsonProperty
+	private DexConfiguration dexConfiguration;
 
 	private LdapConnectionConfig ldapConfiguration;
 
@@ -117,4 +120,8 @@
 	public GcpLoginConfiguration getGcpLoginConfiguration() {
 		return gcpLoginConfiguration;
 	}
+
+	public DexConfiguration getDexConfiguration() {
+		return dexConfiguration;
+	}
 }
diff --git a/services/security-service/src/main/java/com/epam/dlab/auth/dao/UserInfoDAOMongoImpl.java b/services/security-service/src/main/java/com/epam/dlab/auth/dao/UserInfoDAOMongoImpl.java
index 67b28ea..adfe979 100644
--- a/services/security-service/src/main/java/com/epam/dlab/auth/dao/UserInfoDAOMongoImpl.java
+++ b/services/security-service/src/main/java/com/epam/dlab/auth/dao/UserInfoDAOMongoImpl.java
@@ -13,7 +13,6 @@
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-
  ****************************************************************************/
 
 package com.epam.dlab.auth.dao;
@@ -35,6 +34,7 @@
 @Singleton
 @Slf4j
 public class UserInfoDAOMongoImpl implements UserInfoDAO {
+	private static final String LAST_ACCESS_FIELD = "lastAccess";
 	private final MongoService ms;
 	private final long inactiveUserTimeoutMsec;
 
@@ -55,14 +55,16 @@
 			log.warn("UI not found {}", accessToken);
 			return null;
 		}
-		Date lastAccess = uiDoc.getDate("expireAt");
-		if (inactiveUserTimeoutMsec < Math.abs(new Date().getTime() - lastAccess.getTime())) {
+		Date lastAccess = uiDoc.getDate(LAST_ACCESS_FIELD);
+		final Date expireAt = uiDoc.getDate("expireAt");
+		if ((inactiveUserTimeoutMsec < Math.abs(new Date().getTime() - lastAccess.getTime())) ||
+				(expireAt != null && new Date().after(expireAt))) {
 			log.warn("UI for {} expired but were not evicted from DB. Contact MongoDB admin to create expireable " +
-					"index" +
-					" on 'expireAt' key.", accessToken);
+					"index on 'lastAccess' key.", accessToken);
 			this.deleteUserInfo(accessToken);
 			return null;
 		}
+
 		String name = uiDoc.get("name").toString();
 		String firstName = uiDoc.getString("firstName", "");
 		String lastName = uiDoc.getString("lastName", "");
@@ -89,7 +91,7 @@
 
 		BasicDBObject uiDoc = new BasicDBObject();
 		uiDoc.put("_id", accessToken);
-		uiDoc.put("expireAt", new Date(System.currentTimeMillis()));
+		uiDoc.put(LAST_ACCESS_FIELD, new Date(System.currentTimeMillis()));
 		MongoCollection<BasicDBObject> security = ms.getCollection("security", BasicDBObject.class);
 		security.updateOne(new BasicDBObject("_id", accessToken), new BasicDBObject("$set", uiDoc));
 		log.debug("Updated persistent {}", accessToken);
@@ -119,8 +121,9 @@
 		uiDoc.put("roles", ui.getRoles());
 		uiDoc.put("remoteIp", ui.getRemoteIp());
 		uiDoc.put("awsUser", ui.isAwsUser());
-		uiDoc.put("expireAt", new Date(System.currentTimeMillis()));
+		uiDoc.put(LAST_ACCESS_FIELD, new Date(System.currentTimeMillis()));
 		uiDoc.put("awsKeys", ui.getKeys());
+		uiDoc.put("expireAt", ui.getExpireAt());
 		MongoCollection<BasicDBObject> security = ms.getCollection("security", BasicDBObject.class);
 		security.insertOne(uiDoc);
 		log.debug("Saved persistent {}", ui);
diff --git a/services/security-service/src/main/java/com/epam/dlab/auth/dex/DexConfiguration.java b/services/security-service/src/main/java/com/epam/dlab/auth/dex/DexConfiguration.java
new file mode 100644
index 0000000..3fe8323
--- /dev/null
+++ b/services/security-service/src/main/java/com/epam/dlab/auth/dex/DexConfiguration.java
@@ -0,0 +1,15 @@
+package com.epam.dlab.auth.dex;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class DexConfiguration {
+	private String url;
+	private String clientId;
+	private String clientSecret;
+	private String redirectUri;
+	private String authorizationPath;
+	private String scope;
+}
diff --git a/services/security-service/src/main/java/com/epam/dlab/auth/model/DexTokenResponse.java b/services/security-service/src/main/java/com/epam/dlab/auth/model/DexTokenResponse.java
new file mode 100644
index 0000000..9eff5de
--- /dev/null
+++ b/services/security-service/src/main/java/com/epam/dlab/auth/model/DexTokenResponse.java
@@ -0,0 +1,18 @@
+package com.epam.dlab.auth.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public class DexTokenResponse {
+	@JsonProperty("access_token")
+	private final String accessToken;
+	@JsonProperty("token_type")
+	private final String tokenType;
+	@JsonProperty("expires_in")
+	private final long exprires;
+	@JsonProperty("id_token")
+	private final String idToken;
+}
diff --git a/services/security-service/src/main/java/com/epam/dlab/auth/model/DexUser.java b/services/security-service/src/main/java/com/epam/dlab/auth/model/DexUser.java
new file mode 100644
index 0000000..b8001dd
--- /dev/null
+++ b/services/security-service/src/main/java/com/epam/dlab/auth/model/DexUser.java
@@ -0,0 +1,16 @@
+package com.epam.dlab.auth.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+
+@AllArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+@Getter
+public class DexUser {
+
+	private final String email;
+	private final List<String> groups;
+}
diff --git a/services/security-service/src/main/java/com/epam/dlab/auth/modules/SecurityServiceModule.java b/services/security-service/src/main/java/com/epam/dlab/auth/modules/SecurityServiceModule.java
index b2ba95d..a444625 100644
--- a/services/security-service/src/main/java/com/epam/dlab/auth/modules/SecurityServiceModule.java
+++ b/services/security-service/src/main/java/com/epam/dlab/auth/modules/SecurityServiceModule.java
@@ -23,15 +23,22 @@
 import com.epam.dlab.auth.dao.LdapUserDAO;
 import com.epam.dlab.auth.dao.UserInfoDAODumbImpl;
 import com.epam.dlab.auth.dao.UserInfoDAOMongoImpl;
+import com.epam.dlab.auth.service.DexOauthService;
+import com.epam.dlab.auth.service.DexOauthServiceImpl;
 import com.epam.dlab.mongo.MongoService;
 import com.google.inject.Provides;
 import com.google.inject.Singleton;
+import io.dropwizard.client.HttpClientBuilder;
+import io.dropwizard.client.HttpClientConfiguration;
 import io.dropwizard.setup.Environment;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.http.client.HttpClient;
 
 @Slf4j
 public class SecurityServiceModule extends ModuleBase<SecurityServiceConfiguration> {
 
+	private static final String REST_CLIENT = "restClient";
+
 	public SecurityServiceModule(SecurityServiceConfiguration configuration, Environment environment) {
 		super(configuration, environment);
 	}
@@ -39,6 +46,11 @@
 	@Override
 	protected void configure() {
 		bind(SecurityServiceConfiguration.class).toInstance(configuration);
+		bind(HttpClient.class).toInstance(
+				new HttpClientBuilder(environment)
+						.using(new HttpClientConfiguration())
+						.build(REST_CLIENT));
+		bind(DexOauthService.class).to(DexOauthServiceImpl.class);
 		if (configuration.isUserInfoPersistenceEnabled()) {
 			bind(UserInfoDAO.class).to(UserInfoDAOMongoImpl.class);
 		} else {
diff --git a/services/security-service/src/main/java/com/epam/dlab/auth/resources/DexOauthResource.java b/services/security-service/src/main/java/com/epam/dlab/auth/resources/DexOauthResource.java
new file mode 100644
index 0000000..52ccf32
--- /dev/null
+++ b/services/security-service/src/main/java/com/epam/dlab/auth/resources/DexOauthResource.java
@@ -0,0 +1,36 @@
+package com.epam.dlab.auth.resources;
+
+import com.epam.dlab.auth.service.DexOauthService;
+import com.google.inject.Inject;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("dex")
+public class DexOauthResource {
+
+	private final DexOauthService dexOauthService;
+
+	@Inject
+	public DexOauthResource(DexOauthService dexOauthService) {
+		this.dexOauthService = dexOauthService;
+	}
+
+	@GET
+	@Path("init")
+	public Response redirectUrl() {
+		return Response.ok(dexOauthService.getDexOauthUrl()).build();
+	}
+
+
+	@GET
+	@Path("user")
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response getUserInfo(@QueryParam("code") String code) {
+		return Response.ok(dexOauthService.getUserInfo(code)).build();
+	}
+}
diff --git a/services/security-service/src/main/java/com/epam/dlab/auth/service/DexOauthService.java b/services/security-service/src/main/java/com/epam/dlab/auth/service/DexOauthService.java
new file mode 100644
index 0000000..d2cf1f4
--- /dev/null
+++ b/services/security-service/src/main/java/com/epam/dlab/auth/service/DexOauthService.java
@@ -0,0 +1,10 @@
+package com.epam.dlab.auth.service;
+
+import com.epam.dlab.auth.UserInfo;
+
+public interface DexOauthService {
+
+	String getDexOauthUrl();
+
+	UserInfo getUserInfo(String authorizationCode);
+}
diff --git a/services/security-service/src/main/java/com/epam/dlab/auth/service/DexOauthServiceImpl.java b/services/security-service/src/main/java/com/epam/dlab/auth/service/DexOauthServiceImpl.java
new file mode 100644
index 0000000..ea2bec6
--- /dev/null
+++ b/services/security-service/src/main/java/com/epam/dlab/auth/service/DexOauthServiceImpl.java
@@ -0,0 +1,123 @@
+package com.epam.dlab.auth.service;
+
+import com.epam.dlab.auth.SecurityServiceConfiguration;
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.auth.UserInfoDAO;
+import com.epam.dlab.auth.dex.DexConfiguration;
+import com.epam.dlab.auth.model.DexTokenResponse;
+import com.epam.dlab.auth.model.DexUser;
+import com.epam.dlab.exceptions.DlabException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.http.Consts;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.message.BasicNameValuePair;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.Date;
+import java.util.UUID;
+
+import static java.lang.String.format;
+import static java.util.Arrays.asList;
+
+@Singleton
+@Slf4j
+public class DexOauthServiceImpl implements DexOauthService {
+
+	private static final String DEX_LOGIN_PAGE = "%s%s?&response_type=code&client_id=%s&client_secret=%s" +
+			"&redirect_uri=%s&scope=%s&state=%s";
+	private static final String TOKEN_URI_FORMAT = "%s/token?grant_type=authorization_code&code=%s&redirect_uri=%s";
+	private static final String BASIC_AUTHORIZATION_FORMAT = "Basic %s";
+	private static final String GRANT_TYPE = "grant_type";
+	private static final String CODE = "code";
+	private static final String REDIRECT_URI = "redirect_uri";
+	private static final String AUTHORIZATION_CODE_GRANT_TYPE = "authorization_code";
+	private final DexConfiguration config;
+	private final HttpClient client;
+	private final ObjectMapper mapper;
+	private final UserInfoDAO userInfoDAO;
+
+	@Inject
+	public DexOauthServiceImpl(SecurityServiceConfiguration configuration, HttpClient client, ObjectMapper mapper,
+							   UserInfoDAO userInfoDAO) {
+		this.config = configuration.getDexConfiguration();
+		this.client = client;
+		this.mapper = mapper;
+		this.userInfoDAO = userInfoDAO;
+	}
+
+	@Override
+	public String getDexOauthUrl() {
+		final String dexUrl = config.getUrl();
+		final String authorizationPath = config.getAuthorizationPath();
+		final String clientId = config.getClientId();
+		final String clientSecret = config.getClientSecret();
+		final String redirectUri = config.getRedirectUri();
+		final String scope = config.getScope();
+		final String state = UUID.randomUUID().toString();
+		return format(DEX_LOGIN_PAGE, dexUrl, authorizationPath, clientId, clientSecret, redirectUri, scope, state);
+	}
+
+	@Override
+	public UserInfo getUserInfo(String code) {
+		final DexTokenResponse tokenResponse = getToken(code);
+		final UserInfo userInfo = toUserInfo(tokenResponse.getIdToken(), tokenResponse.getExprires());
+		userInfoDAO.saveUserInfo(userInfo);
+		return userInfo;
+	}
+
+	private UserInfo toUserInfo(String idToken, long expiresAfter) {
+		try {
+			final String tokenPayload = new String(Base64.decodeBase64(idToken.split("\\.")[1]));
+			final DexUser dexUser = mapper.readValue(tokenPayload, DexUser.class);
+			final UserInfo userInfo = new UserInfo(dexUser.getEmail(), idToken);
+			if (dexUser.getGroups() != null) {
+				userInfo.addRoles(dexUser.getGroups());
+			}
+			final ZonedDateTime expirationDateTime =
+					LocalDateTime.now().plusSeconds(expiresAfter).atZone(ZoneId.systemDefault());
+			userInfo.setExpireAt(Date.from(expirationDateTime.toInstant()));
+			return userInfo;
+		} catch (IOException e) {
+			log.error("Can not extract user information due to: {}", e.getMessage());
+			throw new DlabException("Can not extract user information due to: " + e.getMessage());
+		}
+	}
+
+	private DexTokenResponse getToken(String code) {
+		try {
+			final String uri = format(TOKEN_URI_FORMAT, config.getUrl(), code, config.getRedirectUri());
+			final HttpPost tokenRequest = new HttpPost(uri);
+			tokenRequest.addHeader(HttpHeaders.AUTHORIZATION, format(BASIC_AUTHORIZATION_FORMAT, encodedAuthString()));
+			tokenRequest.setEntity(getAccessTokenRequestBody(code));
+			final HttpResponse tokenResponse = client.execute(tokenRequest);
+			return mapper.readValue(tokenResponse.getEntity().getContent(), DexTokenResponse.class);
+		} catch (IOException e) {
+			log.error("Can not get access token due to: {}", e.getMessage());
+			throw new DlabException("Can not get access token due to: " + e.getMessage());
+		}
+	}
+
+	private UrlEncodedFormEntity getAccessTokenRequestBody(String code) {
+
+		return new UrlEncodedFormEntity(asList(
+				new BasicNameValuePair(GRANT_TYPE, AUTHORIZATION_CODE_GRANT_TYPE),
+				new BasicNameValuePair(CODE, code),
+				new BasicNameValuePair(REDIRECT_URI, config.getRedirectUri())
+		), Consts.UTF_8);
+	}
+
+	private String encodedAuthString() {
+		return Base64.encodeBase64String(String.join(":", config.getClientId(), config.getClientSecret()).getBytes());
+	}
+}
diff --git a/services/self-service/self-service.yml b/services/self-service/self-service.yml
index b81293a..6259c4e 100644
--- a/services/self-service/self-service.yml
+++ b/services/self-service/self-service.yml
@@ -131,6 +131,8 @@
     timeout: 5s
     connectionTimeout: 5s
 
+dexIdentityProviderEnabled: false
+
 schedulers:
   inactivity:
     enabled: false
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplicationConfiguration.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplicationConfiguration.java
index c5b30ed..22eeb0b 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplicationConfiguration.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplicationConfiguration.java
@@ -104,6 +104,8 @@
 	private int privateKeySize = 2048;
 	@JsonProperty
 	private SwaggerBundleConfiguration swaggerConfiguration;
+	@JsonProperty
+	private boolean dexIdentityProviderEnabled;
 
 	@Valid
 	@NotNull
@@ -239,4 +241,8 @@
 	public RESTServiceFactory getMavenApiFactory() {
 		return mavenApiFactory;
 	}
+
+	public boolean isDexIdentityProviderEnabled() {
+		return dexIdentityProviderEnabled;
+	}
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/AwsSelfServiceModule.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/AwsSelfServiceModule.java
index ab4a84e..71ef19a 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/AwsSelfServiceModule.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/AwsSelfServiceModule.java
@@ -25,6 +25,7 @@
 import com.epam.dlab.backendapi.dao.KeyDAO;
 import com.epam.dlab.backendapi.dao.aws.AwsBillingDAO;
 import com.epam.dlab.backendapi.dao.aws.AwsKeyDao;
+import com.epam.dlab.backendapi.resources.DexOauthResource;
 import com.epam.dlab.backendapi.interceptor.BudgetLimitInterceptor;
 import com.epam.dlab.backendapi.resources.aws.BillingResourceAws;
 import com.epam.dlab.backendapi.resources.aws.ComputationalResourceAws;
@@ -57,6 +58,12 @@
 	private static final String QUARTZ_MONGO_URI_PROPERTY = "org.quartz.jobStore.mongoUri";
 	private static final String QUARTZ_DB_NAME = "org.quartz.jobStore.dbName";
 
+	private final boolean useDex;
+
+	public AwsSelfServiceModule(boolean useDex) {
+		this.useDex = useDex;
+	}
+
 	@Override
 	protected void configure() {
 		bind(BillingService.class).to(AwsBillingService.class);
@@ -80,6 +87,9 @@
 
 		injector.getInstance(SecurityFactory.class).configure(injector, environment,
 				SelfServiceSecurityAuthenticator.class, injector.getInstance(Authorizer.class));
+		if (useDex) {
+			environment.jersey().register(injector.getInstance(DexOauthResource.class));
+		}
 	}
 
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/AzureSelfServiceModule.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/AzureSelfServiceModule.java
index 18d9f77..aa1187b 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/AzureSelfServiceModule.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/AzureSelfServiceModule.java
@@ -26,6 +26,7 @@
 import com.epam.dlab.backendapi.dao.KeyDAO;
 import com.epam.dlab.backendapi.dao.azure.AzureBillingDAO;
 import com.epam.dlab.backendapi.dao.azure.AzureKeyDao;
+import com.epam.dlab.backendapi.resources.DexOauthResource;
 import com.epam.dlab.backendapi.interceptor.BudgetLimitInterceptor;
 import com.epam.dlab.backendapi.resources.SecurityResource;
 import com.epam.dlab.backendapi.resources.azure.AzureOauthResource;
@@ -63,10 +64,12 @@
 	private static final String QUARTZ_DB_NAME = "org.quartz.jobStore.dbName";
 	private boolean useLdap;
 	private long maxSessionDurabilityMilliseconds;
+	private final boolean useDex;
 
-	public AzureSelfServiceModule(boolean useLdap, long maxSessionDurabilityMilliseconds) {
+	public AzureSelfServiceModule(boolean useLdap, long maxSessionDurabilityMilliseconds, boolean useDex) {
 		this.useLdap = useLdap;
 		this.maxSessionDurabilityMilliseconds = maxSessionDurabilityMilliseconds;
+		this.useDex = useDex;
 	}
 
 	@Override
@@ -101,7 +104,9 @@
 
 		injector.getInstance(SecurityFactory.class).configure(injector, environment,
 				SelfServiceSecurityAuthenticator.class, injector.getInstance(Authorizer.class));
-
+		if (useDex) {
+			environment.jersey().register(injector.getInstance(DexOauthResource.class));
+		}
 	}
 
 	@Provides
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
index 8b52e2b..6a45879 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
@@ -38,6 +38,7 @@
 
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import java.util.Map;
 
 /**
  * Mock class for an application configuration of SelfService for developer mode.
@@ -57,6 +58,7 @@
 	 */
 	DevModule(SelfServiceApplicationConfiguration configuration, Environment environment) {
 		super(configuration, environment);
+
 	}
 
 	@Override
@@ -140,11 +142,6 @@
 			}
 
 			@Override
-			public <T> T get(String path, Class<T> clazz) {
-				throw new UnsupportedOperationException(OPERATION_IS_NOT_SUPPORTED);
-			}
-
-			@Override
 			public <T> T get(String path, String accessToken, Class<T> clazz) {
 				throw new UnsupportedOperationException(OPERATION_IS_NOT_SUPPORTED);
 			}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/GcpSelfServiceModule.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/GcpSelfServiceModule.java
index 03aee60..1629bf0 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/GcpSelfServiceModule.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/GcpSelfServiceModule.java
@@ -24,6 +24,7 @@
 import com.epam.dlab.backendapi.dao.KeyDAO;
 import com.epam.dlab.backendapi.dao.gcp.GcpBillingDao;
 import com.epam.dlab.backendapi.dao.gcp.GcpKeyDao;
+import com.epam.dlab.backendapi.resources.DexOauthResource;
 import com.epam.dlab.backendapi.resources.callback.gcp.EdgeCallbackGcp;
 import com.epam.dlab.backendapi.resources.callback.gcp.KeyUploaderCallbackGcp;
 import com.epam.dlab.backendapi.resources.gcp.ComputationalResourceGcp;
@@ -50,6 +51,12 @@
 	private static final String QUARTZ_MONGO_URI_PROPERTY = "org.quartz.jobStore.mongoUri";
 	private static final String QUARTZ_DB_NAME = "org.quartz.jobStore.dbName";
 
+	private final boolean useDex;
+
+	public GcpSelfServiceModule(boolean useDex) {
+		this.useDex = useDex;
+	}
+
 	@Override
 	@SuppressWarnings("unchecked")
 	public void init(Environment environment, Injector injector) {
@@ -62,6 +69,9 @@
 		}
 		injector.getInstance(SecurityFactory.class).configure(injector, environment,
 				SelfServiceSecurityAuthenticator.class, injector.getInstance(Authorizer.class));
+		if (useDex) {
+			environment.jersey().register(injector.getInstance(DexOauthResource.class));
+		}
 
 	}
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ModuleFactory.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ModuleFactory.java
index 9b688ed..bafb4bc 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ModuleFactory.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ModuleFactory.java
@@ -47,12 +47,12 @@
 	public static CloudModule getCloudProviderModule(SelfServiceApplicationConfiguration configuration) {
 		switch (configuration.getCloudProvider()) {
 			case AWS:
-				return new AwsSelfServiceModule();
+				return new AwsSelfServiceModule(configuration.isDexIdentityProviderEnabled());
 			case AZURE:
 				return new AzureSelfServiceModule(configuration.isAzureUseLdap(),
-						configuration.getMaxSessionDurabilityMilliseconds());
+						configuration.getMaxSessionDurabilityMilliseconds(), configuration.isDexIdentityProviderEnabled());
 			case GCP:
-				return new GcpSelfServiceModule();
+				return new GcpSelfServiceModule(configuration.isDexIdentityProviderEnabled());
 			default:
 				throw new UnsupportedOperationException("Unsupported cloud provider " + configuration.getCloudProvider());
 		}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/DexOauthResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/DexOauthResource.java
new file mode 100644
index 0000000..3516d15
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/DexOauthResource.java
@@ -0,0 +1,41 @@
+package com.epam.dlab.backendapi.resources;
+
+import com.epam.dlab.constants.ServiceConsts;
+import com.epam.dlab.dto.auth.AuthorizationCodeFlowResponse;
+import com.epam.dlab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.net.URI;
+import java.util.Collections;
+import java.util.Map;
+
+@Path("dex")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class DexOauthResource {
+
+	private static final String CODE = "code";
+	@Inject
+	@Named(ServiceConsts.SECURITY_SERVICE_NAME)
+	private RESTService securityService;
+
+
+	@GET
+	@Path("/init")
+	public Response redirectedUrl() {
+		return Response.seeOther(URI.create(securityService.get("/dex/init", String.class)))
+				.build();
+	}
+
+	@POST
+	@Path("/oauth")
+	public Response login(AuthorizationCodeFlowResponse codeFlowResponse) {
+		final Map<String, Object> params = Collections.singletonMap(CODE, codeFlowResponse.getCode());
+		return securityService.get("/dex/user", params, Response.class);
+	}
+
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/AzureOauthResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/AzureOauthResource.java
index 96bd680..637188a 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/AzureOauthResource.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/AzureOauthResource.java
@@ -18,7 +18,7 @@
 package com.epam.dlab.backendapi.resources.azure;
 
 import com.epam.dlab.constants.ServiceConsts;
-import com.epam.dlab.dto.azure.auth.AuthorizationCodeFlowResponse;
+import com.epam.dlab.dto.auth.AuthorizationCodeFlowResponse;
 import com.epam.dlab.rest.client.RESTService;
 import com.epam.dlab.auth.contract.SecurityAPI;
 import com.google.inject.Inject;
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/appRouting.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/appRouting.service.ts
index a458e91..53ded6d 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/appRouting.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/appRouting.service.ts
@@ -43,4 +43,8 @@
   redirectToAzure(): void {
     window.location.href =  `${ window.location.origin }/api/user/azure/init`;
   }
+
+  redirectToDex(): void {
+    window.location.href =  `${ window.location.origin }/api/dex/init`;
+  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
index 8b6167d..78a55a8 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
@@ -29,6 +29,7 @@
   private static readonly LOGOUT = 'logout';
   private static readonly AUTHORIZE = 'authorize';
   private static readonly OAUTH = 'oauth';
+  private static readonly DEX = 'dex';
   private static readonly ACCESS_KEY = 'access_key';
   private static readonly ACTIVE_LIST = 'active_list';
   private static readonly FULL_ACTIVE_LIST = 'full_active_list';
@@ -94,7 +95,7 @@
 
   public buildGetAuthToken(body: any): Observable<Response> {
     return this.buildRequest(RequestMethod.Post,
-      this.requestRegistry.Item(ApplicationServiceFacade.OAUTH),
+      this.requestRegistry.Item(ApplicationServiceFacade.DEX),
       body,
       this.getRequestOptions(true, true));
   }
@@ -543,7 +544,8 @@
     this.requestRegistry.Add(ApplicationServiceFacade.FULL_ACTIVE_LIST, '/api/environment/all');
     this.requestRegistry.Add(ApplicationServiceFacade.ENV, '/api/environment');
 
-    this.requestRegistry.Add(ApplicationServiceFacade.OAUTH, '/api/user/azure/oauth');
+    this.requestRegistry.Add(ApplicationServiceFacade.OAUTH, '/api/dex/oauth');
+    this.requestRegistry.Add(ApplicationServiceFacade.DEX, '/api/dex/oauth');
     this.requestRegistry.Add(ApplicationServiceFacade.ACCESS_KEY, '/api/user/access_key');
     this.requestRegistry.Add(ApplicationServiceFacade.ACCESS_KEY_GENERATE, '/api/user/access_key/generate');
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/login/login.component.html b/services/self-service/src/main/resources/webapp/src/app/login/login.component.html
index 247f250..70df2d6 100644
--- a/services/self-service/src/main/resources/webapp/src/app/login/login.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/login/login.component.html
@@ -21,7 +21,7 @@
     <a class="logo">
       <img src="assets/img/logo.png" alt="">
     </a>
-    <form name="form" class="form-wrap" #f="ngForm" novalidate>
+    <form name="form" *ngIf="!DICTIONARY.dexIdentityProviderEnabled" class="form-wrap" #f="ngForm" novalidate>
 
       <div class="input-icon-group">
         <span class="input-icon"><span class="login-icon icon-username"></span></span>
@@ -55,6 +55,9 @@
           Login with Azure
         </button>
       </div>
-  </form>
+    </form>
+    <div class="text-center" *ngIf="DICTIONARY.dexIdentityProviderEnabled">
+      <button class="butt butt-login" mat-raised-button (click)="loginWithDex_btnClick();">Login with DEX</button>
+    </div>
   </div>
 </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/login/login.component.ts b/services/self-service/src/main/resources/webapp/src/app/login/login.component.ts
index c5b83d6..de644a4 100644
--- a/services/self-service/src/main/resources/webapp/src/app/login/login.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/login/login.component.ts
@@ -89,6 +89,11 @@
     this.appRoutingService.redirectToAzure();
   }
 
+  loginWithDex_btnClick() {
+    console.log('DEX');
+    this.appRoutingService.redirectToDex();
+  }
+
   checkHealthStatusAndRedirect(isLoggedIn) {
     this.healthStatusService.isHealthStatusOk()
       .subscribe(isHealthStatusOk => {
diff --git a/services/self-service/src/main/resources/webapp/src/dictionary/aws.dictionary.ts b/services/self-service/src/main/resources/webapp/src/dictionary/aws.dictionary.ts
index 3a8f568..bc2728e 100644
--- a/services/self-service/src/main/resources/webapp/src/dictionary/aws.dictionary.ts
+++ b/services/self-service/src/main/resources/webapp/src/dictionary/aws.dictionary.ts
@@ -19,6 +19,7 @@
 export const NAMING_CONVENTION = {
     'cloud_provider': 'aws',
     'use_ldap': true,
+    'dexIdentityProviderEnabled': false,
     'notebook_instance_size': 'Instance shape',
     'personal_storage': 'Data bucket',
     'collaboration_storage': 'Collaboration bucket',
diff --git a/services/self-service/src/main/resources/webapp/src/dictionary/azure.dictionary.ts b/services/self-service/src/main/resources/webapp/src/dictionary/azure.dictionary.ts
index f040e97..5e79685 100644
--- a/services/self-service/src/main/resources/webapp/src/dictionary/azure.dictionary.ts
+++ b/services/self-service/src/main/resources/webapp/src/dictionary/azure.dictionary.ts
@@ -19,6 +19,7 @@
 export const NAMING_CONVENTION = {
     'cloud_provider': 'azure',
     'use_ldap': true,
+    'dexIdentityProviderEnabled': false,
     'notebook_instance_size': 'Virtual machine size',
     'personal_storage': 'Personal storage',
     'collaboration_storage': 'Collaboration storage',
diff --git a/services/self-service/src/main/resources/webapp/src/dictionary/gcp.dictionary.ts b/services/self-service/src/main/resources/webapp/src/dictionary/gcp.dictionary.ts
index 7c7f10d..d1ff5a8 100644
--- a/services/self-service/src/main/resources/webapp/src/dictionary/gcp.dictionary.ts
+++ b/services/self-service/src/main/resources/webapp/src/dictionary/gcp.dictionary.ts
@@ -19,6 +19,7 @@
 export const NAMING_CONVENTION = {
   'cloud_provider': 'gcp',
   'use_ldap': true,
+  'dexIdentityProviderEnabled': false,
   'notebook_instance_size': 'Instance type',
   'personal_storage': 'Data bucket',
   'collaboration_storage': 'Collaboration bucket',