diff --git a/gms-ui/src/api/server/index.js b/gms-ui/src/api/server/index.js
index b5f321aa30b71e6524f267dc4c80e438d76aede8..b84d0034088859964d613f2eef04ff552f59d777 100644
--- a/gms-ui/src/api/server/index.js
+++ b/gms-ui/src/api/server/index.js
@@ -108,5 +108,25 @@ export default {
         'Accept': 'application/json',
       }
     });
+  },
+  addPermission (userId, permission, input) {
+    let url = BASE_API_URL + 'permission';
+
+    return apiRequest(url, {
+      method: 'POST',
+      cache: 'no-cache',
+      credentials: 'include',
+      headers: {
+        'Content-Type': 'application/json',
+        'Accept': 'application/json',
+      },
+      body: JSON.stringify({
+        groupId: input.selectedGroupId,
+        userId: userId,
+        permission: permission,
+        paginatorPageSize: input.paginatorPageSize,
+        paginatorPage: input.paginatorPage
+      })
+    });
   }
 };
diff --git a/gms-ui/src/components/Main.vue b/gms-ui/src/components/Main.vue
index 36a15b26068d6884bf0074068c4f0c6b03a5b897..0fc06ebe5f89b1fdb41c0bd944a1439c5ae66c4f 100644
--- a/gms-ui/src/components/Main.vue
+++ b/gms-ui/src/components/Main.vue
@@ -25,6 +25,7 @@ import GroupsPanel from './GroupsPanel.vue'
 import MembersPanel from './MembersPanel.vue'
 import PermissionsPanel from './PermissionsPanel.vue'
 import NewGroupModal from './modals/NewGroupModal.vue'
+import AddMemberModal from './modals/AddMemberModal.vue'
 import AddPermissionModal from './modals/AddPermissionModal.vue'
 import { mapState } from 'vuex';
 
