diff --git a/cabal.project b/cabal.project
index 0aa86598b3aa331eae2b6c7c065966bd45684d5c..38afd1122a5741f813f086617d6c53d10fd5256a 100644
--- a/cabal.project
+++ b/cabal.project
@@ -79,7 +79,7 @@ source-repository-package
 source-repository-package
     type: git
     location: https://gitlab.iscpif.fr/gargantext/crawlers/arxiv-api.git
-    tag: 2d7e5753cbbce248b860b571a0e9885415c846f7
+    tag: eb130c71fa17adaceed6ff66beefbccb13df51ba
 
 source-repository-package
     type: git
diff --git a/gargantext.cabal b/gargantext.cabal
index 38bb4cd0a88420bb8cf2362d3b14a927686183da..3cbf4eb17cb7f18dbb0ff7cb937738e882733a27 100644
--- a/gargantext.cabal
+++ b/gargantext.cabal
@@ -935,13 +935,17 @@ test-suite garg-test-tasty
     , crawlerArxiv
     , duckling ^>= 0.2.0.0
     , extra ^>= 1.7.9
+    , fmt
     , gargantext
     , gargantext-prelude
     , hspec ^>= 2.7.10
     , hspec-core
     , hspec-expectations >= 0.8 && < 0.9
+    , hspec-wai
+    , hspec-wai-json
     , http-client ^>= 0.6.4.1
     , http-client-tls ^>= 0.3.5.3
+    , http-types
     , lens >= 5.2.2 && < 5.3
     , monad-control >= 1.0.3 && < 1.1
     , mtl ^>= 2.2.2
@@ -973,6 +977,8 @@ test-suite garg-test-tasty
     , tmp-postgres >= 1.34.1 && < 1.35
     , unordered-containers ^>= 0.2.16.0
     , validity ^>= 0.11.0.1
+    , wai
+    , wai-extra
     , warp
   default-language: Haskell2010
 
@@ -1029,11 +1035,15 @@ test-suite garg-test-hspec
     , crawlerArxiv
     , duckling ^>= 0.2.0.0
     , extra ^>= 1.7.9
+    , fmt
     , gargantext
     , gargantext-prelude
     , hspec ^>= 2.7.10
     , hspec-core
     , hspec-expectations >= 0.8 && < 0.9
+    , hspec-wai
+    , hspec-wai-json
+    , http-types
     , http-client ^>= 0.6.4.1
     , http-client-tls ^>= 0.3.5.3
     , lens >= 5.2.2 && < 5.3
@@ -1067,6 +1077,8 @@ test-suite garg-test-hspec
     , tmp-postgres >= 1.34.1 && < 1.35
     , unordered-containers ^>= 0.2.16.0
     , validity ^>= 0.11.0.1
+    , wai
+    , wai-extra
     , warp
   default-language: Haskell2010
 
diff --git a/src/Gargantext/API/Routes.hs b/src/Gargantext/API/Routes.hs
index ce40cf1545de3362df1e0bbc71a3eb27d8ef6642..8d6eb8fd4ffa9bb7cede42ad0afab86fb4395002 100644
--- a/src/Gargantext/API/Routes.hs
+++ b/src/Gargantext/API/Routes.hs
@@ -87,7 +87,7 @@ type GargAPI' =
           :<|> "public"      :> Public.API
 
 
-type MkProtectedAPI sub = SA.Auth '[SA.JWT, SA.Cookie] AuthenticatedUser :> sub
+type MkProtectedAPI private = SA.Auth '[SA.JWT, SA.Cookie] AuthenticatedUser :> private
 
 type GargPrivateAPI = MkProtectedAPI GargPrivateAPI'
 
@@ -98,13 +98,16 @@ type GargAdminAPI
            :<|> "nodes" :> Summary "Nodes endpoint"
                         :> ReqBody '[JSON] [NodeId] :> NodesAPI
 
