diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index c1fdcba5bfeb01956aeecd1e3fbb0f5d673670a8..291ff642af34defd923129774ad4856c972e53dc 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -5,6 +5,7 @@ import { NotificationService } from './services/util/notification.service';
 import { MatIconRegistry } from '@angular/material';
 import { DomSanitizer } from '@angular/platform-browser';
 import { Rescale } from './models/rescale';
+import { ApiConfigService } from './services/http/api-config.service';
 
 @Component({
   selector: 'app-root',
@@ -24,7 +25,8 @@ export class AppComponent implements OnInit {
               private update: SwUpdate,
               public notification: NotificationService,
               private matIconRegistry: MatIconRegistry,
-              private domSanitizer: DomSanitizer) {
+              private domSanitizer: DomSanitizer,
+              private apiConfigService: ApiConfigService) {
     translationService.setDefaultLang(this.translationService.getBrowserLang());
     sessionStorage.setItem('currentLang', this.translationService.getBrowserLang());
     for (const icon of this.icons) {
@@ -54,6 +56,7 @@ export class AppComponent implements OnInit {
         }
       });
     });
+    this.apiConfigService.load();
   }
 
   public getRescale(): Rescale {
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 75d38da8e968e9955baa865528047cc149bf2a2f..baf5a4cf53166fdedb1f5890d55b7c126dc7fb30 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -43,6 +43,7 @@ import { HomeParticipantPageComponent } from './components/home/home-participant
 import { CommentSettingsService } from './services/http/comment-settings.service';
 import { ModeratorModule } from './components/moderator/moderator.module';
 import { ImprintComponent } from './components/home/_dialogs/imprint/imprint.component';
+import { ApiConfigService } from './services/http/api-config.service';
 import { DataProtectionComponent } from './components/home/_dialogs/data-protection/data-protection.component';
 import { HelpPageComponent } from './components/shared/_dialogs/help-page/help-page.component';
 import { CookiesComponent } from './components/home/_dialogs/cookies/cookies.component';
@@ -151,6 +152,7 @@ export function initializeApp(appConfig: AppConfig) {
     ModeratorService,
     CommentSettingsService,
     WsConnectorService,
+    ApiConfigService,
     {
       provide: MatDialogRef,
       useValue: {
diff --git a/src/app/models/api-config.ts b/src/app/models/api-config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0776be295bc587da46d0bc2c97d36cc239209092
--- /dev/null
+++ b/src/app/models/api-config.ts
@@ -0,0 +1,34 @@
+export enum AuthenticationProviderType {
+  ANONYMOUS = 'ANONYMOUS',
+  USERNAME_PASSWORD = 'USERNAME_PASSWORD',
+  SSO = 'SSO'
+}
+
+export enum AuthenticationProviderRole {
+  MODERATOR = 'MODERATOR',
+  PARTICIPANT = 'PARTICIPANT'
+}
+
+export interface AuthenticationProvider {
+  id: string;
+  title: string;
+  type: AuthenticationProviderType;
+  order: number;
+  allowedRoles: AuthenticationProviderRole[];
+}
+
+export interface Feature {
+  enabled: boolean;
+}
+
+export interface UiConfig {
+  [configName: string]: any;
+}
+
+export class ApiConfig {
+  constructor(
+      public authenticationProviders: AuthenticationProvider[],
+      public features: { [featureName: string]: Feature },
+      public ui: UiConfig) {
+  }
+}
diff --git a/src/app/services/http/api-config.service.ts b/src/app/services/http/api-config.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..63c21a7869ad9847e57b0c51f9937433228bd776
--- /dev/null
+++ b/src/app/services/http/api-config.service.ts
@@ -0,0 +1,70 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { BaseHttpService } from './base-http.service';
+import { ApiConfig, AuthenticationProvider, Feature, UiConfig } from '../../models/api-config';
+
+@Injectable()
+export class ApiConfigService extends BaseHttpService {
+  private readonly apiUris = {
+    /* TODO: API base URI should be injected. */
+    base: '/api',
+    configPart: '/configuration',
+    get config() {
+      return this.base + this.configPart;
+    }
+  };
+  private config$: Observable<ApiConfig>;
+  private config: ApiConfig;
+
+  constructor(private http: HttpClient) {
+    super();
+    this.config$ = this.http.get<ApiConfig>(this.apiUris.config);
+    this.config = new ApiConfig([], {}, {});
+    this.freezeRecursively(this.config);
+  }
+
+  load() {
+    console.log('Loading API configuration...');
+    this.config$.subscribe((config) => {
+      config.authenticationProviders.sort((p1, p2) => {
+        return p1.order < p2.order ? -1 : p1.order > p2.order ? 1 : 0;
+      });
+      this.freezeRecursively(config);
+      this.config = config;
+      console.log('API configuration loaded.');
+    });
+  }
+
+  get loaded() {
+    return !!this.config;
+  }
+
+  getAuthProviders(): AuthenticationProvider[] {
+    return this.config.authenticationProviders;
+  }
+
+  getFeatureConfig(feature: string): Feature {
+    return this.config.features[feature];
+  }
+
+  getUiConfig(): UiConfig {
+    return this.config.ui;
+  }
+
+  private freezeRecursively(obj: object) {
+    /* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze */
+    if (Object.freeze) {
+      const propNames = Object.getOwnPropertyNames(obj);
+
+      /* Freeze properties before freezing self */
+      for (const name of propNames) {
+        const value = obj[name];
+        obj[name] = value && typeof value === 'object'
+            ? this.freezeRecursively(value) : value;
+      }
+    }
+
+    return Object.freeze(obj);
+  }
+}