diff --git a/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java b/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
index 79f33294ed73eca61c44ad17c50a0a939527e72a..ee88f94dbcff48749c23a3ffdd4456955255b588 100644
--- a/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
+++ b/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
@@ -375,6 +375,26 @@ public class GitlabService {
         return groupApi.getSubGroups(groupId);
     }
 
+    public boolean isMember(long gitProjectId, at.ac.uibk.gitsearch.domain.User user) throws GitLabApiException {
+        try {
+            org.gitlab4j.api.models.User gitUser = this.gitLabRepository.getAdminGitLabApi().getUserApi().getUserByEmail(user.getEmail());
+
+            if (gitUser == null) {
+                return false;
+            }
+
+            return gitLabRepository.getAdminGitLabApi().getProjectApi().getMember(gitProjectId, gitUser.getId(), true) != null;
+        } catch (final GitLabApiException e) {
+            if (e.getHttpStatus() == 404) {
+                return false;
+            }
+            throw e;
+        } catch (IllegalArgumentException e) {
+            // email of user invalid
+            return false;
+        }
+    }
+
     /**
      * Utility function used to set the default JGIT credentials to use the provided
      * OAuth2 token
diff --git a/src/main/java/at/ac/uibk/gitsearch/web/rest/ExerciseResource.java b/src/main/java/at/ac/uibk/gitsearch/web/rest/ExerciseResource.java
index ac296968d52c6ce3dbdce71f6c06241b6f4516a8..37b9222358200b01329a6e803eeea2b14275055e 100644
--- a/src/main/java/at/ac/uibk/gitsearch/web/rest/ExerciseResource.java
+++ b/src/main/java/at/ac/uibk/gitsearch/web/rest/ExerciseResource.java
@@ -1,6 +1,7 @@
 package at.ac.uibk.gitsearch.web.rest;
 
 import at.ac.uibk.gitsearch.domain.ChildInfo;
+import at.ac.uibk.gitsearch.domain.User;
 import at.ac.uibk.gitsearch.es.model.ArtemisExerciseInfo;
 import at.ac.uibk.gitsearch.security.SecurityUtils;
 import at.ac.uibk.gitsearch.service.ArtemisImportError;
@@ -9,6 +10,7 @@ import at.ac.uibk.gitsearch.service.GitlabService;
 import at.ac.uibk.gitsearch.service.SearchService;
 import at.ac.uibk.gitsearch.service.SearchService.ExtractionDepth;
 import at.ac.uibk.gitsearch.service.StatisticsService;
+import at.ac.uibk.gitsearch.service.UserService;
 import at.ac.uibk.gitsearch.service.dto.StatisticsDTO;
 import at.ac.uibk.gitsearch.web.rest.utils.RestUtils;
 import at.ac.uibk.gitsearch.web.util.HeaderUtil;
@@ -84,6 +86,10 @@ public class ExerciseResource {
     @SuppressWarnings({ "PMD.ImmutableField", "PMD.AvoidDuplicateLiterals" })
     private SearchService searchService;
 
+    @Autowired
+    @SuppressWarnings({ "PMD.ImmutableField", "PMD.AvoidDuplicateLiterals" })
+    private UserService userService;
+
     @Autowired
     @SuppressWarnings({ "PMD.ImmutableField", "PMD.AvoidDuplicateLiterals" })
     private StatisticsService statisticsService;
@@ -389,6 +395,35 @@ public class ExerciseResource {
         return ResponseEntity.ok(new URL(baseUrl + "/import/" + exerciseImportService.getTokenFromUrl(exerciseUrl)).toURI());
     }
 
+    @GetMapping("/exercises/{id}/source-authorization")
+    @SuppressWarnings("PMD.AvoidCatchingGenericException")
+    public ResponseEntity<?> getMembers(@PathVariable("id") String exerciseId) {
+        try {
+            if (SecurityUtils.getCurrentUserLogin().isEmpty()) {
+                ResponseEntity.status(HttpStatus.FORBIDDEN).build();
+            }
+
+            final Optional<SearchResultDTO> result = searchService.findExerciseById(ExerciseId.fromString(exerciseId));
+            if (result.isEmpty()) {
+                return ResponseEntity.notFound().build();
+            }
+
+            Optional<User> user = this.userService.getUserByLogin(SecurityUtils.getCurrentUserLogin().get());
+            if (user.isEmpty()) {
+                return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
+            }
+
+            int gitProjectId = result.get().getProject().getProject_id();
+
+            return this.gitLabService.isMember(gitProjectId, user.get())
+                ? ResponseEntity.ok().build()
+                : ResponseEntity.status(HttpStatus.FORBIDDEN).build();
+        } catch (final Exception e) {
+            log.error("Error while getting /source-authorization for exercise {}", exerciseId, e);
+            return ResponseEntity.internalServerError().build();
+        }
+    }
+
     /**
      * GET /exercise/imported-exercise-info/{exerciseToken} : Used to retrieve the exercise's metadata
      * of a given exerciseToken
diff --git a/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts b/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts
index 7777f97641f34fac3d534a8864b325a7918f0ad8..bdad39843287e983cfd2317a1168b4b18a4d1dc4 100644
--- a/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts
+++ b/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts
@@ -80,12 +80,7 @@ export class ExerciseHeaderComponent {
 })
 export class ExerciseBodyComponent implements OnInit, OnDestroy, AfterViewInit {
   @Output() exerciseChangedEvent = new EventEmitter<SearchResultDTO>();
-  @Input() get referencedExercise(): SearchResultDTO | undefined {
-    return this.exercise;
-  }
-  set referencedExercise(exercise: SearchResultDTO | undefined) {
-    this.exercise = exercise as ExtendedSearchResultDTO;
-  }
+  gitlabIsAccessible = false;
   exercise: ExtendedSearchResultDTO | undefined;
 
   parent: SearchResultDTO | undefined;
@@ -102,10 +97,21 @@ export class ExerciseBodyComponent implements OnInit, OnDestroy, AfterViewInit {
 
   treeIcon = faFolderOpen;
   faArrowRight = faArrowRight;
-
   oerLink?: string;
   oerExerciseMatch = /([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})$/;
 
+  @Input() get referencedExercise(): SearchResultDTO | undefined {
+    return this.exercise;
+  }
+
+  set referencedExercise(exercise: SearchResultDTO | undefined) {
+    this.gitlabIsAccessible = false;
+    this.exercise = exercise as ExtendedSearchResultDTO;
+    if (exercise) {
+      this.updateGitIsAccessibleForUser();
+    }
+  }
+
   constructor(
     private reviewManagementService: ReviewManagementService,
     private accountService: AccountService,
@@ -152,6 +158,26 @@ export class ExerciseBodyComponent implements OnInit, OnDestroy, AfterViewInit {
     return '';
   }
 
+  updateGitIsAccessibleForUser(): void {
+    const projectIsPrivate: boolean = this.exercise?.project.visibilty == 'private';
+    const exceptIsEmpty: boolean =
+      !this.exercise?.metadata.publicVisibility?.except || this.exercise?.metadata.publicVisibility?.except.length == 0;
+
+    if (!projectIsPrivate && exceptIsEmpty) {
+      this.gitlabIsAccessible = true;
+      return;
+    }
+
+    if (!this.isAuthenticated()) {
+      this.gitlabIsAccessible = false;
+      return;
+    }
+
+    this.exerciseService
+      .hasUserAccessToGitlabRepo(this.exercise!.exerciseId)
+      .subscribe((accessible: boolean) => (this.gitlabIsAccessible = accessible));
+  }
+
   public startAction(action: PluginActionInfo, exercise: SearchResultDTO): void {
     const basketInfo: ShoppingBasketInfo = {
       plugin: action.plugin,
diff --git a/src/main/webapp/app/exercise/exercise-details/exerciseComponents/exercise-body.component.html b/src/main/webapp/app/exercise/exercise-details/exerciseComponents/exercise-body.component.html
index 52769fb60217ac177d30ad73a1489d33477951ad..5c720c3d44c1fb0158e2d41b609bcb9b05bd0cae 100644
--- a/src/main/webapp/app/exercise/exercise-details/exerciseComponents/exercise-body.component.html
+++ b/src/main/webapp/app/exercise/exercise-details/exerciseComponents/exercise-body.component.html
@@ -182,6 +182,7 @@
         jhiTranslate="exercise.details.allExercises"
       ></button>
       <button
+        [disabled]="!this.gitlabIsAccessible"
         type="button"
         class="btn btn-outline-secondary"
         style="display: block"
diff --git a/src/main/webapp/app/exercise/service/exercise.service.ts b/src/main/webapp/app/exercise/service/exercise.service.ts
index d459c217ced9120134a1355eba7e8f7e55b83883..889dad964bdb53f80864dd43ce12611f1b3832f0 100644
--- a/src/main/webapp/app/exercise/service/exercise.service.ts
+++ b/src/main/webapp/app/exercise/service/exercise.service.ts
@@ -1,12 +1,13 @@
-import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
+import { HttpClient, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { ApplicationConfigService } from 'app/core/config/application-config.service';
 import { LikesService } from 'app/entities/likes/likes.service';
 import { StatisticsService } from 'app/entities/statistics/statistics.service';
 import { SearchService } from 'app/search/service/search-service';
 import { ArtemisExerciseInfo } from 'app/shared/model/artemis-exercise-info.model';
+import { catchError, map } from 'rxjs/operators';
 import { ChildInfo, ExtendedSearchResultDTO, hasChildren, SearchResultDTO } from 'app/shared/model/search/search-result-dto.model';
-import { BehaviorSubject, Observable } from 'rxjs';
+import { BehaviorSubject, Observable, of } from 'rxjs';
 
 @Injectable({ providedIn: 'root' })
 export class ExerciseService {
@@ -36,6 +37,20 @@ export class ExerciseService {
 
   private exerciseCache: { [id: string]: BehaviorSubject<SearchResultDTO> } = {};
 
+  public hasUserAccessToGitlabRepo(exerciseId: string): Observable<boolean> {
+    const endpoint: string = this.applicationConfigService.getEndpointFor(
+      SERVER_API_URL + 'api/exercises/' + encodeURIforExerciseId(exerciseId) + '/source-authorization'
+    );
+    return this.http.get<any>(endpoint, { observe: 'response' }).pipe(
+      map((response: HttpResponse<any>) => {
+        return response.status === 200;
+      }),
+      catchError(() => {
+        return of(false);
+      })
+    );
+  }
+
   public loadExercise(exerciseId: string): Observable<SearchResultDTO> {
     if (this.exerciseCache[exerciseId]) {
       return this.exerciseCache[exerciseId];
@@ -108,18 +123,6 @@ export class ExerciseService {
         },
         error: () => console.warn('Could not load if user has liked or not'),
       });
-
-      /*
-      * the following is not relevant: is now reloaded directly from index
-      this.searchService.getStatisticsForExercise(exercise.exerciseId).subscribe({
-        next: (data: Statistics) => {
-          result.views = data.views!;
-          result.downloads = data.downloads!;
-          result.badgeRewarded = data.badgeRewarded!;
-        },
-        error: () => console.warn('Could not load exercise statistics'),
-      });
-      */
     }
     return result;
   }