+-- Node endpoint
+type NodeEndpoint =
+  "node"     :> Summary "Node endpoint"
+             :> Capture "node_id" NodeId
+             :> NodeAPI HyperdataAny
+
 type GargPrivateAPI' =
                 GargAdminAPI
 
-           -- Node endpoint
-           :<|> "node"     :> Summary "Node endpoint"
-                           :> Capture "node_id" NodeId
-                           :> NodeAPI HyperdataAny
+           :<|> NodeEndpoint
 
            -- Context endpoint
            :<|> "context"  :> Summary "Node endpoint"
diff --git a/test/Test/API/Authentication.hs b/test/Test/API/Authentication.hs
index 389bce20cd555bbc56f87051b42344b0d1c96d61..7c6aa9fa3f11d645368ddf29ae312a1e4936df83 100644
--- a/test/Test/API/Authentication.hs
+++ b/test/Test/API/Authentication.hs
@@ -42,13 +42,13 @@ tests = sequential $ aroundAll withTestDBAndPort $ do
     -- testing scenarios start here
     describe "GET /api/v1.0/version" $ do
       let version_api = client (Proxy :: Proxy (MkGargAPI (GargAPIVersion GargVersion)))
-      it "requires no auth and returns the current version" $ \(_testEnv, port) -> do
+      it "requires no auth and returns the current version" $ \((_testEnv, port), _) -> do
         result <- runClientM version_api (clientEnv port)
         result `shouldBe` (Right "0.0.6.9.9.7.7")
 
     describe "POST /api/v1.0/auth" $ do
 
-      it "requires no auth and authenticates the user 'alice'" $ \(testEnv, port) -> do
+      it "requires no auth and authenticates the user 'alice'" $ \((testEnv, port), _) -> do
 
         -- Let's create the Alice user.
         void $ flip runReaderT testEnv $ runTestMonad $ do
@@ -69,7 +69,7 @@ tests = sequential $ aroundAll withTestDBAndPort $ do
         let result = over (_Right . authRes_valid . _Just . authVal_token) (const cannedToken) result0
         result `shouldBe` (Right expected)
 
