diff --git a/client/src/app/auth/auth.actions.ts b/client/src/app/auth/auth.actions.ts
index 52da0604574a5b963966ee9e99312cf229c29d91..4103bcebd10660ab2d67a814181a2300af67872a 100644
--- a/client/src/app/auth/auth.actions.ts
+++ b/client/src/app/auth/auth.actions.ts
@@ -16,4 +16,5 @@ export const logout = createAction('[Auth] Logout');
 export const authSuccess = createAction('[Auth] Auth Success');
 export const loadUserProfileSuccess = createAction('[Auth] Load User Profile Success', props<{ userProfile: UserProfile }>());
 export const loadUserRoleSuccess = createAction('[Auth] Load User Roles Success', props<{ userRoles: string[] }>());
+export const loadTokenSuccess = createAction('[Auth] Load Token Success', props<{ token: string }>());
 export const openEditProfile = createAction('[Auth] Edit Profile');
diff --git a/client/src/app/auth/auth.effects.ts b/client/src/app/auth/auth.effects.ts
index 69cefb0e2b4f468564a02cdcbafb631a22113e7f..a663b0a069bce19419f982be0a4ce012ac52ff08 100644
--- a/client/src/app/auth/auth.effects.ts
+++ b/client/src/app/auth/auth.effects.ts
@@ -10,7 +10,7 @@
 import { Injectable } from '@angular/core';
 import { Actions, createEffect, ofType } from '@ngrx/effects';
 import { from } from 'rxjs';
-import { tap, switchMap } from 'rxjs/operators';
+import { tap, switchMap, withLatestFrom } from 'rxjs/operators';
 
 import { KeycloakService } from 'keycloak-angular';
 
