diff --git a/src/main/java/it/inaf/oats/vospace/CreateNodeController.java b/src/main/java/it/inaf/oats/vospace/CreateNodeController.java
index 4cd2860cf793f73eb7c04a0e4243e3db7f835573..7a6e047ffbf0461fe2bbe4e1300834005e3f92a4 100644
--- a/src/main/java/it/inaf/oats/vospace/CreateNodeController.java
+++ b/src/main/java/it/inaf/oats/vospace/CreateNodeController.java
@@ -6,7 +6,6 @@
 package it.inaf.oats.vospace;
 
 import it.inaf.ia2.aa.data.User;
-import it.inaf.oats.vospace.exception.InvalidURIException;
 import net.ivoa.xml.vospace.v2.LinkNode;
 import net.ivoa.xml.vospace.v2.Node;
 import org.springframework.http.MediaType;
diff --git a/src/main/java/it/inaf/oats/vospace/URIUtils.java b/src/main/java/it/inaf/oats/vospace/URIUtils.java
index 0250050fd271a772725b8a1097f4a63a367c1f94..36bd239aff98a538cf34d445f402d049577c0465 100644
--- a/src/main/java/it/inaf/oats/vospace/URIUtils.java
+++ b/src/main/java/it/inaf/oats/vospace/URIUtils.java
@@ -18,6 +18,13 @@ public class URIUtils {
     // Slashes are treated separately
     private static final Pattern FORBIDDEN_CHARS = Pattern.compile("[\\x00\\x08\\x0B\\x0C\\x0E-\\x1F" + Pattern.quote("<>?\":\\|'`*") + "]");
     private static final String SCHEME = "vos";
+    
+    public static boolean isURIInternal(String URI) {
+        if(URI == null)
+            throw new IllegalArgumentException("URI can't be null");
+        
+        return URI.toLowerCase().startsWith(SCHEME);
+    }
 
     public static String returnURIFromVosPath(String vosPath, String authority) {
         String result = null;
diff --git a/src/main/java/it/inaf/oats/vospace/UriService.java b/src/main/java/it/inaf/oats/vospace/UriService.java
index 056aa04248b782adcbdd0576ecb876e8d7256b46..6f78cb11d4273cd6d8e3790df6a21a71a6eb43e8 100644
--- a/src/main/java/it/inaf/oats/vospace/UriService.java
+++ b/src/main/java/it/inaf/oats/vospace/UriService.java
@@ -19,6 +19,7 @@ import it.inaf.oats.vospace.exception.NodeNotFoundException;
 import it.inaf.oats.vospace.exception.PermissionDeniedException;
 import it.inaf.oats.vospace.exception.ProtocolNotSupportedException;
 import it.inaf.oats.vospace.exception.NodeBusyException;
+import it.inaf.oats.vospace.persistence.LinkedServiceDAO;
 import it.inaf.oats.vospace.persistence.LocationDAO;
 import it.inaf.oats.vospace.persistence.NodeDAO;
 import it.inaf.oats.vospace.persistence.model.Location;
@@ -58,6 +59,9 @@ public class UriService {
     @Autowired
     private LocationDAO locationDAO;
 
+    @Autowired
+    private LinkedServiceDAO linkedServiceDAO;
+
     @Autowired
     private HttpServletRequest servletRequest;
 
@@ -168,7 +172,7 @@ public class UriService {
         JobService.JobDirection jobType
                 = JobDirection.getJobDirectionEnumFromTransfer(transfer);
         Node node = this.getEndpointNode(relativePath, jobType, user);
-               
+
         switch (jobType) {
             case pushToVoSpace:
             case pullToVoSpace:
@@ -178,7 +182,7 @@ public class UriService {
                 break;
 
             case pullFromVoSpace:
-                // Refresh relative path: it can differ in case of links
+                // Refresh relative path: it can differ in case of links followed 
                 relativePath = NodeUtils.getVosPath(node);
                 if (!NodeUtils.checkIfReadable(node, creator, groups)) {
                     throw PermissionDeniedException.forPath(relativePath);
@@ -197,24 +201,36 @@ public class UriService {
             return fileServiceClient.startArchiveJob(transfer, job.getJobId());
         }
 
-        Location location = locationDAO.getNodeLocation(relativePath).orElse(null);
+        boolean isLinkNode = node instanceof LinkNode;
 
         String endpoint;
 
-        if (location != null && location.getType() == LocationType.PORTAL) {
-            String fileName = nodeDao.getNodeOsName(relativePath);
-            endpoint = "http://" + location.getSource().getHostname() + location.getSource().getBaseUrl();
-            if (!endpoint.endsWith("/")) {
-                endpoint += "/";
-            }
-            endpoint += fileName;
+        if (isLinkNode) {
+            endpoint = ((LinkNode) node).getTarget();
         } else {
-            endpoint = fileServiceUrl + urlEncodePath(relativePath);
+
+            Location location = locationDAO.getNodeLocation(relativePath).orElse(null);
+
+            if (location != null && location.getType() == LocationType.PORTAL) {
+                String fileName = nodeDao.getNodeOsName(relativePath);
+                endpoint = "http://" + location.getSource().getHostname() + location.getSource().getBaseUrl();
+                if (!endpoint.endsWith("/")) {
+                    endpoint += "/";
+                }
+                endpoint += fileName;
+            } else {
+                endpoint = fileServiceUrl + urlEncodePath(relativePath);
+            }
         }
 
         endpoint += "?jobId=" + job.getJobId();
 
-        if (!"true".equals(NodeProperties.getNodePropertyByURI(node, NodeProperties.PUBLIC_READ_URI))) {
+        if (isLinkNode) {
+            String linkTarget = ((LinkNode) node).getTarget();
+            if (linkedServiceDAO.isLinkedServiceUrl(linkTarget)) {
+                endpoint += "&token=" + getEndpointToken(linkTarget);
+            }
+        } else if (!"true".equals(NodeProperties.getNodePropertyByURI(node, NodeProperties.PUBLIC_READ_URI))) {
             endpoint += "&token=" + getEndpointToken(fileServiceUrl + relativePath);
         }
 
@@ -287,21 +303,27 @@ public class UriService {
     }
 
     private Node followLinkRecursive(LinkNode linkNode, int depth) {
-                
-        if(depth >= linkMaxDepth) {
-            throw new InternalFaultException("Max link depth reached at link node: " 
+
+        if (depth >= linkMaxDepth) {
+            throw new InternalFaultException("Max link depth reached at link node: "
                     + NodeUtils.getVosPath(linkNode));
         }
-        
-        String targetPath = URIUtils.returnVosPathFromNodeURI(linkNode.getTarget(), authority);
-        
-        Optional<Node> targetNodeOpt = nodeDao.listNode(targetPath);
-        Node targetNode = targetNodeOpt.orElseThrow(() -> new InternalFaultException("Broken Link to target: " + targetPath));
-        
-        if(targetNode instanceof LinkNode) {            
-            return this.followLinkRecursive(linkNode, ++depth);
-        } else {            
-            return targetNode;
+
+        String linkTarget = linkNode.getTarget();
+
+        if (URIUtils.isURIInternal(linkTarget)) {
+            return linkNode;
+        } else {
+            String targetPath = URIUtils.returnVosPathFromNodeURI(linkTarget, authority);
+
+            Optional<Node> targetNodeOpt = nodeDao.listNode(targetPath);
+            Node targetNode = targetNodeOpt.orElseThrow(() -> new InternalFaultException("Broken Link to target: " + targetPath));
+
+            if (targetNode instanceof LinkNode) {
+                return this.followLinkRecursive(linkNode, ++depth);
+            } else {
+                return targetNode;
+            }
         }
     }
 }
diff --git a/src/main/java/it/inaf/oats/vospace/persistence/LinkedServiceDAO.java b/src/main/java/it/inaf/oats/vospace/persistence/LinkedServiceDAO.java
index e8adf2f3a9601978222645e1e160f5a31df21016..5af99100e53f21cfb02d046e1bd765aea3419065 100644
--- a/src/main/java/it/inaf/oats/vospace/persistence/LinkedServiceDAO.java
+++ b/src/main/java/it/inaf/oats/vospace/persistence/LinkedServiceDAO.java
@@ -27,7 +27,7 @@ public class LinkedServiceDAO {
         jdbcTemplate = new JdbcTemplate(dataSource);
     }
 
-    boolean isLinkedServiceUrl(String targetUrl) {
+    public boolean isLinkedServiceUrl(String targetUrl) {
         String sql = " SELECT COUNT(*) > 0\n"
                 + "FROM linked_service\n"
                 + "WHERE ? LIKE service_base_url || '%'";
diff --git a/src/test/java/it/inaf/oats/vospace/URIUtilsTest.java b/src/test/java/it/inaf/oats/vospace/URIUtilsTest.java
index d630f85de6e0161d6216227d8613799dc3b80beb..6897ae542576e46865db1b494bbb116433f54849 100644
--- a/src/test/java/it/inaf/oats/vospace/URIUtilsTest.java
+++ b/src/test/java/it/inaf/oats/vospace/URIUtilsTest.java
@@ -8,7 +8,9 @@ package it.inaf.oats.vospace;
 import it.inaf.oats.vospace.exception.InvalidURIException;
 import java.net.URISyntaxException;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import org.junit.jupiter.api.Test;
 
 public class URIUtilsTest {
@@ -84,6 +86,12 @@ public class URIUtilsTest {
         String test3 = URIUtils.returnURIFromVosPath("/test1/te# !?st2", authority);
         assertEquals("vos://"+authority+"/test1/te%23%20!%3Fst2", test3);       
     }
+    
+    @Test
+    public void testIsURIInternal() {
+        assertTrue(URIUtils.isURIInternal("vos://"+authority+"/test1/test2"));        
+        assertFalse(URIUtils.isURIInternal("http://host.ia2.inaf.it/test1/test2"));
+    } 
 
     
 }