diff --git a/.java-version b/.java-version
new file mode 100644
index 000000000..aabe6ec39
--- /dev/null
+++ b/.java-version
@@ -0,0 +1 @@
+21
diff --git a/api/src/main/java/io/kafbat/ui/config/auth/AbstractAuthSecurityConfig.java b/api/src/main/java/io/kafbat/ui/config/auth/AbstractAuthSecurityConfig.java
index f23a0dd2a..265bac03f 100644
--- a/api/src/main/java/io/kafbat/ui/config/auth/AbstractAuthSecurityConfig.java
+++ b/api/src/main/java/io/kafbat/ui/config/auth/AbstractAuthSecurityConfig.java
@@ -1,24 +1,53 @@
 package io.kafbat.ui.config.auth;
 
+import io.kafbat.ui.util.EmptyRedirectStrategy;
+import java.net.URI;
+import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;
+import org.springframework.security.web.server.authentication.logout.RedirectServerLogoutSuccessHandler;
+
 abstract class AbstractAuthSecurityConfig {
 
   protected AbstractAuthSecurityConfig() {
 
   }
 
+  protected static final String LOGIN_URL = "/login";
+  protected static final String LOGOUT_URL = "/auth?logout";
+
   protected static final String[] AUTH_WHITELIST = {
-      "/css/**",
-      "/js/**",
-      "/media/**",
+      /* STATIC */
+      "/index.html",
+      "/assets/**",
+      "/manifest.json",
+      "/favicon.svg",
+      "/favicon/**",
+
+      "/static/**",
       "/resources/**",
+
+      /* ACTUATOR */
       "/actuator/health/**",
       "/actuator/info",
       "/actuator/prometheus",
-      "/auth",
+
+      /* AUTH */
       "/login",
       "/logout",
       "/oauth2/**",
-      "/static/**"
+      "/api/config/authentication",
+      "/api/authorization"
   };
 
+  protected RedirectServerAuthenticationSuccessHandler emptyRedirectSuccessHandler() {
+    final var authHandler = new RedirectServerAuthenticationSuccessHandler();
+    authHandler.setRedirectStrategy(new EmptyRedirectStrategy());
+    return authHandler;
+  }
+
+  protected RedirectServerLogoutSuccessHandler redirectLogoutSuccessHandler() {
+    final var logoutSuccessHandler = new RedirectServerLogoutSuccessHandler();
+    logoutSuccessHandler.setLogoutSuccessUrl(URI.create(LOGOUT_URL));
+    return logoutSuccessHandler;
+  }
+
 }
diff --git a/api/src/main/java/io/kafbat/ui/config/auth/BasicAuthSecurityConfig.java b/api/src/main/java/io/kafbat/ui/config/auth/BasicAuthSecurityConfig.java
index 7a25fb3a7..db8ef8153 100644
--- a/api/src/main/java/io/kafbat/ui/config/auth/BasicAuthSecurityConfig.java
+++ b/api/src/main/java/io/kafbat/ui/config/auth/BasicAuthSecurityConfig.java
@@ -1,6 +1,7 @@
 package io.kafbat.ui.config.auth;
 
 import io.kafbat.ui.util.EmptyRedirectStrategy;
+import io.kafbat.ui.util.StaticFileWebFilter;
 import java.net.URI;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -8,6 +9,7 @@
 import org.springframework.context.annotation.Configuration;
 import org.springframework.http.HttpMethod;
 import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
 import org.springframework.security.config.web.server.ServerHttpSecurity;
 import org.springframework.security.web.server.SecurityWebFilterChain;
 import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;
