diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java
index 845e9dc487f3f58d264837bb0a2c0fbdc70a3811..c3e6d98d905f6d329a0e01d0617db6ec62255cd8 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java
@@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 /**
@@ -139,12 +140,7 @@ public class JWTWebServiceController {
 
         try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
             for (String groupName : getGroupsNames(visibleSubgroups)) {
-                if (group.isPresent()) {
-                    String shortName = groupName.substring(group.get().length() + 1);
-                    pw.println(shortName);
-                } else {
-                    pw.println(groupName);
-                }
+                pw.println(getShortGroupName(groupName, group));
             }
         }
     }
@@ -178,8 +174,22 @@ public class JWTWebServiceController {
         }
     }
 
+    @GetMapping(value = {"/membership/{group:.+}", "/membership"}, produces = MediaType.TEXT_PLAIN_VALUE)
+    public void getMembership(@PathVariable("group") Optional<String> group, @RequestParam("user_id") String userId, HttpServletResponse response) throws IOException {
+
+        GroupEntity parent = getGroupFromNames(extractGroupNames(group));
+
+        List<GroupEntity> groups = membershipManager.getUserGroups(parent, userId);
+
+        try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+            for (String groupName : getGroupsNames(groups)) {
+                pw.println(getShortGroupName(groupName, group));
+            }
+        }
+    }
+
     @PostMapping(value = {"/membership/{group:.+}", "/membership"}, produces = MediaType.TEXT_PLAIN_VALUE)
-    public void addMember(@PathVariable("group") Optional<String> group, Principal principal, HttpServletRequest request, HttpServletResponse response) throws IOException {
+    public void addMember(@PathVariable("group") Optional<String> group, HttpServletRequest request, HttpServletResponse response) throws IOException {
 
         String targetUserId = request.getParameter("user_id");
         if (targetUserId == null) {
@@ -240,7 +250,8 @@ public class JWTWebServiceController {
 
     /**
      * Returns the list of the group complete names, given a list of GroupEntity
-     * objects.
+     * objects. TODO: probably this logic is duplicated inside GroupNameService.
+     * Check this.
      */
     private List<String> getGroupsNames(List<GroupEntity> groups) {
 
@@ -324,6 +335,13 @@ public class JWTWebServiceController {
         return String.join(".", names);
     }
 
+    private String getShortGroupName(String completeGroupName, Optional<String> groupPrefix) {
+        if (groupPrefix.isPresent()) {
+            return completeGroupName.substring(groupPrefix.get().length() + 1);
+        }
+        return completeGroupName;
+    }
+
     @PostMapping(value = "/join", produces = MediaType.APPLICATION_JSON_VALUE)
     public ResponseEntity<?> join(RapPrincipal principal) {
 
diff --git a/gms/src/main/java/it/inaf/ia2/gms/manager/MembershipManager.java b/gms/src/main/java/it/inaf/ia2/gms/manager/MembershipManager.java
index 61d3652489303141d224a2763d32459c6e0bb85c..3f2acf9a2e5edb8b45d8c80c21f3adf5b0d63bec 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/manager/MembershipManager.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/manager/MembershipManager.java
@@ -3,11 +3,15 @@ package it.inaf.ia2.gms.manager;
 import it.inaf.ia2.gms.exception.UnauthorizedException;
 import it.inaf.ia2.gms.model.Permission;
 import it.inaf.ia2.gms.model.RapUser;
+import it.inaf.ia2.gms.persistence.GroupsDAO;
 import it.inaf.ia2.gms.persistence.LoggingDAO;
 import it.inaf.ia2.gms.persistence.MembershipsDAO;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
 import it.inaf.ia2.gms.persistence.model.MembershipEntity;
+import it.inaf.ia2.gms.persistence.model.PermissionEntity;
 import it.inaf.ia2.gms.rap.RapClient;
+import it.inaf.ia2.gms.service.PermissionUtils;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -20,6 +24,9 @@ public class MembershipManager extends UserAwareComponent {
     @Autowired
     private MembershipsDAO membershipsDAO;
 
+    @Autowired
+    private GroupsDAO groupsDAO;
+
     @Autowired
     private PermissionsManager permissionsManager;
 
@@ -54,6 +61,21 @@ public class MembershipManager extends UserAwareComponent {
         return rapClient.getUsers(userIdentifiers);
     }
 
+    public List<GroupEntity> getUserGroups(GroupEntity parent, String userId) {
+
+        List<PermissionEntity> permissions = permissionsManager.getCurrentUserPermissions(parent);
+
+        List<GroupEntity> allGroups = membershipsDAO.getUserMemberships(userId, parent.getPath());
+
+        // Select only groups visible to the current user
+        Set<String> visibleGroupIds = new HashSet<>();
+        for (GroupEntity group : allGroups) {
+            PermissionUtils.getGroupPermission(group, permissions)
+                    .ifPresent(p -> visibleGroupIds.add(group.getId()));
+        }
+        return groupsDAO.findGroupsByIds(visibleGroupIds);
+    }
+
     public MembershipEntity addMember(GroupEntity group, String userId) {
 
         verifyUserCanManageMembers(group);
diff --git a/gms/src/main/java/it/inaf/ia2/gms/manager/PermissionsManager.java b/gms/src/main/java/it/inaf/ia2/gms/manager/PermissionsManager.java
index d0cb4ca99c58f12bb9e727777b8b62c4396b414b..2d38ca957fd7caac881a1447df633524a10bcbdf 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/manager/PermissionsManager.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/manager/PermissionsManager.java
@@ -85,6 +85,10 @@ public class PermissionsManager extends UserAwareComponent {
         }
     }
 
+    public List<PermissionEntity> getCurrentUserPermissions(GroupEntity group) {
+        return permissionsService.findUserPermissions(group, getCurrentUserId());
+    }
+
     public Permission getCurrentUserPermission(GroupEntity group) {
         List<PermissionEntity> permissions = permissionsService.findUserPermissions(group, getCurrentUserId());
         return PermissionUtils.getGroupPermission(group, permissions).orElse(null);
diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipsDAO.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipsDAO.java
index d8ff1abdffaad824e08f5a7e2384bd9dc4b7fabe..aedfbf8bf04c2136ab0b1e2da43d5babf4991b13 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipsDAO.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/MembershipsDAO.java
@@ -3,6 +3,7 @@ package it.inaf.ia2.gms.persistence;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
 import it.inaf.ia2.gms.persistence.model.MembershipEntity;
 import java.sql.PreparedStatement;
+import java.sql.Types;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -42,15 +43,28 @@ public class MembershipsDAO {
     }
 
     public List<GroupEntity> getUserMemberships(String userId) {
+        return getUserMemberships(userId, null);
+    }
+
+    public List<GroupEntity> getUserMemberships(String userId, String parentPath) {
 
         String sql = "SELECT g.id, g.name, g.path, g.is_leaf FROM "
                 + " gms_membership m "
                 + " JOIN gms_group g ON g.id = m.group_id"
                 + " WHERE m.user_id = ?";
+        if (parentPath != null) {
+            sql += " AND g.path <@ ? AND g.path <> ? ORDER BY nlevel(g.path) DESC";
+        }
 
+        String query = sql;
         return jdbcTemplate.query(conn -> {
-            PreparedStatement ps = conn.prepareStatement(sql);
-            ps.setString(1, userId);
+            PreparedStatement ps = conn.prepareStatement(query);
+            int i = 0;
+            ps.setString(++i, userId);
+            if (parentPath != null) {
+                ps.setObject(++i, parentPath, Types.OTHER);
+                ps.setObject(++i, parentPath, Types.OTHER);
+            }
             return ps;
         }, resultSet -> {
             List<GroupEntity> memberships = new ArrayList<>();