diff --git a/ad-connector/src/main/java/net/jami/jams/ad/connector/ADConnector.java b/ad-connector/src/main/java/net/jami/jams/ad/connector/ADConnector.java
index 2415b1cd1e21711615fd85c9a7b5407768f50cce..10485f16f577c465c71eec7d2873a987dc0c4f7b 100644
--- a/ad-connector/src/main/java/net/jami/jams/ad/connector/ADConnector.java
+++ b/ad-connector/src/main/java/net/jami/jams/ad/connector/ADConnector.java
@@ -95,6 +95,11 @@ public class ADConnector implements AuthenticationSource {
         return userProfileService.getUserProfile(queryString,field);
     }
 
+    @Override
+    public void setUserProfile(UserProfile userProfile) {
+        //does nothing as we cannot edit user profiles.
+    }
+
     @Override
     public boolean authenticate(String username, String password) {
         try {
diff --git a/api-doc/reference/Admin-API.v1.yaml b/api-doc/reference/Admin-API.v1.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9bb56b5ccde62a74c396cf6fb69d34c4e55f5328
--- /dev/null
+++ b/api-doc/reference/Admin-API.v1.yaml
@@ -0,0 +1,166 @@
+openapi: 3.0.0
+info:
+  title: Administration API
+  version: '1.0'
+  description: "This API is used to provide admin functions which are broader than the user's API and allow modifying users which are not oneself."
+servers:
+  - url: 'http://localhost:8080'
+paths:
+  /api/admin/device:
+    get:
+      summary: User device
+      tags: []
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Device'
+      operationId: get-api-admin-device
+      requestBody:
+        description: ''
+      parameters:
+        - schema:
+            type: string
+          in: query
+          name: username
+        - schema:
+            type: string
+          in: query
+          name: deviceId
+      description: Returns the device information.
+    put:
+      summary: ''
+      operationId: put-api-admin-device
+      responses:
+        '200':
+          description: OK
+    delete:
+      summary: ''
+      operationId: delete-api-admin-device
+      responses:
+        '200':
+          description: OK
+      parameters:
+        - schema:
+            type: string
+          in: query
+          name: username
+        - schema:
+            type: string
+          in: query
+          name: deviceId
+      description: Revokes a device.
+  /api/admin/devices:
+    get:
+      summary: User devices
+      tags: []
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/Device'
+      operationId: get-api-admin-devices
+      parameters:
+        - schema:
+            type: string
+          in: query
+          name: username
+  /api/admin/directory/entry:
+    get:
+      summary: Your GET endpoint
+      tags: []
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/UserProfile'
+      operationId: get-api-admin-directory-entry
+      description: ''
+    put:
+      summary: ''
+      operationId: put-api-admin-directory-entry
+      responses:
+        '200':
+          description: OK
+    post:
+      summary: ''
+      operationId: post-api-admin-directory-entry
+      responses:
+        '200':
+          description: OK
+  /api/admin/user:
+    get:
+      summary: Your GET endpoint
+      tags: []
+      responses: {}
+      operationId: get-api-admin-user
+    post:
+      summary: ''
+      operationId: post-api-admin-user
+      responses:
+        '200':
+          description: OK
+    delete:
+      summary: ''
+      operationId: delete-api-admin-user
+      responses:
+        '200':
+          description: OK
+    put:
+      summary: ''
+      operationId: put-api-admin-user
+      responses:
+        '200':
+          description: OK
+  /api/admin/users:
+    get:
+      summary: Your GET endpoint
+      tags: []
+      responses: {}
+      operationId: get-api-admin-users
+components:
+  schemas:
+    Device:
+      title: Device
+      type: object
+      properties:
+        deviceId:
+          type: string
+        displayName:
+          type: string
+        certificate:
+          type: string
+      description: "The user's Jami device."
+    UserProfile:
+      title: UserProfile
+      type: object
+      properties:
+        username:
+          type: string
+        firstName:
+          type: string
+        lastName:
+          type: string
+        phoneNumber:
+          type: string
+        phoneNumberExtension:
+          type: string
+        mobileNumber:
+          type: string
+        faxNumber:
+          type: string
+        profilePicture:
+          type: string
+        email:
+          type: string
+        organization:
+          type: string
+      description: "The user's extended information which is not critical to Jami operations, usually provided by LDAP, Active Directory or other backend."
diff --git a/api-doc/reference/Install-API.v1.yaml b/api-doc/reference/Install-API.v1.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..03b15027dd565d4523768b30618c33b3af4fbcc2
--- /dev/null
+++ b/api-doc/reference/Install-API.v1.yaml
@@ -0,0 +1,38 @@
+openapi: 3.0.0
+info:
+  title: Install API
+  version: '1.0'
+  description: This API is used by the Web-UI installer in order to get JAMS up and running.
+servers:
+  - url: 'http://localhost:3000'
+paths:
+  /api/install/auth:
+    post:
+      summary: ''
+      operationId: post-api-install-auth
+      responses:
+        '200':
+          description: OK
+  /api/install/ca:
+    post:
+      summary: ''
+      operationId: post-api-install-ca
+      responses:
+        '200':
+          description: OK
+  /api/install/settings:
+    post:
+      summary: ''
+      operationId: post-api-install-settings
+      responses:
+        '200':
+          description: OK
+  /api/install/start:
+    post:
+      summary: ''
+      operationId: post-api-install-start
+      responses:
+        '200':
+          description: OK
+components:
+  schemas: {}
diff --git a/api-doc/reference/Nameserver-API.v1.yaml b/api-doc/reference/Nameserver-API.v1.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..baec648acd279ccffc6982dde2375a150fde71fa
--- /dev/null
+++ b/api-doc/reference/Nameserver-API.v1.yaml
@@ -0,0 +1,36 @@
+openapi: 3.0.0
+info:
+  title: Nameserver API
+  version: '1.0'
+  description: This is the Jami-compatible implementation of the nameserver.
+servers:
+  - url: 'http://localhost:8080'
+paths:
+  '/api/nameserver/addr/{addr}':
+    parameters:
+      - schema:
+          type: string
+        name: addr
+        in: path
+        required: true
+    get:
+      summary: Address lookup
+      tags: []
+      responses: {}
+      operationId: get-api-nameserver-addr-addr
+  '/api/nameserver/name/{name}':
+    parameters:
+      - schema:
+          type: string
+        name: name
+        in: path
+        required: true
+    get:
+      summary: Name lookup
+      tags: []
+      responses:
+        '200':
+          description: OK
+      operationId: get-api-nameserver-name-name
+components:
+  schemas: {}
diff --git a/api-doc/reference/Security-API.v1.yaml b/api-doc/reference/Security-API.v1.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..05e04371a9b6cb270e7d0e9da2c43d8a9f947117
--- /dev/null
+++ b/api-doc/reference/Security-API.v1.yaml
@@ -0,0 +1,16 @@
+openapi: 3.0.0
+info:
+  title: Security API
+  version: '1.0'
+servers:
+  - url: 'http://localhost:8080'
+paths:
+  /api/auth/login:
+    post:
+      summary: Login and Receive Auth Token
+      operationId: post-api-auth-login
+      responses:
+        '200':
+          description: OK
+components:
+  schemas: {}
diff --git a/api-doc/reference/User-API.v1.yaml b/api-doc/reference/User-API.v1.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..07b6a4c77b933afdd75ed1daade127caaaa78e9d
--- /dev/null
+++ b/api-doc/reference/User-API.v1.yaml
@@ -0,0 +1,113 @@
+openapi: 3.0.0
+info:
+  title: User API
+  version: '1.0'
+servers:
+  - url: 'http://localhost:8080'
+paths:
+  /api/auth/contacts:
+    get:
+      summary: Contacts endpoint
+      tags: []
+      responses: {}
+      operationId: get-api-auth-contacts
+  '/api/auth/device/{deviceId}':
+    parameters:
+      - schema:
+          type: string
+        name: deviceId
+        in: path
+        required: true
+    get:
+      summary: Device operations
+      tags: []
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: './Admin-API.v1.yaml#/components/schemas/Device'
+      operationId: get-api-auth-device-deviceId
+    put:
+      summary: ''
+      operationId: put-api-auth-device-deviceId
+      responses:
+        '200':
+          description: OK
+    post:
+      summary: ''
+      operationId: post-api-auth-device-deviceId
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                allOf: []
+  /api/auth/devices:
+    get:
+      summary: Get the list of devices
+      tags: []
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: './Admin-API.v1.yaml#/components/schemas/Device'
+      operationId: get-api-auth-devices
+  /api/auth/directories:
+    get:
+      summary: Get the directories connect to JAMS
+      tags: []
+      responses: {}
+      operationId: get-api-auth-directories
+  /api/auth/directory/entry:
+    get:
+      summary: Get the profile of a user
+      tags: []
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: './Admin-API.v1.yaml#/components/schemas/UserProfile'
+      operationId: get-api-auth-directory-entry
+  /api/auth/directory/search:
+    get:
+      summary: Search the directory
+      tags: []
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: './Admin-API.v1.yaml#/components/schemas/UserProfile'
+        '':
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: './Admin-API.v1.yaml#/components/schemas/UserProfile'
+      operationId: get-api-auth-directory-search
+  /api/auth/user:
+    get:
+      summary: User endpoint
+      tags: []
+      responses: {}
+      operationId: get-api-auth-user
+components:
+  schemas: {}
+  securitySchemes:
+    API Key - 1:
+      name: API Key
+      type: apiKey
+      in: query
diff --git a/authentication-module/src/main/java/net/jami/jams/authmodule/RegisterUserFlow.java b/authentication-module/src/main/java/net/jami/jams/authmodule/RegisterUserFlow.java
index 6e38a49a91a421f99c5397968e5f0912c50e0fae..1efd2de164e6f128adbbd6ca38ebef5bd461e474 100644
--- a/authentication-module/src/main/java/net/jami/jams/authmodule/RegisterUserFlow.java
+++ b/authentication-module/src/main/java/net/jami/jams/authmodule/RegisterUserFlow.java
@@ -59,7 +59,7 @@ public class RegisterUserFlow {
            return false;
         }
         datastore.getUserDao().storeObject(user);
-        log.info("Create the user " + user.getUsername() + " because he did not exist before!");
+        log.info("Created the user " + user.getUsername() + " because he did not exist before!");
         return true;
     }
 }
diff --git a/authentication-module/src/main/java/net/jami/jams/authmodule/UserAuthenticationModule.java b/authentication-module/src/main/java/net/jami/jams/authmodule/UserAuthenticationModule.java
index cf0f51959f8b982fe27e68b91fd6282e2b4f8605..edf450716dc377e0950719fd2aa220bd181ccf5f 100644
--- a/authentication-module/src/main/java/net/jami/jams/authmodule/UserAuthenticationModule.java
+++ b/authentication-module/src/main/java/net/jami/jams/authmodule/UserAuthenticationModule.java
@@ -45,7 +45,6 @@ import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.cert.X509Certificate;
 import java.security.interfaces.RSAPublicKey;
-import java.util.HashMap;
 import java.util.concurrent.ConcurrentHashMap;
 
 
@@ -148,6 +147,7 @@ public class UserAuthenticationModule implements AuthenticationModule {
                 user.setAccessLevel(AccessLevel.USER);
                 user.setRealm(key.getRealm());
                 user.setUserType(key.getType());
+                //This is legal with a null ONLY because in this case there is no relation with a external server.
                 RegisterUserFlow.createUser(user,null);
                 return tokenController.getToken(user);
             }
@@ -194,4 +194,18 @@ public class UserAuthenticationModule implements AuthenticationModule {
         return (RSAPublicKey) publicKey;
     }
 
+    @Override
+    public char[] getOTP(String username) {
+
+        if(datastore.userExists(username)){
+            StatementList statementList = new StatementList();
+            StatementElement statementElement = new StatementElement("username","=",username,"");
+            statementList.addStatement(statementElement);
+            User user = datastore.getUserDao().getObjects(statementList).get(0);
+            return (user.getPassword()).toCharArray();
+        }
+
+        return new char[0];
+    }
+
 }
diff --git a/datastore/src/main/java/net/jami/datastore/dao/AbstractDao.java b/datastore/src/main/java/net/jami/datastore/dao/AbstractDao.java
index 7d708494b6a4b3d017d7a1e1896ae6ba4dd4e347..ffbca27b868807ce98d7fc2ef74ebb7ab41c2904 100644
--- a/datastore/src/main/java/net/jami/datastore/dao/AbstractDao.java
+++ b/datastore/src/main/java/net/jami/datastore/dao/AbstractDao.java
@@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
 import net.jami.datastore.main.DataStore;
 import net.jami.jams.common.dao.SelectStatementBuilder;
 import net.jami.jams.common.dao.StatementList;
+import net.jami.jams.common.dao.UpdateStatementBuilder;
 import net.jami.jams.common.dao.connectivity.SQLConnection;
 
 import java.sql.PreparedStatement;