@@ -20,32 +22,28 @@
 @Slf4j
 public class BasicAuthSecurityConfig extends AbstractAuthSecurityConfig {
 
-  public static final String LOGIN_URL = "/auth";
-  public static final String LOGOUT_URL = "/auth?logout";
-
   @Bean
   public SecurityWebFilterChain configure(ServerHttpSecurity http) {
     log.info("Configuring LOGIN_FORM authentication.");
 
-    final var authHandler = new RedirectServerAuthenticationSuccessHandler();
-    authHandler.setRedirectStrategy(new EmptyRedirectStrategy());
-
-    final var logoutSuccessHandler = new RedirectServerLogoutSuccessHandler();
-    logoutSuccessHandler.setLogoutSuccessUrl(URI.create(LOGOUT_URL));
-
-
-    return http.authorizeExchange(spec -> spec
+    var builder = http.authorizeExchange(spec -> spec
             .pathMatchers(AUTH_WHITELIST)
             .permitAll()
             .anyExchange()
             .authenticated()
         )
-        .formLogin(spec -> spec.loginPage(LOGIN_URL).authenticationSuccessHandler(authHandler))
+        .formLogin(form -> form
+            .loginPage(LOGIN_URL)
+            .authenticationSuccessHandler(emptyRedirectSuccessHandler())
+        )
         .logout(spec -> spec
-            .logoutSuccessHandler(logoutSuccessHandler)
+            .logoutSuccessHandler(redirectLogoutSuccessHandler())
             .requiresLogout(ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/logout")))
-        .csrf(ServerHttpSecurity.CsrfSpec::disable)
-        .build();
+        .csrf(ServerHttpSecurity.CsrfSpec::disable);
+
+    builder.addFilterAt(new StaticFileWebFilter(), SecurityWebFiltersOrder.LOGIN_PAGE_GENERATING);
+
+    return builder.build();
   }
 
 }
diff --git a/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java b/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java
index 1b5a8ca87..4d89a9568 100644
--- a/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java
+++ b/api/src/main/java/io/kafbat/ui/config/auth/LdapSecurityConfig.java
@@ -1,9 +1,8 @@
 package io.kafbat.ui.config.auth;
 
-import static io.kafbat.ui.config.auth.AbstractAuthSecurityConfig.AUTH_WHITELIST;
-
 import io.kafbat.ui.service.rbac.AccessControlService;
 import io.kafbat.ui.service.rbac.extractor.RbacLdapAuthoritiesExtractor;
+import io.kafbat.ui.util.StaticFileWebFilter;
 import java.util.Collection;
 import java.util.List;
 import java.util.Optional;
@@ -14,6 +13,7 @@
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
 import org.springframework.ldap.core.DirContextOperations;
 import org.springframework.ldap.core.support.BaseLdapPathContextSource;
 import org.springframework.ldap.core.support.LdapContextSource;
@@ -21,8 +21,8 @@
 import org.springframework.security.authentication.ProviderManager;
 import org.springframework.security.authentication.ReactiveAuthenticationManager;
 import org.springframework.security.authentication.ReactiveAuthenticationManagerAdapter;
-import org.springframework.security.config.Customizer;
 import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
 import org.springframework.security.config.web.server.ServerHttpSecurity;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.userdetails.UserDetails;
@@ -36,6 +36,7 @@
 import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
 import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
 import org.springframework.security.web.server.SecurityWebFilterChain;
+import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
 
 @Configuration
 @EnableWebFluxSecurity
@@ -43,7 +44,7 @@
 @EnableConfigurationProperties(LdapProperties.class)
 @RequiredArgsConstructor
 @Slf4j
-public class LdapSecurityConfig {
+public class LdapSecurityConfig extends AbstractAuthSecurityConfig {
 
   private final LdapProperties props;
 
@@ -121,16 +122,24 @@ public SecurityWebFilterChain configureLdap(ServerHttpSecurity http) {
       log.info("Active Directory support for LDAP has been enabled.");
     }
 
-    return http.authorizeExchange(spec -> spec
+    var builder = http.authorizeExchange(spec -> spec
             .pathMatchers(AUTH_WHITELIST)
             .permitAll()
             .anyExchange()
             .authenticated()
         )
-        .formLogin(Customizer.withDefaults())
-        .logout(Customizer.withDefaults())
-        .csrf(ServerHttpSecurity.CsrfSpec::disable)
-        .build();
+        .formLogin(form -> form
+            .loginPage(LOGIN_URL)
+            .authenticationSuccessHandler(emptyRedirectSuccessHandler())
+        )
+        .logout(spec -> spec
+            .logoutSuccessHandler(redirectLogoutSuccessHandler())
+            .requiresLogout(ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/logout")))
+        .csrf(ServerHttpSecurity.CsrfSpec::disable);
+
+    builder.addFilterAt(new StaticFileWebFilter(), SecurityWebFiltersOrder.LOGIN_PAGE_GENERATING);
+
+    return builder.build();
   }
 
   private static class UserDetailsMapper extends LdapUserDetailsMapper {
diff --git a/api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java b/api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java
index 09c7df794..4794b83ca 100644
--- a/api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java
+++ b/api/src/main/java/io/kafbat/ui/config/auth/OAuthSecurityConfig.java
@@ -3,6 +3,7 @@
 import io.kafbat.ui.config.auth.logout.OAuthLogoutSuccessHandler;
 import io.kafbat.ui.service.rbac.AccessControlService;
 import io.kafbat.ui.service.rbac.extractor.ProviderAuthorityExtractor;
+import io.kafbat.ui.util.StaticFileWebFilter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -19,6 +20,7 @@
 import org.springframework.security.config.Customizer;
 import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
 import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
 import org.springframework.security.config.web.server.ServerHttpSecurity;
 import org.springframework.security.oauth2.client.oidc.userinfo.OidcReactiveOAuth2UserService;
 import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
@@ -50,7 +52,7 @@ public class OAuthSecurityConfig extends AbstractAuthSecurityConfig {
   public SecurityWebFilterChain configure(ServerHttpSecurity http, OAuthLogoutSuccessHandler logoutHandler) {
     log.info("Configuring OAUTH2 authentication.");
 
-    return http.authorizeExchange(spec -> spec
+    var builder = http.authorizeExchange(spec -> spec
             .pathMatchers(AUTH_WHITELIST)
             .permitAll()
             .anyExchange()
@@ -58,8 +60,12 @@ public SecurityWebFilterChain configure(ServerHttpSecurity http, OAuthLogoutSucc
         )
         .oauth2Login(Customizer.withDefaults())
         .logout(spec -> spec.logoutSuccessHandler(logoutHandler))
-        .csrf(ServerHttpSecurity.CsrfSpec::disable)
-        .build();
+        .csrf(ServerHttpSecurity.CsrfSpec::disable);
+
+
+    builder.addFilterAt(new StaticFileWebFilter(), SecurityWebFiltersOrder.LOGIN_PAGE_GENERATING);
+
+    return builder.build();
   }
 
   @Bean
diff --git a/api/src/main/java/io/kafbat/ui/controller/ApplicationConfigController.java b/api/src/main/java/io/kafbat/ui/controller/ApplicationConfigController.java
index 5d5d4ed98..e8d763545 100644
--- a/api/src/main/java/io/kafbat/ui/controller/ApplicationConfigController.java
+++ b/api/src/main/java/io/kafbat/ui/controller/ApplicationConfigController.java
@@ -6,6 +6,7 @@
 import io.kafbat.ui.api.ApplicationConfigApi;
 import io.kafbat.ui.config.ClustersProperties;
 import io.kafbat.ui.model.ActionDTO;
+import io.kafbat.ui.model.AppAuthenticationSettingsDTO;
 import io.kafbat.ui.model.ApplicationConfigDTO;
 import io.kafbat.ui.model.ApplicationConfigPropertiesDTO;
 import io.kafbat.ui.model.ApplicationConfigValidationDTO;
@@ -66,6 +67,13 @@ public Mono<ResponseEntity<ApplicationInfoDTO>> getApplicationInfo(ServerWebExch
     return Mono.just(applicationInfoService.getApplicationInfo()).map(ResponseEntity::ok);
   }
 
+  @Override
+  public Mono<ResponseEntity<AppAuthenticationSettingsDTO>> getAuthenticationSettings(
+      ServerWebExchange exchange) {
+    return Mono.just(applicationInfoService.getAuthenticationProperties())
+        .map(ResponseEntity::ok);
+  }
+
   @Override
   public Mono<ResponseEntity<ApplicationConfigDTO>> getCurrentConfig(ServerWebExchange exchange) {
     var context = AccessContext.builder()
@@ -109,7 +117,7 @@ public Mono<ResponseEntity<UploadedFileInfoDTO>> uploadConfigRelatedFile(Flux<Pa
         .then(fileFlux.single())
         .flatMap(file ->
             dynamicConfigOperations.uploadConfigRelatedFile((FilePart) file)
-                .map(path -> new UploadedFileInfoDTO().location(path.toString()))
+                .map(path -> new UploadedFileInfoDTO(path.toString()))
                 .map(ResponseEntity::ok))
         .doOnEach(sig -> audit(context, sig));
   }
diff --git a/api/src/main/java/io/kafbat/ui/controller/AuthController.java b/api/src/main/java/io/kafbat/ui/controller/AuthController.java
deleted file mode 100644
index e4532dda3..000000000
--- a/api/src/main/java/io/kafbat/ui/controller/AuthController.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package io.kafbat.ui.controller;
-
-import java.nio.charset.Charset;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.security.web.server.csrf.CsrfToken;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.server.ServerWebExchange;
-import reactor.core.publisher.Mono;
-
-@RestController
-@RequiredArgsConstructor
-@Slf4j
-public class AuthController {
-
-  @GetMapping(value = "/auth", produces = {"text/html"})
-  public Mono<byte[]> getAuth(ServerWebExchange exchange) {
-    Mono<CsrfToken> token = exchange.getAttributeOrDefault(CsrfToken.class.getName(), Mono.empty());
-    return token
-        .map(AuthController::csrfToken)
-        .defaultIfEmpty("")
-        .map(csrfTokenHtmlInput -> createPage(exchange, csrfTokenHtmlInput));
-  }
-
-  private byte[] createPage(ServerWebExchange exchange, String csrfTokenHtmlInput) {
-    MultiValueMap<String, String> queryParams = exchange.getRequest()
-        .getQueryParams();
-    String contextPath = exchange.getRequest().getPath().contextPath().value();
-    String page =
-        "<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + "  <head>\n"
-        + "    <meta charset=\"utf-8\">\n"
-        + "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, "
-        + "shrink-to-fit=no\">\n"
-        + "    <meta name=\"description\" content=\"\">\n"
-        + "    <meta name=\"author\" content=\"\">\n"
-        + "    <title>Please sign in</title>\n"
-        + "    <link href=\"" + contextPath + "/static/css/bootstrap.min.css\" rel=\"stylesheet\" "
-        + "integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" "
-        + "crossorigin=\"anonymous\">\n"
-        + "    <link href=\"" + contextPath + "/static/css/signin.css\" "
-        + "rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
-        + "  </head>\n"
-        + "  <body>\n"
-        + "     <div class=\"container\">\n"
-        + formLogin(queryParams, contextPath, csrfTokenHtmlInput)
-        + "    </div>\n"
-        + "  </body>\n"
-        + "</html>";
-
-    return page.getBytes(Charset.defaultCharset());
-  }
-
-  private String formLogin(
-      MultiValueMap<String, String> queryParams,
-      String contextPath, String csrfTokenHtmlInput) {
-
-    boolean isError = queryParams.containsKey("error");
-    boolean isLogoutSuccess = queryParams.containsKey("logout");
-    return
-        "      <form class=\"form-signin\" method=\"post\" action=\"" + contextPath + "/auth\">\n"
-        + "        <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
-        + createError(isError)
-        + createLogoutSuccess(isLogoutSuccess)
-        + "        <p>\n"
-        + "          <label for=\"username\" class=\"sr-only\">Username</label>\n"
-        + "          <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" "
-        + "placeholder=\"Username\" required autofocus>\n"
-        + "        </p>\n" + "        <p>\n"
-        + "          <label for=\"password\" class=\"sr-only\">Password</label>\n"
-        + "          <input type=\"password\" id=\"password\" name=\"password\" "
-        + "class=\"form-control\" placeholder=\"Password\" required>\n"
-        + "        </p>\n" + csrfTokenHtmlInput
-        + "        <button class=\"btn btn-lg btn-primary btn-block\" "
-        + "type=\"submit\">Sign in</button>\n"
-        + "      </form>\n";
-  }
-
-  private static String csrfToken(CsrfToken token) {
-    return "          <input type=\"hidden\" name=\""
-        + token.getParameterName()
-        + "\" value=\""
-        + token.getToken()
-        + "\">\n";
-  }
-
-  private static String createError(boolean isError) {
-    return isError
-        ? "<div class=\"alert alert-danger\" role=\"alert\">Invalid credentials</div>"
-        : "";
-  }
-
-  private static String createLogoutSuccess(boolean isLogoutSuccess) {
-    return isLogoutSuccess
-        ? "<div class=\"alert alert-success\" role=\"alert\">You have been signed out</div>"
-        : "";
-  }
-}
diff --git a/api/src/main/java/io/kafbat/ui/controller/AuthenticationController.java b/api/src/main/java/io/kafbat/ui/controller/AuthenticationController.java
new file mode 100644
index 000000000..c94c344c9
--- /dev/null
+++ b/api/src/main/java/io/kafbat/ui/controller/AuthenticationController.java
@@ -0,0 +1,22 @@
+package io.kafbat.ui.controller;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import reactor.core.publisher.Mono;
+
+@RestController
+@RequiredArgsConstructor
+@Slf4j
+public class AuthenticationController {
+
+  private static final String INDEX_HTML = "/static/index.html";
+
+  @GetMapping(value = "/login", produces = {"text/html"})
+  public Mono<ClassPathResource> getLoginPage() {
+    return Mono.just(new ClassPathResource(INDEX_HTML));
+  }
+
+}
diff --git a/api/src/main/java/io/kafbat/ui/controller/AccessController.java b/api/src/main/java/io/kafbat/ui/controller/AuthorizationController.java
similarity index 97%
rename from api/src/main/java/io/kafbat/ui/controller/AccessController.java
rename to api/src/main/java/io/kafbat/ui/controller/AuthorizationController.java
index e5b1ea438..1ac0aeb85 100644
--- a/api/src/main/java/io/kafbat/ui/controller/AccessController.java
+++ b/api/src/main/java/io/kafbat/ui/controller/AuthorizationController.java
@@ -26,7 +26,7 @@
 @RestController
 @RequiredArgsConstructor
 @Slf4j
-public class AccessController implements AuthorizationApi {
+public class AuthorizationController implements AuthorizationApi {
 
   private final AccessControlService accessControlService;
 
diff --git a/api/src/main/java/io/kafbat/ui/service/ApplicationInfoService.java b/api/src/main/java/io/kafbat/ui/service/ApplicationInfoService.java
index 7d380036c..7ee28b62d 100644
--- a/api/src/main/java/io/kafbat/ui/service/ApplicationInfoService.java
+++ b/api/src/main/java/io/kafbat/ui/service/ApplicationInfoService.java
@@ -1,16 +1,23 @@
 package io.kafbat.ui.service;
 
+import static io.kafbat.ui.api.model.AuthType.DISABLED;
+import static io.kafbat.ui.api.model.AuthType.OAUTH2;
 import static io.kafbat.ui.model.ApplicationInfoDTO.EnabledFeaturesEnum;
 import static io.kafbat.ui.util.GithubReleaseInfo.GITHUB_RELEASE_INFO_TIMEOUT;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Streams;
+import io.kafbat.ui.model.AppAuthenticationSettingsDTO;
 import io.kafbat.ui.model.ApplicationInfoBuildDTO;
 import io.kafbat.ui.model.ApplicationInfoDTO;
 import io.kafbat.ui.model.ApplicationInfoLatestReleaseDTO;
+import io.kafbat.ui.model.AuthTypeDTO;
+import io.kafbat.ui.model.OAuthProviderDTO;
 import io.kafbat.ui.util.DynamicConfigOperations;
 import io.kafbat.ui.util.GithubReleaseInfo;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
 import java.util.Properties;
@@ -18,20 +25,27 @@
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.info.BuildProperties;
 import org.springframework.boot.info.GitProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.ResolvableType;
 import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.security.oauth2.client.registration.ClientRegistration;
+import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.stereotype.Service;
 
 @Service
 public class ApplicationInfoService {
   private final GithubReleaseInfo githubReleaseInfo;
+  private final ApplicationContext applicationContext;
   private final DynamicConfigOperations dynamicConfigOperations;
   private final BuildProperties buildProperties;
   private final GitProperties gitProperties;
 
   public ApplicationInfoService(DynamicConfigOperations dynamicConfigOperations,
+                                ApplicationContext applicationContext,
                                 @Autowired(required = false) BuildProperties buildProperties,
                                 @Autowired(required = false) GitProperties gitProperties,
                                 @Value("${" + GITHUB_RELEASE_INFO_TIMEOUT + ":10}") int githubApiMaxWaitTime) {
+    this.applicationContext = applicationContext;
     this.dynamicConfigOperations = dynamicConfigOperations;
     this.buildProperties = Optional.ofNullable(buildProperties).orElse(new BuildProperties(new Properties()));
     this.gitProperties = Optional.ofNullable(gitProperties).orElse(new GitProperties(new Properties()));
@@ -70,6 +84,38 @@ private List<EnabledFeaturesEnum> getEnabledFeatures() {
     return enabledFeatures;
   }
 
+  public AppAuthenticationSettingsDTO getAuthenticationProperties() {
+    return new AppAuthenticationSettingsDTO()
+        .authType(AuthTypeDTO.fromValue(getAuthType()))
+        .oAuthProviders(getOAuthProviders());
+  }
+
+  private String getAuthType() {
+    return Optional.ofNullable(applicationContext.getEnvironment().getProperty("auth.type"))
+        .orElse(DISABLED.getValue());
+  }
+
+  @SuppressWarnings("unchecked")
+  private List<OAuthProviderDTO> getOAuthProviders() {
+    if (!getAuthType().equalsIgnoreCase(OAUTH2.getValue())) {
+      return Collections.emptyList();
+    }
+    var type = ResolvableType.forClassWithGenerics(Iterable.class, ClientRegistration.class);
+    String[] names = this.applicationContext.getBeanNamesForType(type);
+    var bean = (Iterable<ClientRegistration>) (names.length == 1 ? this.applicationContext.getBean(names[0]) : null);
+
+    if (bean == null) {
+      return Collections.emptyList();
+    }
+
+    return Streams.stream(bean.iterator())
+        .filter(r -> AuthorizationGrantType.AUTHORIZATION_CODE.equals(r.getAuthorizationGrantType()))
+        .map(r -> new OAuthProviderDTO()
+            .clientName(r.getClientName())
+            .authorizationUri("/oauth2/authorization/" + r.getRegistrationId()))
+        .toList();
+  }
+
   // updating on startup and every hour
   @Scheduled(fixedRateString = "${github-release-info-update-rate:3600000}")
   public void updateGithubReleaseInfo() {
diff --git a/api/src/main/java/io/kafbat/ui/util/StaticFileWebFilter.java b/api/src/main/java/io/kafbat/ui/util/StaticFileWebFilter.java
new file mode 100644
index 000000000..1b74bd374
--- /dev/null
+++ b/api/src/main/java/io/kafbat/ui/util/StaticFileWebFilter.java
@@ -0,0 +1,61 @@
+package io.kafbat.ui.util;
+
+import java.io.IOException;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.buffer.DataBufferFactory;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
+import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.WebFilter;
+import org.springframework.web.server.WebFilterChain;
+import reactor.core.publisher.Mono;
+
+public class StaticFileWebFilter implements WebFilter {
+
+  private static final String INDEX_HTML = "/static/index.html";
+
+  private final ServerWebExchangeMatcher matcher;
+  private final String contents;
+
+  public StaticFileWebFilter() {
+    this("/login", new ClassPathResource(INDEX_HTML));
+  }
+
+  public StaticFileWebFilter(String path, ClassPathResource resource) {
+    this.matcher = ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, path);
+
+    try {
+      this.contents = ResourceUtil.readAsString(resource);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  @Override
+  public @NotNull Mono<Void> filter(@NotNull ServerWebExchange exchange, WebFilterChain chain) {
+    return this.matcher.matches(exchange)
+        .filter(ServerWebExchangeMatcher.MatchResult::isMatch)
+        .switchIfEmpty(chain.filter(exchange).then(Mono.empty()))
+        .flatMap((matchResult) -> this.render(exchange));
+  }
+
+  private Mono<Void> render(ServerWebExchange exchange) {
+    String contextPath = exchange.getRequest().getPath().contextPath().value();
+
+    String contentBody = contents
+        .replace("\"assets/", "\"" + contextPath + "/assets/")
+        .replace("PUBLIC-PATH-VARIABLE", contextPath);
+
+    ServerHttpResponse result = exchange.getResponse();
+    result.setStatusCode(HttpStatus.OK);
+    result.getHeaders().setContentType(MediaType.TEXT_HTML);
+    DataBufferFactory bufferFactory = exchange.getResponse().bufferFactory();
+    return result.writeWith(Mono.just(bufferFactory.wrap(contentBody.getBytes())));
+  }
+
+}
diff --git a/contract/src/main/resources/swagger/kafbat-ui-api.yaml b/contract/src/main/resources/swagger/kafbat-ui-api.yaml
index 04cc17514..dff80b4ce 100644
--- a/contract/src/main/resources/swagger/kafbat-ui-api.yaml
+++ b/contract/src/main/resources/swagger/kafbat-ui-api.yaml
@@ -31,7 +31,6 @@ paths:
                 items:
                   $ref: '#/components/schemas/Cluster'
 
-
   /api/clusters/{clusterName}/cache:
     post:
       tags:
@@ -54,7 +53,6 @@ paths:
         404:
           description: Not found
 
-
   /api/clusters/{clusterName}/brokers:
     get:
       tags:
@@ -432,7 +430,6 @@ paths:
         404:
           description: Not found
 
-
   /api/clusters/{clusterName}/topics/{topicName}:
     get:
       tags:
@@ -2150,7 +2147,7 @@ paths:
     get:
       tags:
         - Authorization
-      summary: Get user authentication related info
+      summary: Get user authorization related info
       operationId: getUserAuthInfo
       responses:
         200:
@@ -2220,7 +2217,6 @@ paths:
               schema:
                 $ref: '#/components/schemas/ApplicationConfigValidation'
 
-
   /api/config/relatedfiles:
     post:
       tags:
@@ -2244,6 +2240,40 @@ paths:
               schema:
                 $ref: '#/components/schemas/UploadedFileInfo'
 
+  /api/config/authentication:
+    get:
+      tags:
+        - ApplicationConfig
+      summary: Get authentication methods enabled for the app and other related settings
+      operationId: getAuthenticationSettings
+      responses:
+        200:
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/AppAuthenticationSettings'
+
+  /login:
+    post:
+      summary: Authenticate
+      requestBody:
+        required: true
+        content:
+          application/x-www-form-urlencoded:
+            schema:
+              type: object
+              properties:
+                username:
+                  type: string
+                password:
+                  type: string
+      responses:
+        '200':
+          description: OK
+        '401':
+          description: Unauthorized
+
 components:
   schemas:
     TopicSerdeSuggestion:
@@ -2354,6 +2384,32 @@ components:
             htmlUrl:
               type: string
 
+    AppAuthenticationSettings:
+      type: object
+      properties:
+        authType:
+          $ref: '#/components/schemas/AuthType'
+        oAuthProviders:
+          type: array
+          items:
+            $ref: '#/components/schemas/OAuthProvider'
+
+    OAuthProvider:
+      type: object
+      properties:
+        clientName:
+          type: string
+        authorizationUri:
+          type: string
+
+    AuthType:
+      type: string
+      enum:
+        - DISABLED
+        - OAUTH2
+        - LOGIN_FORM
+        - LDAP
+
     Cluster:
       type: object
       properties: