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 6fb46a6294b2285aa55788014897968adc42aa7c..2b909cb1dcdee6d28942a34d341f620e194650fb 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
@@ -73,6 +73,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 1ef63a4f58b63c4a6473fc86665607115c747dcd..6b67fc9f2d62fd2f52d2915b0412df07168c43f5 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
@@ -37,7 +37,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 401e0d9041da50fee3151b47a7ec6d1763b4a294..b1c4d7c09ef878655ecb403f9978e4e9488528da 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
@@ -23,7 +23,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;
 
 
@@ -126,6 +125,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);
             }
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 958a77076803eb5b77d334829355cafaca06a9cf..5afd6b3eed50cefb49d4b0b01dec6c02196988f2 100644
--- a/datastore/src/main/java/net/jami/datastore/dao/AbstractDao.java
+++ b/datastore/src/main/java/net/jami/datastore/dao/AbstractDao.java
@@ -6,6 +6,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;
@@ -22,11 +23,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));
@@ -42,7 +46,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 f5074bbdb513901ed2a9140eca489514c4fdaa95..c3e9ad42b9ad07870f437669ccad458bc26a2094 100644
--- a/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java
+++ b/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java
@@ -1,5 +1,6 @@
 package net.jami.datastore.dao;
 
+import net.jami.jams.common.dao.StatementList;
 import net.jami.jams.common.objects.contacts.Contact;
 
 import java.util.LinkedHashMap;
@@ -15,4 +16,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 9f7db3e553425bc8af3fdce2945c59446534c6c1..94e2fc99ea3c729b2501370e12527ab0be0593e9 100644
--- a/datastore/src/main/java/net/jami/datastore/dao/DeviceDao.java
+++ b/datastore/src/main/java/net/jami/datastore/dao/DeviceDao.java
@@ -2,6 +2,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;
 
@@ -59,4 +60,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 63545e5070ff15a148dd846b8df305fc13eeed82..35591e2a6f76f86bb6ba0d733f967dd682596fe8 100644
--- a/datastore/src/main/java/net/jami/datastore/dao/SystemDao.java
+++ b/datastore/src/main/java/net/jami/datastore/dao/SystemDao.java
@@ -2,6 +2,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;
 