-      it "denies login for user 'alice' if password is invalid" $ \(_testEnv, port) -> do
+      it "denies login for user 'alice' if password is invalid" $ \((_testEnv, port), _) -> do
         let authPayload = AuthRequest "alice" (GargPassword "wrong")
         result <- runClientM (auth_api authPayload) (clientEnv port)
         let expected = AuthResponse {
diff --git a/test/Test/API/Private.hs b/test/Test/API/Private.hs
index 601f673d20378df6a968844a918f7dd2c7a04802..f457b8f07fd37a5987675f1c185f921527d0aa42 100644
--- a/test/Test/API/Private.hs
+++ b/test/Test/API/Private.hs
@@ -1,12 +1,16 @@
+{-# LANGUAGE QuasiQuotes #-}
 {-# LANGUAGE TypeApplications #-}
 {-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 
 module Test.API.Private where
 
+import Control.Exception
 import Control.Monad
 import Control.Monad.Reader
 import Data.Maybe
 import Data.Proxy
+import Fmt
 import Gargantext.API.Admin.Auth.Types
 import Gargantext.API.Routes
 import Gargantext.Core.Types.Individu
@@ -20,8 +24,49 @@ import Test.API.Authentication (auth_api)
 import Test.API.Setup (withTestDBAndPort)
 import Test.Database.Types
 import Test.Hspec
+import Test.Hspec.Wai hiding (pendingWith)
+import Test.Hspec.Wai.Internal (withApplication)
+import Test.Hspec.Wai.JSON
 import qualified Data.Text.Encoding as TE
+import qualified Network.Wai.Handler.Warp as Wai
 import qualified Servant.Auth.Client as SA
+import Data.ByteString (ByteString)
+import Network.Wai.Test (SResponse)
+import Network.HTTP.Types
+import qualified Data.ByteString.Lazy as L
+
+type Env = ((TestEnv, Wai.Port), Application)
+
+curApi :: Builder
+curApi = "v1.0"
+
+mkUrl :: Wai.Port -> Builder -> ByteString
+mkUrl _port urlPiece =
+  "/api/" +| curApi |+ urlPiece
+
+-- | Issue a request with a valid 'Authorization: Bearer' inside.
+protected :: Token -> Method -> ByteString -> L.ByteString -> WaiSession () SResponse
+protected tkn mth url payload =
+  request mth url [ (hAccept, "application/json;charset=utf-8")
+                  , (hContentType, "application/json")
+                  , (hAuthorization, TE.encodeUtf8 tkn)
+                  ] payload
+
+getJSON :: ByteString -> WaiSession () SResponse
+getJSON url =
+  request "GET" url [(hContentType, "application/json")] ""
+
+withValidLogin :: MonadIO m => Wai.Port -> Username -> GargPassword -> (Token -> m a) -> m a
+withValidLogin port ur pwd act = do
+  baseUrl <- liftIO $ parseBaseUrl "http://localhost"
+  manager <- liftIO $ newManager defaultManagerSettings
+  let clientEnv = mkClientEnv manager (baseUrl { baseUrlPort = port })
+  let authPayload = AuthRequest ur pwd
+  result <- liftIO $ runClientM (auth_api authPayload) clientEnv
+  case result of
+    Left err  -> liftIO $ throwIO $ userError (show err)
+    Right res -> let token = _authVal_token $ fromJust (_authRes_valid res) in act token
+
 
 tests :: Spec
 tests = sequential $ aroundAll withTestDBAndPort $ do
@@ -33,7 +78,7 @@ tests = sequential $ aroundAll withTestDBAndPort $ do
     describe "GET /api/v1.0/user" $ do
 
       -- FIXME(adn): unclear if this is useful at all. Doesn't do permission checking.
-      it "doesn't allow someone with an invalid token to show the results" $ \(testEnv, port) -> do
+      it "doesn't allow someone with an invalid token to show the results" $ \((testEnv, port), _) -> do
 
         -- Let's create two users, Alice & Bob. Alice shouldn't be able to see
         -- Bob's private data and vice-versa.
@@ -52,16 +97,24 @@ tests = sequential $ aroundAll withTestDBAndPort $ do
         length result `shouldBe` 0
 
       -- FIXME(adn): unclear if this is useful at all. Doesn't do permission checking.
-      it "allows 'alice' to see the results" $ \(_testEnv, port) -> do
+      it "allows 'alice' to see the results" $ \((_testEnv, port), _) -> do
 
-        let authPayload = AuthRequest "alice" (GargPassword "alice")
-        Right result <- runClientM (auth_api authPayload) (clientEnv port)
+        withValidLogin port "alice" (GargPassword "alice") $ \token -> do
+          let ( roots_api :<|> _nodes_api
+                ) = client (Proxy :: Proxy (MkProtectedAPI GargAdminAPI)) (SA.Token $ TE.encodeUtf8 $ token)
+          let ( admin_user_api_get :<|> _) = roots_api
 
-        let token = _authVal_token $ fromJust (_authRes_valid result)
+          _nodes <- runClientM admin_user_api_get (clientEnv port)
+          pendingWith "currently useless"
 
-        let ( roots_api :<|> _nodes_api
-              ) = client (Proxy :: Proxy (MkProtectedAPI GargAdminAPI)) (SA.Token $ TE.encodeUtf8 $ token)
-        let ( admin_user_api_get :<|> _) = roots_api
+    describe "GET /api/v1.0/node" $ do
+
+      it "unauthorised users shouldn't see anything" $ \((_testEnv, port), app) -> do
+        withApplication app $ do
+          get (mkUrl port "/node/1") `shouldRespondWith` 401
+
+      it "allows 'alice' to see her own node info" $ \((_testEnv, port), app) -> do
+        withApplication app $ do
+          withValidLogin port "alice" (GargPassword "alice") $ \token -> do
+            protected token "GET" (mkUrl port "/node/1") "" `shouldRespondWith` [json| { } |]
 
-        _nodes <- runClientM admin_user_api_get (clientEnv port)
-        pendingWith "currently useless"
diff --git a/test/Test/API/Setup.hs b/test/Test/API/Setup.hs
index 668acf2ac1a9011aea8df7d78cb86338cec67114..464cbf23e43a5d28feaa845582e291095abf4f1c 100644
--- a/test/Test/API/Setup.hs
+++ b/test/Test/API/Setup.hs
@@ -2,31 +2,32 @@
 
 module Test.API.Setup where
 
-import Prelude
+import Control.Lens
 import Gargantext.API (makeApp)
 import Gargantext.API.Admin.EnvTypes (Mode(Mock), Env (..))
 import Gargantext.API.Admin.Settings
+import Gargantext.API.Admin.Types
+import Gargantext.API.Prelude
+import Gargantext.Core.NLP
+import Gargantext.Core.NodeStory
+import Gargantext.Database.Prelude
+import Gargantext.Prelude.Config
 import Gargantext.System.Logging
+import Network.HTTP.Client.TLS (newTlsManager)
+import Network.Wai (Application)
+import Prelude
+import Servant.Auth.Client ()
 import Servant.Client
 import Test.Database.Setup (withTestDB, fakeIniPath, testEnvToPgConnectionInfo)
-import qualified Network.Wai.Handler.Warp         as Warp
 import Test.Database.Types
-import Gargantext.API.Prelude
+import qualified Gargantext.Prelude.Mail as Mail
+import qualified Gargantext.Prelude.NLP as NLP
 import qualified Gargantext.Utils.Jobs as Jobs
+import qualified Gargantext.Utils.Jobs.Monad as Jobs
 import qualified Gargantext.Utils.Jobs.Queue as Jobs
 import qualified Gargantext.Utils.Jobs.Settings as Jobs
-import qualified Gargantext.Utils.Jobs.Monad as Jobs
-import qualified Gargantext.Prelude.Mail as Mail
-import qualified Gargantext.Prelude.NLP as NLP
-import Network.HTTP.Client.TLS (newTlsManager)
-import Control.Lens
-import Gargantext.API.Admin.Types
-import Gargantext.Prelude.Config
-import Gargantext.Core.NodeStory
-import Gargantext.Database.Prelude
-import Gargantext.Core.NLP
+import qualified Network.Wai.Handler.Warp         as Warp
 import qualified Servant.Job.Async as ServantAsync
-import Servant.Auth.Client ()
 
 
 newTestEnv :: TestEnv -> Logger (GargM Env GargError) -> Warp.Port -> IO Env
@@ -67,17 +68,15 @@ newTestEnv testEnv logger port = do
     , _env_nlp       = nlp_env
     }
 
-withGargApp :: TestEnv -> (Warp.Port -> IO ()) -> IO ()
-withGargApp testEnv action = do
-  let createApp = do
-        withLoggerHoisted Mock $ \ioLogger -> do
-          env <- newTestEnv testEnv ioLogger 8080
-          makeApp env
-  Warp.testWithApplication createApp action
+withGargApp :: Application -> (Warp.Port -> IO ()) -> IO ()
+withGargApp app action = do
+  Warp.testWithApplication (pure app) action
 
-withTestDBAndPort :: ((TestEnv, Warp.Port) -> IO ()) -> IO ()
+withTestDBAndPort :: (((TestEnv, Warp.Port), Application) -> IO ()) -> IO ()
 withTestDBAndPort action =
-  withTestDB $ \testEnv ->
-    withGargApp testEnv $ \port ->
-      action (testEnv, port)
-
+  withTestDB $ \testEnv -> do
+    app <- withLoggerHoisted Mock $ \ioLogger -> do
+             env <- newTestEnv testEnv ioLogger 8080
+             makeApp env
+    withGargApp app $ \port ->
+      action ((testEnv, port), app)