@@ -44,11 +45,14 @@ public abstract class AbstractDao<T> {
     @Getter @Setter
     private Class<T> tClass;
 
+    public abstract boolean storeObject(T object);
+    public abstract boolean deleteObject(LinkedHashMap<String,String> constraints);
+
     public List<T> getObjects(StatementList constraints){
         List<T> result = new ArrayList<>();
         SQLConnection connection = DataStore.connectionPool.getConnection();
         try{
-            PreparedStatement ps = SelectStatementBuilder.buildStatement(tableName,constraints.getStatements(),connection);
+            PreparedStatement ps = SelectStatementBuilder.buildStatement(tableName,constraints,connection);
             ResultSet rs = ps.executeQuery();
             while(rs.next()){
                 result.add(tClass.getConstructor(ResultSet.class).newInstance(rs));
@@ -64,7 +68,18 @@ public abstract class AbstractDao<T> {
         }
     }
 
-
-    public abstract boolean storeObject(T object);
-    public abstract boolean deleteObject(LinkedHashMap<String,String> constraints);
+    public boolean updateObject(StatementList update, StatementList constraints){
+        SQLConnection connection = DataStore.connectionPool.getConnection();
+        try{
+            PreparedStatement ps = UpdateStatementBuilder.buildStatement(tableName,update,constraints,connection);
+            return ps.execute();
+        }
+        catch (Exception e){
+            log.error("An error has occurred while trying to fetch a device: " + e.toString());
+            return false;
+        }
+        finally {
+            DataStore.connectionPool.returnConnection(connection);
+        }
+    }
 }
diff --git a/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java b/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java
index b6c67e68cfd74e5890760cb7d4caa7fa36a6c1f5..1e33d86b870963fd13319a7f4ef1047d97fceb23 100644
--- a/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java
+++ b/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java
@@ -22,6 +22,7 @@
 */
 package net.jami.datastore.dao;
 
+import net.jami.jams.common.dao.StatementList;
 import net.jami.jams.common.objects.contacts.Contact;
 
 import java.util.LinkedHashMap;
@@ -37,4 +38,9 @@ public class ContactDao extends AbstractDao<Contact> {
     public boolean deleteObject(LinkedHashMap<String, String> constraints) {
         return false;
     }
+
+    @Override
+    public boolean updateObject(StatementList update, StatementList constraints) {
+        return false;
+    }
 }
diff --git a/datastore/src/main/java/net/jami/datastore/dao/DeviceDao.java b/datastore/src/main/java/net/jami/datastore/dao/DeviceDao.java
index d1e5b74eab8d024dc9cd95ba96da8f92040aff6f..6af5941495ee0edb7f6a933f9a93004e25a63f06 100644
--- a/datastore/src/main/java/net/jami/datastore/dao/DeviceDao.java
+++ b/datastore/src/main/java/net/jami/datastore/dao/DeviceDao.java
@@ -24,6 +24,7 @@ package net.jami.datastore.dao;
 
 import lombok.extern.slf4j.Slf4j;
 import net.jami.datastore.main.DataStore;
+import net.jami.jams.common.dao.StatementList;
 import net.jami.jams.common.dao.connectivity.SQLConnection;
 import net.jami.jams.common.objects.devices.Device;
 
@@ -81,4 +82,9 @@ public class DeviceDao extends AbstractDao<Device> {
     public boolean deleteObject(LinkedHashMap<String, String> constraints) {
         return false;
     }
+
+    @Override
+    public boolean updateObject(StatementList update, StatementList constraints) {
+        return false;
+    }
 }
diff --git a/datastore/src/main/java/net/jami/datastore/dao/SystemDao.java b/datastore/src/main/java/net/jami/datastore/dao/SystemDao.java
index c8d8ca660f2d415a481cb0094fb2262751e2939e..7cb9e1587a8ab624870a486a862c109cc27722be 100644
--- a/datastore/src/main/java/net/jami/datastore/dao/SystemDao.java
+++ b/datastore/src/main/java/net/jami/datastore/dao/SystemDao.java
@@ -24,6 +24,7 @@ package net.jami.datastore.dao;
 
 import lombok.extern.slf4j.Slf4j;
 import net.jami.datastore.main.DataStore;
+import net.jami.jams.common.dao.StatementList;
 import net.jami.jams.common.dao.connectivity.SQLConnection;
 import net.jami.jams.common.objects.system.SystemAccount;
 
@@ -79,4 +80,9 @@ public class SystemDao extends AbstractDao<SystemAccount> {
     public boolean deleteObject(LinkedHashMap<String, String> constraints) {
         return false;
     }
+
+    @Override
+    public boolean updateObject(StatementList update, StatementList constraints) {
+        return false;
+    }
 }
diff --git a/datastore/src/main/java/net/jami/datastore/main/DataStore.java b/datastore/src/main/java/net/jami/datastore/main/DataStore.java
index 78db5a3d659094548efbc72ca2b20b338bdd2c62..41ed66eefbed2b3d301b0ed153d381eab663ba7f 100644
--- a/datastore/src/main/java/net/jami/datastore/main/DataStore.java
+++ b/datastore/src/main/java/net/jami/datastore/main/DataStore.java
@@ -73,6 +73,11 @@ public class DataStore implements AuthenticationSource {
         return null;
     }
 
+    @Override
+    public void setUserProfile(UserProfile userProfile) {
+        //TODO: Implement this.
+    }
+
     @Override
     public boolean authenticate(String username, String password) {
         StatementList statementList = new StatementList();
diff --git a/integration-test/install-server.py b/integration-test/install-server.py
index 4add5375b079ca2552a6db951e14ffbbaebd68cd..e9a9de7ec000cdf8efd1203936a76a3ac0279d96 100644
--- a/integration-test/install-server.py
+++ b/integration-test/install-server.py
@@ -118,4 +118,13 @@ print(token)
 
 response = requests.get("http://localhost:8080/api/nameserver/name/aberaud",headers=header)
 print(response.status_code)
+print(response.text)
+
+
+response = requests.get("http://localhost:8080//api/auth/directories",headers=header)
+print(response.status_code)
+print(response.text)
+
+response = requests.get("http://localhost:8080/api/auth/user",headers=header)
+print(response.status_code)
 print(response.text)
\ No newline at end of file
diff --git a/jami-nameserver/src/main/java/net/jami/jams/nameserver/PublicNameServer.java b/jami-nameserver/src/main/java/net/jami/jams/nameserver/PublicNameServer.java
index a56776fe6ca256ffe3b3a25988d1e11b2b83fe8c..ef1c070656ff3a2fa6e806aac5691f1bc32d000d 100644
--- a/jami-nameserver/src/main/java/net/jami/jams/nameserver/PublicNameServer.java
+++ b/jami-nameserver/src/main/java/net/jami/jams/nameserver/PublicNameServer.java
@@ -70,7 +70,7 @@ public class PublicNameServer implements NameServer {
                     responseData.append((char) con.getInputStream().read());
                     currentSize++;
                 }
-                log.info("Reponse received from public nameserver {} ", responseData.toString());
+                log.info("Response received from public nameserver {} ", responseData.toString());
                 return JsonIterator.deserialize(responseData.toString(),NameLookupResponse.class);
             }
             return null;
diff --git a/jams-ca/src/main/java/net/jami/jams/ca/workers/X509Worker.java b/jams-ca/src/main/java/net/jami/jams/ca/workers/X509Worker.java
index f62a027ee44efd82d28d2b006d3cf4917ab40c89..f09fda04757a466769e141344a16bf7a3a9e06c9 100644
--- a/jams-ca/src/main/java/net/jami/jams/ca/workers/X509Worker.java
+++ b/jams-ca/src/main/java/net/jami/jams/ca/workers/X509Worker.java
@@ -25,8 +25,6 @@ package net.jami.jams.ca.workers;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
-import org.bouncycastle.cert.ocsp.OCSPReq;
-import org.bouncycastle.cert.ocsp.OCSPResp;
 
 import java.security.PrivateKey;
 import java.security.cert.X509Certificate;
diff --git a/jams-common/pom.xml b/jams-common/pom.xml
index 065b4c7495ea8df8fa4e347d69376cf681f860ff..5bc99ad07fec94f340f460b601b1f2e8eda156f0 100644
--- a/jams-common/pom.xml
+++ b/jams-common/pom.xml
@@ -27,6 +27,11 @@
             <artifactId>xbean-classloader</artifactId>
             <version>${xbean.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.zeromq</groupId>
+            <artifactId>jeromq</artifactId>
+            <version>0.5.2</version>
+        </dependency>
     </dependencies>
 
 </project>
\ No newline at end of file
diff --git a/jams-common/src/main/java/module-info.java b/jams-common/src/main/java/module-info.java
index f1558dbfc2b476c91a55165c239754d6d0561c4c..a96e0b86c98039385d28ef200f14b31238090a2f 100644
--- a/jams-common/src/main/java/module-info.java
+++ b/jams-common/src/main/java/module-info.java
@@ -74,9 +74,11 @@ module jams.common {
     exports net.jami.jams.common.authentication.local;
     exports net.jami.jams.common.objects.responses;
     exports net.jami.jams.common.cryptoengineapi.ocsp;
+    exports net.jami.jams.common.updater;
     requires jdk.crypto.cryptoki;
     requires java.base;
     requires java.sql;
     requires org.apache.xbean.classloader;
+    requires jeromq;
 }
 
diff --git a/jams-common/src/main/java/net/jami/jams/common/authentication/AuthenticationSource.java b/jams-common/src/main/java/net/jami/jams/common/authentication/AuthenticationSource.java
index b9035222361d2316d675be06aed56a2468df53e0..9b3cb6203152e58d717bae92e182b4f197304b6b 100644
--- a/jams-common/src/main/java/net/jami/jams/common/authentication/AuthenticationSource.java
+++ b/jams-common/src/main/java/net/jami/jams/common/authentication/AuthenticationSource.java
@@ -29,6 +29,7 @@ public interface AuthenticationSource {
 
     boolean createUser(User user);
     UserProfile[] getUserProfile(String queryString, String field);
+    void setUserProfile(UserProfile userProfile);
     boolean authenticate(String username, String password);
     AuthenticationSourceInfo getInfo();
     boolean test();
diff --git a/jams-common/src/main/java/net/jami/jams/common/authentication/AuthenticationSourceType.java b/jams-common/src/main/java/net/jami/jams/common/authentication/AuthenticationSourceType.java
index 380a6d9804aae24162d7a425d138c0f1f446c362..b01fb44d302271aad6cc2dba5485cd819b94e79d 100644
--- a/jams-common/src/main/java/net/jami/jams/common/authentication/AuthenticationSourceType.java
+++ b/jams-common/src/main/java/net/jami/jams/common/authentication/AuthenticationSourceType.java
@@ -25,5 +25,13 @@ package net.jami.jams.common.authentication;
 public enum AuthenticationSourceType {
     AD,
     LDAP,
-    LOCAL
+    LOCAL;
+
+    public static AuthenticationSourceType fromString(String str){
+        if(str.equals("AD")) return AD;
+        if(str.equals("LDAP")) return LDAP;
+        if(str.equals("LOCAL")) return LOCAL;
+        return null;
+    }
+
 }
diff --git a/jams-common/src/main/java/net/jami/jams/common/authmodule/AuthenticationModule.java b/jams-common/src/main/java/net/jami/jams/common/authmodule/AuthenticationModule.java
index 273dfa67347c4ad15d4fadbfe8c1fca5ffbb8942..337a825a3d97db51ef0f24d4c013ffe801ad5097 100644
--- a/jams-common/src/main/java/net/jami/jams/common/authmodule/AuthenticationModule.java
+++ b/jams-common/src/main/java/net/jami/jams/common/authmodule/AuthenticationModule.java
@@ -27,10 +27,11 @@ import net.jami.jams.common.authentication.AuthenticationSourceType;
 import net.jami.jams.common.jami.NameServer;
 import net.jami.jams.common.objects.user.User;
 
+import java.security.SecureRandom;
 import java.security.cert.X509Certificate;
 import java.security.interfaces.RSAPublicKey;
-import java.util.HashMap;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
 
 public interface AuthenticationModule {
 
@@ -41,4 +42,5 @@ public interface AuthenticationModule {
     boolean testModuleConfiguration(AuthenticationSourceType type, String configuration);
     boolean createUser(AuthenticationSourceType type, String realm, NameServer nameServer, User user);
     RSAPublicKey getAuthModulePubKey();
+    char[] getOTP(String username);
 }
diff --git a/jams-common/src/main/java/net/jami/jams/common/dao/SelectStatementBuilder.java b/jams-common/src/main/java/net/jami/jams/common/dao/SelectStatementBuilder.java
index 4d640f24b8c1a7263fd9e7ae31061ce580a2e714..c361e884579819fca538de04fdcedd2c33db2396 100644
--- a/jams-common/src/main/java/net/jami/jams/common/dao/SelectStatementBuilder.java
+++ b/jams-common/src/main/java/net/jami/jams/common/dao/SelectStatementBuilder.java
@@ -25,11 +25,10 @@ package net.jami.jams.common.dao;
 import net.jami.jams.common.dao.connectivity.SQLConnection;
 
 import java.sql.PreparedStatement;
-import java.util.List;
 
 public class SelectStatementBuilder {
 
-    public static PreparedStatement buildStatement(String table, List<StatementElement> statementElements,
+    public static PreparedStatement buildStatement(String table, StatementList statementElements,
                                         SQLConnection connection) throws Exception
     {
         PreparedStatement ps = null;
@@ -37,7 +36,7 @@ public class SelectStatementBuilder {
         stringBuilder.append("SELECT * FROM ").append(table);
         if(statementElements != null) {
             stringBuilder.append(" WHERE ");
-            for (StatementElement statementElement : statementElements) {
+            for (StatementElement statementElement : statementElements.getStatements()) {
                 stringBuilder
                         .append(statementElement.getColumn())
                         .append(" ")
@@ -49,7 +48,7 @@ public class SelectStatementBuilder {
             }
             ps = connection.getConnection().prepareStatement(stringBuilder.toString());
             int i = 1;
-            for (StatementElement statementElement : statementElements) {
+            for (StatementElement statementElement : statementElements.getStatements()) {
                 ps.setString(i, statementElement.getValue());
                 i++;
             }
diff --git a/jams-common/src/main/java/net/jami/jams/common/dao/UpdateStatementBuilder.java b/jams-common/src/main/java/net/jami/jams/common/dao/UpdateStatementBuilder.java
index 1c6db37ab6508ad8efe714e5570b7232f6b5926d..a80161771067daeacf52b2bab0e8521d2fa37159 100644
--- a/jams-common/src/main/java/net/jami/jams/common/dao/UpdateStatementBuilder.java
+++ b/jams-common/src/main/java/net/jami/jams/common/dao/UpdateStatementBuilder.java
@@ -25,25 +25,24 @@ package net.jami.jams.common.dao;
 import net.jami.jams.common.dao.connectivity.SQLConnection;
 
 import java.sql.PreparedStatement;
-import java.util.List;
 
 public class UpdateStatementBuilder {
-    public static PreparedStatement buildStatement(String table, List<StatementElement> updateElements,
-                                                   List<StatementElement> conditionalElements,
+    public static PreparedStatement buildStatement(String table, StatementList updateElements,
+                                                   StatementList conditionalElements,
                                                    SQLConnection connection) throws Exception {
         PreparedStatement ps = null;
         StringBuilder stringBuilder = new StringBuilder();
         stringBuilder.append("UPDATE ").append(table).append(" SET ");
-        for (int i = 0; i < updateElements.size(); i++) {
-            StatementElement statementElement = updateElements.get(i);
+        for (int i = 0; i < updateElements.getStatements().size(); i++) {
+            StatementElement statementElement = updateElements.getStatements().get(i);
             stringBuilder
                     .append(statementElement.getColumn())
                     .append(" = ")
                     .append("?");
-            if (i != updateElements.size() - 1) stringBuilder.append(",");
+            if (i != updateElements.getStatements().size() - 1) stringBuilder.append(",");
         }
         stringBuilder.append(" WHERE ");
-        for (StatementElement statementElement : conditionalElements) {
+        for (StatementElement statementElement : conditionalElements.getStatements()) {
             stringBuilder
                     .append(statementElement.getColumn())
                     .append(" ")
@@ -54,10 +53,10 @@ public class UpdateStatementBuilder {
                     .append(statementElement.getNextStatementRelation());
         }
         ps = connection.getConnection().prepareStatement(stringBuilder.toString());
-        //Now we have to feed this all the elements it hsould have.
-        updateElements.addAll(conditionalElements);
+        //Now we have to feed this all the elements it should have.
+        updateElements.getStatements().addAll(conditionalElements.getStatements());
         int i = 1;
-        for (StatementElement statementElement : updateElements) {
+        for (StatementElement statementElement : updateElements.getStatements()) {
             ps.setString(i, statementElement.getValue());
             i++;
         }
diff --git a/jams-common/src/main/java/net/jami/jams/common/objects/requests/DeviceRevocationRequest.java b/jams-common/src/main/java/net/jami/jams/common/objects/requests/DeviceRevocationRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ef3f7d8514d8efcf6f09f213b394bd6f05fba17
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/objects/requests/DeviceRevocationRequest.java
@@ -0,0 +1,17 @@
+package net.jami.jams.common.objects.requests;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class DeviceRevocationRequest {
+
+    private String owner;
+    private String deviceId;
+
+    public DeviceRevocationRequest(String username, String deviceId) {
+        this.owner = owner;
+        this.deviceId = deviceId;
+    }
+}
diff --git a/jams-common/src/main/java/net/jami/jams/common/objects/responses/DeviceRevocationResponse.java b/jams-common/src/main/java/net/jami/jams/common/objects/responses/DeviceRevocationResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..31f8ae30e7467fab1939910275e024aa1cb1da8f
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/objects/responses/DeviceRevocationResponse.java
@@ -0,0 +1,19 @@
+package net.jami.jams.common.objects.responses;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+@Getter
+@Setter
+public class DeviceRevocationResponse {
+
+
+    private boolean success;
+    private String errorDetails;
+    private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss'Z'X");
+    private String  timestamp = dateFormatter.format(new Date());
+
+}
diff --git a/jams-common/src/main/java/net/jami/jams/common/updater/AppUpdater.java b/jams-common/src/main/java/net/jami/jams/common/updater/AppUpdater.java
new file mode 100644
index 0000000000000000000000000000000000000000..56b431a20e8f43ef2ad37e70cedcab06e37542c4
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/updater/AppUpdater.java
@@ -0,0 +1,11 @@
+package net.jami.jams.common.updater;
+
+public interface AppUpdater {
+
+    String getCurrentVersion();
+    String getLatestVersion();
+    boolean downloadUpdates();
+
+
+
+}
diff --git a/jams-common/src/main/java/net/jami/jams/common/updater/subscription/SubscriptionStatusResponse.java b/jams-common/src/main/java/net/jami/jams/common/updater/subscription/SubscriptionStatusResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..9776ca254be99c5bceaf2e4d1ae66d5c9eea6504
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/updater/subscription/SubscriptionStatusResponse.java
@@ -0,0 +1,12 @@
+package net.jami.jams.common.updater.subscription;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class SubscriptionStatusResponse {
+    private Boolean subscribed;
+    private SubscriptionType subscriptionType;
+    private Long expiryDate;
+}
diff --git a/jams-common/src/main/java/net/jami/jams/common/updater/subscription/SubscriptionType.java b/jams-common/src/main/java/net/jami/jams/common/updater/subscription/SubscriptionType.java
new file mode 100644
index 0000000000000000000000000000000000000000..21467d99f190e03f3f09000da0d534acd1d21a99
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/updater/subscription/SubscriptionType.java
@@ -0,0 +1,5 @@
+package net.jami.jams.common.updater.subscription;
+
+public enum SubscriptionType {
+    COMMUNITY
+}
diff --git a/jams-common/src/main/java/net/jami/jams/common/utils/LicenseUtils.java b/jams-common/src/main/java/net/jami/jams/common/utils/LicenseUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d55a05b787a19676b31454b52b524d1c7e656b3
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/utils/LicenseUtils.java
@@ -0,0 +1,29 @@
+package net.jami.jams.common.utils;
+
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+@Slf4j
+public class LicenseUtils {
+
+
+    public static String checkVersion(String destinationDir, String jarPath) throws IOException {
+        String resp = "";
+        File file = new File(jarPath);
+        JarFile jar = new JarFile(file);
+        Manifest manifest = jar.getManifest();
+        resp = manifest.getMainAttributes().getValue("Implementation-Version");
+        System.out.println("Found version: " + resp);
+        return resp;
+    }
+}
diff --git a/jams-common/src/main/java/net/jami/jams/common/utils/UpdateInterface.java b/jams-common/src/main/java/net/jami/jams/common/utils/UpdateInterface.java
new file mode 100644
index 0000000000000000000000000000000000000000..7bfcf4499a031bca37bc558e7f506bf64edcbcd9
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/utils/UpdateInterface.java
@@ -0,0 +1,46 @@
+package net.jami.jams.common.utils;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.zeromq.SocketType;
+import org.zeromq.ZMQ;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Logger;
+
+@Getter
+@Setter
+public class UpdateInterface extends Thread {
+
+    private AtomicBoolean updateAvailable = new AtomicBoolean(false);
+    private volatile String versions;
+    private ZMQ.Context context = ZMQ.context(1);
+    private ZMQ.Socket sender = context.socket(SocketType.REQ);
+    private ZMQ.Socket receiver = context.socket(SocketType.SUB);
+    private final static Logger logger = Logger.getLogger(UpdateInterface.class.getName());
+
+    public UpdateInterface() {
+        receiver.connect("tcp://localhost:4572");
+        sender.connect("tcp://localhost:4573");
+        receiver.subscribe("UPDATE");
+        this.start();
+    }
+
+    public void approveUpdate(){
+        sender.send("DO-UPDATE");
+    }
+
+    @Override
+    public void run() {
+        while(true){
+            try{
+                receiver.recv();
+                updateAvailable.set(true);
+                versions = receiver.recvStr();
+            }
+            catch (Exception e){
+                System.out.println(e.toString());
+            }
+        }
+    }
+}
diff --git a/jams-launcher/pom.xml b/jams-launcher/pom.xml
index 54ecb9f5d32d9e26da7c18bd05fb75afbe9b5883..9eb9bc4d220b2f0c28d578179eae6d92fea7f15c 100644
--- a/jams-launcher/pom.xml
+++ b/jams-launcher/pom.xml
@@ -14,37 +14,27 @@
         <dependency>
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-model</artifactId>
-            <version>3.2.5</version>
+            <version>${maven.model.version}</version>
         </dependency>
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpcore</artifactId>
-            <version>4.4.12</version>
+            <version>${apache.httpcore.version}</version>
         </dependency>
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
-            <version>4.5.10</version>
-        </dependency>
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <version>1.18.12</version>
+            <version>${apache.httpclient.version}</version>
         </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
-            <version>20.0</version>
+            <version>${google.guava.version}</version>
         </dependency>
         <dependency>
             <groupId>org.zeromq</groupId>
             <artifactId>jeromq</artifactId>
-            <version>0.5.2</version>
-        </dependency>
-        <dependency>
-            <groupId>com.blockfeed</groupId>
-            <artifactId>messaging</artifactId>
-            <version>1.0-SNAPSHOT</version>
+            <version>${jeromq.version}</version>
         </dependency>
     </dependencies>
 
@@ -54,7 +44,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-shade-plugin</artifactId>
-                <version>2.3</version>
+                <version>${maven.shade.version}</version>
                 <executions>
                     <!-- Run shade goal on package phase -->
                     <execution>
diff --git a/jams-launcher/src/main/java/launcher/MessageReceiver.java b/jams-launcher/src/main/java/launcher/MessageReceiver.java
index 05c97888f3c9e437f701c7bdae04e1c388270da8..26e390615748133e6b2271403ca04ba0d3fc752e 100644
--- a/jams-launcher/src/main/java/launcher/MessageReceiver.java
+++ b/jams-launcher/src/main/java/launcher/MessageReceiver.java
@@ -22,10 +22,12 @@
 */
 package launcher;
 
+import lombok.extern.slf4j.Slf4j;
 import org.zeromq.ZMQ;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
+@Slf4j
 public class MessageReceiver extends Thread {
 
     private ZMQ.Socket socket;
@@ -44,7 +46,7 @@ public class MessageReceiver extends Thread {
                 if(message.equals("DO-UPDATE")) atomicBoolean.set(true);
             }
             catch (Exception e){
-                System.out.println("Some exception occurred!");
+                log.error("Some exception occurred on the message receiving thread, details {}!",e.getMessage());
             }
         }
     }
diff --git a/jams-launcher/src/main/java/launcher/UpdateThread.java b/jams-launcher/src/main/java/launcher/UpdateThread.java
index 0b6057eb630f596fea9f797869e1248090d7abfa..bf03bc700957202a4411b64ad4b60df0124f29d7 100644
--- a/jams-launcher/src/main/java/launcher/UpdateThread.java
+++ b/jams-launcher/src/main/java/launcher/UpdateThread.java
@@ -28,6 +28,7 @@ import com.jsoniter.JsonIterator;
 import com.jsoniter.any.Any;
 import lombok.Getter;
 import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
@@ -59,6 +60,7 @@ import java.util.logging.Logger;
 
 @Getter
 @Setter
+@Slf4j
 public class UpdateThread extends Thread {
 
     private HashMap<String, String> localVersions = new HashMap<>();
@@ -68,7 +70,6 @@ public class UpdateThread extends Thread {
     private HashMap<String, String> remoteChecksums = new HashMap<>();
 
     private String[] parentArgs;
-    private final static Logger logger = Logger.getLogger(UpdateThread.class.getName());
     private static volatile String CORE_PACKAGE_MAIN_CLASS_NAME;
     private static volatile String UPDATE_SERVER_URL;
     private static volatile Long UPDATE_INTERVAL;
@@ -93,7 +94,7 @@ public class UpdateThread extends Thread {
             messageReceiver = new MessageReceiver(receiver,doUpdate);
             messageReceiver.start();
         } catch (Exception e) {
-            logger.warning("Could not create and bind publisher and/or receiver! Please contact software developer");
+            log.warn("Could not create and bind publisher and/or receiver! Please contact software developer");
             System.exit(-1);
         }
 
@@ -105,7 +106,7 @@ public class UpdateThread extends Thread {
             UPDATE_INTERVAL = any.get("UPDATE_INTERVAL").toLong();
 
         } catch (IOException e) {
-            logger.warning("Missing OEM configuration! Please contact software developer");
+            log.warn("Missing OEM configuration! Please contact software developer");
             System.exit(-1);
         }
 
@@ -171,7 +172,7 @@ public class UpdateThread extends Thread {
             discoverVersions(folderExec);
             discoverVersions(folderLibs);
         } catch (Exception e) {
-            logger.warning(e.toString());
+            log.warn(e.toString());
         }
     }
 
@@ -200,7 +201,7 @@ public class UpdateThread extends Thread {
                 remoteChecksums.put(k, v.get("md5").toString());
             });
         } catch (Exception e) {
-            logger.warning("Could not establish connection to JAMS Update Center with error: " + e.toString());
+            log.warn("Could not establish connection to JAMS Update Center with error: " + e.toString());
         }
     }
 
@@ -258,13 +259,13 @@ public class UpdateThread extends Thread {
                 ((X509Certificate) c).checkValidity();
                 c.verify(ca.getPublicKey());
             } catch (Exception e) {
-                logger.warning("Your license is no longer valid or has been tampered with - " + e.toString());
+                log.warn("Your license is no longer valid or has been tampered with - " + e.toString());
                 return false;
             }
             sslContext = SSLContexts.custom().loadKeyMaterial(ks, "".toCharArray()).loadTrustMaterial(trustStore, null)
                     .build();
         } catch (Exception e) {
-            logger.warning("Could not read license file with error " + e.toString());
+            log.warn("Could not read license file with error " + e.toString());
             return false;
         }
         return true;
@@ -283,14 +284,14 @@ public class UpdateThread extends Thread {
                 HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
                 HttpResponse httpResponse = httpClient.execute(new HttpGet(UPDATE_SERVER_URL + "/updates/" + v));
                 if (httpResponse.getStatusLine().getStatusCode() == 200) {
-                    logger.info(tmpFolder.getPath() + "/" + files.get(k));
+                    log.info(tmpFolder.getPath() + "/" + files.get(k));
                     FileOutputStream fos = new FileOutputStream(tmpFolder.getPath() + "/" + files.get(k));
                     if (k.equals(CORE_PACKAGE_MAIN_CLASS_NAME)) {
                         httpResponse.getEntity().writeTo(fos);
                         fos.close();
 
                         if (checksum(tmpFolder.getPath() + "/" + files.get(k)).equals(remoteChecksums.get(k))) {
-                            logger.info("Successfully downloaded the core package!");
+                            log.info("Successfully downloaded the core package!");
                             remoteChecksums.remove(CORE_PACKAGE_MAIN_CLASS_NAME);
                         }
 
@@ -299,16 +300,16 @@ public class UpdateThread extends Thread {
                         fos.close();
 
                         if (checksum(tmpFolder.getPath() + "/" + files.get(k)).equals(remoteChecksums.get(k))) {
-                            logger.info("Successfully downloaded a library package!");
+                            log.info("Successfully downloaded a library package!");
                             remoteChecksums.remove(remoteChecksums.get(k));
                         }
                     }
 
                 } else {
-                    logger.warning("The server declared an update but does not have the required files?!");
+                    log.warn("The server declared an update but does not have the required files?!");
                 }
             } catch (Exception e1) {
-                logger.warning("Could not download an update with error " + e1.toString());
+                log.warn("Could not download an update with error " + e1.toString());
             }
         });
     }
@@ -356,14 +357,14 @@ public class UpdateThread extends Thread {
             System.out.println("Murdered process with pid: " + AppStarter.getJamsPID());
             // delete old files
             remoteExecs.forEach((k, v) -> {
-                logger.info(remoteExecs.get(k));
+                log.info(remoteExecs.get(k));
 
                 if (k.equals(CORE_PACKAGE_MAIN_CLASS_NAME)) {
                     File f = new File(System.getProperty("user.dir") + "/" + remoteExecs.get(k));
                     f.delete();
                     f = new File(System.getProperty("user.dir") + "/tmp/" + remoteExecs.get(k));
                     if (!f.renameTo(new File(System.getProperty("user.dir") + "/" + remoteExecs.get(k))))
-                        logger.warning("An error occurred while attempting to move the file!");
+                        log.warn("An error occurred while attempting to move the file!");
                     else
                         f.delete();
                 } else {
@@ -371,7 +372,7 @@ public class UpdateThread extends Thread {
                     f.delete();
                     f = new File(System.getProperty("user.dir") + "/tmp/" + remoteExecs.get(k));
                     if (!f.renameTo(new File(System.getProperty("user.dir") + "/libs/" + remoteExecs.get(k))))
-                        logger.warning("An error occurred while attempting to move the file!");
+                        log.warn("An error occurred while attempting to move the file!");
                     else
                         f.delete();
                 }
@@ -397,7 +398,7 @@ public class UpdateThread extends Thread {
         try {
             FileUtils.deleteDirectory(System.getProperty("user.dir") + "/tmp/");
         } catch (IOException e) {
-            logger.warning("An error occurred while attempting to delete /tmp/ folder!");
+            log.warn("An error occurred while attempting to delete /tmp/ folder!");
         }
     }
 
@@ -406,7 +407,7 @@ public class UpdateThread extends Thread {
         HashCode hash = com.google.common.io.Files
                 .hash(new File(filepath), Hashing.md5());
 
-        logger.info("Calculated md5: " + hash.toString());
+        log.warn("Calculated md5: " + hash.toString());
         return hash.toString();
     }
 
@@ -432,7 +433,7 @@ public class UpdateThread extends Thread {
             };
             timer.scheduleAtFixedRate(pollTask, 15000, UPDATE_INTERVAL);
         } catch (Exception e) {
-            logger.warning("error! " + e.toString());
+            log.warn("error! " + e.toString());
         }
     }
 }
\ No newline at end of file
diff --git a/jams-server/src/main/java/module-info.java b/jams-server/src/main/java/module-info.java
index 5f8fd865bb663681db57337351eef8a0e6f812fd..29b097d812fbd815ec586a36be9f733d978ba460 100644
--- a/jams-server/src/main/java/module-info.java
+++ b/jams-server/src/main/java/module-info.java
@@ -32,15 +32,29 @@ module jams.server {
     requires javassist;
     requires datastore;
     requires org.apache.xbean.classloader;
+    requires org.bouncycastle.pkix;
+    requires org.bouncycastle.provider;
     requires jami.nameserver;
     requires jami.dht;
     requires nimbus.jose.jwt;
     requires java.desktop;
+    requires java.naming;
+    requires java.logging;
+    requires javax.servlet.api;
     exports net.jami.jams.server.servlets.general to org.apache.tomcat.embed.core;
+
     exports net.jami.jams.server.servlets.filters to org.apache.tomcat.embed.core;
+
     exports net.jami.jams.server.servlets.api.auth.login to org.apache.tomcat.embed.core;
     exports net.jami.jams.server.servlets.api.auth.device to org.apache.tomcat.embed.core;
+    exports net.jami.jams.server.servlets.api.auth.directory to org.apache.tomcat.embed.core;
+    exports net.jami.jams.server.servlets.api.auth.user to org.apache.tomcat.embed.core;
+
     exports net.jami.jams.server.servlets.api.install to org.apache.tomcat.embed.core;
+
+    exports net.jami.jams.server.servlets.general to org.apache.tomcat.embed.core;
     exports net.jami.jams.server.servlets.api.jaminameserver to org.apache.tomcat.embed.core;
     exports net.jami.jams.server.servlets.x509 to org.apache.tomcat.embed.core;
-}
\ No newline at end of file
+
+
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/Server.java b/jams-server/src/main/java/net/jami/jams/server/Server.java
index 21f8c3344327a823c370d9d3a4d56d78ef39acf9..860871f7e14a5d4abc60ce80689153ff5c70da6b 100644
--- a/jams-server/src/main/java/net/jami/jams/server/Server.java
+++ b/jams-server/src/main/java/net/jami/jams/server/Server.java
@@ -32,12 +32,15 @@ import net.jami.jams.common.cryptoengineapi.CertificateAuthority;
 import net.jami.jams.common.jami.NameServer;
 import net.jami.jams.common.serialization.JsoniterRegistry;
 import net.jami.jams.common.server.ServerSettings;
+import net.jami.jams.common.updater.AppUpdater;
 import net.jami.jams.common.utils.LibraryLoader;
+import net.jami.jams.common.utils.UpdateInterface;
 import net.jami.jams.nameserver.LocalNameServer;
 import net.jami.jams.nameserver.PublicNameServer;
 import net.jami.jams.server.core.TomcatLauncher;
 import net.jami.jams.server.startup.AuthModuleLoader;
 import net.jami.jams.server.startup.CryptoEngineLoader;
+import net.jami.jams.server.startup.UpdaterLoader;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -47,7 +50,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
 @Slf4j
 public class Server {
 
-    public static AtomicBoolean isInstalled = new AtomicBoolean(false);
+    public  final static AtomicBoolean isInstalled = new AtomicBoolean(false);
+    public  final static AtomicBoolean activated = new AtomicBoolean(false);
 
     static {
         JsoniterRegistry.initCodecs();
@@ -57,8 +61,10 @@ public class Server {
     //This one gets loaded via JAR, to make it more flexible.
     public  static CertificateAuthority certificateAuthority;
     public  static AuthenticationModule userAuthenticationModule;
+    public  static AppUpdater appUpdater;
     public  static NameServer nameServer;
     private static TomcatLauncher tomcatLauncher = null;
+    public static final UpdateInterface updateInterface = new UpdateInterface();
 
     public static void main(String[] args) {
         //Start tomcat.
@@ -99,6 +105,7 @@ public class Server {
                     else nameServer = new LocalNameServer(dataStore,userAuthenticationModule,serverSettings.getServerPublicURI());
                 }
                 else nameServer = new LocalNameServer(dataStore,userAuthenticationModule,serverSettings.getServerPublicURI());
+                appUpdater = UpdaterLoader.loadUpdater();
                 log.info("All services are UP and ready for use...");
             }
             catch (Exception e){
diff --git a/jams-server/src/main/java/net/jami/jams/server/core/TomcatLauncher.java b/jams-server/src/main/java/net/jami/jams/server/core/TomcatLauncher.java
index 48294db227393fdca9f7a1cd9f0644d262876eda..e8643f8d84c29ad66f86941a146531486eab5ec7 100644
--- a/jams-server/src/main/java/net/jami/jams/server/core/TomcatLauncher.java
+++ b/jams-server/src/main/java/net/jami/jams/server/core/TomcatLauncher.java
@@ -37,7 +37,6 @@ import java.net.URI;
 import java.net.URLDecoder;
 import java.nio.charset.StandardCharsets;
 
-import static net.jami.jams.server.core.TomcatConnectorFactory.getSSLConnectorWithTrustStore;
 
 //This class boots the tomcat server which provides the subsystem
 //for the API calls.
@@ -64,6 +63,7 @@ public class TomcatLauncher {
         log.info("JAR Resource File = " + jarName);
         StandardContext context = (StandardContext) tomcat.addWebapp("", new File(System.getProperty("user.dir")).getAbsolutePath());
         //Hack to prevent useless verbose messages.
+
         context.getJarScanner().setJarScanFilter((jarScanType, s) -> false);
         WebResourceRoot resources = new StandardRoot(context);
         if (jarName.contains(".jar")) {
@@ -96,6 +96,4 @@ public class TomcatLauncher {
             log.error("Web-server has failed to start - this is critical!");
         }
     }
-
-
 }
diff --git a/jams-server/src/main/java/net/jami/jams/server/core/workflows/ActivateSubscriptionWorkflow.java b/jams-server/src/main/java/net/jami/jams/server/core/workflows/ActivateSubscriptionWorkflow.java
new file mode 100644
index 0000000000000000000000000000000000000000..601a7e8ee76cd4bcd8505b5a8cd4bd475bf84fad
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/core/workflows/ActivateSubscriptionWorkflow.java
@@ -0,0 +1,35 @@
+package net.jami.jams.server.core.workflows;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.FileOutputStream;
+import java.security.KeyStore;
+
+@Slf4j
+public class ActivateSubscriptionWorkflow {
+
+    public static boolean activateSubscription(String data){
+        try {
+            //TODO: Decode the the data into a certificate and private key.
+
+            //TODO: Verify that the certificate has really been signed by SavoirFaireLinux and is valid.
+
+            //Build a keystore from the data.
+            KeyStore ks = KeyStore.getInstance("JKS");
+            char[] password = "changeit".toCharArray();
+            ks.load(null, password);
+            ks.setKeyEntry("license",null,null);
+            FileOutputStream fos = new FileOutputStream("license.jks");
+            ks.store(fos, password);
+            fos.close();
+            log.info("Succesfully activated your license!");
+            return true;
+        }
+        catch (Exception e){
+            log.error("The activation process failed with error: {}",e.getMessage());
+            return false;
+        }
+    }
+
+
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/core/workflows/InstallationFinalizer.java b/jams-server/src/main/java/net/jami/jams/server/core/workflows/InstallationFinalizer.java
index 8a6c5ab952663a465847bd6fe4074eb7d99dcbbd..78e2a170a6118bcc958bf28310e75b563e18c847 100644
--- a/jams-server/src/main/java/net/jami/jams/server/core/workflows/InstallationFinalizer.java
+++ b/jams-server/src/main/java/net/jami/jams/server/core/workflows/InstallationFinalizer.java
@@ -34,6 +34,7 @@ import net.jami.jams.nameserver.PublicNameServer;
 import net.jami.jams.server.Server;
 import net.jami.jams.server.servlets.api.install.CachedObjects;
 import net.jami.jams.server.startup.AuthModuleLoader;
+import net.jami.jams.server.startup.UpdaterLoader;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -114,6 +115,8 @@ public class InstallationFinalizer {
             ks.store(fos, password);
             fos.close();
             log.info("Successfully built keystore for for tomcat!");
+            appUpdater = UpdaterLoader.loadUpdater();
+            log.info("Started subscription and update service!");
             Server.isInstalled.set(true);
             log.info("The installation has completed successfully, you can now use JAMS!");
         } catch (Exception e) {
diff --git a/jams-server/src/main/java/net/jami/jams/server/core/workflows/RegisterDeviceFlow.java b/jams-server/src/main/java/net/jami/jams/server/core/workflows/RegisterDeviceFlow.java
index 4d4d5b64111063ca0f1ff107a89459f6c9fd902a..8c70a2f05ca25f8e524b72d0a78ace2614a033ae 100644
--- a/jams-server/src/main/java/net/jami/jams/server/core/workflows/RegisterDeviceFlow.java
+++ b/jams-server/src/main/java/net/jami/jams/server/core/workflows/RegisterDeviceFlow.java
@@ -82,7 +82,4 @@ public class RegisterDeviceFlow {
             return null;
         }
     }
-
-
-
 }
diff --git a/jams-server/src/main/java/net/jami/jams/server/core/workflows/RevokeDeviceFlow.java b/jams-server/src/main/java/net/jami/jams/server/core/workflows/RevokeDeviceFlow.java
index aaa60f5fdbc17c00ef8d79498e2a248d58ce25f6..02590f9152a2287329a35490aee75c84fc28ea88 100644
--- a/jams-server/src/main/java/net/jami/jams/server/core/workflows/RevokeDeviceFlow.java
+++ b/jams-server/src/main/java/net/jami/jams/server/core/workflows/RevokeDeviceFlow.java
@@ -22,5 +22,56 @@
 */
 package net.jami.jams.server.core.workflows;
 
+import lombok.extern.slf4j.Slf4j;
+import net.jami.jams.common.dao.StatementElement;
+import net.jami.jams.common.dao.StatementList;
+import net.jami.jams.common.objects.devices.Device;
+import net.jami.jams.common.objects.requests.RevocationRequest;
+import net.jami.jams.common.objects.requests.RevocationType;
+import net.jami.jams.common.objects.responses.DeviceRevocationResponse;
+
+import static net.jami.jams.server.Server.certificateAuthority;
+import static net.jami.jams.server.Server.dataStore;
+
+@Slf4j
 public class RevokeDeviceFlow {
+
+    public static DeviceRevocationResponse revokeDevice(String username, String deviceId){
+        DeviceRevocationResponse response = new DeviceRevocationResponse();
+        try {
+            StatementList statementList = new StatementList();
+            StatementElement st1 = new StatementElement("owner","=",username,"AND");
+            StatementElement st2 = new StatementElement("deviceId","=",deviceId,"");
+            statementList.addStatement(st1);
+            statementList.addStatement(st2);
+            Device device = dataStore.getDeviceDao().getObjects(statementList).get(0);
+            if (device == null) {
+                log.error("Could not find device!");
+                return null;
+            }
+            RevocationRequest request = new RevocationRequest();
+            request.setRevocationType(RevocationType.DEVICE);
+            request.setIdentifier(device.getCertificate().getSerialNumber());
+            certificateAuthority.revokeCertificate(request);
+            long statTime = System.currentTimeMillis();
+            while(certificateAuthority.getLatestCRL().get()
+                    .getRevokedCertificate(device.getCertificate().getSerialNumber()) == null){
+                log.warn("Certificate has not yet appeared in CRL!");
+                if(System.currentTimeMillis() - statTime > 1000){
+                    log.error("The certificate has not appeared within 1 second, we are considering the operation has failed");
+                    response.setSuccess(false);
+                    return response;
+                }
+            }
+            //Finally we return the successful response
+            response.setSuccess(true);
+            return response;
+        }
+        catch (Exception e){
+            log.error("An exception has occurred while trying to revoke a device with error {}", e.getMessage());
+            response.setSuccess(false);
+            response.setErrorDetails(e.getMessage());
+            return response;
+        }
+    }
 }
diff --git a/jams-server/src/main/java/net/jami/jams/server/core/workflows/RevokeUserFlow.java b/jams-server/src/main/java/net/jami/jams/server/core/workflows/RevokeUserFlow.java
index 371de583c6c35e09878fd69ba8b0c1d5aa20051e..d12e325adb8a1dcb0289083df24191419922ba01 100644
--- a/jams-server/src/main/java/net/jami/jams/server/core/workflows/RevokeUserFlow.java
+++ b/jams-server/src/main/java/net/jami/jams/server/core/workflows/RevokeUserFlow.java
@@ -22,5 +22,54 @@
 */
 package net.jami.jams.server.core.workflows;
 
+import lombok.extern.slf4j.Slf4j;
+import net.jami.jams.common.dao.StatementElement;
+import net.jami.jams.common.dao.StatementList;
+import net.jami.jams.common.objects.requests.RevocationRequest;
+import net.jami.jams.common.objects.requests.RevocationType;
+import net.jami.jams.common.objects.responses.DeviceRevocationResponse;
+import net.jami.jams.common.objects.user.User;
+
+import static net.jami.jams.server.Server.certificateAuthority;
+import static net.jami.jams.server.Server.dataStore;
+
+@Slf4j
 public class RevokeUserFlow {
+
+    public static DeviceRevocationResponse revokeUser(String username){
+        DeviceRevocationResponse response = new DeviceRevocationResponse();
+        try {
+            StatementList statementList = new StatementList();
+            StatementElement st1 = new StatementElement("username","=",username,"");
+            statementList.addStatement(st1);
+            User user = dataStore.getUserDao().getObjects(statementList).get(0);
+            if (user == null) {
+                log.error("Could not find user!");
+                return null;
+            }
+            RevocationRequest request = new RevocationRequest();
+            request.setRevocationType(RevocationType.USER);
+            request.setIdentifier(user.getCertificate().getSerialNumber());
+            certificateAuthority.revokeCertificate(request);
+            long statTime = System.currentTimeMillis();
+            while(certificateAuthority.getLatestCRL().get()
+                    .getRevokedCertificate(user.getCertificate().getSerialNumber()) == null){
+                log.warn("Certificate has not yet appeared in CRL!");
+                if(System.currentTimeMillis() - statTime > 1000){
+                    log.error("The certificate has not appeared within 1 second, we are considering the operation has failed");
+                    response.setSuccess(false);
+                    return response;
+                }
+            }
+            //Finally we return the successful response
+            response.setSuccess(true);
+            return response;
+        }
+        catch (Exception e){
+            log.error("An exception has occurred while trying to revoke a device with error {}", e.getMessage());
+            response.setSuccess(false);
+            response.setErrorDetails(e.getMessage());
+            return response;
+        }
+    }
 }
diff --git a/jams-server/src/main/java/net/jami/jams/server/licensing/LicenseService.java b/jams-server/src/main/java/net/jami/jams/server/licensing/LicenseService.java
new file mode 100644
index 0000000000000000000000000000000000000000..14d58c9c23520ec845b9985db04afb3e5bfc8143
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/licensing/LicenseService.java
@@ -0,0 +1,90 @@
+package net.jami.jams.server.licensing;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import net.jami.jams.server.Server;
+import org.json.JSONObject;
+
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Base64;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@Getter
+@Setter
+@Slf4j
+public class LicenseService {
+
+    private AtomicBoolean activationStatus = new AtomicBoolean(false);
+    private String licenseType = "COMMUNITY";
+
+    //Load the license.
+    public void loadLicense() {
+        try {
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            //Assuming the file exists, we just read the file.
+            String b64License = new String(Files.readAllBytes(Path.of(System.getProperty("user.dir") + File.separator + "license.dat")));
+            //Since this is base64, we need to decode it.
+            String strLicense = new String(Base64.getDecoder().decode(b64License));
+            //Now we need to split it. This is actually easy.
+            int cutPoint = strLicense.indexOf("-----BEGIN PRIVATE KEY-----");
+            String publicKey = strLicense.substring(0,cutPoint);
+
+            InputStream inputStream = new ByteArrayInputStream(publicKey.getBytes(StandardCharsets.UTF_8));
+            Certificate c = cf.generateCertificate(inputStream);
+            String dn = ((X509Certificate)c).getSubjectDN().toString();
+            LdapName ln = new LdapName(dn);
+            byte[] array = null;
+            for(Rdn rdn : ln.getRdns()) {
+                try {
+                    array = Base64.getDecoder().decode(((String)rdn.getValue()).getBytes());
+                } catch (IllegalArgumentException e) {
+
+                }
+            }
+
+            //This is kept inside the resources/oem folder, this is a lot less violent than what we had before.
+            //TODO: You should re-use the same technique to validate whatever they stick in the textbox.
+            InputStream input = LicenseService.class.getClassLoader().getResourceAsStream("oem/ca.crt");
+            if (input == null) {
+                System.out.println("No CA Found... this is critical!");
+                System.exit(-1);
+            }
+            Certificate ca = cf.generateCertificate(input);
+            try{
+                ((X509Certificate) c).checkValidity();
+                c.verify(ca.getPublicKey());
+                Server.setActivated(true);
+                if (array != null) {
+                    JSONObject jsonObject = new JSONObject(new String(array));
+                    licenseType = (String) jsonObject.get("type");
+                }
+            }
+            catch (Exception e){
+                Server.setActivated(false);
+                licenseType = "COMMUNITY";
+                log.warn("Your license is no longer valid or has been tampered with - " + e.toString());
+            }
+        }
+        catch (Exception e){
+            Server.activated.set(false);
+            licenseType = "COMMUNITY";
+            //logger.warning("An exception occurred while checking your license: " + e.toString());
+        }
+    }
+
+    public String getLicenseType() {
+        loadLicense();
+        return licenseType;
+    }
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/devices/DeviceServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/devices/DeviceServlet.java
index 7b0143e546ed6ef5456d1e4f387f0d2c05cca5f2..ef068abbecc5a2f36db70cb26fa3c114c7d48a39 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/devices/DeviceServlet.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/devices/DeviceServlet.java
@@ -22,32 +22,60 @@
 */
 package net.jami.jams.server.servlets.api.admin.devices;
 
+import com.jsoniter.output.JsonStream;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.annotation.WebServlet;
 import jakarta.servlet.http.HttpServlet;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import net.jami.jams.common.dao.StatementElement;
+import net.jami.jams.common.dao.StatementList;
+import net.jami.jams.common.objects.responses.DeviceRevocationResponse;
+import net.jami.jams.server.core.workflows.RevokeDeviceFlow;
 
 import java.io.IOException;
 
-@WebServlet("/api/admin/device/*")
+import static net.jami.jams.server.Server.dataStore;
+
+@WebServlet("/api/admin/device")
 public class DeviceServlet extends HttpServlet {
 
     //Get a detailed device info.
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doGet(req, resp);
+        String username = req.getParameter("username");
+        String deviceId = req.getParameter("deviceId");
+        StatementList statementList = new StatementList();
+        StatementElement st1 = new StatementElement("owner","=",username,"AND");
+        StatementElement st2 = new StatementElement("deviceId","=",deviceId,"");
+        statementList.addStatement(st1);
+        statementList.addStatement(st2);
+        resp.getOutputStream().write(JsonStream.serialize(dataStore.getDeviceDao().getObjects(statementList).get(0)).getBytes());
     }
 
     //Update device data.
     @Override
     protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doPut(req, resp);
+        String username = req.getParameter("username");
+        String deviceId = req.getParameter("deviceId");
+        String deviceName = req.getParameter("deviceName");
+        StatementList update = new StatementList();
+        StatementElement st0 = new StatementElement("deviceName","=",deviceName,"");
+        update.addStatement(st0);
+        StatementList constraint = new StatementList();
+        StatementElement st1 = new StatementElement("owner","=",username,"AND");
+        StatementElement st2 = new StatementElement("deviceId","=",deviceId,"");
+        update.addStatement(st1);
+        update.addStatement(st2);
+        if(dataStore.getDeviceDao().updateObject(update,constraint)) resp.setStatus(200);
+        else resp.sendError(500,"could not update the device's information!");
     }
 
     //Revoke/delete a device.
     @Override
     protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doDelete(req, resp);
+        DeviceRevocationResponse devResponse = RevokeDeviceFlow.revokeDevice(req.getParameter("username").toString(),req.getParameter("deviceId"));
+        if(devResponse != null) resp.getOutputStream().write(JsonStream.serialize(devResponse).getBytes());
+        else resp.sendError(500,"An exception has occurred while trying to revoke a device!");
     }
 }
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/devices/DevicesServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/devices/DevicesServlet.java
index 57a0b50c070d7afa2cde9b7ac9f656604494a380..05dca7927ea98d71bcff42f3a147a89e07b5043d 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/devices/DevicesServlet.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/devices/DevicesServlet.java
@@ -22,20 +22,29 @@
 */
 package net.jami.jams.server.servlets.api.admin.devices;
 
+import com.jsoniter.output.JsonStream;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.annotation.WebServlet;
 import jakarta.servlet.http.HttpServlet;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import net.jami.jams.common.dao.StatementElement;
+import net.jami.jams.common.dao.StatementList;
 
 import java.io.IOException;
 
-@WebServlet("/api/admin/devices/*")
+import static net.jami.jams.server.Server.dataStore;
+
+@WebServlet("/api/admin/devices")
 public class DevicesServlet extends HttpServlet {
 
     //Get a list of devices for a user.
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doGet(req, resp);
+        String username = req.getParameter("username");
+        StatementList statementList = new StatementList();
+        StatementElement st1 = new StatementElement("owner","=",username,"");
+        statementList.addStatement(st1);
+        resp.getOutputStream().write(JsonStream.serialize(dataStore.getDeviceDao().getObjects(statementList)).getBytes());
     }
 }
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/directory/DirectoryEntryServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/directory/DirectoryEntryServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..88d3d7e1aa2f0c5d3d45d2025939d6bc5a219340
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/directory/DirectoryEntryServlet.java
@@ -0,0 +1,48 @@
+package net.jami.jams.server.servlets.api.admin.directory;
+
+import com.jsoniter.JsonIterator;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.annotation.WebServlet;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import net.jami.jams.common.authentication.AuthenticationSourceType;
+import net.jami.jams.common.authmodule.AuthModuleKey;
+import net.jami.jams.common.objects.user.UserProfile;
+
+import java.io.IOException;
+
+import static net.jami.jams.server.Server.userAuthenticationModule;
+
+@WebServlet("/api/admin/directory/entry")
+@Slf4j
+public class DirectoryEntryServlet extends HttpServlet {
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        //Create a user profile.
+        try {
+            String realm = req.getParameter("directory");
+            UserProfile userProfile = JsonIterator.deserialize(req.getInputStream().readAllBytes(), UserProfile.class);
+            userAuthenticationModule.getAuthSources().get(new AuthModuleKey(realm, AuthenticationSourceType.LOCAL))
+                    .setUserProfile(userProfile);
+            resp.setStatus(200);
+        }
+        catch (Exception e){
+            log.error("Could not store a user profile with error {}",e.getMessage());
+            resp.sendError(500,e.getMessage());
+        }
+
+    }
+
+    @Override
+    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        //Update a user's profile.
+    }
+
+    @Override
+    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        //This method will probably never be implemented.
+    }
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/users/UserServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/users/UserServlet.java
index 8d02e5c0b08014fd2dd27115ab63414ebd39738a..17a7176b37cefa93aaa5a881c0a904afed3dd514 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/users/UserServlet.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/users/UserServlet.java
@@ -22,38 +22,76 @@
 */
 package net.jami.jams.server.servlets.api.admin.users;
 
+import com.jsoniter.output.JsonStream;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.annotation.WebServlet;
 import jakarta.servlet.http.HttpServlet;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import net.jami.jams.common.authentication.AuthenticationSourceType;
+import net.jami.jams.common.dao.StatementElement;
+import net.jami.jams.common.dao.StatementList;
+import net.jami.jams.common.objects.responses.DeviceRevocationResponse;
+import net.jami.jams.common.objects.user.User;
+import net.jami.jams.server.core.workflows.RevokeUserFlow;
 
 import java.io.IOException;
 
-@WebServlet("/api/admin/user/*")
+import static net.jami.jams.server.Server.*;
+
+@WebServlet("/api/admin/user")
 public class UserServlet extends HttpServlet {
 
     //Get the user profile.
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doGet(req, resp);
+        StatementList statementList = new StatementList();
+        StatementElement st1 = new StatementElement("username","=",req.getParameter("username"),"");
+        statementList.addStatement(st1);
+        resp.getOutputStream().write(JsonStream.serialize(dataStore.getUserDao().getObjects(statementList)).getBytes());
     }
 
     //Create an internal user - this is always technically available, because internal users have the right to exist.
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doPost(req, resp);
+        User user = new User();
+        user.setUsername(req.getParameter("username"));
+        user.setPassword("TEMP-PASSWORD");
+        user.setRealm("LOCAL");
+        user.setUserType(AuthenticationSourceType.LOCAL);
+        if(userAuthenticationModule.createUser(user.getUserType(),user.getRealm(),nameServer,user)){
+            resp.getOutputStream().write(JsonStream.serialize(user).getBytes());
+            return;
+        }
+        resp.sendError(500,"Could not create a user successfully!");
     }
 
     //Update user data.
     @Override
     protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doPut(req, resp);
+        String username = req.getParameter("username");
+        //Check if he is AD/LDAP - then return a 403, because we can't set such password.
+        StatementList select = new StatementList();
+        StatementElement st = new StatementElement("username","=",username,"");
+        if(dataStore.getUserDao().getObjects(select).get(0).getUserType() != AuthenticationSourceType.LOCAL){
+            resp.sendError(500,"The user is not a local user, therefore we cannot change his data!");
+            return;
+        }
+        StatementList update = new StatementList();
+        StatementElement st0 = new StatementElement("password","=",req.getParameter("password"),"");
+        update.addStatement(st0);
+        StatementList constraint = new StatementList();
+        StatementElement st1 = new StatementElement("username","=",username,"");
+        update.addStatement(st1);
+        if(dataStore.getUserDao().updateObject(update,constraint)) resp.setStatus(200);
+        else resp.sendError(500,"could not update the users's data field!");
     }
 
     //Revoke a user.
     @Override
     protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doDelete(req, resp);
+        DeviceRevocationResponse devResponse = RevokeUserFlow.revokeUser(req.getParameter("username"));
+        if(devResponse != null) resp.getOutputStream().write(JsonStream.serialize(devResponse).getBytes());
+        else resp.sendError(500,"An exception has occurred while trying to revoke a device!");
     }
 }
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/users/UsersServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/users/UsersServlet.java
index ddafb44102861363ca2b80c2eb51dd28cfc74d99..d0ba9762ae8ed335b0db6c1abdd6f293c44d5a29 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/users/UsersServlet.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/users/UsersServlet.java
@@ -22,6 +22,7 @@
 */
 package net.jami.jams.server.servlets.api.admin.users;
 
+import com.jsoniter.output.JsonStream;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.annotation.WebServlet;
 import jakarta.servlet.http.HttpServlet;
@@ -30,12 +31,14 @@ import jakarta.servlet.http.HttpServletResponse;
 
 import java.io.IOException;
 
+import static net.jami.jams.server.Server.dataStore;
+
 @WebServlet("/api/admin/users")
 public class UsersServlet extends HttpServlet {
 
     //Returns a list of users.
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doGet(req, resp);
+        resp.getOutputStream().write(JsonStream.serialize(dataStore.getDeviceDao().getObjects(null).get(0)).getBytes());
     }
 }
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/device/DeviceServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/device/DeviceServlet.java
index b8ade2b83ec91da277ecdc9fefce376b93db3b44..18a3c81344769f92f7ab0090723aca91e15c3544 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/device/DeviceServlet.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/device/DeviceServlet.java
@@ -33,7 +33,9 @@ import net.jami.jams.common.dao.StatementElement;
 import net.jami.jams.common.dao.StatementList;
 import net.jami.jams.common.objects.requests.DeviceRegistrationRequest;
 import net.jami.jams.common.objects.responses.DeviceRegistrationResponse;
+import net.jami.jams.common.objects.responses.DeviceRevocationResponse;
 import net.jami.jams.server.core.workflows.RegisterDeviceFlow;
+import net.jami.jams.server.core.workflows.RevokeDeviceFlow;
 
 import java.io.IOException;
 
@@ -64,11 +66,26 @@ public class DeviceServlet extends HttpServlet {
 
     @Override
     protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doPut(req, resp);
+        String username = req.getAttribute("username").toString();
+        String deviceId = req.getPathInfo().replace("/","");
+        String deviceName = req.getParameter("deviceName");
+        StatementList update = new StatementList();
+        StatementElement st0 = new StatementElement("deviceName","=",deviceName,"");
+        update.addStatement(st0);
+        StatementList constraint = new StatementList();
+        StatementElement st1 = new StatementElement("owner","=",username,"AND");
+        StatementElement st2 = new StatementElement("deviceId","=",deviceId,"");
+        update.addStatement(st1);
+        update.addStatement(st2);
+        if(dataStore.getDeviceDao().updateObject(update,constraint)) resp.setStatus(200);
+        else resp.sendError(500,"could not update the device's information!");
     }
 
     @Override
     protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doDelete(req, resp);
+        String deviceId = req.getPathInfo().replace("/","");
+        DeviceRevocationResponse devResponse = RevokeDeviceFlow.revokeDevice(req.getAttribute("username").toString(),deviceId);
+        if(devResponse != null) resp.getOutputStream().write(JsonStream.serialize(devResponse).getBytes());
+        else resp.sendError(500,"An exception has occurred while trying to revoke a device!");
     }
 }
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/directory/DirectoriesServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/directory/DirectoriesServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f5b05e18235c26d95ce7524b8a4a805910222c4
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/directory/DirectoriesServlet.java
@@ -0,0 +1,21 @@
+package net.jami.jams.server.servlets.api.auth.directory;
+
+import com.jsoniter.output.JsonStream;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.annotation.WebServlet;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+
+import static net.jami.jams.server.Server.userAuthenticationModule;
+
+@WebServlet("/api/auth/directories")
+public class DirectoriesServlet extends HttpServlet {
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        resp.getOutputStream().write(JsonStream.serialize(userAuthenticationModule.getAuthSources().keySet()).getBytes());
+    }
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/directory/DirectoryEntryServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/directory/DirectoryEntryServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a28415519396b9a2b5066a894a7816d60b5a914
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/directory/DirectoryEntryServlet.java
@@ -0,0 +1,47 @@
+package net.jami.jams.server.servlets.api.auth.directory;
+
+import com.jsoniter.output.JsonStream;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.annotation.WebServlet;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import net.jami.jams.common.authentication.AuthenticationSourceType;
+import net.jami.jams.common.authmodule.AuthModuleKey;
+import net.jami.jams.common.objects.user.UserProfile;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static net.jami.jams.server.Server.userAuthenticationModule;
+
+//This is an endpoint to manipulate directory entry-data, this make sense only for local setups.
+
+@WebServlet("/api/auth/directory/entry")
+public class DirectoryEntryServlet extends HttpServlet {
+
+    //Get a profile from a directory, we are assuming here
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        if (req.getParameter("directory") != null && req.getParameter("directoryType") != null) {
+            UserProfile[] profiles = userAuthenticationModule.getAuthSources()
+                    .get(new AuthModuleKey(req.getParameter("directory"), AuthenticationSourceType.fromString(req.getParameter("directoryType"))))
+                    .getUserProfile(req.getParameter("username"), "LOGON_NAME");
+            resp.getOutputStream().write(JsonStream.serialize(profiles[0]).getBytes());
+            return;
+        }
+        List<UserProfile> userProfiles = new ArrayList<>();
+        userAuthenticationModule.getAuthSources().forEach((k, v) -> {
+            UserProfile[] profiles = v.getUserProfile(req.getParameter("username"), "LOGON_NAME");
+            if (profiles != null && profiles.length != 0) userProfiles.addAll(Arrays.asList(profiles));
+        });
+        resp.getOutputStream().write(JsonStream.serialize(userProfiles.get(0)).getBytes());
+    }
+
+    @Override
+    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        //This should work to modify a profile only in the case of a LOCAL directory.
+    }
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/directory/SearchDirectoryServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/directory/SearchDirectoryServlet.java
index d4428d6e1b2784c2dd3087c329cb8d0134792ebd..69e318c33e4f376173589eeb3759b6f975420969 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/directory/SearchDirectoryServlet.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/directory/SearchDirectoryServlet.java
@@ -29,7 +29,6 @@ import jakarta.servlet.http.HttpServlet;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import net.jami.jams.common.objects.user.UserProfile;
-import net.jami.jams.server.Server;
 
 import java.io.IOException;
 import java.util.ArrayList;
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/user/UserServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/user/UserServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..c89b7bd944511ba3c00f6e35b08d594d7b31d498
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/user/UserServlet.java
@@ -0,0 +1,51 @@
+package net.jami.jams.server.servlets.api.auth.user;
+
+import com.jsoniter.output.JsonStream;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.annotation.WebServlet;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import net.jami.jams.common.authentication.AuthenticationSourceType;
+import net.jami.jams.common.dao.StatementElement;
+import net.jami.jams.common.dao.StatementList;
+
+import java.io.IOException;
+
+import static net.jami.jams.server.Server.dataStore;
+
+@WebServlet("/api/auth/user")
+public class UserServlet extends HttpServlet {
+
+    //User can "read" his own profile.
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String username = req.getAttribute("username").toString();
+        StatementList select = new StatementList();
+        StatementElement st = new StatementElement("username","=",username,"");
+        select.addStatement(st);
+        resp.getOutputStream().write(JsonStream.serialize(dataStore.getUserDao().getObjects(select).get(0)).getBytes());
+    }
+
+    //The user can update 3 fields: password,privatekey,publickey
+    //For now we do not consider the possibility for privatekey, publickey for other reasons.
+    @Override
+    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String username = req.getAttribute("username").toString();
+        //Check if he is AD/LDAP - then return a 401, because we can't set such password.
+        StatementList select = new StatementList();
+        StatementElement st = new StatementElement("username","=",username,"");
+        if(dataStore.getUserDao().getObjects(select).get(0).getUserType() != AuthenticationSourceType.LOCAL){
+            resp.sendError(500,"The user is not a local user, therefore we cannot change his data!");
+            return;
+        }
+        StatementList update = new StatementList();
+        StatementElement st0 = new StatementElement("password","=",req.getParameter("password"),"");
+        update.addStatement(st0);
+        StatementList constraint = new StatementList();
+        StatementElement st1 = new StatementElement("username","=",username,"");
+        update.addStatement(st1);
+        if(dataStore.getUserDao().updateObject(update,constraint)) resp.setStatus(200);
+        else resp.sendError(500,"could not update the users's data field!");
+    }
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/StartInstallServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/StartInstallServlet.java
index 6a9e1340779dfb8a00ee2e29f98b58a21dc0c435..50f6f9e6e6b0987d2046450290ded0e9fabaf404 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/StartInstallServlet.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/StartInstallServlet.java
@@ -68,9 +68,7 @@ public class StartInstallServlet extends HttpServlet {
     //This is the ONLY case where we write directy to the DB
     @Override
     protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        StatementList statementList = new StatementList();
-        statementList.setStatements(null);
-        if(dataStore.getUserDao().getObjects(statementList).size() != 0){
+        if(dataStore.getUserDao().getObjects(null).size() != 0){
             resp.sendError(500,"We have tried to create an administrative account where one already exists!");
             return;
         }
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/LicenseServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/LicenseServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..de2518e1b2e002f8e5be1458852755164d38260d
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/LicenseServlet.java
@@ -0,0 +1,39 @@
+package net.jami.jams.server.servlets.api.update;
+
+import com.jsoniter.output.JsonStream;
+import net.jami.jams.ca.JamsCA;
+import net.jami.jams.common.cryptoengineapi.CertificateAuthority;
+import net.jami.jams.common.utils.LicenseUtils;
+import net.jami.jams.server.Server;
+import net.jami.jams.server.licensing.LicenseService;
+import net.jami.jams.server.startup.CryptoEngineLoader;
+
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+
+
+@WebServlet("/api/auth/license")
+public class LicenseServlet extends HttpServlet {
+
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
+        resp.setHeader("Access-Control-Allow-Origin", JamsCA.serverDomain);
+        resp.setContentType("application/json");
+        try {
+            resp.setStatus(200);
+            HashMap<String,Object> payload = new HashMap<>();
+            payload.put("isActive", Server.isActivated());
+            payload.put("licenseType", new LicenseService().getLicenseType());
+            payload.put("currentVersion", LicenseUtils.checkVersion(System.getProperty("user.dir") + "/tmpjar/", System.getProperty("user.dir") + "/jams-server.jar"));
+            resp.getOutputStream().write(JsonStream.serialize(payload).getBytes());
+        }
+        catch (Exception e){
+            resp.setStatus(403);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/NeedsUpdateServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/NeedsUpdateServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..cae916d93dc1f27aeb0a5e280ba50d3381d675f7
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/NeedsUpdateServlet.java
@@ -0,0 +1,46 @@
+package net.jami.jams.server.servlets.api.update;
+
+import com.jsoniter.output.JsonStream;
+import net.jami.jams.ca.JamsCA;
+import net.jami.jams.server.Server;
+
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.logging.Logger;
+
+@WebServlet("/api/checkupdate")
+public class NeedsUpdateServlet extends HttpServlet {
+
+    private final static Logger logger = Logger.getLogger(NeedsUpdateServlet.class.getName());
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
+        resp.setHeader("Access-Control-Allow-Origin", JamsCA.serverDomain);
+        resp.setContentType("application/json");
+        try {
+            HashMap<String,Object> payload = new HashMap<>();
+            if(!Server.updateInterface.getVersions().equals("{}")) {
+                payload.put("updateAvailable", Server.updateInterface.getUpdateAvailable().get());
+                payload.put("newVersions", Server.updateInterface.getVersions());
+            }
+            else
+                payload.put("updateAvailable",false);
+
+            resp.getOutputStream().write(JsonStream.serialize(payload).getBytes());
+            resp.setStatus(200);
+        }
+        catch (Exception e){
+            resp.setStatus(500);
+        }
+    }
+
+    @Override
+    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+
+    }
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/StartUpdateServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/StartUpdateServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..52b1e38be8fd68afd411a3c070d54a2b812abe71
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/StartUpdateServlet.java
@@ -0,0 +1,29 @@
+package net.jami.jams.server.servlets.api.update;
+
+import net.jami.jams.ca.JamsCA;
+import net.jami.jams.server.Server;
+
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.logging.Logger;
+
+@WebServlet("/api/startupdate")
+public class StartUpdateServlet extends HttpServlet {
+
+    private final static Logger logger = Logger.getLogger(StartUpdateServlet.class.getName());
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
+        resp.setHeader("Access-Control-Allow-Origin", JamsCA.serverDomain);
+        resp.setContentType("application/json");
+        try {
+            Server.updateInterface.approveUpdate();
+            resp.setStatus(200);
+        }
+        catch (Exception e){
+            resp.setStatus(500);
+        }
+    }
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/SubscriptionServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/SubscriptionServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..67239407bd82517d61f4ddd67e39167ec0d81b96
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/SubscriptionServlet.java
@@ -0,0 +1,29 @@
+package net.jami.jams.server.servlets.api.update;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.annotation.WebServlet;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+
+@WebServlet("/api/subscription")
+public class SubscriptionServlet extends HttpServlet {
+
+    //Get the subscription status (see: SubscriptionStatusResponse.class)
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        super.doGet(req, resp);
+    }
+
+    //Upload the license here, which is really just uploading a base64 representation of the keypair - and store it
+    //somewhere.
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        //Create the keystore based on the uploadaded keypair.
+
+
+        super.doPost(req, resp);
+    }
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/UpdateServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/UpdateServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..3d5464613c9184b396022e96448d36426cf3d246
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/update/UpdateServlet.java
@@ -0,0 +1,25 @@
+package net.jami.jams.server.servlets.api.update;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.annotation.WebServlet;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+
+@WebServlet("/api/update")
+public class UpdateServlet extends HttpServlet {
+
+    //Return the current version number and the available version number.
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        super.doGet(req, resp);
+    }
+
+    //This is the do-update button.
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        super.doPost(req, resp);
+    }
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/user/LocalUserExistsServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/user/LocalUserExistsServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..5313cd79d72265f002dc14143070480000abc62f
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/user/LocalUserExistsServlet.java
@@ -0,0 +1,75 @@
+package net.jami.jams.server.servlets.api.user;
+
+import com.jsoniter.JsonIterator;
+import com.jsoniter.any.Any;
+import com.jsoniter.output.JsonStream;
+import lombok.extern.slf4j.Slf4j;
+import net.jami.jams.ca.JamsCA;
+import net.jami.jams.common.authentication.AuthenticationSourceType;
+import net.jami.jams.common.dao.StatementElement;
+import net.jami.jams.common.dao.StatementList;
+import net.jami.jams.common.objects.user.User;
+import net.jami.jams.server.Server;
+
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+
+@WebServlet("/api/user/exists")
+@Slf4j
+public class LocalUserExistsServlet extends HttpServlet {
+
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
+        resp.setHeader("Access-Control-Allow-Origin", JamsCA.serverDomain);
+        resp.setContentType("application/json");
+        StringBuilder stringBuilder = new StringBuilder();
+
+        try {
+            int x = 0;
+            while (true) {
+                x = req.getInputStream().read();
+                if(x == -1) break;
+                stringBuilder.append((char) x);
+            }
+        }
+        catch (Exception e) {
+            log.error("error decoding request body");
+        }
+
+
+        if(stringBuilder.toString() != null) {
+
+            Any userData = JsonIterator.deserialize(stringBuilder.toString());
+            String username = userData.get("username").toString();
+            try {
+                    if (Server.dataStore.userExists(username)) {
+
+                        StatementList statementList = new StatementList();
+                        StatementElement statementElement = new StatementElement("username", "=", username, "");
+                        statementList.addStatement(statementElement);
+                        User user = Server.dataStore.getUserDao().getObjects(statementList).get(0);
+
+                        if (user != null && user.getUserType() == AuthenticationSourceType.LOCAL) {
+                            resp.setStatus(200);
+                            HashMap<String, String> statusInfo = new HashMap<>();
+                            statusInfo.put("exists", "true");
+                            resp.getOutputStream().write(JsonStream.serialize(statusInfo).getBytes());
+                        } else {
+                            resp.setStatus(500);
+                            HashMap<String, String> statusInfo = new HashMap<>();
+                            statusInfo.put("exists", "false");
+                            resp.getOutputStream().write(JsonStream.serialize(statusInfo).getBytes());
+                        }
+                    }
+
+            } catch (Exception e) {
+                log.info(e.toString());
+                resp.setStatus(500);
+            }
+        }
+    }
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/user/LocalUserNeedsResetServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/user/LocalUserNeedsResetServlet.java
new file mode 100644
index 0000000000000000000000000000000000000000..9650dd8234ced5c776c648474bce2711067077cc
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/user/LocalUserNeedsResetServlet.java
@@ -0,0 +1,94 @@
+package net.jami.jams.server.servlets.api.user;
+
+
+import com.jsoniter.output.JsonStream;
+import lombok.extern.slf4j.Slf4j;
+import net.jami.jams.ca.JamsCA;
+import net.jami.jams.common.authentication.local.LocalAuthSettings;
+import net.jami.jams.common.authmodule.AuthModuleKey;
+import net.jami.jams.common.dao.StatementElement;
+import net.jami.jams.common.dao.StatementList;
+import net.jami.jams.common.objects.user.User;
+import net.jami.jams.server.Server;
+import net.jami.jams.server.servlets.api.install.CachedObjects;
+import net.jami.jams.common.authentication.AuthenticationSourceType;
+
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.security.SecureRandom;
+import java.util.HashMap;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+@WebServlet("/api/user/needsreset")
+@Slf4j
+public class LocalUserNeedsResetServlet extends HttpServlet {
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
+        resp.setHeader("Access-Control-Allow-Origin", JamsCA.serverDomain);
+        resp.setContentType("application/json");
+        StringBuilder stringBuilder = new StringBuilder();
+
+        try {
+            int x = 0;
+            while (true) {
+                x = req.getInputStream().read();
+                if(x == -1) break;
+                stringBuilder.append((char) x);
+            }
+        }
+        catch (Exception e){
+            log.error("error decoding request body");
+        }
+
+
+        if(stringBuilder.toString() != null) {
+
+            try {
+                if (CachedObjects.localAuthSettings != null && req.getParameterMap().containsKey("username")) {
+
+                    HashMap<String,String> statusInfo = new HashMap<>();
+                    String username = req.getParameter("username");
+
+                    if(Server.dataStore.userExists(username)){
+                        StatementList statementList = new StatementList();
+                        StatementElement statementElement = new StatementElement("username","=",username,"");
+                        statementList.addStatement(statementElement);
+                        User user = Server.dataStore.getUserDao().getObjects(statementList).get(0);
+
+                        if (user != null && user.getNeedsPasswordReset() && user.getUserType() ==  AuthenticationSourceType.LOCAL) {
+                            // show the OTP modal
+                            char[] otp = Server.userAuthenticationModule.getOTP(req.getParameter("username"));
+                            statusInfo.put("needsReset", "true");
+                            statusInfo.put("otp", new String(otp));
+                        } else {
+                            // change status for user, generate new password and update info
+                            // Server.userAuthenticationModule.updateReset(user, 1);
+                            user.setNeedsPasswordReset(false);
+                            String newPW = generateRandomPassword();
+                            user.setPassword(newPW);
+                            Server.dataStore.getUserDao().storeObject(user);
+                            statusInfo.put("needsReset", "false");
+                            statusInfo.put("newPW", newPW);
+                        }
+                    }
+
+                    resp.getOutputStream().write(JsonStream.serialize(statusInfo).getBytes());
+                    resp.setStatus(200);
+                }
+
+            } catch (Exception e) {
+                log.info(e.toString());
+                resp.setStatus(500);
+            }
+        }
+    }
+
+    // TODO : change to char array
+    public String generateRandomPassword() {
+        return new SecureRandom().ints(12, 48, 58).mapToObj(i -> String.valueOf((char)i)).collect(Collectors.joining());
+    }
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/filters/AdminApiFilter.java b/jams-server/src/main/java/net/jami/jams/server/servlets/filters/AdminApiFilter.java
index a109f437b264eee2a5583ba674656b86a709bf48..d0f324accc0534d568589127a7384b4b8b4159be 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/filters/AdminApiFilter.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/filters/AdminApiFilter.java
@@ -34,7 +34,6 @@ import net.jami.jams.common.objects.user.AccessLevel;
 import net.jami.jams.server.Server;
 
 import java.io.IOException;
-import java.util.Date;
 
 import static net.jami.jams.server.Server.userAuthenticationModule;
 import static net.jami.jams.server.servlets.filters.JWTValidator.verifyLevel;
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/filters/ApiFilter.java b/jams-server/src/main/java/net/jami/jams/server/servlets/filters/ApiFilter.java
index c25b7c9d7cca8ddfe34ae1218f532961cf8ddf4d..056965d0f1d51cfe9dcfb1b5f9d37e89d217f477 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/filters/ApiFilter.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/filters/ApiFilter.java
@@ -33,7 +33,6 @@ import lombok.extern.slf4j.Slf4j;
 import net.jami.jams.server.Server;
 
 import java.io.IOException;
-import java.util.Date;
 
 import static net.jami.jams.server.Server.userAuthenticationModule;
 import static net.jami.jams.server.servlets.filters.JWTValidator.verifyValidity;
diff --git a/jams-server/src/main/java/net/jami/jams/server/startup/UpdaterLoader.java b/jams-server/src/main/java/net/jami/jams/server/startup/UpdaterLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..bf0b9cb6d57f8ce08a1e4c2132f1f17942533e69
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/startup/UpdaterLoader.java
@@ -0,0 +1,22 @@
+package net.jami.jams.server.startup;
+
+import lombok.extern.slf4j.Slf4j;
+import net.jami.jams.common.updater.AppUpdater;
+import net.jami.jams.common.utils.LibraryLoader;
+
+@Slf4j
+public class UpdaterLoader {
+
+    public static AppUpdater loadUpdater() {
+        try {
+            Class<?> cls = LibraryLoader.classLoader.loadClass("net.jami.jams.updater.JAMSUpdater");
+            log.info("Updater service started...");
+            return (AppUpdater) cls.getConstructor().newInstance();
+        }
+        catch (Exception e){
+            log.error("Could not load update module...");
+            return null;
+        }
+    }
+
+}
diff --git a/ldap-connector/src/main/java/net/jami/jams/ldap/connector/LDAPConnector.java b/ldap-connector/src/main/java/net/jami/jams/ldap/connector/LDAPConnector.java
index 1e734b75b670e74862172fa91308d70617a591bd..b6489bfa3dcb6293a8bfff24136f7033512da930 100644
--- a/ldap-connector/src/main/java/net/jami/jams/ldap/connector/LDAPConnector.java
+++ b/ldap-connector/src/main/java/net/jami/jams/ldap/connector/LDAPConnector.java
@@ -71,6 +71,11 @@ public class LDAPConnector implements AuthenticationSource {
         return userProfileService.getUserProfile(queryString,field);
     }
 
+    @Override
+    public void setUserProfile(UserProfile userProfile) {
+        //does nothing since we cannot edit LDAP profiles.
+    }
+
     @Override
     public boolean authenticate(String username, String password) {
         return authenticationService.authenticateUser(username,password);
diff --git a/pom.xml b/pom.xml
index e55eb9726a217afc9d8e262b4cb5eb0eacd5ff85..2e60499d4adf8f50dc746160a781d9e96de07d2a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,6 +8,7 @@
     <artifactId>jams3-parent</artifactId>
     <packaging>pom</packaging>
     <version>${revision}</version>
+    <name>Jami Account Management Server</name>
     <modules>
         <module>jams-server</module>
         <module>jams-common</module>
@@ -18,7 +19,7 @@
         <module>jami-dht</module>
         <module>authentication-module</module>
         <module>jami-nameserver</module>
-        <module>jams-launcher</module>
+        <module>updater</module>
     </modules>
 
     <properties>
@@ -47,6 +48,11 @@
         <maven.clean.version>3.1.0</maven.clean.version>
         <nimbus.jwt.version>8.17</nimbus.jwt.version>
         <asm.version>8.0</asm.version>
+        <jeromq.version>0.5.2</jeromq.version>
+        <maven.model.version>3.2.5</maven.model.version>
+        <apache.httpcore.version>4.4.12</apache.httpcore.version>
+        <apache.httpclient.version>4.5.10</apache.httpclient.version>
+        <google.guava.version>20.0</google.guava.version>
     </properties>
 
     <dependencies>
@@ -135,4 +141,4 @@
         </plugins>
     </build>
 
-</project>
\ No newline at end of file
+</project>
diff --git a/updater/pom.xml b/updater/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fc45cafa89560c6bbb9fbaea72ba50efa10db524
--- /dev/null
+++ b/updater/pom.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>jams3-parent</artifactId>
+        <groupId>net.jami</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>updater</artifactId>
+    <dependencies>
+        <dependency>
+            <groupId>net.jami</groupId>
+            <artifactId>jams-common</artifactId>
+            <version>${revision}</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>${maven.shade.version}</version>
+                <executions>
+                    <!-- Run shade goal on package phase -->
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <outputFile>../jams/libs/${project.artifactId}.jar</outputFile>
+                            <filters>
+                                <filter>
+                                    <artifact>*:*</artifact>
+                                    <excludes>
+                                        <exclude>META-INF/*.SF</exclude>
+                                        <exclude>META-INF/*.DSA</exclude>
+                                        <exclude>META-INF/*.RSA</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                            <transformers>
+                                <!-- add Main-Class to manifest file -->
+                                <transformer
+                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <manifestEntries>
+                                        <Main-Class>net.jami.jams.server.Server</Main-Class>
+                                        <Implementation-Title>${project.artifactId}</Implementation-Title>
+                                        <Implementation-Version>${project.version}</Implementation-Version>
+                                        <Class-Path>.</Class-Path>
+                                    </manifestEntries>
+                                </transformer>
+                                <transformer
+                                        implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+                            </transformers>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/updater/src/main/java/module-info.java b/updater/src/main/java/module-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ac87ad45e5d283e339fc567447f5b35347c98f0
--- /dev/null
+++ b/updater/src/main/java/module-info.java
@@ -0,0 +1,6 @@
+module updater {
+    requires jams.common;
+    requires lombok;
+    requires org.slf4j;
+
+}
\ No newline at end of file
diff --git a/updater/src/main/java/net/jami/jams/updater/JAMSUpdater.java b/updater/src/main/java/net/jami/jams/updater/JAMSUpdater.java
new file mode 100644
index 0000000000000000000000000000000000000000..b8a49d0157a3a2e0caf8c7b2151cf92477ce2a46
--- /dev/null
+++ b/updater/src/main/java/net/jami/jams/updater/JAMSUpdater.java
@@ -0,0 +1,26 @@
+package net.jami.jams.updater;
+
+import net.jami.jams.common.updater.AppUpdater;
+
+public class JAMSUpdater implements AppUpdater {
+
+    UpdateDownloader updateDownloader = new UpdateDownloader();
+
+    public JAMSUpdater() {
+    }
+
+    @Override
+    public String getCurrentVersion() {
+        return null;
+    }
+
+    @Override
+    public String getLatestVersion() {
+        return null;
+    }
+
+    @Override
+    public boolean downloadUpdates() {
+        return updateDownloader.doUpdate();
+    }
+}
diff --git a/updater/src/main/java/net/jami/jams/updater/SFLTrustStore.java b/updater/src/main/java/net/jami/jams/updater/SFLTrustStore.java
new file mode 100644
index 0000000000000000000000000000000000000000..3f7b5cc2a32221b34608c992cd13d59d1bfe3916
--- /dev/null
+++ b/updater/src/main/java/net/jami/jams/updater/SFLTrustStore.java
@@ -0,0 +1,51 @@
+package net.jami.jams.updater;
+
+import lombok.extern.slf4j.Slf4j;
+import net.jami.jams.common.utils.X509Utils;
+
+import javax.net.ssl.X509TrustManager;
+import java.io.InputStream;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+@Slf4j
+public class SFLTrustStore implements X509TrustManager {
+
+    X509Certificate[] sflCertificate = new X509Certificate[1];
+
+    //TODO: This just returns the SavoirFaireLinux CA everywhere - get this from the OEM resources folder.
+    public SFLTrustStore() {
+        try {
+            InputStream is = SFLTrustStore.class.getClassLoader().getResourceAsStream("ca.crt");
+            X509Certificate certificate = X509Utils.getCertificateFromPEMString(new String(is.readAllBytes()));
+            sflCertificate[0] = certificate;
+        }
+        catch (Exception e){
+            log.error("Could not load the SavoirFaireLinux certificate with error: {}",e.getMessage());
+        }
+    }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
+        boolean failedCheck = false;
+        for(int i=0; i < x509Certificates.length; i++){
+            try {
+                x509Certificates[i].verify(sflCertificate[0].getPublicKey());
+            }
+            catch (Exception e){
+                throw new CertificateException("Failed to verify the server's identity...");
+            }
+        }
+    }
+
+    //Implement this.
+    @Override
+    public X509Certificate[] getAcceptedIssuers() {
+       return sflCertificate;
+    }
+}
diff --git a/updater/src/main/java/net/jami/jams/updater/UpdateCheckTask.java b/updater/src/main/java/net/jami/jams/updater/UpdateCheckTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..d41fd0d60aeea9fb7bfe828e808f26c1f2e8264c
--- /dev/null
+++ b/updater/src/main/java/net/jami/jams/updater/UpdateCheckTask.java
@@ -0,0 +1,45 @@
+package net.jami.jams.updater;
+
+import lombok.extern.slf4j.Slf4j;
+
+import javax.net.ssl.HttpsURLConnection;
+import java.net.URL;
+import java.util.List;
+import java.util.TimerTask;
+
+import static net.jami.jams.updater.UpdateDaemon.UPDATE_SERVER_URI;
+
+@Slf4j
+public class UpdateCheckTask extends TimerTask {
+
+    private final List<String> files;
+
+    protected UpdateCheckTask(List<String> files) {
+        this.files = files;
+    }
+
+    @Override
+    public void run() {
+        try {
+            URL url = new URL(UPDATE_SERVER_URI);
+            HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
+            con.setRequestMethod("GET");
+            if (con.getResponseCode() == 200) {
+                StringBuilder responseData = new StringBuilder();
+                int respSize = Integer.parseInt(con.getHeaderField("Content-Length"));
+                int currentSize = 0;
+                while (currentSize < respSize) {
+                    responseData.append((char) con.getInputStream().read());
+                    currentSize++;
+                }
+                log.info("Response received from update server {} ",con.getResponseCode());
+                //TODO: Populate the files which "need" to be downloaded.
+            } else {
+                log.info("An error has occurred while checking for an update: {} ", con.getResponseCode());
+            }
+        }
+        catch (Exception e){
+            log.error("Could not check for updates with error: {}",e.getMessage());
+        }
+    }
+}
diff --git a/updater/src/main/java/net/jami/jams/updater/UpdateDaemon.java b/updater/src/main/java/net/jami/jams/updater/UpdateDaemon.java
new file mode 100644
index 0000000000000000000000000000000000000000..5eeb87147bf3f8a2a831abfc7e4ed4990be6e077
--- /dev/null
+++ b/updater/src/main/java/net/jami/jams/updater/UpdateDaemon.java
@@ -0,0 +1,22 @@
+package net.jami.jams.updater;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+
+@Getter
+@Setter
+public class UpdateDaemon extends Timer {
+
+    //TODO: This should come from the resources file.
+    public  static final String UPDATE_SERVER_URI = "https://jami.net";
+    public static final List<String> updateFiles = new ArrayList<>();
+
+    public UpdateDaemon() {
+        this.schedule(new UpdateCheckTask(updateFiles),0,150_000);
+    }
+
+}
diff --git a/updater/src/main/java/net/jami/jams/updater/UpdateDownloader.java b/updater/src/main/java/net/jami/jams/updater/UpdateDownloader.java
new file mode 100644
index 0000000000000000000000000000000000000000..a66798c1d23ebb97aa0058add2f4f557f3b4c650
--- /dev/null
+++ b/updater/src/main/java/net/jami/jams/updater/UpdateDownloader.java
@@ -0,0 +1,78 @@
+package net.jami.jams.updater;
+
+import lombok.extern.slf4j.Slf4j;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import java.net.URL;
+
+import static net.jami.jams.updater.UpdateDaemon.UPDATE_SERVER_URI;
+import static net.jami.jams.updater.UpdateDaemon.updateFiles;
+
+@Slf4j
+public class UpdateDownloader {
+
+    private SSLSocketFactory sslSocketFactory;
+
+    //returns the activation status of the server.
+    public boolean getActivationStatus(){
+        return loadLicense();
+    }
+
+
+    public boolean doUpdate(){
+        try {
+            if (!loadLicense()) {
+                log.warn("This server does not have a valid license, no files will be download and no update" +
+                        " will take place...");
+                return false;
+            }
+            for(String file : UpdateDaemon.updateFiles) {
+                URL url = new URL(UPDATE_SERVER_URI);
+                HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
+                con.setSSLSocketFactory(sslSocketFactory);
+                con.setRequestMethod("GET");
+                if (con.getResponseCode() == 200) {
+                    StringBuilder responseData = new StringBuilder();
+                    int respSize = Integer.parseInt(con.getHeaderField("Content-Length"));
+                    int currentSize = 0;
+                    while (currentSize < respSize) {
+                        responseData.append((char) con.getInputStream().read());
+                        currentSize++;
+                    }
+                    updateFiles.remove(file);
+                    log.info("Successfully downloaded file...");
+                } else {
+                    log.info("An error has occurred while trying to download a file: {} ", con.getResponseCode());
+                    return false;
+                }
+            }
+            return true;
+        }
+        catch (Exception e){
+            log.error("Could not check for updates with error: {}",e.getMessage());
+            return false;
+        }
+    }
+
+    private boolean loadLicense(){
+        try {
+            //We assume the keystore already exists, because it gets created upon upload.
+            //Basically just load the JKS keystore here.
+            //TODO: Load keystore from file.
+            //Initialize the SSL context & load the SFL trust store.
+            SSLContext sslContext = SSLContext.getInstance("SSL");
+            //sslContext.init(kmf.getKeyManagers(), new SFLTrustStore[]{new SFLTrustStore()},null);
+            log.info("License loaded successfully!");
+            sslSocketFactory = sslContext.getSocketFactory();
+            return true;
+        }
+        catch (Exception e){
+            log.error("An error occurred while trying to load the license: {}",e.getMessage());
+            return false;
+        }
+    }
+
+
+}
diff --git a/updater/src/main/resources/ca.crt b/updater/src/main/resources/ca.crt
new file mode 100644
index 0000000000000000000000000000000000000000..4e4a1fdcdc732799485e301a3686560a26e1ef96
--- /dev/null
+++ b/updater/src/main/resources/ca.crt
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGJTCCBA2gAwIBAgIBATANBgkqhkiG9w0BAQsFADCBmzELMAkGA1UEBhMCQ0Ex
+CzAJBgNVBAgTAlFDMREwDwYDVQQHEwhNb250cmVhbDEgMB4GA1UEChMXU2F2b2ly
+LWZhaXJlIExpbnV4IEluYy4xDTALBgNVBAsTBEpBTVMxGjAYBgNVBAMTEUpBTVMg
+TGljZW5zaW5nIENBMR8wHQYJKoZIhvcNAQkBFhBzdXBwb3J0QGphbWkubmV0MB4X
+DTIwMDIxNzIzNDQwMFoXDTMwMDIxNzIzNDQwMFowgZsxCzAJBgNVBAYTAkNBMQsw
+CQYDVQQIEwJRQzERMA8GA1UEBxMITW9udHJlYWwxIDAeBgNVBAoTF1Nhdm9pci1m
+YWlyZSBMaW51eCBJbmMuMQ0wCwYDVQQLEwRKQU1TMRowGAYDVQQDExFKQU1TIExp
+Y2Vuc2luZyBDQTEfMB0GCSqGSIb3DQEJARYQc3VwcG9ydEBqYW1pLm5ldDCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANwPgPJLFvPUrP6e2H+OzZZuF3+3
+EqJ5/2a2khT+VziqkEwwm0DUQP6sABuNnZq9VeA8dBknLCCJpPCzmXjjn75hR2kB
+B1jDKjJMBIs2rlXdy/EZ2668ndt3bi06I0GWBJUKzbchTtAW+J75SXtdCSiBR0pM
+LnvhfyEQEF2tMO8xFqtEfjDxi5TFXoKZyZXgJ+Q6JAC2eRxdOFdP0V+FDArXnAkY
+Y7/psBb45nKWut2EQP9fJacP8TWat7oXNgJ3c8JD+0NqwE6qZWVnC5ggS0PEFeo+
+MhQENoJua0UEVliKDHnXCms1AbjZu4/DLuuN1HqgrqTowGQ8DQf7WXa944u++ZLa
+G8BJ3jCDoOvUpEkGwC81rmto5ehVq8y+TaElpjHR2btUcDpQ4c/dleSxBm8OkDLA
+mkernsOsyIgfAy/sXKoCUZwpZsCy0+NUoCkKcljNh9YgI8apPg3fQ2r5/bheJZGe
+evrCn0/ZB4KEN0VzdEiWR89AUsgw+tez6HIngKNPft2fmKR8rAbgs/Ls/pqItlkG
+yOJw0DVhwHXtfMHk0P9AeaBqtvcjLbn4ZLEB2+rsceef/2quCenlGJ9V2xga2kpk
+sfbosSF0qx/1IsVw8NlqRQCJ1ys5hQ94UF/QQt/+v3qw8eqWtmoIdPpo1UBQdQog
+1PMJdcZaumsihKIhAgMBAAGjcjBwMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FLpkHueN4c6HBF0E2tgSa+sviwNIMAsGA1UdDwQEAwIBBjARBglghkgBhvhCAQEE
+BAMCAAcwHgYJYIZIAYb4QgENBBEWD3hjYSBjZXJ0aWZpY2F0ZTANBgkqhkiG9w0B
+AQsFAAOCAgEAMtqlnIed+BaKhH9b1qJBRnSQqLLIYCa1NrWVRZ1J6ynxF+/amBZE
+X6BsgnjAXFk4U4LnMgYV9ZunhawZiOnh8YxUFGKNtlToh08GyjYAi+2br06plWaL
+0bmJk2QSybBjfU1H7XgaDGHJy4AsRkpL+7vhSFLqsczEJRo0k4yG6MdMsJD0tc8O
+pukUF0f2dsQyg9Br8EOiVF4jz4aKAOHRPURbb9V7FssnIHBvgWfbQGYuK3eVorek
+MIdmzYliUbJc0MuHPwhRYgw7lrwQKGnJNJP9+5WBawP4IFJt5TlAyFyXm7W0Vfui
+5szsy+aEAp3TPbNJ16gZKRzT/1kT4HaPiiKo5PJmBIonvT6A0XTIJvHIBAoGSORG
+bNMf894jG299Xtavz7O3jxqGqkBFB6O/KLa4loVQn7G0mpDnStRP7xHEVEx/hNyA
+PnRIap6ymiYx6anEr96wTpRcbhIX2XSTQk4Boz9og5AMv046bS/othVtAwk6BlXF
++RLe6XB3P7tiLIU0c8x5FdDZjid2igUDiTHWFmLT5SFTo3aCaSb7QVXO+YAxomBz
+6RFQ2Hto+9kSyiU/4fgWdQAngDSupI4dTNBfp7EDEStqoa3ewgD3f4dWoeh0VIxN
+Rl2PC6898uZF35FBrXOWjh8sx8tlCaflFOAdIfizVdDez2dDZtZlREY=
+-----END CERTIFICATE-----