@@ -49,9 +49,11 @@ export class AuthEffects {
             ofType(authActions.authSuccess),
             switchMap(() => from(this.keycloak.loadUserProfile())
                 .pipe(
-                    switchMap(userProfile => [
+                    withLatestFrom(this.keycloak.getToken()),
+                    switchMap(([userProfile, token]) => [
                         authActions.loadUserProfileSuccess({ userProfile }),
-                        authActions.loadUserRoleSuccess({ userRoles: this.keycloak.getUserRoles() })
+                        authActions.loadUserRoleSuccess({ userRoles: this.keycloak.getUserRoles() }),
+                        authActions.loadTokenSuccess({ token })
                     ])
                 )
             )
diff --git a/client/src/app/auth/auth.reducer.ts b/client/src/app/auth/auth.reducer.ts
index d0805affc1d7dfeb02d4b6f6c2cc2bf728c401c5..d181f446c38c60c85008746abebb2709a3d74e64 100644
--- a/client/src/app/auth/auth.reducer.ts
+++ b/client/src/app/auth/auth.reducer.ts
@@ -16,12 +16,14 @@ export interface State {
     isAuthenticated: boolean;
     userProfile: UserProfile;
     userRoles: string[];
+    token: string;
 }
 
 export const initialState: State = {
     isAuthenticated: false,
     userProfile: null,
-    userRoles: []
+    userRoles: [],
+    token: null
 };
 
 export const authReducer = createReducer(
@@ -37,9 +39,14 @@ export const authReducer = createReducer(
     on(authActions.loadUserRoleSuccess, (state, { userRoles }) => ({
         ...state,
         userRoles
+    })),
+    on(authActions.loadTokenSuccess, (state, { token }) => ({
+        ...state,
+        token
     }))
 );
 
 export const selectIsAuthenticated = (state: State) => state.isAuthenticated;
 export const selectUserProfile = (state: State) => state.userProfile;
 export const selectUserRoles = (state: State) => state.userRoles;
+export const selectToken = (state: State) => state.token;
diff --git a/client/src/app/auth/auth.selector.ts b/client/src/app/auth/auth.selector.ts
index 8b0e4f734c29257f3e9004722e5aa802053d6a6d..3822a9055d1df824dc751a6ac04ecf7b6c9ea866 100644
--- a/client/src/app/auth/auth.selector.ts
+++ b/client/src/app/auth/auth.selector.ts
@@ -27,3 +27,8 @@ export const selectUserRoles = createSelector(
     selectAuthState,
     fromAuth.selectUserRoles
 );
+
+export const selectToken = createSelector(
+    selectAuthState,
+    fromAuth.selectToken
+);
diff --git a/client/src/app/instance/search/components/result/datatable-tab.component.html b/client/src/app/instance/search/components/result/datatable-tab.component.html
index f9f6b3aaa6a57531613c217cf6a1ebf3501bc5be..f854be3243fe7e38b59814ca08d52593e70da7ca 100644
--- a/client/src/app/instance/search/components/result/datatable-tab.component.html
+++ b/client/src/app/instance/search/components/result/datatable-tab.component.html
@@ -19,6 +19,7 @@
                 [dataIsLoading]="dataIsLoading"
                 [dataIsLoaded]="dataIsLoaded"
                 [selectedData]="selectedData"
+                [token]="token"
                 (retrieveData)="retrieveData.emit($event)"
                 (addSelectedData)="addSelectedData.emit($event)"
                 (deleteSelectedData)="deleteSelectedData.emit($event)">
diff --git a/client/src/app/instance/search/components/result/datatable-tab.component.ts b/client/src/app/instance/search/components/result/datatable-tab.component.ts
index a276dec48ebe3974e8494c21d4cda2602d64794b..51d18381cc91d321ea591568700f04fafcd0f0e9 100644
--- a/client/src/app/instance/search/components/result/datatable-tab.component.ts
+++ b/client/src/app/instance/search/components/result/datatable-tab.component.ts
@@ -33,6 +33,7 @@ export class DatatableTabComponent {
     @Input() dataIsLoading: boolean;
     @Input() dataIsLoaded: boolean;
     @Input() selectedData: any[];
+    @Input() token: string;
     @Output() retrieveData: EventEmitter<Pagination> = new EventEmitter();
     @Output() addSelectedData: EventEmitter<number | string> = new EventEmitter();
     @Output() deleteSelectedData: EventEmitter<number | string> = new EventEmitter();
diff --git a/client/src/app/instance/search/containers/result.component.html b/client/src/app/instance/search/containers/result.component.html
index d9b4fdbf2a8260fc9d97ecb02df3294d25a04e9f..a350d6ef113a40dcaa15ac265b88c56f50a7df22 100644
--- a/client/src/app/instance/search/containers/result.component.html
+++ b/client/src/app/instance/search/containers/result.component.html
@@ -82,6 +82,7 @@
                 [dataIsLoading]="dataIsLoading | async"
                 [dataIsLoaded]="dataIsLoaded | async"
                 [selectedData]="selectedData | async"
+                [token]="token | async"
                 (retrieveData)="retrieveData($event)"
                 (addSelectedData)="addSearchData($event)"
                 (deleteSelectedData)="deleteSearchData($event)">
diff --git a/client/src/app/instance/search/containers/result.component.ts b/client/src/app/instance/search/containers/result.component.ts
index f62ca538ed8b10b2a94be5d2b5e3778e92907a22..16a1278464bba34e97cd60d30acc9d3457784daf 100644
--- a/client/src/app/instance/search/containers/result.component.ts
+++ b/client/src/app/instance/search/containers/result.component.ts
@@ -20,6 +20,7 @@ import * as searchActions from '../../store/actions/search.actions';
 import * as searchSelector from '../../store/selectors/search.selector';
 import * as sampActions from '../../store/actions/samp.actions';
 import * as sampSelector from '../../store/selectors/samp.selector';
+import * as authSelector from 'src/app/auth/auth.selector';
 
 @Component({
     selector: 'app-result',
@@ -42,6 +43,7 @@ export class ResultComponent extends AbstractSearchComponent {
     public dataIsLoaded: Observable<boolean>;
     public selectedData: Observable<any>;
     public sampRegistered: Observable<boolean>;
+    public token: Observable<string>;
 
     private pristineSubscription: Subscription;
 
@@ -56,6 +58,7 @@ export class ResultComponent extends AbstractSearchComponent {
         this.dataIsLoaded = this.store.select(searchSelector.selectDataIsLoaded);
         this.selectedData = this.store.select(searchSelector.selectSelectedData);
         this.sampRegistered = this.store.select(sampSelector.selectRegistered);
+        this.token = this.store.select(authSelector.selectToken);
     }
 
     ngOnInit() {
diff --git a/client/src/app/instance/shared-search/components/datatable/datatable.component.html b/client/src/app/instance/shared-search/components/datatable/datatable.component.html
index 7b7ee23a3405f901e1183f30f59c9dbbbfeceefc..f97a2bb29e04aa12762b429657b683a4db5dce70 100644
--- a/client/src/app/instance/shared-search/components/datatable/datatable.component.html
+++ b/client/src/app/instance/shared-search/components/datatable/datatable.component.html
@@ -61,6 +61,8 @@
                             <app-download-renderer
                                 [value]="datum[attribute.label]"
                                 [datasetName]="dataset.name"
+                                [datasetPublic]="dataset.public"
+                                [token]="token"
                                 [config]="getRendererConfig(attribute)">
                             </app-download-renderer>
                         </div>
diff --git a/client/src/app/instance/shared-search/components/datatable/datatable.component.ts b/client/src/app/instance/shared-search/components/datatable/datatable.component.ts
index 1e90851ca9be53f1a232c612002eb5a8ae64981f..83c362b75644e90dbf392f7fe73b316c52aaa462 100644
--- a/client/src/app/instance/shared-search/components/datatable/datatable.component.ts
+++ b/client/src/app/instance/shared-search/components/datatable/datatable.component.ts
@@ -34,6 +34,7 @@ export class DatatableComponent implements OnInit {
     @Input() dataIsLoading: boolean;
     @Input() dataIsLoaded: boolean;
     @Input() selectedData: any[] = [];
+    @Input() token: string;
     @Output() retrieveData: EventEmitter<Pagination> = new EventEmitter();
     @Output() addSelectedData: EventEmitter<number | string> = new EventEmitter();
     @Output() deleteSelectedData: EventEmitter<number | string> = new EventEmitter();
diff --git a/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.ts b/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.ts
index 19bcc38572ede27f043ee814f2f330d76eabeb25..40b49a0b16daa0f7c6014b8a854d6117d0f6dca4 100644
--- a/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.ts
+++ b/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.ts
@@ -25,6 +25,8 @@ import { AppConfigService } from 'src/app/app-config.service';
 export class DownloadRendererComponent {
     @Input() value: string;
     @Input() datasetName: string;
+    @Input() datasetPublic: boolean;
+    @Input() token: string;
     @Input() config: DownloadRendererConfig;
 
     constructor(private appConfig: AppConfigService) { }
@@ -35,7 +37,11 @@ export class DownloadRendererComponent {
      * @return string
      */
     getHref(): string {
-        return getHost(this.appConfig.apiUrl) + '/download-file/' + this.datasetName + '/' + this.value;
+        let href = getHost(this.appConfig.apiUrl) + '/download-file/' + this.datasetName + '/' + this.value;
+        if (!this.datasetPublic && this.token) {
+            href += '?token=' + this.token;
+        }
+        return href;
     }
 
     /**
diff --git a/conf-dev/public_key b/conf-dev/public_key
index 7a109409de071d2cc41b153c799ebddb3f142318..6d9fd24a85f3dbb188e0bbc86e620415f641b46c 100644
--- a/conf-dev/public_key
+++ b/conf-dev/public_key
@@ -1,3 +1,3 @@
 -----BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/mnnVnoX4yuiq1AXklR//PCcNOLibWzoRcyhGQQ+Rfokcxny0uBrVmFb7xNAxgqaf3hyo0789ONUf41xQF8CO0+YdLmOfQDRegohZP4mRvppCQUozroKphGAvYt90xaFJL/IttXeRKmUk6Noc/3V0oUA+1P8SbdpIq8s+L9yXfqWmW+mjlMAU31/3gVM/Q/dTmKFnkVlwprhy4OoGzHlNaFElIjFOEICL6M3ANTBLoZwDHiwvxqXuyA9IA8LeHuVpxWmaShGA0UxA99cF3edCmkc6R4d1R7rWP0XjnjYEOYDcVhJZJlRamNuYtgnr82sgr/bJahHFxAnF3GlBHs+gwIDAQAB
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiXxjO2Z+Mnc/L4fcY7oLIvSQXrkADSUQVnAXqfcMzfuNH/clLBMmXIHoPoIOYImIbXFMNaBAFLMWqURSaz2LDEQy5dIfllU9e3kIAV0mJeafjaN3QdxKX8TcJAnrTeQ7soooeZzen7kfPWxfjAaiEtbxo5h2xW4qup+VvADQg15C3dwBS5VV2Lc41z4prQubQNs2WT4IOVfYYhtpp+R/3IuCAFS6qfmAuBUIu8gSq/VpCqJ5Sm/YdmBZDwhyBRYOKJJlkqlNFdGPnHAkBDOL5LeU54cXCBMxPEeomtu22Kv1PIF4w2kfwUie9Qq06yWsTDwyrSAjvQ3xXHAcuAqPRQIDAQAB
 -----END PUBLIC KEY-----
diff --git a/server/src/Middleware/AuthorizationMiddleware.php b/server/src/Middleware/AuthorizationMiddleware.php
index d03a3f459243bff3864772d70d858c037e5f38dc..82b5b4e040383a817331333364af1065016b4012 100644
--- a/server/src/Middleware/AuthorizationMiddleware.php
+++ b/server/src/Middleware/AuthorizationMiddleware.php
@@ -57,15 +57,20 @@ final class AuthorizationMiddleware implements MiddlewareInterface
     {
         if (
             $request->getMethod() === OPTIONS
-            || !$request->hasHeader('Authorization')
+            || (!$request->hasHeader('Authorization') && !array_key_exists('token', $request->getQueryParams()))
             || !boolval($this->settings['enabled'])
         ) {
             return $handler->handle($request);
         }
 
         // Get token string from Authorizarion header
-        $bearer = $request->getHeader('Authorization');
-        $data = explode(' ', $bearer[0]);
+        if ($request->hasHeader('Authorization')) {
+            $bearer = $request->getHeader('Authorization')[0];
+        } else {
+            $bearer = 'Bearer ' . $request->getQueryParams()['token'];
+        }
+
+        $data = explode(' ', $bearer);
         if ($data[0] !== 'Bearer') {
             return $this->getUnauthorizedResponse(
                 'HTTP 401: Authorization must contain a string with the following format -> Bearer JWT'
@@ -89,7 +94,7 @@ final class AuthorizationMiddleware implements MiddlewareInterface
      *
      * @return Response
      */
-    private function getUnauthorizedResponse(string $message): Response
+    private function getUnauthorizedResponse(string $message): NyholmResponse
     {
         $resonse = new NyholmResponse();
         $resonse->getBody()->write(json_encode(array(