diff --git a/src/main/webapp/app/shared/model/search/project-dto.model.ts b/src/main/webapp/app/shared/model/search/project-dto.model.ts
index 4b62548d9f9e7a96d4bb7ff3d21de711ba1f4aa9..713eb524ee56d690e2b20224608bb36244e5844f 100644
--- a/src/main/webapp/app/shared/model/search/project-dto.model.ts
+++ b/src/main/webapp/app/shared/model/search/project-dto.model.ts
@@ -5,5 +5,6 @@ export interface ProjectDTO {
   main_group: string;
   sub_group: string;
   url: string;
+  visibilty: string;
   last_activity_at: Date;
 }
diff --git a/src/main/webapp/app/shared/model/search/public-visibility-dto.model.ts b/src/main/webapp/app/shared/model/search/public-visibility-dto.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6ece5e0585ec545423b93205c8cea099d3197411
--- /dev/null
+++ b/src/main/webapp/app/shared/model/search/public-visibility-dto.model.ts
@@ -0,0 +1,3 @@
+export interface PublicVisibilityDTOModel {
+  except: string[];
+}
diff --git a/src/main/webapp/app/shared/model/search/user-provided-metadata-dto.model.ts b/src/main/webapp/app/shared/model/search/user-provided-metadata-dto.model.ts
index bab099bfcb851cb33efe4338dcb667a4eb0cdae4..8d649b636c1ac6ff0298c2678951ce3797b72c74 100644
--- a/src/main/webapp/app/shared/model/search/user-provided-metadata-dto.model.ts
+++ b/src/main/webapp/app/shared/model/search/user-provided-metadata-dto.model.ts
@@ -1,5 +1,6 @@
 import { Person } from '../person.model';
 import { IInteractivityType } from '../exercise.model';
+import { PublicVisibilityDTOModel } from './public-visibility-dto.model';
 
 export interface UserProvidedMetadataDTO {
   assesses: string[];
@@ -33,4 +34,5 @@ export interface UserProvidedMetadataDTO {
   title: string;
   typicalAgeRange: string;
   version: string;
+  publicVisibility: PublicVisibilityDTOModel;
 }