@@ -36,6 +37,7 @@ export default {
     MembersPanel,
     PermissionsPanel,
     NewGroupModal,
+    AddMemberModal,
     AddPermissionModal
   },
   computed: mapState({
diff --git a/gms-ui/src/components/modals/AddMemberModal.vue b/gms-ui/src/components/modals/AddMemberModal.vue
new file mode 100644
index 0000000000000000000000000000000000000000..23d47959172fb7f90f70188bad2bda21e25663a3
--- /dev/null
+++ b/gms-ui/src/components/modals/AddMemberModal.vue
@@ -0,0 +1,27 @@
+<template>
+  <b-modal id="add-member-modal" title="Add member" ok-title="Add" @ok="addMember">
+    <SearchUser />
+  </b-modal>
+</template>
+
+<script>
+import client from 'api-client';
+import SearchUser from './SearchUser.vue'
+
+export default {
+  name: 'AddMemberModal',
+  components: {
+    SearchUser
+  },
+  data: function() {
+    return {
+      permission: 'VIEW_MEMBERS'
+    }
+  },
+  methods: {
+    addMember: function() {
+
+    }
+  }
+};
+</script>
diff --git a/gms-ui/src/components/modals/AddPermissionModal.vue b/gms-ui/src/components/modals/AddPermissionModal.vue
index 7fccb7ec88f2ec50298e1c4be4adb62336ab3ac1..7b792e9fb52dae185fecc7ecc5cb4b97d677b923 100644
--- a/gms-ui/src/components/modals/AddPermissionModal.vue
+++ b/gms-ui/src/components/modals/AddPermissionModal.vue
@@ -1,6 +1,6 @@
 <template>
   <b-modal id="add-permission-modal" title="Add permission" ok-title="Add" @ok="addPermission">
-    <SearchUser />
+    <SearchUser ref="searchUser" />
   </b-modal>
 </template>
 
@@ -15,12 +15,21 @@ export default {
   },
   data: function() {
     return {
-
     }
   },
   methods: {
-    addPermission: function() {
+    addPermission: function(event) {
+      // Prevent modal from closing
+      event.preventDefault();
+
+      let userId = this.$refs.searchUser.selectedUser;
+      let permission = this.$refs.searchUser.permission;
 
+      client.addPermission(userId, permission, this.$store.state.input)
+        .then(res => {
+          this.$store.commit('updatePermissionsPanel', res);
+          this.$bvModal.hide('add-permission-modal');
+        });
     }
   }
 };
diff --git a/gms-ui/src/components/modals/SearchUser.vue b/gms-ui/src/components/modals/SearchUser.vue
index 391a54bb383f0f4a84902c5a7fc166df7e1ea08a..20ecfa1b2b74d94a71d78817e4fa1f110c1ea7ce 100644
--- a/gms-ui/src/components/modals/SearchUser.vue
+++ b/gms-ui/src/components/modals/SearchUser.vue
@@ -11,12 +11,13 @@
     <label class="w-25" for="user-input" v-if="users.length > 0">Selected user:</label>
     <b-form-select v-model="selectedUser" :options="users" class="w-75" v-if="users.length > 0"></b-form-select>
     <div class="w-25"></div>
-    <b-form-group label="Permissions:" v-if="users.length > 0" class="w-75 mt-3">
+    <b-form-group label="Permission:" v-if="users.length > 0 && model.permission === 'ADMIN'" class="w-75 mt-3">
       <b-form-radio-group
-        id="permissions-radio-group"
+        id="permission-radio-group"
         v-model="permission">
         <b-form-radio value="ADMIN">Admin</b-form-radio>
         <b-form-radio value="MANAGE_MEMBERS">Manage members</b-form-radio>
+        <b-form-radio value="VIEW_MEMBERS">View members</b-form-radio>
       </b-form-radio-group>
     </b-form-group>
   </b-form>
@@ -24,15 +25,19 @@
 
 <script>
 import client from 'api-client';
+import { mapState } from 'vuex';
 
 export default {
   name: 'SearchUser',
+  computed: mapState({
+    model: state => state.model,
+  }),
   data: function() {
     return {
       searchInput: null,
       users: [],
       selectedUser: null,
-      permission: null
+      permission: 'VIEW_MEMBERS'
     }
   },
   methods: {
diff --git a/gms-ui/src/store.js b/gms-ui/src/store.js
index c6e95938d4ec09717f28576cf62fcf007f60a5f2..44ce164d27bc34d376eab01eb6b16c4d4f467ace 100644
--- a/gms-ui/src/store.js
+++ b/gms-ui/src/store.js
@@ -28,6 +28,9 @@ export default new Vuex.Store({
     },
     updateGroupsPanel(state, groupsPanel) {
       this.state.model.groupsPanel = groupsPanel;
+    },
+    updatePermissionsPanel(state, permissionsPanel) {
+      this.state.model.permissionsPanel = permissionsPanel;
     }
   },
   getters: {
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java
index 4b91c0e98009cfb6de8eac0cb903df4ee6c6c3c8..dc12bfb49506810ff3e7b8c150400f2a42d2362e 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java
@@ -56,7 +56,7 @@ public class GroupsController {
 
         GroupEntity parent = groupsService.getGroupById(request.getParentGroupId());
 
-        if (permissionsService.getGroupPermission(parent, session.getUserId()) != Permission.ADMIN) {
+        if (permissionsService.getUserPermissionForGroup(parent, session.getUserId()) != Permission.ADMIN) {
             throw new UnauthorizedException("Missing admin privileges");
         }
 
@@ -84,7 +84,7 @@ public class GroupsController {
 
         GroupEntity group = groupsService.getGroupById(groupId);
 
-        if (permissionsService.getGroupPermission(group, session.getUserId()) != Permission.ADMIN) {
+        if (permissionsService.getUserPermissionForGroup(group, session.getUserId()) != Permission.ADMIN) {
             throw new UnauthorizedException("Missing admin privileges");
         }
 
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java
index 9c204e7165ce5fe2eddea59b1c491fd710d6722b..fbf9879277ea6080b49a103e8017e72965100a51 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java
@@ -1,13 +1,23 @@
 package it.inaf.ia2.gms.controller;
 
 import it.inaf.ia2.gms.authn.SessionData;
+import it.inaf.ia2.gms.exception.UnauthorizedException;
+import it.inaf.ia2.gms.model.PermissionRequest;
+import it.inaf.ia2.gms.model.PaginatedData;
 import it.inaf.ia2.gms.model.Permission;
+import it.inaf.ia2.gms.model.UserPermission;
+import it.inaf.ia2.gms.persistence.model.GroupEntity;
+import it.inaf.ia2.gms.service.GroupsService;
 import it.inaf.ia2.gms.service.PermissionsService;
+import java.util.List;
+import javax.validation.Valid;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 
 @RestController
@@ -16,11 +26,43 @@ public class PermissionsController {
     @Autowired
     private SessionData session;
 
+    @Autowired
+    private GroupsService groupsService;
+
     @Autowired
     private PermissionsService permissionsService;
 
-    @DeleteMapping(value = "/permission", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
-    public ResponseEntity deletePermission(@RequestParam("user") String userId, @RequestParam("group") String group, @RequestParam("permission") Permission permission) {
-        return null;
+    @PostMapping(value = "/permission", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public ResponseEntity<PaginatedData<UserPermission>> addPermission(@Valid @RequestBody PermissionRequest request) {
+
+        GroupEntity group = groupsService.getGroupById(request.getGroupId());
+        verifyAdminSession(group);
+
+        permissionsService.addPermission(group, request.getUserId(), request.getPermission());
+
+        return new ResponseEntity<>(getPermissionsPanel(group, request), HttpStatus.CREATED);
+    }
+
+    @DeleteMapping(value = "/permission", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    public ResponseEntity<PaginatedData<UserPermission>> deletePermission(@Valid PermissionRequest request) {
+
+        GroupEntity group = groupsService.getGroupById(request.getGroupId());
+        verifyAdminSession(group);
+
+        permissionsService.deletePermission(group, request.getUserId(), request.getPermission());
+
+        return ResponseEntity.ok(getPermissionsPanel(group, request));
+    }
+
+    private void verifyAdminSession(GroupEntity group) {
+        Permission currentNodePermissions = permissionsService.getUserPermissionForGroup(group, session.getUserId());
+        if (currentNodePermissions != Permission.ADMIN) {
+            throw new UnauthorizedException("Only admin users can handle permissions");
+        }
+    }
+
+    private PaginatedData<UserPermission> getPermissionsPanel(GroupEntity group, PermissionRequest request) {
+        List<UserPermission> permissions = permissionsService.getAllPermissions(group);
+        return new PaginatedData<>(permissions, request.getPaginatorPage(), request.getPaginatorPageSize());
     }
 }
diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/PermissionRequest.java b/gms/src/main/java/it/inaf/ia2/gms/model/PermissionRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..17764538ba035424c5efe042ecd0dfa820b84aeb
--- /dev/null
+++ b/gms/src/main/java/it/inaf/ia2/gms/model/PermissionRequest.java
@@ -0,0 +1,38 @@
+package it.inaf.ia2.gms.model;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+public class PermissionRequest extends PaginatedModelRequest {
+
+    @NotEmpty
+    private String groupId;
+    @NotEmpty
+    private String userId;
+    @NotNull
+    private Permission permission;
+
+    public String getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public Permission getPermission() {
+        return permission;
+    }
+
+    public void setPermission(Permission permission) {
+        this.permission = permission;
+    }
+}
diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsModelBuilder.java b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsModelBuilder.java
index f47426daf030357e14cdf6ddd3bd355f80d38817..a0577470119ad1e1571e531be8713011ea04ce76 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsModelBuilder.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsModelBuilder.java
@@ -36,7 +36,7 @@ public class GroupsModelBuilder {
 
         response.setBreadcrumbs(groupsService.getBreadcrumbs(group.getPath()));
 
-        Permission currentNodePermissions = permissionsService.getGroupPermission(group, userId);
+        Permission currentNodePermissions = permissionsService.getUserPermissionForGroup(group, userId);
         response.setPermission(currentNodePermissions);
 
         switch (request.getTab()) {
@@ -51,7 +51,7 @@ public class GroupsModelBuilder {
                 break;
             case "permissions":
                 if (currentNodePermissions == Permission.ADMIN) {
-                    List<UserPermission> permissions = permissionsService.getUserPermissions(group);
+                    List<UserPermission> permissions = permissionsService.getAllPermissions(group);
                     response.setPermissionsPanel(new PaginatedData<>(permissions, request.getPaginatorPage(), request.getPaginatorPageSize()));
                 }
                 break;
diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java
index 16476167058884682ecd9d2bdd20533948b3ee23..1960fd236eed5892a211064ec465e38e20d8e2bb 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/service/GroupsService.java
@@ -67,7 +67,7 @@ public class GroupsService {
 
         GroupEntity group = getGroupById(groupId);
 
-        if (permissionsService.getGroupPermission(group, userId) != Permission.ADMIN) {
+        if (permissionsService.getUserPermissionForGroup(group, userId) != Permission.ADMIN) {
             throw new UnauthorizedException("Missing admin privileges");
         }
 
diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java b/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java
index 96170b11d7c72209c72164e02814367184758df3..ea9761d257384e8b3e216bb83178c270eed8a269 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java
@@ -29,7 +29,7 @@ public class PermissionsService {
         this.rapClient = rapClient;
     }
 
-    public List<UserPermission> getUserPermissions(GroupEntity group) {
+    public List<UserPermission> getAllPermissions(GroupEntity group) {
 
         List<PermissionEntity> permissions = permissionsDAO.getGroupsPermissions(group.getId());
 
@@ -55,7 +55,7 @@ public class PermissionsService {
         return result;
     }
 
-    public Permission getGroupPermission(GroupEntity group, String userId) {
+    public Permission getUserPermissionForGroup(GroupEntity group, String userId) {
         List<PermissionEntity> permissions = permissionsDAO.findUserPermissions(userId, group.getPath());
         return PermissionUtils.getGroupPermission(group, permissions).orElse(null);
     }
@@ -78,7 +78,7 @@ public class PermissionsService {
     public Optional<PermissionEntity> findPermissionEntity(String groupId, String userId, Permission permission) {
         return permissionsDAO.findPermissionEntity(groupId, userId, permission);
     }
-    
+
     public void movePermissions(String fromUserId, String toUserId) {
         permissionsDAO.movePermissions(fromUserId, toUserId);
     }
diff --git a/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java b/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f36cb3a1f4f9b90f260994f6b9e591d9347915ad
--- /dev/null
+++ b/gms/src/test/java/it/inaf/ia2/gms/controller/PermissionsControllerTest.java
@@ -0,0 +1,103 @@
+package it.inaf.ia2.gms.controller;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import it.inaf.ia2.gms.authn.SessionData;
+import it.inaf.ia2.gms.model.Permission;
+import it.inaf.ia2.gms.model.PermissionRequest;
+import it.inaf.ia2.gms.persistence.model.GroupEntity;
+import it.inaf.ia2.gms.service.GroupsService;
+import it.inaf.ia2.gms.service.PermissionsService;
+import static org.hamcrest.CoreMatchers.is;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import static org.mockito.ArgumentMatchers.eq;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+@RunWith(MockitoJUnitRunner.class)
+public class PermissionsControllerTest {
+
+    @Mock
+    private SessionData session;
+
+    @Mock
+    private GroupsService groupsService;
+
+    @Mock
+    private PermissionsService permissionsService;
+
+    @InjectMocks
+    private PermissionsController controller;
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    private final ObjectMapper mapper = new ObjectMapper();
+
+    @Before
+    public void init() {
+        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+    }
+
+    @Test
+    public void testAddPermission() throws Exception {
+
+        when(session.getUserId()).thenReturn("admin_id");
+
+        GroupEntity group = new GroupEntity();
+        group.setId("group_id");
+        group.setName("GroupName");
+        group.setPath("parent_id.group_id");
+
+        when(groupsService.getGroupById(eq("group_id"))).thenReturn(group);
+        when(permissionsService.getUserPermissionForGroup(eq(group), eq("admin_id"))).thenReturn(Permission.ADMIN);
+
+        PermissionRequest request = new PermissionRequest();
+        request.setGroupId(group.getId());
+        request.setUserId("user_id");
+        request.setPermission(Permission.ADMIN);
+        request.setPaginatorPage(1);
+        request.setPaginatorPageSize(10);
+
+        mockMvc.perform(post("/permission")
+                .content(mapper.writeValueAsString(request))
+                .contentType(MediaType.APPLICATION_JSON_UTF8))
+                .andExpect(status().isCreated())
+                .andExpect(jsonPath("$.currentPage", is(1)));
+
+        verify(permissionsService, times(1)).addPermission(eq(group), eq("user_id"), eq(Permission.ADMIN));
+    }
+
+    @Test
+    public void testDeletePermission() throws Exception {
+
+        when(session.getUserId()).thenReturn("admin_id");
+
+        GroupEntity group = new GroupEntity();
+        group.setId("group_id");
+        group.setName("GroupName");
+        group.setPath("parent_id.group_id");
+
+        when(groupsService.getGroupById(eq("group_id"))).thenReturn(group);
+        when(permissionsService.getUserPermissionForGroup(eq(group), eq("admin_id"))).thenReturn(Permission.ADMIN);
+
+        mockMvc.perform(delete("/permission?groupId=group_id&userId=user_id&permission=ADMIN&paginatorPage=1&paginatorPageSize=10"))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.currentPage", is(1)));
+
+        verify(permissionsService, times(1)).deletePermission(eq(group), eq("user_id"), eq(Permission.ADMIN));
+    }
+}
diff --git a/gms/src/test/java/it/inaf/ia2/gms/service/PermissionsServiceIntegrationTest.java b/gms/src/test/java/it/inaf/ia2/gms/service/PermissionsServiceIntegrationTest.java
index 07be29526e48ba0743dd7bb6e8d8a9c89a0e910d..3d5c94493ce32cb7f45109d5ded8c977fd62ea1d 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/service/PermissionsServiceIntegrationTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/service/PermissionsServiceIntegrationTest.java
@@ -61,7 +61,7 @@ public class PermissionsServiceIntegrationTest {
         superAdminPermission.setGroupPath(root.getPath());
         permissionsDAO.createPermission(superAdminPermission);
 
-        List<UserPermission> permissions = permissionsService.getUserPermissions(root);
+        List<UserPermission> permissions = permissionsService.getAllPermissions(root);
 
         assertEquals(1, permissions.size());
         assertEquals(Permission.ADMIN, permissions.get(0).getPermission());