@@ -57,4 +58,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 457f9074877c8752f4356a64e41122b19920b0ff..2ec325c04cccd3420a91e23a4c52f3f62df4ff5b 100644
--- a/datastore/src/main/java/net/jami/datastore/main/DataStore.java
+++ b/datastore/src/main/java/net/jami/datastore/main/DataStore.java
@@ -51,6 +51,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 3fae34ca28b97fd2552cd2d76610c638ca9ac35d..7ffa8559029efac0003c025f140c0ea02daf662c 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
@@ -48,7 +48,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 1f8579677451a7f6d2bdaab10610bd1f25cdb086..91048b57b0d37def0ba9e27212c42022fb343b3c 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
@@ -3,8 +3,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/src/main/java/module-info.java b/jams-common/src/main/java/module-info.java
index 4358de73c8dc950dee314af827dfc1df62752566..4be6ec881a3acfbea1fa52d65dd855b636ea0b8d 100644
--- a/jams-common/src/main/java/module-info.java
+++ b/jams-common/src/main/java/module-info.java
@@ -52,6 +52,7 @@ 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;
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 1b27f44b9cfd024f768cb8c7302418a22519c344..68c1314369c81ece50dcd5ddfde9251c3e0d047e 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
@@ -7,6 +7,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 329f003b8d5c5ded471bae9d7fc51e1b8053d514..ed5c90c3ffe2c7a750a574a179a9c47698cc8ee8 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
@@ -3,5 +3,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 3283283dd8d8e2b9fc2484f06931001d748857da..bfa65444657b5b402670881fe0a93d352d8abfc3 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
@@ -8,7 +8,6 @@ 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;
 
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 d5d53104dbda41eeb4b04e4ce6aae7d9189cfa9c..ebb6269bd5df314721312326911a1f04a669690e 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
@@ -3,11 +3,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;
@@ -15,7 +14,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(" ")
@@ -27,7 +26,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 d67273725f6635649bad1b7e382bd1101b74f8da..a572578cdfa01bba7f37ee8fde4477b16308a8e2 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
@@ -3,25 +3,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(" ")
@@ -32,10 +31,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-server/src/main/java/module-info.java b/jams-server/src/main/java/module-info.java
index ff32d400b7c3bc1f666899b05ebb1faf0fce6c5c..e8eff064935dffa28d51186710d73a45749408ea 100644
--- a/jams-server/src/main/java/module-info.java
+++ b/jams-server/src/main/java/module-info.java
@@ -10,6 +10,8 @@ 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;
@@ -18,10 +20,19 @@ module jams.server {
     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 48b23a5b2aa34ec97d31d2a49d669ae940c01128..dd1ff6112e4b6e8c56ae160079c9788a223ba390 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
@@ -10,6 +10,7 @@ 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;
@@ -17,6 +18,7 @@ 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;
@@ -37,6 +39,7 @@ 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();
@@ -80,6 +83,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 a7d8e8c714f38a9541a920198b00b59a2ca18fed..daaf7ec01faedded5635541847495e98d907fbab 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
@@ -15,7 +15,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.
@@ -42,6 +41,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")) {
@@ -74,6 +74,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 8916f9d27e93b6b6cdd68d03482c0b91eee367d0..e82870be59862379d3ae3efb844a2e5407fc092b 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
@@ -12,6 +12,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;
@@ -92,6 +93,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 0b5640e9213ebf60055e79605a895b8bbd685f7f..673a5b136c2f9a6f42cc06f3dc50017a805b1353 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
@@ -60,7 +60,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 ea433ee5ed2420848a78507ddfa44a0ac6c5733e..9f2fb9eda5d7e74bd930d939fd16d9ed3422cf37 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
@@ -1,4 +1,55 @@
 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 59bc146717729cd36b853be788145030dad0a9ad..65da0414a20f13c397222b87aa8d9765ada399e3 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
@@ -1,4 +1,53 @@
 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/servlets/api/admin/devices/DeviceServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/admin/devices/DeviceServlet.java
index dff1de3f6122db25ac1d73a2d918fac1b20b9324..4f67a0e77994987c2a67bef280e852b1bab009d9 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
@@ -1,31 +1,59 @@
 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 ba3162715ceea23e7aee24e86af6b50b75f84be2..b28b616c565aa546c025e53e8b7373cc8dae6aa5 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
@@ -1,19 +1,28 @@
 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 9b4cb4373ae36b90b7ff161334f75a22c2f7bc79..13411abe4b39631ae3138ab92c982d0203cea80c 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
@@ -1,37 +1,75 @@
 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 70047352ef4e6e72e6ce91ecb75cac7c0370acc7..0c71a02f55e0f466f3366c8fbae7f41a27bf170a 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
@@ -1,5 +1,6 @@
 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;
@@ -8,12 +9,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 91dd970c7bacfbd888636313260f21a695d40781..622956d68d5e17e18b40786032a5005dcfa15494 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
@@ -11,7 +11,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;
 
@@ -42,11 +44,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 ebea63526637a1857e6c378de8ec422134db024a..96c4f943c9dc32d12026370652eaf16457de8b38 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
@@ -7,7 +7,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 a41aaac61f45d84a90ba852d641cf0479151a24a..5bb3d82a889ad19b3f55f1bb24d766e4b2b4b4e1 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
@@ -46,9 +46,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/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/filters/AdminApiFilter.java b/jams-server/src/main/java/net/jami/jams/server/servlets/filters/AdminApiFilter.java
index 0aa48f863c335a16930920c7cd996b034c279b09..7996b7cacff529fb003f394f628d7e53dc753e92 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
@@ -12,7 +12,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 e0fec4868ee33fd4d94a00546b1ba469baa10126..2ae16b84b95a1c2e3b22b250d48bb67eb806181b 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
@@ -11,7 +11,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 6865ba19f8269d377cfe57f1b8b2daca0931bf9d..427421595a53d9f54fa6a522f22f6c874f952010 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
@@ -49,6 +49,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 512c694dd5214312bc6b3152f4873765d8a2cd9f..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>
@@ -140,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-----