You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2021/10/01 06:54:34 UTC

[incubator-streampipes] branch STREAMPIPES-426 created (now 2013f49)

This is an automated email from the ASF dual-hosted git repository.

riemer pushed a change to branch STREAMPIPES-426
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git.


      at 2013f49  Merge branch 'dev' into STREAMPIPES-426

This branch includes the following new commits:

     new c7c2656  [STREAMPIPES-426] Use JWT for auth token exchange
     new 2013f49  Merge branch 'dev' into STREAMPIPES-426

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[incubator-streampipes] 02/02: Merge branch 'dev' into STREAMPIPES-426

Posted by ri...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch STREAMPIPES-426
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git

commit 2013f499b376295a9cb28221467b7c606efa93ed
Merge: c7c2656 6d99501
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Fri Oct 1 08:54:13 2021 +0200

    Merge branch 'dev' into STREAMPIPES-426

 .../apache/streampipes/connect/SendToPipeline.java |  38 ---
 .../template/PipelineTemplateDescription.java      |   2 +
 .../model/template/PipelineTemplateInvocation.java |   5 +-
 .../template/PipelineTemplateGenerator.java        |   8 +-
 .../streampipes/rest/impl/PipelineTemplate.java    |   2 +-
 .../support/builder/SpecificAdapterBuilder.ts      |  77 ++---
 ui/cypress/support/general/resetStreamPipes.ts     |   4 +-
 ui/cypress/support/model/AdapterInput.ts           |   7 +-
 ui/cypress/support/utils/AdapterUtils.ts           |  30 +-
 ui/cypress/support/utils/DataLakeUtils.ts          |   3 +-
 ui/cypress/support/utils/PipelineUtils.ts          |   6 +
 .../tests/adapter/persistInDataLake.ts}            |  36 ++-
 .../datalake-configuration.component.ts            |   6 +-
 .../new-adapter/new-adapter.component.html         |   9 +-
 .../new-adapter/new-adapter.component.ts           | 342 +++++++++------------
 .../start-adapter-configuration.component.html     |  43 +--
 .../start-adapter-configuration.component.ts       |  29 +-
 ui/src/app/connect/connect.module.ts               |   1 +
 .../adapter-started-dialog.component.html          |  75 +++--
 .../adapter-started-dialog.component.ts            |  57 ++--
 ui/src/app/connect/filter/timestamp.pipe.ts        |  26 +-
 ui/src/app/connect/services/connect.service.ts     |  34 +-
 ui/src/app/core-model/gen/streampipes-model.ts     |  69 ++++-
 .../template/PipelineInvocationBuilder.ts          |  68 ++++
 ui/src/app/core-ui/core-ui.module.ts               |   7 +-
 .../pipeline-started-status.component.html         |  68 ++++
 .../pipeline-started-status.component.scss}        |   9 +-
 .../pipeline-started-status.component.ts           |  56 ++++
 .../runtime-resolvable.service.ts                  |  17 +-
 .../delete-pipeline-dialog.component.ts            |  20 +-
 .../import-pipeline-dialog.component.ts            |  65 ++--
 .../pipeline-categories-dialog.component.ts        |  45 ++-
 .../pipeline-notifications.component.ts            |  16 +-
 .../pipeline-status-dialog.component.html          |  58 +---
 .../pipeline-status-dialog.component.ts            | 145 +++++----
 .../start-all-pipelines-dialog.component.ts        | 239 +++++++-------
 ui/src/app/pipelines/pipelines.module.ts           |  48 +--
 .../apis/pipeline-template.service.ts              | 199 ++++++------
 .../apis/semantic-types.service.ts                 |  17 +-
 ui/src/app/platform-services/platform.module.ts    |   5 +-
 40 files changed, 1114 insertions(+), 877 deletions(-)

diff --cc ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/runtime-resolvable.service.ts
index bec052d,9f20e94..7f0e52b
--- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/runtime-resolvable.service.ts
+++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/runtime-resolvable.service.ts
@@@ -17,12 -17,10 +17,9 @@@
   */
  
  import { Observable } from 'rxjs';
- import {
-   RuntimeOptionsRequest,
-   RuntimeOptionsResponse
- } from '../../../core-model/gen/streampipes-model';
+ import { RuntimeOptionsRequest, RuntimeOptionsResponse } from '../../../core-model/gen/streampipes-model';
  import { map } from 'rxjs/operators';
  import { HttpClient } from '@angular/common/http';
 -import { AuthStatusService } from '../../../services/auth-status.service';
  import { PlatformServicesCommons } from '../../../platform-services/apis/commons.service';
  import { Injectable } from '@angular/core';
  
diff --cc ui/src/app/platform-services/apis/semantic-types.service.ts
index 3373ec4,b8c0b5f..42071c8
--- a/ui/src/app/platform-services/apis/semantic-types.service.ts
+++ b/ui/src/app/platform-services/apis/semantic-types.service.ts
@@@ -30,9 -30,10 +30,10 @@@ export class SemanticTypesService 
  
    }
  
-   getSemanticTypes(text: string): Observable<Array<string>> {
-     return this.http.get(this.platformServicesCommons.apiBasePath + "/autocomplete/semantic-type?text=" + text).pipe(map(response => {
-       return response as Array<string>;
+   getSemanticTypes(text: string): Observable<string[]> {
 -    return this.http.get(this.platformServicesCommons.unauthenticatedBasePath +
 -      '/autocomplete/semantic-type?text=' + text).pipe(map(response => {
++    return this.http.get(this.platformServicesCommons.apiBasePath +
++        '/autocomplete/semantic-type?text=' + text).pipe(map(response => {
+       return response as string[];
      }));
    }
  

[incubator-streampipes] 01/02: [STREAMPIPES-426] Use JWT for auth token exchange

Posted by ri...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch STREAMPIPES-426
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git

commit c7c26567bed93f2f1b542898420f67416ee361c2
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Fri Oct 1 08:43:47 2021 +0200

    [STREAMPIPES-426] Use JWT for auth token exchange
---
 pom.xml                                            |  30 ++-
 .../backend/StreamPipesBackendApplication.java     |  21 +-
 .../backend/StreamPipesResourceConfig.java         |   4 +-
 .../backend/UnauthenticatedInterfaces.java         |  25 ++-
 .../backend/UnauthorizedRequestEntryPoint.java     |  22 +++
 .../streampipes/backend/WebSecurityConfig.java     |  80 ++++++++
 .../apache/streampipes/commons/constants/Envs.java |   3 +-
 .../streampipes/commons/random/TokenGenerator.java |  23 ++-
 .../streampipes/config/backend/BackendConfig.java  |  29 +--
 .../config/backend/BackendConfigKeys.java          |   1 +
 .../config/backend/model/LocalAuthConfig.java      |  61 ++++++
 .../client/user/JwtAuthenticationResponse.java     |  34 ++++
 .../apache/streampipes/model/client/user/User.java |  32 +--
 .../streampipes/model/client/user/UserInfo.java    |  85 ++++++++
 .../rest/core/base/impl/AbstractRestResource.java  |  26 +--
 .../rest/authentication/StreamPipesFilter.java     | 110 +++++------
 .../rest/filter/TokenAuthenticationFilter.java     |  67 +++++++
 .../streampipes/rest/impl/Authentication.java      |  92 ++++-----
 .../rest/impl/SemanticEventConsumer.java           |   7 -
 .../rest/impl/SemanticEventProcessingAgent.java    |   7 -
 .../rest/impl/SemanticEventProducer.java           |   7 -
 .../rest/impl/{User.java => UserProfile.java}      |  25 +--
 .../interceptor/AuthenticationInterceptor.java     |   3 +-
 .../streampipes/storage/api/IPipelineStorage.java  |   2 -
 streampipes-storage-couchdb/pom.xml                |   4 -
 .../storage/couchdb/impl/PipelineStorageImpl.java  |  20 +-
 streampipes-user-management/pom.xml                |  16 +-
 .../StreamPipesCredentialsMatcher.java             |  44 +++--
 .../authentication/StreamPipesRealm.java           | 218 ++++++++++-----------
 .../user/management/jwt/JwtTokenProvider.java      |  80 ++++++++
 .../user/management/model/LocalUser.java           |  82 ++++++++
 ...{UserService.java => SpUserDetailsService.java} |  33 ++--
 .../user/management/service/TokenService.java      |   6 +-
 .../user/management/service/UserService.java       |   7 +-
 ui/deployment/app-routing.module.mst               |   4 +-
 ui/deployment/appng5.module.mst                    |   6 +-
 ui/package.json                                    |   1 +
 .../already-configured.can-activate.guard.ts       |  18 +-
 .../_guards/auth.can-activate-children.guard.ts    |  44 ++---
 .../_guards/base-configured.can-activate.guard.ts  |  18 +-
 .../app/_guards/configured.can-activate.guard.ts   |  18 +-
 ui/src/app/_guards/logged-in.can-activate.guard.ts |  58 ------
 ui/src/app/add/services/add.service.ts             |  12 +-
 .../app-asset-monitoring/services/rest.service.ts  |   4 +-
 ui/src/app/app-routing.module.ts                   |   4 +-
 .../app-transport-monitoring-rest.service.ts       |  25 ++-
 .../connect/services/data-marketplace.service.ts   |   7 +-
 ui/src/app/connect/services/rest.service.ts        |  12 +-
 .../app/core-model/gen/streampipes-model-client.ts |  26 ++-
 .../datalake/datalake-rest.service.ts              |   4 +-
 .../shared/shared-dashboard.service.ts             |   8 +-
 ui/src/app/core-ui/core-ui.module.ts               |   2 -
 .../app/core-ui/labels/services/label.service.ts   |   2 +-
 .../static-file-input.component.ts                 |   4 +-
 .../static-file-input/static-file-rest.service.ts  |  88 ---------
 .../runtime-resolvable.service.ts                  |   7 +-
 .../core/components/iconbar/iconbar.component.html |   4 +-
 .../core/components/iconbar/iconbar.component.ts   |  44 ++---
 .../streampipes/streampipes.component.html         |   2 +-
 .../streampipes/streampipes.component.ts           |   9 +-
 .../core/components/toolbar/toolbar.component.ts   |  91 ++++-----
 ui/src/app/dashboard/services/dashboard.service.ts |   4 +-
 .../dialog/welcome-tour/welcome-tour.component.ts  |  12 +-
 ui/src/app/editor/editor.component.ts              | 113 +++++------
 ui/src/app/editor/services/editor.service.ts       |  22 +--
 .../app/editor/services/object-provider.service.ts |  17 +-
 ...rement-units.service.ts => http-interceptor.ts} |  31 ++-
 .../app/login/components/login/login.component.ts  |  45 ++---
 .../login/components/startup/startup.component.ts  |  24 ++-
 ui/src/app/login/login.module.ts                   |  43 ++--
 ui/src/app/login/services/login.service.ts         |  20 +-
 .../app/notifications/notifications.component.ts   |   8 +-
 .../notifications/service/notifications.service.ts |  10 +-
 .../app/platform-services/apis/commons.service.ts  |  13 +-
 .../apis/data-view-data-explorer.service.ts        |   2 -
 .../apis/datalake-rest.service.ts                  |   4 +-
 ui/src/app/platform-services/apis/files.service.ts |   6 +-
 .../apis/measurement-units.service.ts              |   2 +-
 .../apis/pipeline-canvas-metadata.service.ts       |   2 +-
 .../apis/pipeline-element-endpoint.service.ts      |  16 +-
 .../apis/pipeline-element-template.service.ts      |   8 +-
 .../apis/pipeline-element.service.ts               |   8 +-
 .../apis/pipeline-monitoring.service.ts            |  16 +-
 .../app/platform-services/apis/pipeline.service.ts |   2 +-
 .../apis/semantic-types.service.ts                 |  12 +-
 .../profile/components/basic-profile-settings.ts   |  16 +-
 .../general/general-profile-settings.component.ts  |  36 ++--
 ui/src/app/profile/profile.service.ts              |  32 +--
 ui/src/app/services/auth.service.ts                | 102 +++++++---
 .../jwt-token-storage.service.ts}                  |  35 ++--
 ui/src/app/services/pipeline-icon.service.ts       |  80 --------
 ui/src/app/services/rest-api.service.ts            | 138 +------------
 .../route-transition-interceptor.service.ts        |  79 --------
 ui/src/app/services/services.module.ts             |  20 +-
 94 files changed, 1455 insertions(+), 1351 deletions(-)

diff --git a/pom.xml b/pom.xml
index f571c6e..43a8c62 100644
--- a/pom.xml
+++ b/pom.xml
@@ -76,6 +76,7 @@
         <jersey.version>2.33</jersey.version>
         <jetty.version>9.4.19.v20190610</jetty.version>
         <jgrapht.version>1.3.1</jgrapht.version>
+        <jjwt.version>0.11.2</jjwt.version>
         <json-path.version>3.1.0</json-path.version>
         <jsr305.version>3.0.2</jsr305.version>
         <kafka.version>2.7.0</kafka.version>
@@ -99,8 +100,8 @@
         <snakeyaml.version>1.26</snakeyaml.version>
         <snappy-java.version>1.1.7.7</snappy-java.version>
         <spark.version>2.1.2</spark.version>
-        <spring.version>5.3.2</spring.version>
-        <spring-boot.version>2.4.1</spring-boot.version>
+        <spring.version>5.3.10</spring.version>
+        <spring-boot.version>2.5.5</spring-boot.version>
         <swagger.version>2.1.6</swagger.version>
         <type-parser.version>0.6.0</type-parser.version>
         <underscore.version>1.47</underscore.version>
@@ -282,6 +283,21 @@
                 <version>${json-path.version}</version>
             </dependency>
             <dependency>
+                <groupId>io.jsonwebtoken</groupId>
+                <artifactId>jjwt-api</artifactId>
+                <version>${jjwt.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.jsonwebtoken</groupId>
+                <artifactId>jjwt-impl</artifactId>
+                <version>${jjwt.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.jsonwebtoken</groupId>
+                <artifactId>jjwt-jackson</artifactId>
+                <version>${jjwt.version}</version>
+            </dependency>
+            <dependency>
                 <groupId>io.swagger.core.v3</groupId>
                 <artifactId>swagger-annotations</artifactId>
                 <version>${swagger.version}</version>
@@ -663,6 +679,11 @@
             </dependency>
             <dependency>
                 <groupId>org.springframework</groupId>
+                <artifactId>spring-expression</artifactId>
+                <version>${spring.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework</groupId>
                 <artifactId>spring-web</artifactId>
                 <version>${spring.version}</version>
             </dependency>
@@ -678,6 +699,11 @@
             </dependency>
             <dependency>
                 <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-oauth2-client</artifactId>
+                <version>${spring-boot.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-undertow</artifactId>
                 <version>${spring-boot.version}</version>
             </dependency>
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesBackendApplication.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesBackendApplication.java
index 6b3bb4d..3ece3e7 100644
--- a/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesBackendApplication.java
+++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesBackendApplication.java
@@ -17,9 +17,6 @@
  */
 package org.apache.streampipes.backend;
 
-import org.apache.shiro.web.env.EnvironmentLoaderListener;
-import org.apache.shiro.web.servlet.OncePerRequestFilter;
-import org.apache.shiro.web.servlet.ShiroFilter;
 import org.apache.streampipes.container.base.BaseNetworkingConfig;
 import org.apache.streampipes.container.base.StreamPipesServiceBase;
 import org.apache.streampipes.manager.health.PipelineHealthCheck;
@@ -35,7 +32,6 @@ import org.apache.streampipes.svcdiscovery.api.model.SpServiceTag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -56,7 +52,7 @@ import java.util.stream.Collectors;
 
 @Configuration
 @EnableAutoConfiguration
-@Import({StreamPipesResourceConfig.class, WelcomePageController.class})
+@Import({StreamPipesResourceConfig.class, WelcomePageController.class, WebSecurityConfig.class})
 public class StreamPipesBackendApplication extends StreamPipesServiceBase {
 
   private static final Logger LOG = LoggerFactory.getLogger(StreamPipesBackendApplication.class.getCanonicalName());
@@ -218,19 +214,6 @@ public class StreamPipesBackendApplication extends StreamPipesServiceBase {
   }
 
   @Bean
-  public FilterRegistrationBean shiroFilterBean() {
-    FilterRegistrationBean<OncePerRequestFilter> bean = new FilterRegistrationBean<>();
-    bean.setFilter(new ShiroFilter());
-    bean.addUrlPatterns("/api/*");
-    return bean;
-  }
-
-  @Bean
-  public ServletListenerRegistrationBean shiroListenerBean() {
-    return listener(new EnvironmentLoaderListener());
-  }
-
-  @Bean
   public ServletListenerRegistrationBean streamPipesNotificationListenerBean() {
     return listener(new NotificationListener());
   }
@@ -253,6 +236,6 @@ public class StreamPipesBackendApplication extends StreamPipesServiceBase {
 
   @Override
   protected String getHealthCheckPath() {
-    return "/streampipes-backend";
+    return "/streampipes-backend/";
   }
 }
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesResourceConfig.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesResourceConfig.java
index dde7dcd..14d92a1 100644
--- a/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesResourceConfig.java
+++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesResourceConfig.java
@@ -43,12 +43,14 @@ import org.glassfish.jersey.server.ResourceConfig;
 import org.springframework.context.annotation.Configuration;
 
 import javax.ws.rs.ApplicationPath;
+import java.util.Collections;
 
 @Configuration
 @ApplicationPath("/api")
 public class StreamPipesResourceConfig extends ResourceConfig {
 
     public StreamPipesResourceConfig() {
+        setProperties(Collections.singletonMap("jersey.config.server.response.setStatusOverSendError", true));
         register(Authentication.class);
         register(AssetDashboard.class);
         register(AutoComplete.class);
@@ -90,7 +92,7 @@ public class StreamPipesResourceConfig extends ResourceConfig {
         register(SemanticEventProducer.class);
         register(Setup.class);
         register(ResetResource.class);
-        register(User.class);
+        register(UserProfile.class);
         register(Version.class);
         register(PipelineElementAsset.class);
         register(DataLakeDashboardResource.class);
diff --git a/ui/src/app/services/init-tooltips.service.ts b/streampipes-backend/src/main/java/org/apache/streampipes/backend/UnauthenticatedInterfaces.java
similarity index 61%
rename from ui/src/app/services/init-tooltips.service.ts
rename to streampipes-backend/src/main/java/org/apache/streampipes/backend/UnauthenticatedInterfaces.java
index 89c13ed..68dba7a 100644
--- a/ui/src/app/services/init-tooltips.service.ts
+++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/UnauthenticatedInterfaces.java
@@ -15,15 +15,24 @@
  * limitations under the License.
  *
  */
+package org.apache.streampipes.backend;
 
-import * as $ from "jquery";
+import java.util.Arrays;
+import java.util.Collection;
 
-export class InitTooltips {
-    constructor() {}
+public class UnauthenticatedInterfaces {
 
-    initTooltips() {
-        return function () {
-            (<any>$('.tt')).tooltip();
-        }
-    };
+  public static Collection<String> get() {
+    return Arrays.asList(
+            "/api/v2/setup/configured",
+            "/api/v2/auth/login",
+            "/api/auth/**",
+            "/oauth2/**",
+            "/api/all",
+            "/error",
+            "/",
+            "/streampipes-backend/",
+            "/streampipes-backend/index.html"
+            );
+  }
 }
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/UnauthorizedRequestEntryPoint.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/UnauthorizedRequestEntryPoint.java
new file mode 100644
index 0000000..6ff424b
--- /dev/null
+++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/UnauthorizedRequestEntryPoint.java
@@ -0,0 +1,22 @@
+package org.apache.streampipes.backend;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public class UnauthorizedRequestEntryPoint implements AuthenticationEntryPoint {
+
+	private static final Logger LOG = LoggerFactory.getLogger(UnauthorizedRequestEntryPoint.class);
+
+	@Override
+	public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException {
+		LOG.error("Unauthorized request - {}", e.getMessage());
+
+		httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getLocalizedMessage());
+	}
+}
diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/WebSecurityConfig.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/WebSecurityConfig.java
new file mode 100644
index 0000000..e3dde9e
--- /dev/null
+++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/WebSecurityConfig.java
@@ -0,0 +1,80 @@
+package org.apache.streampipes.backend;
+
+import org.apache.streampipes.rest.filter.TokenAuthenticationFilter;
+import org.apache.streampipes.user.management.authentication.StreamPipesCredentialsMatcher;
+import org.apache.streampipes.user.management.service.SpUserDetailsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.BeanIds;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+
+  private final UserDetailsService userDetailsService;
+
+  public WebSecurityConfig() {
+    this.userDetailsService = new SpUserDetailsService();
+  }
+
+  @Autowired
+  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
+  }
+
+  @Override
+  protected void configure(HttpSecurity http) throws Exception {
+
+    http
+            .cors()
+            .and()
+            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+            .and()
+            .csrf().disable()
+            .formLogin().disable()
+            .httpBasic().disable()
+            .exceptionHandling()
+            .authenticationEntryPoint(new UnauthorizedRequestEntryPoint())
+            .and()
+            .authorizeRequests()
+            .antMatchers(UnauthenticatedInterfaces.get().toArray(new String[0])).permitAll()
+            .anyRequest()
+            .authenticated().and()
+    //.and()
+    //.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
+.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
+  }
+
+  public TokenAuthenticationFilter tokenAuthenticationFilter() {
+    return new TokenAuthenticationFilter();
+  }
+
+  @Override
+  public UserDetailsService userDetailsService() {
+    return userDetailsService;
+  }
+
+  @Bean
+  public PasswordEncoder passwordEncoder() {
+    return new StreamPipesCredentialsMatcher();
+  }
+
+  @Bean(BeanIds.AUTHENTICATION_MANAGER)
+  @Override
+  public AuthenticationManager authenticationManagerBean() throws Exception {
+    return super.authenticationManagerBean();
+  }
+
+}
diff --git a/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/Envs.java b/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/Envs.java
index c37c12b..edae3de 100644
--- a/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/Envs.java
+++ b/streampipes-commons/src/main/java/org/apache/streampipes/commons/constants/Envs.java
@@ -22,7 +22,8 @@ public enum Envs {
   SP_HOST("SP_HOST"),
   SP_PORT("SP_PORT"),
   SP_CONSUL_LOCATION("CONSUL_LOCATION"),
-  SP_KAFKA_RETENTION_MS("SP_KAFKA_RETENTION_MS");
+  SP_KAFKA_RETENTION_MS("SP_KAFKA_RETENTION_MS"),
+  SP_JWT_SECRET("JWT_SECRET");
 
   private final String envVariableName;
 
diff --git a/ui/src/app/services/auth-status.service.ts b/streampipes-commons/src/main/java/org/apache/streampipes/commons/random/TokenGenerator.java
similarity index 63%
rename from ui/src/app/services/auth-status.service.ts
rename to streampipes-commons/src/main/java/org/apache/streampipes/commons/random/TokenGenerator.java
index 760d39e..101db08 100644
--- a/ui/src/app/services/auth-status.service.ts
+++ b/streampipes-commons/src/main/java/org/apache/streampipes/commons/random/TokenGenerator.java
@@ -15,21 +15,20 @@
  * limitations under the License.
  *
  */
+package org.apache.streampipes.commons.random;
 
-import {Injectable} from '@angular/core';
+import java.security.SecureRandom;
+import java.util.Base64;
 
-@Injectable()
-export class AuthStatusService {
+public class TokenGenerator {
 
-    user: any;
-    email: string;
-    username: string;
-    token: string;
-    authenticated: boolean = false;
-    configured: boolean = false;
-    darkMode: boolean = false;
+  private static final SecureRandom secureRandom = new SecureRandom();
+  private static final Base64.Encoder base64Encoder = Base64.getUrlEncoder();
 
-    constructor() {
-    }
+  public static String generateNewToken() {
+    byte[] randomBytes = new byte[24];
+    secureRandom.nextBytes(randomBytes);
+    return base64Encoder.encodeToString(randomBytes);
+  }
 
 }
diff --git a/streampipes-config/src/main/java/org/apache/streampipes/config/backend/BackendConfig.java b/streampipes-config/src/main/java/org/apache/streampipes/config/backend/BackendConfig.java
index a1e8db6..bb0f678 100644
--- a/streampipes-config/src/main/java/org/apache/streampipes/config/backend/BackendConfig.java
+++ b/streampipes-config/src/main/java/org/apache/streampipes/config/backend/BackendConfig.java
@@ -20,6 +20,9 @@ package org.apache.streampipes.config.backend;
 
 
 import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.streampipes.commons.constants.Envs;
+import org.apache.streampipes.commons.random.TokenGenerator;
+import org.apache.streampipes.config.backend.model.LocalAuthConfig;
 import org.apache.streampipes.svcdiscovery.SpServiceDiscovery;
 import org.apache.streampipes.svcdiscovery.api.SpConfig;
 
@@ -67,6 +70,7 @@ public enum BackendConfig {
             "Default Messaging Settings");
 
     config.register(BackendConfigKeys.ENCRYPTION_KEY, randomKey(), "A random secret key");
+    config.registerObject(BackendConfigKeys.LOCAL_AUTH_CONFIG, LocalAuthConfig.fromDefaults(getJwtSecret()), "Local authentication settings");
   }
 
   private String makeAssetLocation() {
@@ -156,14 +160,6 @@ public enum BackendConfig {
     config.setString(BackendConfigKeys.KAFKA_HOST, s);
   }
 
-  public void setZookeeperHost(String s) {
-    config.setString(BackendConfigKeys.ZOOKEEPER_HOST, s);
-  }
-
-  public void setJmsHost(String s) {
-    config.setString(BackendConfigKeys.JMS_HOST, s);
-  }
-
   public void setMessagingSettings(MessagingSettings settings) {
     config.setObject(BackendConfigKeys.MESSAGING_SETTINGS, settings);
   }
@@ -184,10 +180,6 @@ public enum BackendConfig {
     return config.getString(BackendConfigKeys.ELASTICSEARCH_PROTOCOL);
   }
 
-  public String getElasticsearchURL() {
-    return getElasticsearchProtocol()+ "://" + getElasticsearchHost() + ":" + getElasticsearchPort();
-  }
-
   public String getKafkaRestHost() {
     return config.getString(BackendConfigKeys.KAFKA_REST_HOST);
   }
@@ -240,7 +232,20 @@ public enum BackendConfig {
     return config.getString(BackendConfigKeys.ENCRYPTION_KEY);
   }
 
+  public LocalAuthConfig getLocalAuthConfig() {
+    return config.getObject(BackendConfigKeys.LOCAL_AUTH_CONFIG, LocalAuthConfig.class, LocalAuthConfig.fromDefaults(getJwtSecret()));
+  }
 
+  private String getJwtSecret() {
+    if (Envs.SP_JWT_SECRET.exists()) {
+      return Envs.SP_JWT_SECRET.getValue();
+    } else {
+      return makeDefaultJwtSecret();
+    }
+  }
 
+  private String makeDefaultJwtSecret() {
+    return TokenGenerator.generateNewToken();
+  }
 
 }
diff --git a/streampipes-config/src/main/java/org/apache/streampipes/config/backend/BackendConfigKeys.java b/streampipes-config/src/main/java/org/apache/streampipes/config/backend/BackendConfigKeys.java
index 257427a..0aec6c8 100644
--- a/streampipes-config/src/main/java/org/apache/streampipes/config/backend/BackendConfigKeys.java
+++ b/streampipes-config/src/main/java/org/apache/streampipes/config/backend/BackendConfigKeys.java
@@ -45,6 +45,7 @@ public class BackendConfigKeys {
   public static final String INFLUX_DATA_BASE = "SP_INFLUX_DATA_BASE";
   public static final String MESSAGING_SETTINGS = "SP_MESSAGING_SETTINGS";
 
+  public static final String LOCAL_AUTH_CONFIG = "SP_LOCAL_AUTH_CONFIG";
   public static final String ENCRYPTION_KEY = "SP_ENCRYPTION_KEY";
 
 
diff --git a/streampipes-config/src/main/java/org/apache/streampipes/config/backend/model/LocalAuthConfig.java b/streampipes-config/src/main/java/org/apache/streampipes/config/backend/model/LocalAuthConfig.java
new file mode 100644
index 0000000..0325233
--- /dev/null
+++ b/streampipes-config/src/main/java/org/apache/streampipes/config/backend/model/LocalAuthConfig.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.streampipes.config.backend.model;
+
+public class LocalAuthConfig {
+
+  private static final long TokenExpirationTimeMillisDefault = 900000;
+
+  private String tokenSecret;
+  private long tokenExpirationTimeMillis;
+
+  public static LocalAuthConfig fromDefaults(String jwtSecret) {
+    return new LocalAuthConfig(jwtSecret, TokenExpirationTimeMillisDefault);
+  }
+
+  public static LocalAuthConfig from(String tokenSecret,
+                                     long tokenExpirationTimeMillis) {
+    return new LocalAuthConfig(tokenSecret, tokenExpirationTimeMillis);
+  }
+
+  public LocalAuthConfig() {
+
+  }
+
+  private LocalAuthConfig(String tokenSecret,
+                          long tokenExpirationTimeMillis) {
+    this.tokenSecret = tokenSecret;
+    this.tokenExpirationTimeMillis = tokenExpirationTimeMillis;
+  }
+
+  public String getTokenSecret() {
+    return tokenSecret;
+  }
+
+  public long getTokenExpirationTimeMillis() {
+    return tokenExpirationTimeMillis;
+  }
+
+  public void setTokenSecret(String tokenSecret) {
+    this.tokenSecret = tokenSecret;
+  }
+
+  public void setTokenExpirationTimeMillis(long tokenExpirationTimeMillis) {
+    this.tokenExpirationTimeMillis = tokenExpirationTimeMillis;
+  }
+}
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/JwtAuthenticationResponse.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/JwtAuthenticationResponse.java
new file mode 100644
index 0000000..f3d1bce
--- /dev/null
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/JwtAuthenticationResponse.java
@@ -0,0 +1,34 @@
+package org.apache.streampipes.model.client.user;
+
+public class JwtAuthenticationResponse {
+
+	private String accessToken;
+	private UserInfo userInfo;
+
+	public static JwtAuthenticationResponse from(String accessToken,
+																							 UserInfo userInfo) {
+		return new JwtAuthenticationResponse(accessToken, userInfo);
+	}
+
+	private JwtAuthenticationResponse(String accessToken,
+																		UserInfo userInfo) {
+		this.accessToken = accessToken;
+		this.userInfo = userInfo;
+	}
+
+	public String getAccessToken() {
+		return accessToken;
+	}
+
+	public void setAccessToken(String accessToken) {
+		this.accessToken = accessToken;
+	}
+
+	public UserInfo getUserInfo() {
+		return userInfo;
+	}
+
+	public void setUserInfo(UserInfo userInfo) {
+		this.userInfo = userInfo;
+	}
+}
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/User.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/User.java
index 84cf051..aa76714 100644
--- a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/User.java
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/User.java
@@ -28,28 +28,28 @@ import java.util.Set;
 @TsModel
 public class User {
 
-	private @SerializedName("_id") String userId;
+	protected @SerializedName("_id") String userId;
 	protected @SerializedName("_rev") String rev;
 	protected String email;
 
-	private String username;
-	private String fullName;
-	private String password;
-	
-	private List<Element> ownSources;
-	private List<Element> ownSepas;
-	private List<Element> ownActions;
-	
-	private List<String> preferredSources;
-	private List<String> preferredSepas;
-	private List<String> preferredActions;
+	protected String username;
+	protected String fullName;
+	protected String password;
+
+	protected List<Element> ownSources;
+	protected List<Element> ownSepas;
+	protected List<Element> ownActions;
+
+	protected List<String> preferredSources;
+	protected List<String> preferredSepas;
+	protected List<String> preferredActions;
 
-	private List<UserApiToken> userApiTokens;
+	protected List<UserApiToken> userApiTokens;
 
-	private boolean hideTutorial;
-	private boolean darkMode = false;
+	protected boolean hideTutorial;
+	protected boolean darkMode = false;
 
-	private Set<Role> roles;	
+	protected Set<Role> roles;
 
 	public User() {
 		this.hideTutorial = false;
diff --git a/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserInfo.java b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserInfo.java
new file mode 100644
index 0000000..0f8bc98
--- /dev/null
+++ b/streampipes-model-client/src/main/java/org/apache/streampipes/model/client/user/UserInfo.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.streampipes.model.client.user;
+
+
+import org.apache.streampipes.model.shared.annotation.TsModel;
+
+import java.util.List;
+
+@TsModel
+public class UserInfo {
+
+  private String userId;
+  private String displayName;
+  private String email;
+  private List<String> roles;
+  private boolean showTutorial;
+  private boolean darkMode;
+
+  public UserInfo() {
+  }
+
+  public String getUserId() {
+    return userId;
+  }
+
+  public void setUserId(String userId) {
+    this.userId = userId;
+  }
+
+  public String getDisplayName() {
+    return displayName;
+  }
+
+  public void setDisplayName(String displayName) {
+    this.displayName = displayName;
+  }
+
+  public String getEmail() {
+    return email;
+  }
+
+  public void setEmail(String email) {
+    this.email = email;
+  }
+
+  public List<String> getRoles() {
+    return roles;
+  }
+
+  public void setRoles(List<String> roles) {
+    this.roles = roles;
+  }
+
+  public boolean isShowTutorial() {
+    return showTutorial;
+  }
+
+  public void setShowTutorial(boolean showTutorial) {
+    this.showTutorial = showTutorial;
+  }
+
+  public boolean isDarkMode() {
+    return darkMode;
+  }
+
+  public void setDarkMode(boolean darkMode) {
+    this.darkMode = darkMode;
+  }
+}
diff --git a/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractRestResource.java b/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractRestResource.java
index 1ae36f9..92796fc 100644
--- a/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractRestResource.java
+++ b/streampipes-rest-core-base/src/main/java/org/apache/streampipes/rest/core/base/impl/AbstractRestResource.java
@@ -19,8 +19,6 @@
 package org.apache.streampipes.rest.core.base.impl;
 
 import org.apache.http.client.ClientProtocolException;
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.authc.AuthenticationException;
 import org.apache.streampipes.manager.endpoint.HttpJsonParser;
 import org.apache.streampipes.manager.storage.UserManagementService;
 import org.apache.streampipes.manager.storage.UserService;
@@ -107,19 +105,17 @@ public abstract class AbstractRestResource extends AbstractSharedRestInterface {
     return statusMessage(new ErrorMessage(notifications));
   }
 
-  protected String getCurrentUsername() throws AuthenticationException {
-    if (SecurityUtils.getSubject().isAuthenticated()) {
-      return SecurityUtils.getSubject().getPrincipal().toString();
-    }
-    throw new AuthenticationException("Not authenticated");
-  }
+//  protected String getCurrentUsername() throws AuthenticationException {
+//    if (SecurityContext.getSubject().isAuthenticated()) {
+//      return SecurityUtils.getSubject().getPrincipal().toString();
+//    }
+//    throw new AuthenticationException("Not authenticated");
+//  }
 
   protected boolean authorized(String username) {
-    return username.equals(SecurityUtils.getSubject().getPrincipal().toString());
-  }
-
-  protected boolean isAuthenticated() {
-    return SecurityUtils.getSubject().isAuthenticated();
+    // TODO SEC
+    //return username.equals(SecurityUtils.getSubject().getPrincipal().toString());
+    return true;
   }
 
   @SuppressWarnings("deprecation")
@@ -140,6 +136,10 @@ public abstract class AbstractRestResource extends AbstractSharedRestInterface {
             .build();
   }
 
+  protected Response unauthorized() {
+    return Response.status(Response.Status.UNAUTHORIZED).build();
+  }
+
   protected ISpKvManagement getKeyValueStore() {
     return SpServiceDiscovery.getKeyValueStore();
   }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/authentication/StreamPipesFilter.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/authentication/StreamPipesFilter.java
index 0af5b7f..f1e7c8e 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/authentication/StreamPipesFilter.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/authentication/StreamPipesFilter.java
@@ -1,55 +1,55 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.streampipes.rest.authentication;
-
-import org.apache.shiro.web.filter.authc.UserFilter;
-import org.apache.shiro.web.util.WebUtils;
-
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- *
- * Requires the requesting user to be authenticated for the request to continue and if they are not,
- * responds with HTML Error code 403.
- *
- * See https://stackoverflow.com/questions/30344441/shiro-filter-without-redirect/30344953#30344953
- *
- */
-
-public class StreamPipesFilter extends UserFilter {
-    private static final String message = "Access denied!";
-
-    @Override
-    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
-        HttpServletResponse httpResponse ;
-        try { httpResponse = WebUtils.toHttp(response); }
-
-        catch (ClassCastException ex) {
-            // Not a HTTP Servlet operation
-            return super.onAccessDenied(request, response) ;
-        }
-        if ( message == null )
-            httpResponse.sendError(403) ;
-        else
-            httpResponse.sendError(403, message) ;
-        return false ;
-    }
-}
+///*
+// * Licensed to the Apache Software Foundation (ASF) under one or more
+// * contributor license agreements.  See the NOTICE file distributed with
+// * this work for additional information regarding copyright ownership.
+// * The ASF licenses this file to You under the Apache License, Version 2.0
+// * (the "License"); you may not use this file except in compliance with
+// * the License.  You may obtain a copy of the License at
+// *
+// *    http://www.apache.org/licenses/LICENSE-2.0
+// *
+// * Unless required by applicable law or agreed to in writing, software
+// * distributed under the License is distributed on an "AS IS" BASIS,
+// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+// * limitations under the License.
+// *
+// */
+//
+//package org.apache.streampipes.rest.authentication;
+//
+//import org.apache.shiro.web.filter.authc.UserFilter;
+//import org.apache.shiro.web.util.WebUtils;
+//
+//import javax.servlet.ServletRequest;
+//import javax.servlet.ServletResponse;
+//import javax.servlet.http.HttpServletResponse;
+//
+///**
+// *
+// * Requires the requesting user to be authenticated for the request to continue and if they are not,
+// * responds with HTML Error code 403.
+// *
+// * See https://stackoverflow.com/questions/30344441/shiro-filter-without-redirect/30344953#30344953
+// *
+// */
+//
+//public class StreamPipesFilter extends UserFilter {
+//    private static final String message = "Access denied!";
+//
+//    @Override
+//    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+//        HttpServletResponse httpResponse ;
+//        try { httpResponse = WebUtils.toHttp(response); }
+//
+//        catch (ClassCastException ex) {
+//            // Not a HTTP Servlet operation
+//            return super.onAccessDenied(request, response) ;
+//        }
+//        if ( message == null )
+//            httpResponse.sendError(403) ;
+//        else
+//            httpResponse.sendError(403, message) ;
+//        return false ;
+//    }
+//}
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/filter/TokenAuthenticationFilter.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/filter/TokenAuthenticationFilter.java
new file mode 100644
index 0000000..04a3692
--- /dev/null
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/filter/TokenAuthenticationFilter.java
@@ -0,0 +1,67 @@
+package org.apache.streampipes.rest.filter;
+
+import org.apache.streampipes.storage.api.IUserStorage;
+import org.apache.streampipes.storage.management.StorageDispatcher;
+import org.apache.streampipes.user.management.jwt.JwtTokenProvider;
+import org.apache.streampipes.user.management.model.LocalUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.util.StringUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public class TokenAuthenticationFilter extends OncePerRequestFilter {
+
+
+	private JwtTokenProvider tokenProvider;
+
+	private IUserStorage userStorage;
+
+	private static final Logger logger = LoggerFactory.getLogger(TokenAuthenticationFilter.class);
+
+	public TokenAuthenticationFilter() {
+		this.tokenProvider = new JwtTokenProvider();
+		this.userStorage = StorageDispatcher.INSTANCE.getNoSqlStore().getUserStorageAPI();
+	}
+
+	@Override
+	protected void doFilterInternal(HttpServletRequest request,
+																	HttpServletResponse response,
+																	FilterChain filterChain) throws ServletException, IOException {
+		try {
+			String jwt = getJwtFromRequest(request);
+
+			if (StringUtils.hasText(jwt) && tokenProvider.validateJwtToken(jwt)) {
+				String username = tokenProvider.getUserIdFromToken(jwt);
+
+				UserDetails userDetails = new LocalUser(userStorage.getUser(username));
+				UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
+				authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+
+				SecurityContextHolder.getContext().setAuthentication(authentication);
+			}
+		} catch (Exception ex) {
+			logger.error("Could not set user authentication in security context", ex);
+		}
+
+		filterChain.doFilter(request, response);
+
+	}
+
+	private String getJwtFromRequest(HttpServletRequest request) {
+		String bearerToken = request.getHeader("Authorization");
+		if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
+			return bearerToken.substring(7);
+		}
+		return null;
+	}
+}
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/Authentication.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/Authentication.java
index aa9f0b4..433f0c2 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/Authentication.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/Authentication.java
@@ -18,11 +18,6 @@
 
 package org.apache.streampipes.rest.impl;
 
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.authc.AuthenticationException;
-import org.apache.shiro.authc.UsernamePasswordToken;
-import org.apache.shiro.subject.Subject;
-import org.apache.streampipes.config.backend.BackendConfig;
 import org.apache.streampipes.manager.storage.UserManagementService;
 import org.apache.streampipes.model.client.user.*;
 import org.apache.streampipes.model.message.ErrorMessage;
@@ -31,43 +26,58 @@ import org.apache.streampipes.model.message.Notifications;
 import org.apache.streampipes.model.message.SuccessMessage;
 import org.apache.streampipes.rest.core.base.impl.AbstractRestResource;
 import org.apache.streampipes.rest.shared.annotation.GsonWithIds;
+import org.apache.streampipes.rest.shared.annotation.JacksonSerialized;
+import org.apache.streampipes.user.management.jwt.JwtTokenProvider;
+import org.apache.streampipes.user.management.model.LocalUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
 
-import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.*;
-import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import java.util.HashSet;
 import java.util.Set;
 
-@Path("/v2/admin")
+@Path("/v2/auth")
 public class Authentication extends AbstractRestResource {
 
+  @Autowired
+  AuthenticationManager authenticationManager;
+
   @Produces(MediaType.APPLICATION_JSON)
   @Consumes(MediaType.APPLICATION_JSON)
-  @GsonWithIds
+  @JacksonSerialized
   @POST
   @Path("/login")
   public Response doLogin(ShiroAuthenticationRequest token) {
     try {
-      ShiroAuthenticationResponse authResponse = login(token);
-      return ok(authResponse);
-    } catch (AuthenticationException e) {
-      return ok(new ErrorMessage(NotificationType.LOGIN_FAILED.uiNotification()));
+      org.springframework.security.core.Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(token.getUsername(), token.getPassword()));
+      SecurityContextHolder.getContext().setAuthentication(authentication);
+      JwtAuthenticationResponse tokenResp = makeJwtResponse(authentication);
+      return ok(tokenResp);
+    } catch (BadCredentialsException e) {
+      return unauthorized();
     }
   }
 
-
-  @Path("/logout")
+  @Produces(MediaType.APPLICATION_JSON)
+  @Consumes(MediaType.APPLICATION_JSON)
+  @JacksonSerialized
   @GET
-  @GsonWithIds
-  public Response doLogout() {
-    Subject subject = SecurityUtils.getSubject();
-    subject.logout();
-    return ok(new SuccessMessage(NotificationType.LOGOUT_SUCCESS.uiNotification()));
+  @Path("/token/renew")
+  public Response doLogin() {
+    try {
+      org.springframework.security.core.Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+      JwtAuthenticationResponse tokenResp = makeJwtResponse(auth);
+      return ok(tokenResp);
+    } catch (BadCredentialsException e) {
+      return ok(new ErrorMessage(NotificationType.LOGIN_FAILED.uiNotification()));
+    }
   }
 
-
   @Path("/register")
   @POST
   @GsonWithIds
@@ -85,36 +95,18 @@ public class Authentication extends AbstractRestResource {
     }
   }
 
-  @GET
-  @GsonWithIds
-  @Path("/authc")
-  public Response userAuthenticated(@Context HttpServletRequest req) {
-
-    if (BackendConfig.INSTANCE.isConfigured()) {
-      if (SecurityUtils.getSubject().isAuthenticated()) {
-        ShiroAuthenticationResponse response = ShiroAuthenticationResponseFactory
-                .create(getUserStorage()
-                        .getUser((String) SecurityUtils.getSubject().getPrincipal()));
-        return ok(response);
-      }
-    }
-    return ok(new ErrorMessage(NotificationType.NOT_LOGGED_IN.uiNotification()));
+  private JwtAuthenticationResponse makeJwtResponse(org.springframework.security.core.Authentication auth) {
+    String jwt = new JwtTokenProvider().createToken(auth);
+    LocalUser localUser = (LocalUser) auth.getPrincipal();
+    return JwtAuthenticationResponse.from(jwt, toUserInfo(localUser));
   }
 
-
-  private ShiroAuthenticationResponse login(ShiroAuthenticationRequest token) {
-    Subject subject = SecurityUtils.getSubject();
-    UsernamePasswordToken shiroToken = new UsernamePasswordToken(token.getUsername(),
-            token.getPassword());
-    shiroToken.setRememberMe(true);
-
-    subject.login(shiroToken);
-    ShiroAuthenticationResponse response = ShiroAuthenticationResponseFactory
-            .create(getUserStorage().getUser((String) subject.getPrincipal()));
-    response.setToken(subject.getSession().getId().toString());
-
-    return response;
-
+  private UserInfo toUserInfo(LocalUser localUser) {
+    UserInfo userInfo = new UserInfo();
+    userInfo.setUserId("id");
+    userInfo.setEmail(localUser.getEmail());
+    userInfo.setDisplayName(localUser.getUsername());
+    userInfo.setShowTutorial(!localUser.isHideTutorial());
+    return userInfo;
   }
-
 }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/SemanticEventConsumer.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/SemanticEventConsumer.java
index 8df882e..71f8633 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/SemanticEventConsumer.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/SemanticEventConsumer.java
@@ -18,7 +18,6 @@
 
 package org.apache.streampipes.rest.impl;
 
-import org.apache.shiro.authz.annotation.RequiresAuthentication;
 import org.apache.streampipes.model.graph.DataSinkDescription;
 import org.apache.streampipes.model.graph.DataSinkInvocation;
 import org.apache.streampipes.model.message.NotificationType;
@@ -42,7 +41,6 @@ public class SemanticEventConsumer extends AbstractAuthGuardedRestResource imple
 
   @GET
   @Path("/available")
-  @RequiresAuthentication
   @Produces(MediaType.APPLICATION_JSON)
   @GsonWithIds
   @Override
@@ -54,7 +52,6 @@ public class SemanticEventConsumer extends AbstractAuthGuardedRestResource imple
 
   @GET
   @Path("/favorites")
-  @RequiresAuthentication
   @Produces(MediaType.APPLICATION_JSON)
   @GsonWithIds
   @Override
@@ -66,7 +63,6 @@ public class SemanticEventConsumer extends AbstractAuthGuardedRestResource imple
 
   @GET
   @Path("/own")
-  @RequiresAuthentication
   @Produces({MediaType.APPLICATION_JSON, SpMediaType.JSONLD})
   @JacksonSerialized
   @Override
@@ -79,7 +75,6 @@ public class SemanticEventConsumer extends AbstractAuthGuardedRestResource imple
 
   @POST
   @Path("/favorites")
-  @RequiresAuthentication
   @Produces(MediaType.APPLICATION_JSON)
   @GsonWithIds
   @Override
@@ -90,7 +85,6 @@ public class SemanticEventConsumer extends AbstractAuthGuardedRestResource imple
 
   @DELETE
   @Path("/favorites/{elementId}")
-  @RequiresAuthentication
   @Produces(MediaType.APPLICATION_JSON)
   @GsonWithIds
   @Override
@@ -101,7 +95,6 @@ public class SemanticEventConsumer extends AbstractAuthGuardedRestResource imple
 
   @DELETE
   @Path("/own/{elementId}")
-  @RequiresAuthentication
   @Produces(MediaType.APPLICATION_JSON)
   @GsonWithIds
   @Override
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/SemanticEventProcessingAgent.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/SemanticEventProcessingAgent.java
index 1491506..3fdd8d4 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/SemanticEventProcessingAgent.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/SemanticEventProcessingAgent.java
@@ -18,7 +18,6 @@
 
 package org.apache.streampipes.rest.impl;
 
-import org.apache.shiro.authz.annotation.RequiresAuthentication;
 import org.apache.streampipes.model.graph.DataProcessorDescription;
 import org.apache.streampipes.model.graph.DataProcessorInvocation;
 import org.apache.streampipes.model.message.NotificationType;
@@ -41,7 +40,6 @@ public class SemanticEventProcessingAgent extends AbstractAuthGuardedRestResourc
 
 	@GET
 	@Path("/available")
-	@RequiresAuthentication
 	@Produces(MediaType.APPLICATION_JSON)
 	@GsonWithIds
 	@Override
@@ -53,7 +51,6 @@ public class SemanticEventProcessingAgent extends AbstractAuthGuardedRestResourc
 	
 	@GET
 	@Path("/favorites")
-	@RequiresAuthentication
 	@Produces(MediaType.APPLICATION_JSON)
 	@GsonWithIds
 	@Override
@@ -65,7 +62,6 @@ public class SemanticEventProcessingAgent extends AbstractAuthGuardedRestResourc
 
 	@GET
 	@Path("/own")
-	@RequiresAuthentication
 	@JacksonSerialized
 	@Produces({MediaType.APPLICATION_JSON, SpMediaType.JSONLD})
 	@Override
@@ -82,7 +78,6 @@ public class SemanticEventProcessingAgent extends AbstractAuthGuardedRestResourc
 
 	@POST
 	@Path("/favorites")
-	@RequiresAuthentication
 	@Produces(MediaType.APPLICATION_JSON)
 	@GsonWithIds
 	@Override
@@ -93,7 +88,6 @@ public class SemanticEventProcessingAgent extends AbstractAuthGuardedRestResourc
 
 	@DELETE
 	@Path("/favorites/{elementUri}")
-	@RequiresAuthentication
 	@Produces(MediaType.APPLICATION_JSON)
 	@GsonWithIds
 	@Override
@@ -104,7 +98,6 @@ public class SemanticEventProcessingAgent extends AbstractAuthGuardedRestResourc
 	
 	@DELETE
 	@Path("/own/{elementId}")
-	@RequiresAuthentication
 	@Produces(MediaType.APPLICATION_JSON)
 	@GsonWithIds
 	@Override
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/SemanticEventProducer.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/SemanticEventProducer.java
index 45c9d02..284761d 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/SemanticEventProducer.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/SemanticEventProducer.java
@@ -18,7 +18,6 @@
 
 package org.apache.streampipes.rest.impl;
 
-import org.apache.shiro.authz.annotation.RequiresAuthentication;
 import org.apache.streampipes.model.SpDataStream;
 import org.apache.streampipes.model.message.NotificationType;
 import org.apache.streampipes.model.message.Notifications;
@@ -41,7 +40,6 @@ public class SemanticEventProducer extends AbstractAuthGuardedRestResource imple
 
 	@GET
 	@Path("/available")
-	@RequiresAuthentication
 	@Produces(MediaType.APPLICATION_JSON)
 	@GsonWithIds
 	@Override
@@ -53,7 +51,6 @@ public class SemanticEventProducer extends AbstractAuthGuardedRestResource imple
 	
 	@GET
 	@Path("/favorites")
-	@RequiresAuthentication
 	@Produces(MediaType.APPLICATION_JSON)
 	@GsonWithIds
 	@Override
@@ -65,7 +62,6 @@ public class SemanticEventProducer extends AbstractAuthGuardedRestResource imple
 
 	@GET
 	@Path("/own")
-	@RequiresAuthentication
 	@Produces({MediaType.APPLICATION_JSON, SpMediaType.JSONLD})
 	@JacksonSerialized
 	@Override
@@ -79,7 +75,6 @@ public class SemanticEventProducer extends AbstractAuthGuardedRestResource imple
 
 	@POST
 	@Path("/favorites")
-	@RequiresAuthentication
 	@Produces(MediaType.APPLICATION_JSON)
 	@GsonWithIds
 	@Override
@@ -90,7 +85,6 @@ public class SemanticEventProducer extends AbstractAuthGuardedRestResource imple
 
 	@DELETE
 	@Path("/favorites/{elementUri}")
-	@RequiresAuthentication
 	@Produces(MediaType.APPLICATION_JSON)
 	@GsonWithIds
 	@Override
@@ -101,7 +95,6 @@ public class SemanticEventProducer extends AbstractAuthGuardedRestResource imple
 	
 	@DELETE
 	@Path("/own/{elementId}")
-	@RequiresAuthentication
 	@Produces(MediaType.APPLICATION_JSON)
 	@GsonWithIds
 	@Override
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/User.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/UserProfile.java
similarity index 82%
rename from streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/User.java
rename to streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/UserProfile.java
index 80879e9..5a67aca 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/User.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/UserProfile.java
@@ -20,7 +20,7 @@ package org.apache.streampipes.rest.impl;
 
 import org.apache.streampipes.model.client.user.RawUserApiToken;
 import org.apache.streampipes.model.message.Notifications;
-import org.apache.streampipes.rest.core.base.impl.AbstractRestResource;
+import org.apache.streampipes.rest.core.base.impl.AbstractAuthGuardedRestResource;
 import org.apache.streampipes.rest.shared.annotation.JacksonSerialized;
 import org.apache.streampipes.user.management.service.TokenService;
 
@@ -29,13 +29,13 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import java.util.stream.Collectors;
 
-@Path("/v2/users/{email}")
-public class User extends AbstractRestResource {
+@Path("/v2/users/profile")
+public class UserProfile extends AbstractAuthGuardedRestResource {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    public Response getUserDetails(@PathParam("email") String email) {
-        org.apache.streampipes.model.client.user.User user = getUser(email);
+    public Response getUserDetails() {
+        org.apache.streampipes.model.client.user.User user = getUser(getAuthenticatedUsername());
         user.setPassword("");
 
         if (user != null) {
@@ -48,10 +48,10 @@ public class User extends AbstractRestResource {
     @Path("/appearance/mode/{darkMode}")
     @PUT
     @Produces(MediaType.APPLICATION_JSON)
-    public Response updateAppearanceMode(@PathParam("email") String email,
-                                         @PathParam("darkMode") boolean darkMode) {
-        if (email != null) {
-            org.apache.streampipes.model.client.user.User user = getUser(email);
+    public Response updateAppearanceMode(@PathParam("darkMode") boolean darkMode) {
+        String authenticatedUserId = getAuthenticatedUsername();
+        if (authenticatedUserId != null) {
+            org.apache.streampipes.model.client.user.User user = getUser(authenticatedUserId);
             user.setDarkMode(darkMode);
             getUserStorage().updateUser(user);
 
@@ -65,7 +65,8 @@ public class User extends AbstractRestResource {
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
     public Response updateUserDetails(org.apache.streampipes.model.client.user.User user) {
-        if (user != null) {
+        String authenticatedUserId = getAuthenticatedUsername();
+        if (user != null && authenticatedUserId.equals(user.getEmail())) {
             org.apache.streampipes.model.client.user.User existingUser = getUser(user.getEmail());
             user.setPassword(existingUser.getPassword());
             user.setUserApiTokens(existingUser
@@ -94,8 +95,8 @@ public class User extends AbstractRestResource {
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
     @JacksonSerialized
-    public Response createNewApiToken(@PathParam("email") String email, RawUserApiToken rawToken) {
-        RawUserApiToken generatedToken = new TokenService().createAndStoreNewToken(email, rawToken);
+    public Response createNewApiToken(RawUserApiToken rawToken) {
+        RawUserApiToken generatedToken = new TokenService().createAndStoreNewToken(getAuthenticatedUsername(), rawToken);
         return ok(generatedToken);
     }
 }
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/interceptor/AuthenticationInterceptor.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/interceptor/AuthenticationInterceptor.java
index cc93b45..c2a091d 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/interceptor/AuthenticationInterceptor.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/interceptor/AuthenticationInterceptor.java
@@ -17,7 +17,6 @@
  */
 package org.apache.streampipes.rest.interceptor;
 
-import org.apache.streampipes.rest.authentication.StreamPipesFilter;
 import org.apache.streampipes.rest.shared.annotation.NoAuthenticationRequired;
 
 import javax.ws.rs.container.DynamicFeature;
@@ -30,7 +29,7 @@ public class AuthenticationInterceptor implements DynamicFeature {
   @Override
   public void configure(ResourceInfo resourceInfo, FeatureContext context) {
     if (!resourceInfo.getResourceMethod().isAnnotationPresent(NoAuthenticationRequired.class)) {
-      context.register(StreamPipesFilter.class);
+      //context.register(StreamPipesFilter.class);
     }
   }
 }
diff --git a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineStorage.java b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineStorage.java
index 2bf7a8e..9783668 100644
--- a/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineStorage.java
+++ b/streampipes-storage-api/src/main/java/org/apache/streampipes/storage/api/IPipelineStorage.java
@@ -29,8 +29,6 @@ public interface IPipelineStorage {
 
 	List<Pipeline> getSystemPipelines();
 
-	List<Pipeline> getAllUserPipelines();
-
 	void storePipeline(Pipeline pipeline);
 
 	void updatePipeline(Pipeline pipeline);
diff --git a/streampipes-storage-couchdb/pom.xml b/streampipes-storage-couchdb/pom.xml
index 7617642..9ed670d 100644
--- a/streampipes-storage-couchdb/pom.xml
+++ b/streampipes-storage-couchdb/pom.xml
@@ -57,10 +57,6 @@
 
         <!-- External dependencies -->
         <dependency>
-            <groupId>org.apache.shiro</groupId>
-            <artifactId>shiro-core</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.lightcouch</groupId>
             <artifactId>lightcouch</artifactId>
         </dependency>
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineStorageImpl.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineStorageImpl.java
index 95de6ae..1a419db 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineStorageImpl.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/impl/PipelineStorageImpl.java
@@ -18,16 +18,11 @@
 
 package org.apache.streampipes.storage.couchdb.impl;
 
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import org.apache.streampipes.model.pipeline.Pipeline;
 import org.apache.streampipes.model.VirtualSensor;
+import org.apache.streampipes.model.pipeline.Pipeline;
 import org.apache.streampipes.storage.api.IPipelineStorage;
 import org.apache.streampipes.storage.couchdb.dao.AbstractDao;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
-
-import org.apache.shiro.SecurityUtils;
 import org.lightcouch.CouchDbClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -65,19 +60,6 @@ public class PipelineStorageImpl extends AbstractDao<Pipeline> implements IPipel
                 .collect(Collectors.toList());
     }
 
-    public List<Pipeline> getAllUserPipelines() {
-        CouchDbClient dbClientUser = Utils.getCouchDbUserClient();
-        List<Pipeline> pipelines = new ArrayList<>();
-        if (SecurityUtils.getSubject().isAuthenticated()) {
-            String username = SecurityUtils.getSubject().getPrincipal().toString();
-            JsonArray pipelineIds = dbClientUser.view("users/pipelines").key(username).query(JsonObject.class).get(0).get("value").getAsJsonArray();
-            for (JsonElement id : pipelineIds) {
-                pipelines.add(getPipeline(id.getAsString()));
-            }
-        }
-        return pipelines;
-    }
-
     @Override
     public void storePipeline(Pipeline pipeline) {
         persist(pipeline);
diff --git a/streampipes-user-management/pom.xml b/streampipes-user-management/pom.xml
index f3a56c8..6e39373 100644
--- a/streampipes-user-management/pom.xml
+++ b/streampipes-user-management/pom.xml
@@ -47,12 +47,20 @@
 
         <!-- External dependencies -->
         <dependency>
-            <groupId>org.apache.shiro</groupId>
-            <artifactId>shiro-core</artifactId>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-oauth2-client</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.apache.shiro</groupId>
-            <artifactId>shiro-web</artifactId>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-jackson</artifactId>
         </dependency>
 
         <!-- Test dependencies -->
diff --git a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/authentication/StreamPipesCredentialsMatcher.java b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/authentication/StreamPipesCredentialsMatcher.java
index 94278f2..e4cbea6 100644
--- a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/authentication/StreamPipesCredentialsMatcher.java
+++ b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/authentication/StreamPipesCredentialsMatcher.java
@@ -18,25 +18,47 @@
 
 package org.apache.streampipes.user.management.authentication;
 
-import org.apache.shiro.authc.AuthenticationInfo;
-import org.apache.shiro.authc.AuthenticationToken;
-import org.apache.shiro.authc.credential.CredentialsMatcher;
 import org.apache.streampipes.user.management.util.PasswordUtil;
+import org.springframework.security.crypto.password.PasswordEncoder;
 
 import java.security.NoSuchAlgorithmException;
 import java.security.spec.InvalidKeySpecException;
 
-public class StreamPipesCredentialsMatcher implements CredentialsMatcher {
+public class StreamPipesCredentialsMatcher implements PasswordEncoder {
+
+//  @Override
+//  public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {
+//    try {
+//      return PasswordUtil.validatePassword(new String((char[]) authenticationToken
+//                      .getCredentials()),
+//              authenticationInfo
+//              .getCredentials().toString());
+//    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+//      return false;
+//    }
+//  }
+
+  @Override
+  public String encode(CharSequence charSequence) {
+    try {
+      return PasswordUtil.encryptPassword(charSequence.toString());
+    } catch (NoSuchAlgorithmException e) {
+      e.printStackTrace();
+    } catch (InvalidKeySpecException e) {
+      e.printStackTrace();
+    }
+    return null;
+  }
 
   @Override
-  public boolean doCredentialsMatch(AuthenticationToken authenticationToken, AuthenticationInfo authenticationInfo) {
+  public boolean matches(CharSequence charSequence, String s) {
     try {
-      return PasswordUtil.validatePassword(new String((char[]) authenticationToken
-                      .getCredentials()),
-              authenticationInfo
-              .getCredentials().toString());
-    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
-      return false;
+      return PasswordUtil.validatePassword(charSequence.toString(), s);
+    } catch (NoSuchAlgorithmException e) {
+      e.printStackTrace();
+    } catch (InvalidKeySpecException e) {
+      e.printStackTrace();
     }
+    return false;
   }
 }
diff --git a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/authentication/StreamPipesRealm.java b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/authentication/StreamPipesRealm.java
index 6bcd452..c13552d 100644
--- a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/authentication/StreamPipesRealm.java
+++ b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/authentication/StreamPipesRealm.java
@@ -1,109 +1,109 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.streampipes.user.management.authentication;
-
-
-import org.apache.shiro.authc.*;
-import org.apache.shiro.realm.Realm;
-import org.apache.shiro.subject.SimplePrincipalCollection;
-import org.apache.streampipes.model.client.user.User;
-import org.apache.streampipes.user.management.service.TokenService;
-import org.apache.streampipes.user.management.service.UserService;
-import org.apache.streampipes.user.management.util.TokenUtil;
-import org.lightcouch.CouchDbException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-/**
- * Principals are a subjects identifying attributes  such as first name, last name or user name.
- * Credentials are usually secret values known only by the subject
- */
-public class StreamPipesRealm implements Realm {
-
-  private static final Logger LOG = LoggerFactory.getLogger(StreamPipesRealm.class);
-
-  private StreamPipesCredentialsMatcher credentialsMatcher;
-
-  public StreamPipesRealm() {
-    this.credentialsMatcher = new StreamPipesCredentialsMatcher();
-  }
-
-  @Override
-  public String getName() {
-    return "StreamPipeRealm";
-  }
-
-  @Override
-  /**
-   * Check if type of AuthenticationToken is supported.
-   * So far we only support UsernamePasswordToken.
-   */
-  public boolean supports(AuthenticationToken authenticationToken) {
-    return authenticationToken instanceof UsernamePasswordToken || authenticationToken instanceof BearerToken;
-  }
-
-  @Override
-  /**
-   * Checks if token is correct. See class JavaDoc for creating the password view.
-   */
-  public AuthenticationInfo getAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
-
-    if (authenticationToken instanceof UsernamePasswordToken) {
-
-      try {
-        String email = ((UsernamePasswordToken) authenticationToken).getUsername();
-        UserService userService = new UserService(email);
-
-        SimpleAuthenticationInfo info = makeInfo(email);
-        info.setCredentials(userService.getPassword());
-
-        if (credentialsMatcher.doCredentialsMatch(authenticationToken, info)) {
-          LOG.info("User successfully authenticated");
-        } else {
-          throw new AuthenticationException("Could not authenticate");
-        }
-        return info;
-
-      } catch (CouchDbException | NullPointerException e) {
-        e.printStackTrace();
-      }
-    } else if (authenticationToken instanceof BearerToken) {
-      BearerToken token = (BearerToken) authenticationToken;
-      String hashedToken = TokenUtil.hashToken(token.getToken());
-      User user = new TokenService().findUserForToken(hashedToken);
-      SimpleAuthenticationInfo info = makeInfo(user.getEmail());
-
-      return info;
-    }
-
-    return null;
-  }
-
-  private SimpleAuthenticationInfo makeInfo(String email) {
-    SimpleAuthenticationInfo info = new SimpleAuthenticationInfo();
-    SimplePrincipalCollection principals = new SimplePrincipalCollection();
-    principals.add(email, this.getName());
-
-    LOG.info(principals.toString());
-    info.setPrincipals(principals);
-
-    return info;
-  }
-}
+///*
+// * Licensed to the Apache Software Foundation (ASF) under one or more
+// * contributor license agreements.  See the NOTICE file distributed with
+// * this work for additional information regarding copyright ownership.
+// * The ASF licenses this file to You under the Apache License, Version 2.0
+// * (the "License"); you may not use this file except in compliance with
+// * the License.  You may obtain a copy of the License at
+// *
+// *    http://www.apache.org/licenses/LICENSE-2.0
+// *
+// * Unless required by applicable law or agreed to in writing, software
+// * distributed under the License is distributed on an "AS IS" BASIS,
+// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// * See the License for the specific language governing permissions and
+// * limitations under the License.
+// *
+// */
+//
+//package org.apache.streampipes.user.management.authentication;
+//
+//
+//import org.apache.shiro.authc.*;
+//import org.apache.shiro.realm.Realm;
+//import org.apache.shiro.subject.SimplePrincipalCollection;
+//import org.apache.streampipes.model.client.user.User;
+//import org.apache.streampipes.user.management.service.TokenService;
+//import org.apache.streampipes.user.management.service.UserService;
+//import org.apache.streampipes.user.management.util.TokenUtil;
+//import org.lightcouch.CouchDbException;
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;
+//
+//
+///**
+// * Principals are a subjects identifying attributes  such as first name, last name or user name.
+// * Credentials are usually secret values known only by the subject
+// */
+//public class StreamPipesRealm implements Realm {
+//
+//  private static final Logger LOG = LoggerFactory.getLogger(StreamPipesRealm.class);
+//
+//  private StreamPipesCredentialsMatcher credentialsMatcher;
+//
+//  public StreamPipesRealm() {
+//    this.credentialsMatcher = new StreamPipesCredentialsMatcher();
+//  }
+//
+//  @Override
+//  public String getName() {
+//    return "StreamPipeRealm";
+//  }
+//
+//  @Override
+//  /**
+//   * Check if type of AuthenticationToken is supported.
+//   * So far we only support UsernamePasswordToken.
+//   */
+//  public boolean supports(AuthenticationToken authenticationToken) {
+//    return authenticationToken instanceof UsernamePasswordToken || authenticationToken instanceof BearerToken;
+//  }
+//
+//  @Override
+//  /**
+//   * Checks if token is correct. See class JavaDoc for creating the password view.
+//   */
+//  public AuthenticationInfo getAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
+//
+//    if (authenticationToken instanceof UsernamePasswordToken) {
+//
+//      try {
+//        String email = ((UsernamePasswordToken) authenticationToken).getUsername();
+//        UserService userService = new UserService(email);
+//
+//        SimpleAuthenticationInfo info = makeInfo(email);
+//        info.setCredentials(userService.getPassword());
+//
+//        if (credentialsMatcher.doCredentialsMatch(authenticationToken, info)) {
+//          LOG.info("User successfully authenticated");
+//        } else {
+//          throw new AuthenticationException("Could not authenticate");
+//        }
+//        return info;
+//
+//      } catch (CouchDbException | NullPointerException e) {
+//        e.printStackTrace();
+//      }
+//    } else if (authenticationToken instanceof BearerToken) {
+//      BearerToken token = (BearerToken) authenticationToken;
+//      String hashedToken = TokenUtil.hashToken(token.getToken());
+//      User user = new TokenService().findUserForToken(hashedToken);
+//      SimpleAuthenticationInfo info = makeInfo(user.getEmail());
+//
+//      return info;
+//    }
+//
+//    return null;
+//  }
+//
+//  private SimpleAuthenticationInfo makeInfo(String email) {
+//    SimpleAuthenticationInfo info = new SimpleAuthenticationInfo();
+//    SimplePrincipalCollection principals = new SimplePrincipalCollection();
+//    principals.add(email, this.getName());
+//
+//    LOG.info(principals.toString());
+//    info.setPrincipals(principals);
+//
+//    return info;
+//  }
+//}
diff --git a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/jwt/JwtTokenProvider.java b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/jwt/JwtTokenProvider.java
new file mode 100644
index 0000000..1a90e14
--- /dev/null
+++ b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/jwt/JwtTokenProvider.java
@@ -0,0 +1,80 @@
+package org.apache.streampipes.user.management.jwt;
+
+import io.jsonwebtoken.*;
+import io.jsonwebtoken.security.Keys;
+import io.jsonwebtoken.security.WeakKeyException;
+import org.apache.streampipes.config.backend.BackendConfig;
+import org.apache.streampipes.config.backend.model.LocalAuthConfig;
+import org.apache.streampipes.user.management.model.LocalUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+
+import javax.crypto.SecretKey;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+
+public class JwtTokenProvider {
+
+	private static final Logger LOG = LoggerFactory.getLogger(JwtTokenProvider.class);
+	private BackendConfig config;
+
+	public JwtTokenProvider() {
+		this.config = BackendConfig.INSTANCE;
+	}
+
+	public String createToken(Authentication authentication) {
+		LocalUser userPrincipal = (LocalUser) authentication.getPrincipal();
+		Date tokenExpirationDate = makeExpirationDate();
+		SecretKey key = Keys.hmacShaKeyFor(tokenSecret().getBytes(StandardCharsets.UTF_8));
+
+		return Jwts
+						.builder()
+						.setSubject(userPrincipal.getEmail())
+						.setIssuedAt(new Date())
+						.setExpiration(tokenExpirationDate)
+				.signWith(key).compact();
+	}
+
+	public String getUserIdFromToken(String token) {
+		Claims claims = jwtParser().parseClaimsJws(token).getBody();
+		return claims.getSubject();
+	}
+
+	public boolean validateJwtToken(String jwtToken) {
+		try {
+			jwtParser().parseClaimsJws(jwtToken);
+			return true;
+		} catch (MalformedJwtException ex) {
+			LOG.error("Invalid JWT token");
+		} catch (ExpiredJwtException ex) {
+			LOG.error("Expired JWT token");
+		} catch (UnsupportedJwtException ex) {
+			LOG.error("Unsupported JWT token");
+		} catch (IllegalArgumentException ex) {
+			LOG.error("JWT claims are empty.");
+		} catch (WeakKeyException ex) {
+			LOG.error("Weak Key");
+		}
+		return false;
+	}
+
+	private JwtParser jwtParser() {
+		return Jwts.parserBuilder()
+						.setSigningKey(tokenSecret().getBytes(StandardCharsets.UTF_8))
+						.build();
+	}
+
+	private String tokenSecret() {
+		return authConfig().getTokenSecret();
+	}
+
+	private LocalAuthConfig authConfig() {
+		return this.config.getLocalAuthConfig();
+	}
+
+	private Date makeExpirationDate() {
+		Date now = new Date();
+		return new Date(now.getTime() + authConfig().getTokenExpirationTimeMillis());
+	}
+}
diff --git a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/model/LocalUser.java b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/model/LocalUser.java
new file mode 100644
index 0000000..d7aeffd
--- /dev/null
+++ b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/model/LocalUser.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.streampipes.user.management.model;
+
+import org.apache.streampipes.model.client.user.User;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public class LocalUser extends User implements UserDetails {
+
+  public LocalUser(User user) {
+    this.username = user.getUsername();
+    this.email = user.getEmail();
+    this.ownSepas = user.getOwnSepas();
+    this.ownActions = user.getOwnActions();
+    this.darkMode = user.isDarkMode();
+    this.hideTutorial = user.isHideTutorial();
+    this.fullName = user.getFullName();
+    this.ownSources = user.getOwnSources();
+    this.preferredActions = user.getPreferredActions();
+    this.preferredSepas = user.getPreferredSepas();
+    this.preferredSources = user.getPreferredSources();
+    this.password = user.getPassword();
+    this.rev = user.getRev();
+    this.userId = user.getUserId();
+    this.roles= user.getRoles();
+    this.userApiTokens = user.getUserApiTokens();
+  }
+
+  @Override
+  public Collection<? extends GrantedAuthority> getAuthorities() {
+    return Collections.emptyList();
+  }
+
+  @Override
+  public String getPassword() {
+    return password;
+  }
+
+  @Override
+  public String getUsername() {
+    return email;
+  }
+
+  @Override
+  public boolean isAccountNonExpired() {
+    return true;
+  }
+
+  @Override
+  public boolean isAccountNonLocked() {
+    return true;
+  }
+
+  @Override
+  public boolean isCredentialsNonExpired() {
+    return true;
+  }
+
+  @Override
+  public boolean isEnabled() {
+    return true;
+  }
+}
diff --git a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/UserService.java b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/SpUserDetailsService.java
similarity index 53%
copy from streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/UserService.java
copy to streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/SpUserDetailsService.java
index d8455f4..dd6fff1 100644
--- a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/UserService.java
+++ b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/SpUserDetailsService.java
@@ -17,28 +17,19 @@
  */
 package org.apache.streampipes.user.management.service;
 
-import com.google.gson.JsonObject;
-import org.apache.shiro.authc.AuthenticationException;
-import org.lightcouch.CouchDbClient;
-import org.apache.streampipes.storage.couchdb.utils.Utils;
+import org.apache.streampipes.model.client.user.User;
+import org.apache.streampipes.storage.management.StorageDispatcher;
+import org.apache.streampipes.user.management.model.LocalUser;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
 
-import java.util.List;
+public class SpUserDetailsService implements UserDetailsService {
 
-public class UserService {
-
-  private JsonObject user;
-
-  public UserService(String email) throws AuthenticationException {
-    CouchDbClient dbClient = Utils.getCouchDbUserClient();
-    List<JsonObject> users = dbClient.view("users/password").key(email).includeDocs(true).query(JsonObject.class);
-    if (users.size() != 1) {
-      throw new AuthenticationException("None or too many users with matching username");
-    }
-    this.user = users.get(0);
-
-  }
-
-  public String getPassword() {
-    return user.get("password").getAsString();
+  @Override
+  public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
+    User user = StorageDispatcher.INSTANCE.getNoSqlStore().getUserStorageAPI().getUser(s);
+    LocalUser localUser = new LocalUser(user);
+    return new LocalUser(localUser);
   }
 }
diff --git a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/TokenService.java b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/TokenService.java
index 76444e3..a6eea99 100644
--- a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/TokenService.java
+++ b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/TokenService.java
@@ -18,7 +18,6 @@
 package org.apache.streampipes.user.management.service;
 
 import com.google.gson.JsonObject;
-import org.apache.shiro.authc.AuthenticationException;
 import org.apache.streampipes.model.client.user.RawUserApiToken;
 import org.apache.streampipes.model.client.user.User;
 import org.apache.streampipes.storage.api.IUserStorage;
@@ -27,6 +26,7 @@ import org.apache.streampipes.storage.management.StorageDispatcher;
 import org.apache.streampipes.user.management.util.TokenUtil;
 import org.lightcouch.CouchDbClient;
 
+import java.nio.file.attribute.UserPrincipalNotFoundException;
 import java.util.List;
 
 public class TokenService {
@@ -50,11 +50,11 @@ public class TokenService {
             .getUserStorageAPI();
   }
 
-  public User findUserForToken(String token) {
+  public User findUserForToken(String token) throws UserPrincipalNotFoundException {
     CouchDbClient dbClient = Utils.getCouchDbUserClient();
     List<JsonObject> users = dbClient.view("users/token").key(token).includeDocs(true).query(JsonObject.class);
     if (users.size() != 1) {
-      throw new AuthenticationException("None or too many users with matching token");
+      throw new UserPrincipalNotFoundException("None or too many users with matching token");
     }
     return getUserStorage().getUser(users.get(0).get("email").getAsString());
   }
diff --git a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/UserService.java b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/UserService.java
index d8455f4..9b651aa 100644
--- a/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/UserService.java
+++ b/streampipes-user-management/src/main/java/org/apache/streampipes/user/management/service/UserService.java
@@ -18,9 +18,8 @@
 package org.apache.streampipes.user.management.service;
 
 import com.google.gson.JsonObject;
-import org.apache.shiro.authc.AuthenticationException;
-import org.lightcouch.CouchDbClient;
 import org.apache.streampipes.storage.couchdb.utils.Utils;
+import org.lightcouch.CouchDbClient;
 
 import java.util.List;
 
@@ -28,11 +27,11 @@ public class UserService {
 
   private JsonObject user;
 
-  public UserService(String email) throws AuthenticationException {
+  public UserService(String email) throws IllegalArgumentException {
     CouchDbClient dbClient = Utils.getCouchDbUserClient();
     List<JsonObject> users = dbClient.view("users/password").key(email).includeDocs(true).query(JsonObject.class);
     if (users.size() != 1) {
-      throw new AuthenticationException("None or too many users with matching username");
+      throw new IllegalArgumentException("None or too many users with matching username");
     }
     this.user = users.get(0);
 
diff --git a/ui/deployment/app-routing.module.mst b/ui/deployment/app-routing.module.mst
index 2dde0cf..4ddc5e2 100644
--- a/ui/deployment/app-routing.module.mst
+++ b/ui/deployment/app-routing.module.mst
@@ -28,7 +28,6 @@ import {AuthCanActivateChildrenGuard} from "./_guards/auth.can-activate-children
 import {ConfiguredCanActivateGuard} from "./_guards/configured.can-activate.guard";
 import {StartupComponent} from "./login/components/startup/startup.component";
 import {AlreadyConfiguredCanActivateGuard} from "./_guards/already-configured.can-activate.guard";
-import {LoggedInCanActivateGuard} from "./_guards/logged-in.can-activate.guard";
 import {InfoComponent} from "./info/info.component";
 import {NotificationsComponent} from "./notifications/notifications.component";
 import {ProfileComponent} from "./profile/profile.component";
@@ -42,7 +41,7 @@ import { {{{ng5_component}}} } from '{{{ng5_componentPath}}}';
 
 const routes: Routes = [
   { path: 'apidocs', component: ApidocsComponent, canActivate: [ConfiguredCanActivateGuard]},
-  { path: 'login', component: LoginComponent, canActivate: [ConfiguredCanActivateGuard, LoggedInCanActivateGuard],
+  { path: 'login', component: LoginComponent, canActivate: [ConfiguredCanActivateGuard],
   data: {animation: 'LoginPage'}},
   { path: 'setup', component: SetupComponent, canActivate: [AlreadyConfiguredCanActivateGuard] },
   { path: 'startup', component: StartupComponent },
@@ -68,7 +67,6 @@ const routes: Routes = [
       AuthCanActivateChildrenGuard,
       AlreadyConfiguredCanActivateGuard,
       ConfiguredCanActivateGuard,
-      LoggedInCanActivateGuard
   ]
 })
 export class AppRoutingModule { }
diff --git a/ui/deployment/appng5.module.mst b/ui/deployment/appng5.module.mst
index 2678a24..9fd3b77 100644
--- a/ui/deployment/appng5.module.mst
+++ b/ui/deployment/appng5.module.mst
@@ -20,13 +20,12 @@ import { NgModule } from '@angular/core';
 import { BrowserModule } from '@angular/platform-browser';
 import { MatGridListModule } from '@angular/material/grid-list';
 import { FlexLayoutModule } from '@angular/flex-layout';
-import { HttpClientModule } from '@angular/common/http';
+import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
 import { MatIconModule } from '@angular/material/icon';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { FormsModule } from '@angular/forms';
 
 import { CustomMaterialModule } from './CustomMaterial/custom-material.module';
-import { AuthStatusService } from './services/auth-status.service';
 
 import { CoreModule } from './core/core.module';
 import { LoginModule } from './login/login.module';
@@ -56,6 +55,7 @@ import { AppRoutingModule } from './app-routing.module';
 import { PlatformServicesModule } from "./platform-services/platform.module";
 import { ServicesModule } from "./services/services.module";
 import { ApidocsModule } from "./apidocs/apidocs.module";
+import { HttpInterceptorProvider } from './http-interceptor';
 
 import * as $ from 'jquery';
 
@@ -91,9 +91,9 @@ import * as $ from 'jquery';
         {{/modulesActive}}
     ],
     providers: [
-        AuthStatusService,
         AuthService,
         NotificationCountService,
+        { provide: HTTP_INTERCEPTORS, useClass: HttpInterceptorProvider, multi: true },
         { provide: Logger, useClass: ConsoleLogService },
         { provide: LOADING_BAR_CONFIG, useValue: { latencyThreshold: 100 }},
         {
diff --git a/ui/package.json b/ui/package.json
index 736972a..92f47c2 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -30,6 +30,7 @@
     "@angular/router": "11.0.5",
     "@angular/upgrade": "11.0.5",
     "@asymmetrik/ngx-leaflet": "6.0.1",
+    "@auth0/angular-jwt": "^5.0.2",
     "@ctrl/ngx-codemirror": "3.1.3",
     "@danielmoncada/angular-datetime-picker": "10.0.0",
     "@fortawesome/fontawesome-free": "5.12.1",
diff --git a/ui/src/app/_guards/already-configured.can-activate.guard.ts b/ui/src/app/_guards/already-configured.can-activate.guard.ts
index f4f9512..874819f 100644
--- a/ui/src/app/_guards/already-configured.can-activate.guard.ts
+++ b/ui/src/app/_guards/already-configured.can-activate.guard.ts
@@ -16,21 +16,21 @@
  *
  */
 
-import {Injectable} from "@angular/core";
-import {Router, UrlTree} from "@angular/router";
-import {AuthService} from "../services/auth.service";
-import {BaseConfiguredCanActivateGuard} from "./base-configured.can-activate.guard";
+import { Injectable } from '@angular/core';
+import { Router, UrlTree } from '@angular/router';
+import { AuthService } from '../services/auth.service';
+import { BaseConfiguredCanActivateGuard } from './base-configured.can-activate.guard';
 
 @Injectable()
 export class AlreadyConfiguredCanActivateGuard extends BaseConfiguredCanActivateGuard {
 
-  constructor(Router: Router,
-              AuthService: AuthService) {
-    super(Router, AuthService);
+  constructor(router: Router,
+              authService: AuthService) {
+    super(router, authService);
   }
 
   onIsConfigured(): boolean | UrlTree {
-    return this.Router.parseUrl('login');
+    return this.router.parseUrl('login');
   }
 
   onIsUnconfigured(): boolean | UrlTree {
@@ -40,4 +40,4 @@ export class AlreadyConfiguredCanActivateGuard extends BaseConfiguredCanActivate
 
 
 
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/_guards/auth.can-activate-children.guard.ts b/ui/src/app/_guards/auth.can-activate-children.guard.ts
index fef6239..8887c90 100644
--- a/ui/src/app/_guards/auth.can-activate-children.guard.ts
+++ b/ui/src/app/_guards/auth.can-activate-children.guard.ts
@@ -16,43 +16,31 @@
  *
  */
 
-import {Injectable} from "@angular/core";
+import { Injectable } from '@angular/core';
 import {
   ActivatedRouteSnapshot,
   CanActivateChild,
   Router,
-  RouterStateSnapshot,
-  UrlTree
-} from "@angular/router";
-import {Observable} from "rxjs";
-import {RestApi} from "../services/rest-api.service";
-import {AuthStatusService} from "../services/auth-status.service";
+  RouterStateSnapshot
+} from '@angular/router';
+import { AuthService } from '../services/auth.service';
 
 @Injectable()
 export class AuthCanActivateChildrenGuard implements CanActivateChild {
 
-  constructor(private RestApi: RestApi,
-              private AuthStatusService: AuthStatusService,
-              private Router: Router) {
+  constructor(private authService: AuthService,
+              private router: Router) {
   }
 
-
-  canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
-    return new Promise((resolve) => this.RestApi.getAuthc().subscribe(response => {
-      if (response.success) {
-        this.AuthStatusService.username = response.info.authc.principal.username;
-        this.AuthStatusService.email = response.info.authc.principal.email;
-        this.AuthStatusService.authenticated = true;
-        this.AuthStatusService.token = response.token;
-        resolve(true);
-      } else {
-        this.AuthStatusService.authenticated = false;
-        let url = this.Router.parseUrl('login');
-        resolve(url);
+  canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
+    //this.authService.logout();
+      if (this.authService.authenticated()) {
+        return true;
       }
-    }, error => {
-      let url = this.Router.parseUrl('startup');
-      resolve(url);
-    }));
+      this.authService.logout();
+      this.router.navigate(['/login']);
+
+      return false;
+
   }
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/_guards/base-configured.can-activate.guard.ts b/ui/src/app/_guards/base-configured.can-activate.guard.ts
index 1656e03..4b28598 100644
--- a/ui/src/app/_guards/base-configured.can-activate.guard.ts
+++ b/ui/src/app/_guards/base-configured.can-activate.guard.ts
@@ -22,26 +22,24 @@ import {
   Router,
   RouterStateSnapshot,
   UrlTree
-} from "@angular/router";
-import {Observable} from "rxjs";
-import {AuthService} from "../services/auth.service";
+} from '@angular/router';
+import { Observable } from 'rxjs';
+import { AuthService } from '../services/auth.service';
 
 export abstract class BaseConfiguredCanActivateGuard implements CanActivate {
 
-  constructor(protected Router: Router,
-              protected AuthService: AuthService) {
-
-  }
+  constructor(protected router: Router,
+              protected authService: AuthService) { }
 
   canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
-    return new Promise((resolve) => this.AuthService.checkConfiguration().subscribe((configured) => {
+    return new Promise((resolve) => this.authService.checkConfiguration().subscribe((configured) => {
       if (!configured) {
         resolve(this.onIsUnconfigured());
       } else {
         resolve(this.onIsConfigured());
       }
     }, error => {
-      let url = this.Router.parseUrl('startup');
+      const url = this.router.parseUrl('startup');
       resolve(url);
     }));
   }
@@ -49,4 +47,4 @@ export abstract class BaseConfiguredCanActivateGuard implements CanActivate {
   abstract onIsConfigured(): boolean | UrlTree;
 
   abstract onIsUnconfigured(): boolean | UrlTree;
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/_guards/configured.can-activate.guard.ts b/ui/src/app/_guards/configured.can-activate.guard.ts
index 45bb001..c787a60 100644
--- a/ui/src/app/_guards/configured.can-activate.guard.ts
+++ b/ui/src/app/_guards/configured.can-activate.guard.ts
@@ -16,17 +16,17 @@
  *
  */
 
-import {Injectable} from "@angular/core";
-import {Router, UrlTree} from "@angular/router";
-import {AuthService} from "../services/auth.service";
-import {BaseConfiguredCanActivateGuard} from "./base-configured.can-activate.guard";
+import { Injectable } from '@angular/core';
+import { Router, UrlTree } from '@angular/router';
+import { AuthService } from '../services/auth.service';
+import { BaseConfiguredCanActivateGuard } from './base-configured.can-activate.guard';
 
 @Injectable()
 export class ConfiguredCanActivateGuard extends BaseConfiguredCanActivateGuard {
 
-  constructor(Router: Router,
-              AuthService: AuthService) {
-    super(Router, AuthService)
+  constructor(router: Router,
+              authService: AuthService) {
+    super(router, authService);
   }
 
   onIsConfigured(): boolean | UrlTree {
@@ -34,7 +34,7 @@ export class ConfiguredCanActivateGuard extends BaseConfiguredCanActivateGuard {
   }
 
   onIsUnconfigured(): boolean | UrlTree {
-    return this.Router.parseUrl('setup');
+    return this.router.parseUrl('setup');
   }
 
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/_guards/logged-in.can-activate.guard.ts b/ui/src/app/_guards/logged-in.can-activate.guard.ts
deleted file mode 100644
index 506f793..0000000
--- a/ui/src/app/_guards/logged-in.can-activate.guard.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import {Injectable} from "@angular/core";
-import {
-  ActivatedRouteSnapshot,
-  CanActivate,
-  Router,
-  RouterStateSnapshot,
-  UrlTree
-} from "@angular/router";
-import {Observable} from "rxjs";
-import {AuthStatusService} from "../services/auth-status.service";
-import {RestApi} from "../services/rest-api.service";
-
-@Injectable()
-export class LoggedInCanActivateGuard implements CanActivate {
-
-  constructor(private AuthStatusService: AuthStatusService,
-              private Router: Router,
-              private RestApi: RestApi) {
-
-  }
-
-  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
-    return new Promise((resolve) => this.RestApi.getAuthc().subscribe(response => {
-      if (response.success) {
-        this.AuthStatusService.username = response.info.authc.principal.username;
-        this.AuthStatusService.email = response.info.authc.principal.email;
-        this.AuthStatusService.authenticated = true;
-        this.AuthStatusService.token = response.token;
-        let url = this.Router.parseUrl('');
-        resolve(url);
-      } else {
-        this.AuthStatusService.authenticated = false;
-        resolve(true);
-      }
-    }, error => {
-      let url = this.Router.parseUrl('startup');
-      resolve(url);
-    }));
-  }
-}
\ No newline at end of file
diff --git a/ui/src/app/add/services/add.service.ts b/ui/src/app/add/services/add.service.ts
index 2be78dc..0b6b1bd 100644
--- a/ui/src/app/add/services/add.service.ts
+++ b/ui/src/app/add/services/add.service.ts
@@ -18,7 +18,6 @@
 
 import { Injectable } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
-import { AuthStatusService } from '../../services/auth-status.service';
 import { PlatformServicesCommons } from '../../platform-services/apis/commons.service';
 import { Observable } from 'rxjs';
 import { map } from 'rxjs/operators';
@@ -28,33 +27,32 @@ import { ExtensionsServiceEndpointItem } from '../../core-model/gen/streampipes-
 export class AddService {
 
   constructor(private http: HttpClient,
-              private authStatusService: AuthStatusService,
               private platformServicesCommons: PlatformServicesCommons) {
   }
 
   getRdfEndpoints(): Observable<any> {
-    return this.http.get(this.platformServicesCommons.apiBasePath() + '/rdfendpoints');
+    return this.http.get(this.platformServicesCommons.apiBasePath + '/rdfendpoints');
   }
 
   getRdfEndpointItems(): Observable<ExtensionsServiceEndpointItem[]> {
     return this
         .http
-        .get(this.platformServicesCommons.apiBasePath() + '/rdfendpoints/items')
+        .get(this.platformServicesCommons.apiBasePath + '/rdfendpoints/items')
         .pipe(map(response => {
           return (response as any[]).map(item => ExtensionsServiceEndpointItem.fromData(item));
         }));
   }
 
   addRdfEndpoint(rdfEndpoint): Observable<any> {
-    return this.http.post(this.platformServicesCommons.apiBasePath() + '/rdfendpoints', rdfEndpoint);
+    return this.http.post(this.platformServicesCommons.apiBasePath + '/rdfendpoints', rdfEndpoint);
   }
 
   removeRdfEndpoint(rdfEndpointId): Observable<any> {
-    return this.http.delete(this.platformServicesCommons.apiBasePath() + '/rdfendpoints/' + rdfEndpointId);
+    return this.http.delete(this.platformServicesCommons.apiBasePath + '/rdfendpoints/' + rdfEndpointId);
   }
 
   getRdfEndpointIcon(item: ExtensionsServiceEndpointItem): Observable<any> {
-    return this.http.post(this.platformServicesCommons.apiBasePath()
+    return this.http.post(this.platformServicesCommons.apiBasePath
         + '/rdfendpoints/items/icon', item, {responseType: 'blob'});
   }
 }
diff --git a/ui/src/app/app-asset-monitoring/services/rest.service.ts b/ui/src/app/app-asset-monitoring/services/rest.service.ts
index 2797cc5..af422b2 100644
--- a/ui/src/app/app-asset-monitoring/services/rest.service.ts
+++ b/ui/src/app/app-asset-monitoring/services/rest.service.ts
@@ -20,7 +20,6 @@ import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { map } from 'rxjs/operators';
 import { Observable } from 'rxjs';
-import { AuthStatusService } from '../../services/auth-status.service';
 import { DashboardConfiguration } from '../model/dashboard-configuration.model';
 import { PlatformServicesCommons } from '../../platform-services/apis/commons.service';
 
@@ -28,7 +27,6 @@ import { PlatformServicesCommons } from '../../platform-services/apis/commons.se
 export class RestService {
 
   constructor(private http: HttpClient,
-              private authStatusService: AuthStatusService,
               private platformServicesCommons: PlatformServicesCommons) {
   }
 
@@ -68,7 +66,7 @@ export class RestService {
   }
 
   private get url() {
-    return `${this.platformServicesCommons.apiBasePath()}/asset-dashboards`;
+    return `${this.platformServicesCommons.apiBasePath}/asset-dashboards`;
   }
 
   private get imagePath() {
diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts
index 94249aa..251238f 100644
--- a/ui/src/app/app-routing.module.ts
+++ b/ui/src/app/app-routing.module.ts
@@ -28,7 +28,6 @@ import {AuthCanActivateChildrenGuard} from "./_guards/auth.can-activate-children
 import {ConfiguredCanActivateGuard} from "./_guards/configured.can-activate.guard";
 import {StartupComponent} from "./login/components/startup/startup.component";
 import {AlreadyConfiguredCanActivateGuard} from "./_guards/already-configured.can-activate.guard";
-import {LoggedInCanActivateGuard} from "./_guards/logged-in.can-activate.guard";
 import {InfoComponent} from "./info/info.component";
 import {NotificationsComponent} from "./notifications/notifications.component";
 import {ProfileComponent} from "./profile/profile.component";
@@ -46,7 +45,7 @@ import { ConfigurationComponent } from './configuration/configuration.component'
 
 const routes: Routes = [
   { path: 'apidocs', component: ApidocsComponent, canActivate: [ConfiguredCanActivateGuard]},
-  { path: 'login', component: LoginComponent, canActivate: [ConfiguredCanActivateGuard, LoggedInCanActivateGuard],
+  { path: 'login', component: LoginComponent, canActivate: [ConfiguredCanActivateGuard],
   data: {animation: 'LoginPage'}},
   { path: 'setup', component: SetupComponent, canActivate: [AlreadyConfiguredCanActivateGuard] },
   { path: 'startup', component: StartupComponent },
@@ -76,7 +75,6 @@ const routes: Routes = [
       AuthCanActivateChildrenGuard,
       AlreadyConfiguredCanActivateGuard,
       ConfiguredCanActivateGuard,
-      LoggedInCanActivateGuard
   ]
 })
 export class AppRoutingModule { }
diff --git a/ui/src/app/app-transport-monitoring/services/app-transport-monitoring-rest.service.ts b/ui/src/app/app-transport-monitoring/services/app-transport-monitoring-rest.service.ts
index 3f278c1..2043629 100644
--- a/ui/src/app/app-transport-monitoring/services/app-transport-monitoring-rest.service.ts
+++ b/ui/src/app/app-transport-monitoring/services/app-transport-monitoring-rest.service.ts
@@ -16,18 +16,17 @@
  *
  */
 
-import {HttpClient} from "@angular/common/http";
-import {Injectable} from "@angular/core";
-import {map} from "rxjs/operators";
-import {Observable} from "rxjs";
-import {AuthStatusService} from "../../services/auth-status.service";
-import {ActivityDetectionModel} from "../model/activity-detection.model";
-import {ParcelInfoModel} from "../model/parcel-info.model";
-import {ParcelInfoEventModel} from "../model/parcel-info-event.model";
-import {OldEventModel} from "../model/old-event.model";
-import {TransportProcessEventModel} from "../model/transport-process-event.model";
-import {TransportProcessModel} from "../model/transport-process.model";
-import {OpenBoxModel} from "../model/open-box.model";
+import { HttpClient } from "@angular/common/http";
+import { Injectable } from "@angular/core";
+import { map } from "rxjs/operators";
+import { Observable } from "rxjs";
+import { ActivityDetectionModel } from "../model/activity-detection.model";
+import { ParcelInfoModel } from "../model/parcel-info.model";
+import { ParcelInfoEventModel } from "../model/parcel-info-event.model";
+import { OldEventModel } from "../model/old-event.model";
+import { TransportProcessEventModel } from "../model/transport-process-event.model";
+import { TransportProcessModel } from "../model/transport-process.model";
+import { OpenBoxModel } from "../model/open-box.model";
 
 @Injectable()
 export class AppTransportMonitoringRestService {
@@ -36,7 +35,7 @@ export class AppTransportMonitoringRestService {
     startTimestampDefault: number = 0;
     endTimestampDefault: number = 2653100861941;
 
-    constructor(private http: HttpClient, private authStatusService: AuthStatusService) {
+    constructor(private http: HttpClient) {
     }
 
     getTransportProcesses(): Observable<TransportProcessEventModel[]> {
diff --git a/ui/src/app/connect/services/data-marketplace.service.ts b/ui/src/app/connect/services/data-marketplace.service.ts
index 8df76ab..de185c0 100644
--- a/ui/src/app/connect/services/data-marketplace.service.ts
+++ b/ui/src/app/connect/services/data-marketplace.service.ts
@@ -19,7 +19,6 @@
 import { Injectable } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
 import { map } from 'rxjs/operators';
-import { AuthStatusService } from '../../services/auth-status.service';
 import { ConnectService } from './connect.service';
 import {
   AdapterDescription,
@@ -27,7 +26,8 @@ import {
   AdapterDescriptionUnion,
   EventSchema,
   GenericAdapterSetDescription,
-  GenericAdapterStreamDescription, Message,
+  GenericAdapterStreamDescription,
+  Message,
   ProtocolDescription,
   ProtocolDescriptionList,
   SpDataSet,
@@ -43,13 +43,12 @@ export class DataMarketplaceService {
 
   constructor(
       private http: HttpClient,
-      private authStatusService: AuthStatusService,
       private connectService: ConnectService,
       private platformServicesCommons: PlatformServicesCommons) {
   }
 
   get connectPath() {
-    return this.platformServicesCommons.apiBasePath() + '/connect';
+    return this.platformServicesCommons.apiBasePath + '/connect';
   }
 
   getAdapterDescriptions(): Observable<AdapterDescriptionUnion[]> {
diff --git a/ui/src/app/connect/services/rest.service.ts b/ui/src/app/connect/services/rest.service.ts
index 868b979..b10b2d9 100644
--- a/ui/src/app/connect/services/rest.service.ts
+++ b/ui/src/app/connect/services/rest.service.ts
@@ -32,7 +32,7 @@ import {
   SpDataStream
 } from '../../core-model/gen/streampipes-model';
 import { PlatformServicesCommons } from '../../platform-services/apis/commons.service';
-import { AuthStatusService } from '../../services/auth-status.service';
+import { AuthService } from '../../services/auth.service';
 
 @Injectable()
 export class RestService {
@@ -40,11 +40,11 @@ export class RestService {
   constructor(
       private http: HttpClient,
       private platformServicesCommons: PlatformServicesCommons,
-      private authStatusService: AuthStatusService) {
+      private authService: AuthService) {
   }
 
   get connectPath() {
-    return this.platformServicesCommons.apiBasePath() + '/connect';
+    return this.platformServicesCommons.apiBasePath + '/connect';
   }
 
   addAdapter(adapter: AdapterDescription): Observable<Message> {
@@ -56,7 +56,7 @@ export class RestService {
   }
 
   addAdapterDescription(adapter: AdapterDescription, url: string): Observable<Message> {
-    adapter.userName = this.authStatusService.email;
+    adapter.userName = this.authService.getCurrentUser().email;
     const promise = new Promise<Message>((resolve, reject) => {
       this.http
           .post(
@@ -83,13 +83,13 @@ export class RestService {
 
   getSourceDetails(sourceElementId): Observable<SpDataStream> {
     return this.http
-        .get(this.platformServicesCommons.apiBasePath() + '/streams/' + encodeURIComponent(sourceElementId)).pipe(map(response => {
+        .get(this.platformServicesCommons.apiBasePath + '/streams/' + encodeURIComponent(sourceElementId)).pipe(map(response => {
           return SpDataStream.fromData(response as SpDataStream);
         }));
   }
 
   getRuntimeInfo(sourceDescription): Observable<any> {
-    return this.http.post(this.platformServicesCommons.apiBasePath() + '/pipeline-element/runtime', sourceDescription, {
+    return this.http.post(this.platformServicesCommons.apiBasePath + '/pipeline-element/runtime', sourceDescription, {
       headers: {ignoreLoadingBar: ''}
     });
   }
diff --git a/ui/src/app/core-model/gen/streampipes-model-client.ts b/ui/src/app/core-model/gen/streampipes-model-client.ts
index 94ab771..98b0297 100644
--- a/ui/src/app/core-model/gen/streampipes-model-client.ts
+++ b/ui/src/app/core-model/gen/streampipes-model-client.ts
@@ -16,10 +16,11 @@
  *
  */
 
+
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 2.27.744 on 2021-07-19 21:39:30.
+// Generated using typescript-generator version 2.27.744 on 2021-09-30 14:45:03.
 
 export class Element {
     elementId: string;
@@ -198,6 +199,29 @@ export class UserApiToken {
     }
 }
 
+export class UserInfo {
+    darkMode: boolean;
+    displayName: string;
+    email: string;
+    roles: string[];
+    showTutorial: boolean;
+    userId: string;
+
+    static fromData(data: UserInfo, target?: UserInfo): UserInfo {
+        if (!data) {
+            return data;
+        }
+        const instance = target || new UserInfo();
+        instance.userId = data.userId;
+        instance.displayName = data.displayName;
+        instance.email = data.email;
+        instance.roles = __getCopyArrayFn(__identity<string>())(data.roles);
+        instance.showTutorial = data.showTutorial;
+        instance.darkMode = data.darkMode;
+        return instance;
+    }
+}
+
 export type Role = "SYSTEM_ADMINISTRATOR" | "MANAGER" | "OPERATOR" | "DIMENSION_OPERATOR" | "USER_DEMO" | "BUSINESS_ANALYST";
 
 function __getCopyArrayFn<T>(itemCopyFn: (item: T) => T): (array: T[]) => T[] {
diff --git a/ui/src/app/core-services/datalake/datalake-rest.service.ts b/ui/src/app/core-services/datalake/datalake-rest.service.ts
index a12a317..fc7a276 100644
--- a/ui/src/app/core-services/datalake/datalake-rest.service.ts
+++ b/ui/src/app/core-services/datalake/datalake-rest.service.ts
@@ -19,7 +19,6 @@
 import { HttpClient, HttpRequest } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { Observable } from 'rxjs';
-import { AuthStatusService } from '../../services/auth-status.service';
 import { DataLakeMeasure, SpQueryResult } from '../../core-model/gen/streampipes-model';
 import { map } from 'rxjs/operators';
 import { DatalakeQueryParameters } from './DatalakeQueryParameters';
@@ -27,8 +26,7 @@ import { DatalakeQueryParameters } from './DatalakeQueryParameters';
 @Injectable()
 export class DatalakeRestService {
 
-  constructor(private http: HttpClient,
-              private authStatusService: AuthStatusService) {
+  constructor(private http: HttpClient) {
   }
 
   private get baseUrl() {
diff --git a/ui/src/app/core-services/shared/shared-dashboard.service.ts b/ui/src/app/core-services/shared/shared-dashboard.service.ts
index c5df99b..86d7044 100644
--- a/ui/src/app/core-services/shared/shared-dashboard.service.ts
+++ b/ui/src/app/core-services/shared/shared-dashboard.service.ts
@@ -19,15 +19,13 @@
 import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { Dashboard } from '../../dashboard/models/dashboard.model';
-import { AuthStatusService } from '../../services/auth-status.service';
-import {map} from "rxjs/operators";
-import {Observable} from "rxjs";
+import { map } from "rxjs/operators";
+import { Observable } from "rxjs";
 
 @Injectable()
 export class SharedDatalakeRestService {
 
-    constructor(private http: HttpClient,
-                private authStatusService: AuthStatusService) {
+    constructor(private http: HttpClient) {
     }
 
     getDashboards(dashboardUrl: string): Observable<Dashboard[]> {
diff --git a/ui/src/app/core-ui/core-ui.module.ts b/ui/src/app/core-ui/core-ui.module.ts
index 9265d2b..89a87c8 100644
--- a/ui/src/app/core-ui/core-ui.module.ts
+++ b/ui/src/app/core-ui/core-ui.module.ts
@@ -66,7 +66,6 @@ import { StaticOneOfInputComponent } from './static-properties/static-one-of-inp
 import { StaticRuntimeResolvableAnyInputComponent } from './static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component';
 import { StaticRuntimeResolvableOneOfInputComponent } from './static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component';
 import { RuntimeResolvableService } from './static-properties/static-runtime-resolvable-input/runtime-resolvable.service';
-import { StaticFileRestService } from './static-properties/static-file-input/static-file-rest.service';
 import { DisplayRecommendedPipe } from './static-properties/filter/display-recommended.pipe';
 import { ColorPickerModule } from 'ngx-color-picker';
 import { QuillModule } from 'ngx-quill';
@@ -148,7 +147,6 @@ import { AddToCollectionComponent } from './static-properties/static-collection/
     LabelingModeService,
     DialogService,
     RuntimeResolvableService,
-    StaticFileRestService
   ],
   entryComponents: [],
   exports: [
diff --git a/ui/src/app/core-ui/labels/services/label.service.ts b/ui/src/app/core-ui/labels/services/label.service.ts
index 9281166..56d612e 100644
--- a/ui/src/app/core-ui/labels/services/label.service.ts
+++ b/ui/src/app/core-ui/labels/services/label.service.ts
@@ -29,7 +29,7 @@ export class LabelService {
   private bufferedLabels = [];
 
   urlBase() {
-    return this.platformServicesCommons.apiBasePath();
+    return this.platformServicesCommons.apiBasePath;
   }
 
   constructor(
diff --git a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.ts b/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.ts
index 2519941..6b1be2d 100644
--- a/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.ts
+++ b/ui/src/app/core-ui/static-properties/static-file-input/static-file-input.component.ts
@@ -17,7 +17,6 @@
  */
 
 import { Component, EventEmitter, OnInit, Output } from '@angular/core';
-import { StaticFileRestService } from './static-file-rest.service';
 import { HttpEventType, HttpResponse } from '@angular/common/http';
 import { FileStaticProperty } from '../../../core-model/gen/streampipes-model';
 import { FilesService } from '../../../platform-services/apis/files.service';
@@ -53,8 +52,7 @@ export class StaticFileInputComponent extends AbstractValidatedStaticPropertyRen
 
     filesLoaded = false;
 
-    constructor(private staticFileRestService: StaticFileRestService,
-                private filesService: FilesService) {
+    constructor(private filesService: FilesService) {
         super();
 
     }
diff --git a/ui/src/app/core-ui/static-properties/static-file-input/static-file-rest.service.ts b/ui/src/app/core-ui/static-properties/static-file-input/static-file-rest.service.ts
deleted file mode 100644
index f965cb7..0000000
--- a/ui/src/app/core-ui/static-properties/static-file-input/static-file-rest.service.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import {Injectable} from '@angular/core';
-import {Observable} from 'rxjs';
-import {HttpClient, HttpEvent, HttpParams, HttpRequest} from '@angular/common/http';
-import {AuthStatusService} from '../../../services/auth-status.service';
-
-@Injectable()
-export class StaticFileRestService {
-
-
-    constructor(
-        private http: HttpClient,
-        private authStatusService: AuthStatusService
-    ) {
-    }
-
-    private get baseUrl() {
-        return '/streampipes-connect';
-    }
-
-    private get url() {
-        // TODO
-        return this.baseUrl + '/api/v1/' + this.authStatusService.email + '/master/file'
-    }
-
-
-    /**
-     *  @deprecated use uploadFile
-     */
-    upload(file: File): Observable<HttpEvent<any>> {
-        const data: FormData = new FormData();
-        data.append('file_upload', file, file.name);
-
-        let params = new HttpParams();
-        const options = {
-            params: params,
-            reportProgress: true,
-        };
-
-        const req = new HttpRequest('POST', this.url, data, options);
-        return this.http.request(req);
-    }
-
-    uploadFile(adapterId, file: File): Observable<HttpEvent<any>> {
-        const data: FormData = new FormData();
-        data.append('file_upload', file, file.name);
-        data.append('appId', adapterId);
-
-        let params = new HttpParams();
-        const options = {
-            params: params,
-            reportProgress: true,
-        };
-
-        //let url = this.url + '/' + adapterId;
-        const req = new HttpRequest('POST', this.url, data, options);
-        return this.http.request(req);
-    }
-
-    /**
-     *  @deprecated use deleteFile
-     */
-    delete(id: string) {
-        return this.http.delete(this.url + '/' + id);
-    }
-
-    deleteFile(adapterId: string, id: string) {
-        const req = new HttpRequest('DELETE', this.url + '/' + id, adapterId);
-        return this.http.request(req);
-    }
-}
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/runtime-resolvable.service.ts b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/runtime-resolvable.service.ts
index 1f95fe6..bec052d 100644
--- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/runtime-resolvable.service.ts
+++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/runtime-resolvable.service.ts
@@ -23,7 +23,6 @@ import {
 } from '../../../core-model/gen/streampipes-model';
 import { map } from 'rxjs/operators';
 import { HttpClient } from '@angular/common/http';
-import { AuthStatusService } from '../../../services/auth-status.service';
 import { PlatformServicesCommons } from '../../../platform-services/apis/commons.service';
 import { Injectable } from '@angular/core';
 
@@ -31,22 +30,20 @@ import { Injectable } from '@angular/core';
 export class RuntimeResolvableService {
 
   constructor(private http: HttpClient,
-              private authStatusService: AuthStatusService,
               private platformServicesCommons: PlatformServicesCommons) {
 
   }
 
   fetchRemoteOptionsForAdapter(resolvableOptionsParameterRequest: RuntimeOptionsRequest, adapterId: string): Observable<RuntimeOptionsResponse> {
     const url: string = '/streampipes-backend/api/v2/connect/'
-        + this.authStatusService.email
-        + '/master/resolvable/'
+        + 'master/resolvable/'
         + encodeURIComponent(adapterId)
         + '/configurations';
     return this.fetchRemoteOptions(url, resolvableOptionsParameterRequest);
   }
 
   fetchRemoteOptionsForPipelineElement(resolvableOptionsParameterRequest: RuntimeOptionsRequest): Observable<RuntimeOptionsResponse> {
-    const url: string = this.platformServicesCommons.apiBasePath() + '/pe/options';
+    const url: string = this.platformServicesCommons.apiBasePath + '/pe/options';
     return this.fetchRemoteOptions(url, resolvableOptionsParameterRequest);
   }
 
diff --git a/ui/src/app/core/components/iconbar/iconbar.component.html b/ui/src/app/core/components/iconbar/iconbar.component.html
index 051b245..b5a74ee 100644
--- a/ui/src/app/core/components/iconbar/iconbar.component.html
+++ b/ui/src/app/core/components/iconbar/iconbar.component.html
@@ -31,8 +31,8 @@
         <button mat-button mat-icon-button class="md-icon-button button-margin-iconbar iconbar-size"
                 (click)="go('notifications')"
                 matTooltip="Notifications" matTooltipPosition="right">
-            <mat-icon [matBadge]="NotificationCountService.unreadNotificationCount"
-                      [matBadgeHidden]="NotificationCountService.unreadNotificationCount == 0"
+            <mat-icon [matBadge]="notificationCountService.unreadNotificationCount"
+                      [matBadgeHidden]="notificationCountService.unreadNotificationCount == 0"
                       [ngClass]="'notifications' === activePage ?'sp-navbar-icon-selected' : 'sp-navbar-icon'">chat
             </mat-icon>
         </button>
diff --git a/ui/src/app/core/components/iconbar/iconbar.component.ts b/ui/src/app/core/components/iconbar/iconbar.component.ts
index 46aabdb..8e20f84 100644
--- a/ui/src/app/core/components/iconbar/iconbar.component.ts
+++ b/ui/src/app/core/components/iconbar/iconbar.component.ts
@@ -16,13 +16,13 @@
  *
  */
 
-import {Component, OnInit} from "@angular/core";
-import {BaseNavigationComponent} from "../base-navigation.component";
-import {Client} from "@stomp/stompjs";
-import {NotificationItem} from "../../../notifications/model/notifications.model";
-import {Router} from "@angular/router";
-import {AuthStatusService} from "../../../services/auth-status.service";
-import {NotificationCountService} from "../../../services/notification-count-service";
+import { Component, OnInit } from '@angular/core';
+import { BaseNavigationComponent } from '../base-navigation.component';
+import { Client } from '@stomp/stompjs';
+import { NotificationItem } from '../../../notifications/model/notifications.model';
+import { Router } from '@angular/router';
+import { NotificationCountService } from '../../../services/notification-count-service';
+import { AuthService } from '../../../services/auth.service';
 
 @Component({
   selector: 'iconbar',
@@ -31,32 +31,32 @@ import {NotificationCountService} from "../../../services/notification-count-ser
 })
 export class IconbarComponent extends BaseNavigationComponent implements OnInit {
 
-  unreadNotifications: number = 0;
+  unreadNotifications = 0;
 
-  constructor(Router: Router,
-              private AuthStatusService: AuthStatusService,
-              public NotificationCountService: NotificationCountService) {
-    super(Router);
+  constructor(router: Router,
+              private authService: AuthService,
+              public notificationCountService: NotificationCountService) {
+    super(router);
   }
 
   ngOnInit(): void {
     super.onInit();
     this.connectToBroker();
-    this.NotificationCountService.loadUnreadNotifications();
+    this.notificationCountService.loadUnreadNotifications();
   }
 
   connectToBroker() {
-    var login = 'admin';
-    var passcode = 'admin';
-    var websocketProtocol = window.location.protocol === "http:" ? "ws" : "wss";
-    var brokerUrl = websocketProtocol + '://' + window.location.hostname + ':' + window.location.port + '/streampipes/ws';
-    var inputTopic = '/topic/org.apache.streampipes.notifications.' + this.AuthStatusService.email;
+    const login = 'admin';
+    const passcode = 'admin';
+    const websocketProtocol = window.location.protocol === 'http:' ? 'ws' : 'wss';
+    const brokerUrl = websocketProtocol + '://' + window.location.hostname + ':' + window.location.port + '/streampipes/ws';
+    const inputTopic = '/topic/org.apache.streampipes.notifications.' + this.authService.getCurrentUser().email;
 
-    let stompClient = new Client({
+    const stompClient = new Client({
       brokerURL: brokerUrl,
       connectHeaders: {
-        login: login,
-        passcode: passcode
+        login,
+        passcode
       },
       reconnectDelay: 5000
     });
@@ -64,7 +64,7 @@ export class IconbarComponent extends BaseNavigationComponent implements OnInit
     stompClient.onConnect = (frame) => {
 
       stompClient.subscribe(inputTopic, message => {
-        this.NotificationCountService.increaseNotificationCount(JSON.parse(message.body) as NotificationItem);
+        this.notificationCountService.increaseNotificationCount(JSON.parse(message.body) as NotificationItem);
       });
     };
 
diff --git a/ui/src/app/core/components/streampipes/streampipes.component.html b/ui/src/app/core/components/streampipes/streampipes.component.html
index 3154e84..168f6e2 100644
--- a/ui/src/app/core/components/streampipes/streampipes.component.html
+++ b/ui/src/app/core/components/streampipes/streampipes.component.html
@@ -16,7 +16,7 @@
   ~
   -->
 
-<div [ngClass]="authStatusService.darkMode ? 'dark-mode base-style' : 'light-mode base-style'">
+<div [ngClass]="darkMode ? 'dark-mode base-style' : 'light-mode base-style'">
     <div class="sp-toolbar-outer">
         <toolbar></toolbar>
     </div>
diff --git a/ui/src/app/core/components/streampipes/streampipes.component.ts b/ui/src/app/core/components/streampipes/streampipes.component.ts
index 954d1ba..6a80133 100644
--- a/ui/src/app/core/components/streampipes/streampipes.component.ts
+++ b/ui/src/app/core/components/streampipes/streampipes.component.ts
@@ -16,8 +16,8 @@
  *
  */
 
-import {Component, OnInit} from "@angular/core";
-import {AuthStatusService} from "../../../services/auth-status.service";
+import { Component, OnInit } from '@angular/core';
+import { AuthService } from '../../../services/auth.service';
 
 @Component({
   selector: 'streampipes',
@@ -26,11 +26,14 @@ import {AuthStatusService} from "../../../services/auth-status.service";
 })
 export class StreampipesComponent implements OnInit {
 
-  constructor(public authStatusService: AuthStatusService) {
+  darkMode: boolean;
+
+  constructor(public authService: AuthService) {
 
   }
 
   ngOnInit(): void {
+    this.authService.darkMode$.subscribe(dm => this.darkMode = dm);
   }
 
 
diff --git a/ui/src/app/core/components/toolbar/toolbar.component.ts b/ui/src/app/core/components/toolbar/toolbar.component.ts
index 9af947f..a8604cb 100644
--- a/ui/src/app/core/components/toolbar/toolbar.component.ts
+++ b/ui/src/app/core/components/toolbar/toolbar.component.ts
@@ -16,16 +16,16 @@
  *
  */
 
-import {Component, HostBinding, OnInit, ViewChild} from "@angular/core";
-import {BaseNavigationComponent} from "../base-navigation.component";
-import {Router} from "@angular/router";
-import {RestApi} from "../../../services/rest-api.service";
-import {AuthStatusService} from "../../../services/auth-status.service";
-import {MatMenuTrigger} from "@angular/material/menu";
-import {FormControl} from "@angular/forms";
-import {OverlayContainer} from "@angular/cdk/overlay";
-import {ProfileService} from "../../../profile/profile.service";
-import {VersionInfo} from "../../../info/versions/service/version-info.model";
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { BaseNavigationComponent } from '../base-navigation.component';
+import { Router } from '@angular/router';
+import { RestApi } from '../../../services/rest-api.service';
+import { MatMenuTrigger } from '@angular/material/menu';
+import { FormControl } from '@angular/forms';
+import { OverlayContainer } from '@angular/cdk/overlay';
+import { ProfileService } from '../../../profile/profile.service';
+import { VersionInfo } from '../../../info/versions/service/version-info.model';
+import { AuthService } from '../../../services/auth.service';
 
 @Component({
   selector: 'toolbar',
@@ -39,76 +39,79 @@ export class ToolbarComponent extends BaseNavigationComponent implements OnInit
 
   userEmail;
   versionInfo: VersionInfo;
+  darkMode: boolean;
 
   appearanceControl: FormControl;
 
-  constructor(Router: Router,
+  constructor(router: Router,
               private profileService: ProfileService,
-              private RestApi: RestApi,
-              public AuthStatusService: AuthStatusService,
-              private overlay: OverlayContainer) {
-    super(Router);
+              private restApi: RestApi,
+              private overlay: OverlayContainer,
+              private authService: AuthService) {
+    super(router);
   }
 
   ngOnInit(): void {
     this.getVersion();
-    this.userEmail = this.AuthStatusService.email;
-    this.profileService.getUserProfile().subscribe(user => {
-      this.AuthStatusService.darkMode = user.darkMode;
-      this.modifyAppearance(user.darkMode);
-    })
-    this.appearanceControl = new FormControl(this.AuthStatusService.darkMode);
-    //this.modifyAppearance(this.AuthStatusService.darkMode);
+    this.authService.user$.subscribe(user => {
+      this.userEmail = user.displayName;
+      this.profileService.getUserProfile().subscribe(userInfo => {
+        this.darkMode = this.authService.darkMode$.getValue();
+        this.modifyAppearance(userInfo.darkMode);
+      });
+    });
+
+    this.appearanceControl = new FormControl(this.authService.darkMode$.getValue());
     this.appearanceControl.valueChanges.subscribe(darkMode => {
-      this.AuthStatusService.darkMode = darkMode;
+      this.authService.darkMode$.next(darkMode);
       this.modifyAppearance(darkMode);
-
     });
-    //this.darkMode = this.AuthStatusService.darkMode;
     super.onInit();
   }
 
   modifyAppearance(darkMode: boolean) {
     if (darkMode) {
-      this.overlay.getContainerElement().classList.remove("light-mode");
-      this.overlay.getContainerElement().classList.add("dark-mode");
+      this.overlay.getContainerElement().classList.remove('light-mode');
+      this.overlay.getContainerElement().classList.add('dark-mode');
     } else {
-      this.overlay.getContainerElement().classList.remove("dark-mode");
-      this.overlay.getContainerElement().classList.add("light-mode");
+      this.overlay.getContainerElement().classList.remove('dark-mode');
+      this.overlay.getContainerElement().classList.add('light-mode');
     }
   }
 
   closeFeedbackWindow() {
-    //this.feedbackOpen = false;
+    // this.feedbackOpen = false;
     this.feedbackOpen.closeMenu();
   }
 
   openDocumentation() {
     window.open('https://streampipes.apache.org/docs', '_blank');
-  };
+  }
 
   openInfo() {
-    this.Router.navigate(["info"]);
-    this.activePage = "Info";
+    this.Router.navigate(['info']);
+    this.activePage = 'Info';
   }
 
   openProfile() {
-    this.Router.navigate(["profile"]);
-    this.activePage = "Profile";
+    this.Router.navigate(['profile']);
+    this.activePage = 'Profile';
   }
 
   logout() {
-    this.RestApi.logout().subscribe(() => {
-      this.AuthStatusService.user = undefined;
-      this.AuthStatusService.authenticated = false;
-      this.Router.navigateByUrl('login');
-    });
-  };
+    this.authService.logout();
+    this.Router.navigate(['login']);
+    // this.RestApi.logout().subscribe(() => {
+    //   this.AuthStatusService.user = undefined;
+    //   this.AuthStatusService.authenticated = false;
+    //   this.Router.navigateByUrl('login');
+    // });
+  }
 
-  getVersion(){
-    this.RestApi.getVersionInfo().subscribe((response) => {
+  getVersion() {
+    this.restApi.getVersionInfo().subscribe((response) => {
       this.versionInfo = response as VersionInfo;
-    })
+    });
   }
 
 }
diff --git a/ui/src/app/dashboard/services/dashboard.service.ts b/ui/src/app/dashboard/services/dashboard.service.ts
index b436658..ec36ed4 100644
--- a/ui/src/app/dashboard/services/dashboard.service.ts
+++ b/ui/src/app/dashboard/services/dashboard.service.ts
@@ -20,7 +20,6 @@ import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { map } from 'rxjs/operators';
 import { Observable } from 'rxjs';
-import { AuthStatusService } from '../../services/auth-status.service';
 import { Dashboard } from '../models/dashboard.model';
 import { MeasurementUnit } from '../../core-model/measurement-unit/MeasurementUnit';
 import {
@@ -35,7 +34,6 @@ export class DashboardService {
 
 
   constructor(private http: HttpClient,
-              private authStatusService: AuthStatusService,
               private platformServicesCommons: PlatformServicesCommons) {
   }
 
@@ -94,7 +92,7 @@ export class DashboardService {
   }
 
   private get baseUrl() {
-    return this.platformServicesCommons.apiBasePath();
+    return this.platformServicesCommons.apiBasePath;
   }
 
   private get measurementUnitsUrl() {
diff --git a/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.ts b/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.ts
index eea09a4..9793c0d 100644
--- a/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.ts
+++ b/ui/src/app/editor/dialog/welcome-tour/welcome-tour.component.ts
@@ -16,11 +16,11 @@
  *
  */
 
-import {DialogRef} from "../../../core-ui/dialog/base-dialog/dialog-ref";
-import {RestApi} from "../../../services/rest-api.service";
-import {ShepherdService} from "../../../services/tour/shepherd.service";
-import {Component} from "@angular/core";
-import {AppConstants} from "../../../services/app.constants";
+import { DialogRef } from "../../../core-ui/dialog/base-dialog/dialog-ref";
+import { RestApi } from "../../../services/rest-api.service";
+import { ShepherdService } from "../../../services/tour/shepherd.service";
+import { Component } from "@angular/core";
+import { AppConstants } from "../../../services/app.constants";
 
 @Component({
   selector: 'welcome-tour',
@@ -51,5 +51,5 @@ export class WelcomeTourComponent {
 
   close() {
     this.DialogRef.close();
-  };
+  }
 }
diff --git a/ui/src/app/editor/editor.component.ts b/ui/src/app/editor/editor.component.ts
index f281b24..241cfb7 100644
--- a/ui/src/app/editor/editor.component.ts
+++ b/ui/src/app/editor/editor.component.ts
@@ -16,30 +16,30 @@
  *
  */
 
-import {Component, Inject, OnInit} from "@angular/core";
-import {EditorService} from "./services/editor.service";
+import { Component, OnInit } from '@angular/core';
+import { EditorService } from './services/editor.service';
 import {
   DataProcessorInvocation,
   DataSinkInvocation,
   DataSourceDescription,
   SpDataSet,
   SpDataStream
-} from "../core-model/gen/streampipes-model";
-import {PipelineElementService} from "../platform-services/apis/pipeline-element.service";
+} from '../core-model/gen/streampipes-model';
+import { PipelineElementService } from '../platform-services/apis/pipeline-element.service';
 import {
-    PipelineElementConfig, PipelineElementIdentifier,
-    PipelineElementType,
-    PipelineElementUnion, TabsModel
-} from "./model/editor.model";
-import {PipelineElementTypeUtils} from "./utils/editor.utils";
-import {AuthStatusService} from "../services/auth-status.service";
-import {PanelType} from "../core-ui/dialog/base-dialog/base-dialog.model";
-import {WelcomeTourComponent} from "./dialog/welcome-tour/welcome-tour.component";
-import {DialogService} from "../core-ui/dialog/base-dialog/base-dialog.service";
-import {MissingElementsForTutorialComponent} from "./dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component";
-import {ShepherdService} from "../services/tour/shepherd.service";
-import {ActivatedRoute} from "@angular/router";
-import {EditorConstants} from "./constants/editor.constants";
+  PipelineElementConfig,
+  PipelineElementIdentifier,
+  PipelineElementUnion,
+  TabsModel
+} from './model/editor.model';
+import { PanelType } from '../core-ui/dialog/base-dialog/base-dialog.model';
+import { WelcomeTourComponent } from './dialog/welcome-tour/welcome-tour.component';
+import { DialogService } from '../core-ui/dialog/base-dialog/base-dialog.service';
+import { MissingElementsForTutorialComponent } from './dialog/missing-elements-for-tutorial/missing-elements-for-tutorial.component';
+import { ShepherdService } from '../services/tour/shepherd.service';
+import { ActivatedRoute } from '@angular/router';
+import { EditorConstants } from './constants/editor.constants';
+import { AuthService } from '../services/auth.service';
 
 @Component({
     selector: 'editor',
@@ -48,7 +48,7 @@ import {EditorConstants} from "./constants/editor.constants";
 })
 export class EditorComponent implements OnInit {
 
-    selectedIndex: number = 1;
+    selectedIndex = 1;
     activeType: PipelineElementIdentifier = EditorConstants.DATA_STREAM_IDENTIFIER;
     activeShorthand: string;
 
@@ -58,56 +58,56 @@ export class EditorComponent implements OnInit {
     availableDataSinks: DataSinkInvocation[] = [];
 
     allElements: PipelineElementUnion[] = [];
-    currentElements: Array<(SpDataStream | DataProcessorInvocation | DataSinkInvocation)> = [];
+    currentElements: (SpDataStream | DataProcessorInvocation | DataSinkInvocation)[] = [];
 
     rawPipelineModel: PipelineElementConfig[] = [];
     currentModifiedPipelineId: string;
 
     elementsLoaded = [false, false, false];
-    allElementsLoaded: boolean = false;
+    allElementsLoaded = false;
 
-    requiredStreamForTutorialAppId: any = "org.apache.streampipes.sources.simulator.flowrate1";
-    requiredProcessorForTutorialAppId: any = "org.apache.streampipes.processors.filters.jvm.numericalfilter";
-    requiredSinkForTutorialAppId: any = "org.apache.streampipes.sinks.internal.jvm.dashboard";
+    requiredStreamForTutorialAppId: any = 'org.apache.streampipes.sources.simulator.flowrate1';
+    requiredProcessorForTutorialAppId: any = 'org.apache.streampipes.processors.filters.jvm.numericalfilter';
+    requiredSinkForTutorialAppId: any = 'org.apache.streampipes.sinks.internal.jvm.dashboard';
     missingElementsForTutorial: any = [];
 
-    pipelineCanvasMaximized: boolean = false;
+    pipelineCanvasMaximized = false;
 
-    isTutorialOpen: boolean = false;
+    isTutorialOpen = false;
 
     tabs: TabsModel[] = [
         {
             title: 'Data Sets',
             type: EditorConstants.DATA_SET_IDENTIFIER,
-            shorthand: "set"
+            shorthand: 'set'
         },
         {
             title: 'Data Streams',
             type: EditorConstants.DATA_STREAM_IDENTIFIER,
-            shorthand: "stream"
+            shorthand: 'stream'
         },
         {
             title: 'Data Processors',
             type: EditorConstants.DATA_PROCESSOR_IDENTIFIER,
-            shorthand: "sepa"
+            shorthand: 'sepa'
         },
         {
             title: 'Data Sinks',
             type: EditorConstants.DATA_SINK_IDENTIFIER,
-            shorthand: "action"
+            shorthand: 'action'
         }
     ];
 
     constructor(private editorService: EditorService,
                 private pipelineElementService: PipelineElementService,
-                private AuthStatusService: AuthStatusService,
+                private authService: AuthService,
                 private dialogService: DialogService,
                 private shepherdService: ShepherdService,
-                private ActivatedRoute: ActivatedRoute) {
+                private activatedRoute: ActivatedRoute) {
     }
 
     ngOnInit() {
-        this.ActivatedRoute.queryParams.subscribe(params => {
+        this.activatedRoute.queryParams.subscribe(params => {
             if (params['pipeline']) {
                 this.currentModifiedPipelineId = params['pipeline'];
             }
@@ -118,7 +118,7 @@ export class EditorComponent implements OnInit {
             this.afterPipelineElementLoaded(0);
         });
         this.pipelineElementService.getDataStreams().subscribe(streams => {
-            //let allStreams = this.collectStreams(sources);
+            // let allStreams = this.collectStreams(sources);
             this.availableDataStreams = streams.filter(s => !(s instanceof SpDataSet));
             this.availableDataSets = streams
                 .filter(s => s instanceof SpDataSet)
@@ -133,7 +133,7 @@ export class EditorComponent implements OnInit {
             this.availableDataSinks = sinks;
             this.allElements = this.allElements.concat(this.availableDataSinks);
             this.afterPipelineElementLoaded(2);
-        })
+        });
 
     }
 
@@ -146,28 +146,23 @@ export class EditorComponent implements OnInit {
     }
 
     checkForTutorial() {
-        if (this.AuthStatusService.email != undefined) {
-            this.editorService
-                .getUserDetails()
-                .subscribe(user => {
-                    if ((!user.hideTutorial) && !this.isTutorialOpen) {
-                        if (this.requiredPipelineElementsForTourPresent()) {
-                            this.isTutorialOpen = true;
-                            this.dialogService.open(WelcomeTourComponent, {
-                                panelType: PanelType.STANDARD_PANEL,
-                                title: "Welcome to StreamPipes",
-                                data: {
-                                    "user": user
-                                }
-                            });
-                        }
+        const currentUser = this.authService.getCurrentUser();
+        if (currentUser.showTutorial && !this.isTutorialOpen) {
+            if (this.requiredPipelineElementsForTourPresent()) {
+                this.isTutorialOpen = true;
+                this.dialogService.open(WelcomeTourComponent, {
+                    panelType: PanelType.STANDARD_PANEL,
+                    title: 'Welcome to StreamPipes',
+                    data: {
+                        'user': currentUser.displayName
                     }
                 });
+            }
         }
     }
 
-    collectStreams(sources: Array<DataSourceDescription>): SpDataStream[] {
-        let streams: SpDataStream[] = [];
+    collectStreams(sources: DataSourceDescription[]): SpDataStream[] {
+        const streams: SpDataStream[] = [];
         sources.forEach(source => {
             source.spDataStreams.forEach(stream => {
                 streams.push(stream);
@@ -176,16 +171,16 @@ export class EditorComponent implements OnInit {
         return streams;
     }
 
-    selectPipelineElements(index : number) {
+    selectPipelineElements(index: number) {
         this.selectedIndex = index;
         this.activeType = this.tabs[index].type;
         this.activeShorthand = this.tabs[index].shorthand;
         this.currentElements = this.allElements
-            .filter(pe => pe["@class"] === this.activeType)
+            .filter(pe => pe['@class'] === this.activeType)
             .sort((a, b) => {
                 return a.name.localeCompare(b.name);
             });
-        this.shepherdService.trigger("select-" +this.activeShorthand);
+        this.shepherdService.trigger('select-' + this.activeShorthand);
     }
 
     startCreatePipelineTour() {
@@ -194,20 +189,20 @@ export class EditorComponent implements OnInit {
         } else {
             this.missingElementsForTutorial = [];
             if (!this.requiredStreamForTourPresent()) {
-                this.missingElementsForTutorial.push({"name" : "Flow Rate 1", "appId" : this.requiredStreamForTutorialAppId });
+                this.missingElementsForTutorial.push({'name' : 'Flow Rate 1', 'appId' : this.requiredStreamForTutorialAppId });
             }
             if (!this.requiredProcessorForTourPresent()) {
-                this.missingElementsForTutorial.push({"name" : "Numerical Filter", "appId" : this.requiredProcessorForTutorialAppId});
+                this.missingElementsForTutorial.push({'name' : 'Numerical Filter', 'appId' : this.requiredProcessorForTutorialAppId});
             }
             if (!this.requiredSinkForTourPresent()) {
-                this.missingElementsForTutorial.push({"name" : "Dashboard Sink", "appId" : this.requiredSinkForTutorialAppId});
+                this.missingElementsForTutorial.push({'name' : 'Dashboard Sink', 'appId' : this.requiredSinkForTutorialAppId});
             }
 
             this.dialogService.open(MissingElementsForTutorialComponent, {
                 panelType: PanelType.STANDARD_PANEL,
-                title: "Tutorial requires pipeline elements",
+                title: 'Tutorial requires pipeline elements',
                 data: {
-                    "missingElementsForTutorial": this.missingElementsForTutorial
+                    'missingElementsForTutorial': this.missingElementsForTutorial
                 }
             });
         }
diff --git a/ui/src/app/editor/services/editor.service.ts b/ui/src/app/editor/services/editor.service.ts
index 189924e..c990a46 100644
--- a/ui/src/app/editor/services/editor.service.ts
+++ b/ui/src/app/editor/services/editor.service.ts
@@ -53,7 +53,7 @@ export class EditorService {
     }
 
     get apiBasePath() {
-      return this.platformServicesCommons.apiBasePath();
+      return this.platformServicesCommons.apiBasePath;
     }
 
     recommendPipelineElement(pipeline): Observable<PipelineElementRecommendationMessage> {
@@ -69,7 +69,7 @@ export class EditorService {
     }
 
   updateDataSet(dataSet): Observable<DataSetModificationMessage> {
-    return this.http.post(this.platformServicesCommons.apiBasePath() + '/pipelines/update/dataset', dataSet)
+    return this.http.post(this.platformServicesCommons.apiBasePath + '/pipelines/update/dataset', dataSet)
         .pipe(map(data => DataSetModificationMessage.fromData(data as DataSetModificationMessage)));
   }
 
@@ -106,23 +106,15 @@ export class EditorService {
     }
 
     getEpCategories() {
-        return this.http.get(this.platformServicesCommons.unauthenticatedBasePath + '/categories/ep');
+        return this.http.get(this.platformServicesCommons.apiBasePath + '/categories/ep');
     }
 
     getEpaCategories() {
-        return this.http.get(this.platformServicesCommons.unauthenticatedBasePath + '/categories/epa');
+        return this.http.get(this.platformServicesCommons.apiBasePath + '/categories/epa');
     }
 
     getEcCategories() {
-        return this.http.get(this.platformServicesCommons.unauthenticatedBasePath + '/categories/ec');
-    }
-
-    getUserDetails(): Observable<any> {
-        return this.http.get(this.platformServicesCommons.authUserBasePath());
-    }
-
-    updateUserDetails(user) {
-        return this.http.put(this.platformServicesCommons.authUserBasePath(), user);
+        return this.http.get(this.platformServicesCommons.apiBasePath + '/categories/ec');
     }
 
     updateCachedPipeline(rawPipelineModel: any) {
@@ -130,7 +122,7 @@ export class EditorService {
     }
 
     updateCachedCanvasMetadata(pipelineCanvasMetadata: PipelineCanvasMetadata) {
-      return this.http.post(this.platformServicesCommons.apiBasePath()
+      return this.http.post(this.platformServicesCommons.apiBasePath
           + '/pipeline-canvas-cache', pipelineCanvasMetadata);
     }
 
@@ -143,7 +135,7 @@ export class EditorService {
     }
 
     private get pipelinesResourceUrl() {
-        return this.platformServicesCommons.apiBasePath() + '/pipelines';
+        return this.platformServicesCommons.apiBasePath + '/pipelines';
     }
 
     announceConfiguredElement(pipelineElementDomId: string) {
diff --git a/ui/src/app/editor/services/object-provider.service.ts b/ui/src/app/editor/services/object-provider.service.ts
index 5e951c7..ff64406 100644
--- a/ui/src/app/editor/services/object-provider.service.ts
+++ b/ui/src/app/editor/services/object-provider.service.ts
@@ -16,12 +16,12 @@
  *
  */
 
-import {Injectable} from "@angular/core";
-import {RestApi} from "../../services/rest-api.service";
-import {InvocablePipelineElementUnion, PipelineElementConfig} from "../model/editor.model";
-import {DataSinkInvocation, Pipeline} from "../../core-model/gen/streampipes-model";
-import {EditorService} from "./editor.service";
-import {JsplumbFactoryService} from "./jsplumb-factory.service";
+import { Injectable } from "@angular/core";
+import { RestApi } from "../../services/rest-api.service";
+import { InvocablePipelineElementUnion, PipelineElementConfig } from "../model/editor.model";
+import { DataSinkInvocation, Pipeline } from "../../core-model/gen/streampipes-model";
+import { EditorService } from "./editor.service";
+import { JsplumbFactoryService } from "./jsplumb-factory.service";
 
 @Injectable()
 export class ObjectProvider {
@@ -107,10 +107,5 @@ export class ObjectProvider {
 
     updatePipeline(pipeline: Pipeline) {
         return this.EditorService.updatePartialPipeline(pipeline);
-    };
-
-    storePipeline(pipeline) {
-        return this.RestApi.storePipeline(pipeline);
-
     }
 }
diff --git a/ui/src/app/platform-services/apis/measurement-units.service.ts b/ui/src/app/http-interceptor.ts
similarity index 58%
copy from ui/src/app/platform-services/apis/measurement-units.service.ts
copy to ui/src/app/http-interceptor.ts
index 65b3e75..e0a52d8 100644
--- a/ui/src/app/platform-services/apis/measurement-units.service.ts
+++ b/ui/src/app/http-interceptor.ts
@@ -16,21 +16,32 @@
  *
  */
 
-import { Injectable } from '@angular/core';
-import { HttpClient } from '@angular/common/http';
-import { PlatformServicesCommons } from './commons.service';
+import {
+  HttpEvent,
+  HttpHandler,
+  HttpInterceptor,
+  HttpRequest,
+  HttpResponse
+} from '@angular/common/http';
 import { Observable } from 'rxjs';
+import { AuthService } from './services/auth.service';
+import { Injectable } from '@angular/core';
 import { map } from 'rxjs/operators';
 
 @Injectable()
-export class MeasurementUnitsService {
+export class HttpInterceptorProvider implements HttpInterceptor {
 
-  constructor(private http: HttpClient,
-              private platformServicesCommons: PlatformServicesCommons) { }
+  constructor(private authService: AuthService) { }
 
-  getAllMeasurementUnits(): Observable<any> {
-    return this.http.get(this.platformServicesCommons.apiBasePath() + '/measurement-units').pipe(map(response => {
-      return response;
-    }));
+  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
+    if (this.authService.authToken$.getValue()) {
+      const clonedReq = req.clone({
+        headers: req.headers
+            .set('Authorization', 'Bearer ' + this.authService.authToken$.getValue()),
+      });
+      return next.handle(clonedReq);
+    } else {
+      return next.handle(req);
+    }
   }
 }
diff --git a/ui/src/app/login/components/login/login.component.ts b/ui/src/app/login/components/login/login.component.ts
index ea7b3ca..3d170ca 100644
--- a/ui/src/app/login/components/login/login.component.ts
+++ b/ui/src/app/login/components/login/login.component.ts
@@ -16,13 +16,11 @@
  *
  */
 
-import {ShepherdService} from "../../../services/tour/shepherd.service";
-import {Component, Inject} from "@angular/core";
-import {RestApi} from "../../../services/rest-api.service";
-import {AuthStatusService} from "../../../services/auth-status.service";
-import {FormGroup} from "@angular/forms";
-import {LoginService} from "../../services/login.service";
-import {Router} from "@angular/router";
+import { ShepherdService } from '../../../services/tour/shepherd.service';
+import { Component } from '@angular/core';
+import { LoginService } from '../../services/login.service';
+import { Router } from '@angular/router';
+import { AuthService } from '../../../services/auth.service';
 
 @Component({
     selector: 'login',
@@ -35,45 +33,34 @@ export class LoginComponent {
     credentials: any;
 
     constructor(private loginService: LoginService,
-                private Router: Router,
-                private AuthStatusService: AuthStatusService,
-                private ShepherdService: ShepherdService) {
+                private router: Router,
+                private shepherdService: ShepherdService,
+                private authService: AuthService) {
         this.loading = false;
         this.authenticationFailed = false;
         this.credentials = {};
     }
 
-    openDocumentation(){
+    openDocumentation() {
        window.open('https://streampipes.apache.org/docs', '_blank');
-    };
+    }
 
     logIn() {
         this.authenticationFailed = false;
         this.loading = true;
         this.loginService.login(this.credentials)
             .subscribe(response => { // success
+                    this.authService.login(response);
                     this.loading = false;
-                    if (response.success) {
-                        this.AuthStatusService.username = response.info.authc.principal.username;
-                        this.AuthStatusService.email = response.info.authc.principal.email;
-                        this.AuthStatusService.token = response.token;
-                        this.AuthStatusService.authenticated = true;
-                        this.Router.navigateByUrl("");
-                    }
-                    else {
-                        this.AuthStatusService.authenticated = false;
-                        this.authenticationFailed = true;
-                    }
-
+                    this.router.navigate(['']);
                 }, response => { // error
                     this.loading = false;
-                    this.AuthStatusService.authenticated = false;
                     this.authenticationFailed = true;
                 }
-            )
-    };
+            );
+    }
 
     setSheperdServiceDelay() {
-        //this.ShepherdService.setTimeWaitMillies(100);
+        // this.ShepherdService.setTimeWaitMillies(100);
     }
-};
\ No newline at end of file
+}
diff --git a/ui/src/app/login/components/startup/startup.component.ts b/ui/src/app/login/components/startup/startup.component.ts
index 7d01845..7f8e34a 100644
--- a/ui/src/app/login/components/startup/startup.component.ts
+++ b/ui/src/app/login/components/startup/startup.component.ts
@@ -16,11 +16,10 @@
  *
  */
 
-import {AuthService} from "../../../services/auth.service";
-import {AuthStatusService} from "../../../services/auth-status.service";
-import {Component, Inject, OnInit} from "@angular/core";
-import {Router} from "@angular/router";
-import {AppConstants} from "../../../services/app.constants";
+import { AuthService } from '../../../services/auth.service';
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { AppConstants } from '../../../services/app.constants';
 
 @Component({
     selector: 'startup',
@@ -28,14 +27,13 @@ import {AppConstants} from "../../../services/app.constants";
 })
 export class StartupComponent implements OnInit {
 
-    progress: number = 0;
+    progress = 0;
     currentStep = 0;
     maxLoadingTimeInSeconds = 300;
     loadingIntervalInSeconds = 1;
 
-    constructor(private AuthService: AuthService,
-                private AuthStatusService: AuthStatusService,
-                private Router: Router,
+    constructor(private authService: AuthService,
+                private router: Router,
                 public appConstants: AppConstants) {
     }
 
@@ -44,16 +42,16 @@ export class StartupComponent implements OnInit {
     }
 
     checkStatus() {
-        this.AuthService.checkConfiguration().subscribe((configured) => {
+        this.authService.checkConfiguration().subscribe((configured) => {
             this.progress = 100;
-            let target: string = configured ? 'login' : 'setup';
-            this.Router.navigate([target]);
+            const target: string = configured ? 'login' : 'setup';
+            this.router.navigate([target]);
         }, () => {
             this.currentStep += this.loadingIntervalInSeconds;
             this.progress = (this.currentStep / this.maxLoadingTimeInSeconds) * 100;
             setTimeout(() => {
                 this.checkStatus();
-            }, this.loadingIntervalInSeconds*1000);
+            }, this.loadingIntervalInSeconds * 1000);
         });
     }
 }
diff --git a/ui/src/app/login/login.module.ts b/ui/src/app/login/login.module.ts
index 0ef6286..f763fa4 100644
--- a/ui/src/app/login/login.module.ts
+++ b/ui/src/app/login/login.module.ts
@@ -16,27 +16,25 @@
  *
  */
 
-import {NgModule} from '@angular/core';
-import {MatGridListModule} from '@angular/material/grid-list';
-import {MatIconModule} from '@angular/material/icon';
-import {FlexLayoutModule} from '@angular/flex-layout';
-import {CommonModule} from '@angular/common';
-import {LoginComponent} from "./components/login/login.component";
-import {SetupComponent} from "./components/setup/setup.component";
-import {MatCardModule} from "@angular/material/card";
-import {MatProgressSpinnerModule} from "@angular/material/progress-spinner";
-import {MatButtonModule} from "@angular/material/button";
-import {MatCheckboxModule} from "@angular/material/checkbox";
-import {MatFormFieldModule} from "@angular/material/form-field";
-import {FormsModule, ReactiveFormsModule} from "@angular/forms";
-import {MatInputModule} from "@angular/material/input";
-import {StartupComponent} from './components/startup/startup.component';
-import {MatDividerModule} from "@angular/material/divider";
-import {MatProgressBarModule} from "@angular/material/progress-bar";
-import {LoginService} from "./services/login.service";
-import {AuthStatusService} from "../services/auth-status.service";
-import {RestApi} from "../services/rest-api.service";
-import {AppRoutingModule} from "../app-routing.module";
+import { NgModule } from '@angular/core';
+import { MatGridListModule } from '@angular/material/grid-list';
+import { MatIconModule } from '@angular/material/icon';
+import { FlexLayoutModule } from '@angular/flex-layout';
+import { CommonModule } from '@angular/common';
+import { LoginComponent } from './components/login/login.component';
+import { SetupComponent } from './components/setup/setup.component';
+import { MatCardModule } from '@angular/material/card';
+import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatInputModule } from '@angular/material/input';
+import { StartupComponent } from './components/startup/startup.component';
+import { MatDividerModule } from '@angular/material/divider';
+import { MatProgressBarModule } from '@angular/material/progress-bar';
+import { LoginService } from './services/login.service';
+import { AppRoutingModule } from '../app-routing.module';
 
 @NgModule({
   imports: [
@@ -62,8 +60,7 @@ import {AppRoutingModule} from "../app-routing.module";
     StartupComponent,
   ],
   providers: [
-    LoginService,
-    AuthStatusService,
+    LoginService
   ],
   entryComponents: [
     LoginComponent,
diff --git a/ui/src/app/login/services/login.service.ts b/ui/src/app/login/services/login.service.ts
index 006cb1b..d3ac74d 100644
--- a/ui/src/app/login/services/login.service.ts
+++ b/ui/src/app/login/services/login.service.ts
@@ -16,10 +16,10 @@
  *
  */
 
-import {Injectable} from "@angular/core";
-import {HttpClient} from "@angular/common/http";
-import {PlatformServicesCommons} from "../../platform-services/apis/commons.service";
-import {Observable} from "rxjs";
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { PlatformServicesCommons } from '../../platform-services/apis/commons.service';
+import { Observable } from 'rxjs';
 
 @Injectable()
 export class LoginService {
@@ -29,10 +29,16 @@ export class LoginService {
   }
 
   login(credentials): Observable<any> {
-    return this.http.post(this.platformServicesCommons.unauthenticatedBasePath + "/admin/login", credentials);
+    return this.http.post(this.platformServicesCommons.apiBasePath + '/auth/login', credentials);
+  }
+
+  renewToken(): Observable<any> {
+    return this.http.get(this.platformServicesCommons.apiBasePath + '/auth/token/renew', {
+      headers: { ignoreLoadingBar: '' }
+    });
   }
 
   setupInstall(setup, installationStep): Observable<any> {
-    return this.http.post(this.platformServicesCommons.unauthenticatedBasePath + "/setup/install/" +installationStep, setup);
+    return this.http.post(this.platformServicesCommons.apiBasePath + '/setup/install/' + installationStep, setup);
   }
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/notifications/notifications.component.ts b/ui/src/app/notifications/notifications.component.ts
index 5f15856..64a2371 100644
--- a/ui/src/app/notifications/notifications.component.ts
+++ b/ui/src/app/notifications/notifications.component.ts
@@ -23,11 +23,11 @@ import { NotificationsService } from './service/notifications.service';
 import { Message } from '@stomp/stompjs';
 import { Subscription } from 'rxjs';
 import { RxStompService } from '@stomp/ng2-stompjs';
-import { AuthStatusService } from '../services/auth-status.service';
 import { NotificationUtils } from './utils/notifications.utils';
 import { NotificationCountService } from '../services/notification-count-service';
 import { FreeTextStaticProperty, Pipeline } from '../core-model/gen/streampipes-model';
 import { PipelineService } from '../platform-services/apis/pipeline.service';
+import { AuthService } from '../services/auth.service';
 
 @Component({
     selector: 'notifications',
@@ -62,15 +62,15 @@ export class NotificationsComponent implements OnInit, OnDestroy {
 
     newEventArriving = false;
 
-    constructor(private pipelineService: PipelineService,
-                private authStatusService: AuthStatusService,
+    constructor(private authService: AuthService,
+                private pipelineService: PipelineService,
                 public elementIconText: ElementIconText,
                 private notificationService: NotificationsService,
                 private rxStompService: RxStompService,
                 private notificationCountService: NotificationCountService) {
         this.notifications = [];
         this.unreadNotifications = [];
-        this.notificationTopic = NotificationsComponent.NOTIFICATION_TOPIC_PREFIX + authStatusService.email;
+        this.notificationTopic = NotificationsComponent.NOTIFICATION_TOPIC_PREFIX + this.authService.getCurrentUser().email;
     }
 
     ngOnInit() {
diff --git a/ui/src/app/notifications/service/notifications.service.ts b/ui/src/app/notifications/service/notifications.service.ts
index 2c60ca2..8ac5d39 100644
--- a/ui/src/app/notifications/service/notifications.service.ts
+++ b/ui/src/app/notifications/service/notifications.service.ts
@@ -16,9 +16,12 @@
  */
 
 import { HttpClient } from '@angular/common/http';
-import { AuthStatusService } from '../../services/auth-status.service';
 import { Observable } from 'rxjs';
-import { ExistingNotification, NotificationCount, NotificationItem } from '../model/notifications.model';
+import {
+    ExistingNotification,
+    NotificationCount,
+    NotificationItem
+} from '../model/notifications.model';
 import { Injectable } from '@angular/core';
 import { NotificationUtils } from '../utils/notifications.utils';
 import { map } from 'rxjs/operators';
@@ -28,7 +31,6 @@ import { PlatformServicesCommons } from '../../platform-services/apis/commons.se
 export class NotificationsService {
 
     constructor(private http: HttpClient,
-                private authStatusService: AuthStatusService,
                 private platformServicesCommons: PlatformServicesCommons) {
     }
 
@@ -59,6 +61,6 @@ export class NotificationsService {
     }
 
     private get notificationUrl() {
-        return this.platformServicesCommons.apiBasePath() + '/notifications';
+        return this.platformServicesCommons.apiBasePath + '/notifications';
     }
 }
diff --git a/ui/src/app/platform-services/apis/commons.service.ts b/ui/src/app/platform-services/apis/commons.service.ts
index 6ed5b73..7d3055d 100644
--- a/ui/src/app/platform-services/apis/commons.service.ts
+++ b/ui/src/app/platform-services/apis/commons.service.ts
@@ -16,27 +16,20 @@
  *
  */
 
-import {AuthStatusService} from "../../services/auth-status.service";
-import {Injectable} from "@angular/core";
+import { Injectable } from '@angular/core';
 
 @Injectable()
 export class PlatformServicesCommons {
 
-  constructor(private authStatusService: AuthStatusService) {
-
-  }
+  constructor() { }
 
   get basePath(): string {
     return '/streampipes-backend';
   }
 
-  apiBasePath() {
+  get apiBasePath() {
     return this.basePath + '/api/v2';
   }
-  
-  authUserBasePath() {
-    return this.basePath + '/api/v2/users/' + this.authStatusService.email;
-  }
 
   get unauthenticatedBasePath() {
     return this.basePath + '/api/v2';
diff --git a/ui/src/app/platform-services/apis/data-view-data-explorer.service.ts b/ui/src/app/platform-services/apis/data-view-data-explorer.service.ts
index 91c8ef6..0320f7d 100644
--- a/ui/src/app/platform-services/apis/data-view-data-explorer.service.ts
+++ b/ui/src/app/platform-services/apis/data-view-data-explorer.service.ts
@@ -20,7 +20,6 @@ import { HttpClient } from '@angular/common/http';
 import { Observable } from 'rxjs';
 import { map } from 'rxjs/operators';
 import { SharedDatalakeRestService } from '../../core-services/shared/shared-dashboard.service';
-import { AuthStatusService } from '../../services/auth-status.service';
 import { DataExplorerWidgetModel, DataLakeMeasure } from '../../core-model/gen/streampipes-model';
 import { Dashboard } from '../../dashboard/models/dashboard.model';
 import { Injectable } from '@angular/core';
@@ -33,7 +32,6 @@ export class DataViewDataExplorerService {
   localDashboards: Dashboard[] = [];
 
   constructor(private http: HttpClient,
-              private authStatusService: AuthStatusService,
               private dataLakeRestService: DatalakeRestService,
               private sharedDatalakeRestService: SharedDatalakeRestService) {
   }
diff --git a/ui/src/app/platform-services/apis/datalake-rest.service.ts b/ui/src/app/platform-services/apis/datalake-rest.service.ts
index 09e472d..f6d35cd 100644
--- a/ui/src/app/platform-services/apis/datalake-rest.service.ts
+++ b/ui/src/app/platform-services/apis/datalake-rest.service.ts
@@ -18,7 +18,6 @@
 
 import { Injectable } from '@angular/core';
 import { HttpClient, HttpRequest } from '@angular/common/http';
-import { AuthStatusService } from '../../services/auth-status.service';
 import { Observable } from 'rxjs';
 import { DataLakeMeasure, PageResult, SpQueryResult } from '../../core-model/gen/streampipes-model';
 import { map } from 'rxjs/operators';
@@ -26,8 +25,7 @@ import { DatalakeQueryParameters } from '../../core-services/datalake/DatalakeQu
 
 @Injectable()
 export class DatalakeRestService {
-  constructor(private http: HttpClient,
-              private authStatusService: AuthStatusService) {
+  constructor(private http: HttpClient) {
   }
 
   private get baseUrl() {
diff --git a/ui/src/app/platform-services/apis/files.service.ts b/ui/src/app/platform-services/apis/files.service.ts
index 480cc55..1267a6a 100644
--- a/ui/src/app/platform-services/apis/files.service.ts
+++ b/ui/src/app/platform-services/apis/files.service.ts
@@ -41,7 +41,7 @@ export class FilesService {
       reportProgress: true,
     };
 
-    const req = new HttpRequest('POST', this.platformServicesCommons.apiBasePath() + '/files', data, options);
+    const req = new HttpRequest('POST', this.platformServicesCommons.apiBasePath + '/files', data, options);
     return this.http.request(req);
   }
 
@@ -51,13 +51,13 @@ export class FilesService {
       requiredFiletypeAppendix = '?filetypes=' + requiredFiletypes.join();
     }
     return this.http
-        .get(this.platformServicesCommons.apiBasePath() + '/files' + requiredFiletypeAppendix)
+        .get(this.platformServicesCommons.apiBasePath + '/files' + requiredFiletypeAppendix)
         .pipe(map(response => {
           return (response as any[]).map(fm => FileMetadata.fromData(fm));
         }));
   }
 
   deleteFile(fileId: string) {
-    return this.http.delete(this.platformServicesCommons.apiBasePath() + '/files/' + fileId);
+    return this.http.delete(this.platformServicesCommons.apiBasePath + '/files/' + fileId);
   }
 }
diff --git a/ui/src/app/platform-services/apis/measurement-units.service.ts b/ui/src/app/platform-services/apis/measurement-units.service.ts
index 65b3e75..47e4f00 100644
--- a/ui/src/app/platform-services/apis/measurement-units.service.ts
+++ b/ui/src/app/platform-services/apis/measurement-units.service.ts
@@ -29,7 +29,7 @@ export class MeasurementUnitsService {
               private platformServicesCommons: PlatformServicesCommons) { }
 
   getAllMeasurementUnits(): Observable<any> {
-    return this.http.get(this.platformServicesCommons.apiBasePath() + '/measurement-units').pipe(map(response => {
+    return this.http.get(this.platformServicesCommons.apiBasePath + '/measurement-units').pipe(map(response => {
       return response;
     }));
   }
diff --git a/ui/src/app/platform-services/apis/pipeline-canvas-metadata.service.ts b/ui/src/app/platform-services/apis/pipeline-canvas-metadata.service.ts
index b7f72df..91dc597 100644
--- a/ui/src/app/platform-services/apis/pipeline-canvas-metadata.service.ts
+++ b/ui/src/app/platform-services/apis/pipeline-canvas-metadata.service.ts
@@ -52,7 +52,7 @@ export class PipelineCanvasMetadataService {
   }
 
   private get pipelineCanvasMetadataBasePath() {
-    return this.platformServicesCommons.apiBasePath() + '/pipeline-canvas-metadata';
+    return this.platformServicesCommons.apiBasePath + '/pipeline-canvas-metadata';
   }
 
   private get pipelineCanvasMetadataPipelinePath() {
diff --git a/ui/src/app/platform-services/apis/pipeline-element-endpoint.service.ts b/ui/src/app/platform-services/apis/pipeline-element-endpoint.service.ts
index d62d230..b81d64c 100644
--- a/ui/src/app/platform-services/apis/pipeline-element-endpoint.service.ts
+++ b/ui/src/app/platform-services/apis/pipeline-element-endpoint.service.ts
@@ -1,7 +1,7 @@
-import {Injectable} from "@angular/core";
-import {HttpClient, HttpParams} from "@angular/common/http";
-import {PlatformServicesCommons} from "./commons.service";
-import {Observable} from "rxjs";
+import { Injectable } from '@angular/core';
+import { HttpClient, HttpParams } from '@angular/common/http';
+import { PlatformServicesCommons } from './commons.service';
+import { Observable } from 'rxjs';
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -32,21 +32,21 @@ export class PipelineElementEndpointService {
     const payload = new HttpParams()
         .set('uri', elementUri)
         .set('publicElement', ispublic);
-    return this.http.post(this.platformServicesCommons.apiBasePath() + "/element", payload);
+    return this.http.post(this.platformServicesCommons.apiBasePath + '/element', payload);
   }
 
   addBatch(elementUris, ispublic): Observable<any> {
     const payload = new HttpParams()
         .set('uri', elementUris)
         .set('publicElement', ispublic);
-    return this.http.post(this.platformServicesCommons.apiBasePath() + "/element/batch", payload);
+    return this.http.post(this.platformServicesCommons.apiBasePath + '/element/batch', payload);
   }
 
   update(elementUri): Observable<any> {
-    return this.http.put(this.platformServicesCommons.apiBasePath() + "/element/" + encodeURIComponent(elementUri), undefined);
+    return this.http.put(this.platformServicesCommons.apiBasePath + '/element/' + encodeURIComponent(elementUri), undefined);
   }
 
   del(elementUri): Observable<any> {
-    return this.http.delete(this.platformServicesCommons.apiBasePath() + "/element/" + encodeURIComponent(elementUri));
+    return this.http.delete(this.platformServicesCommons.apiBasePath + '/element/' + encodeURIComponent(elementUri));
   }
 }
diff --git a/ui/src/app/platform-services/apis/pipeline-element-template.service.ts b/ui/src/app/platform-services/apis/pipeline-element-template.service.ts
index 27dc59d..8acb8a2 100644
--- a/ui/src/app/platform-services/apis/pipeline-element-template.service.ts
+++ b/ui/src/app/platform-services/apis/pipeline-element-template.service.ts
@@ -37,7 +37,7 @@ export class PipelineElementTemplateService {
 
   getPipelineElementTemplates(appId: string): Observable<PipelineElementTemplate[]> {
     return this.http
-        .get(this.platformServicesCommons.apiBasePath()
+        .get(this.platformServicesCommons.apiBasePath
             + '/pipeline-element-templates?appId=' + appId)
         .pipe(map(data => {
           return (data as []).map(dpi => PipelineElementTemplate.fromData(dpi));
@@ -45,7 +45,7 @@ export class PipelineElementTemplateService {
   }
 
   getConfiguredDataProcessorForTemplate(templateId: string, invocation: DataProcessorInvocation): Observable<DataProcessorInvocation> {
-    return this.http.post(this.platformServicesCommons.apiBasePath()
+    return this.http.post(this.platformServicesCommons.apiBasePath
         + '/pipeline-element-templates/' + templateId + '/processor', invocation)
         .pipe(map(response => {
           return DataProcessorInvocation.fromData(response as DataProcessorInvocation);
@@ -53,7 +53,7 @@ export class PipelineElementTemplateService {
   }
 
   getConfiguredDataSinkForTemplate(templateId: string, invocation: DataSinkInvocation): Observable<DataSinkInvocation> {
-    return this.http.post(this.platformServicesCommons.apiBasePath()
+    return this.http.post(this.platformServicesCommons.apiBasePath
         + '/pipeline-element-templates/' + templateId + '/sink', invocation)
         .pipe(map(response => {
           return DataSinkInvocation.fromData(response as DataSinkInvocation);
@@ -61,7 +61,7 @@ export class PipelineElementTemplateService {
   }
 
   storePipelineElementTemplate(template: PipelineElementTemplate) {
-    return this.http.post(this.platformServicesCommons.apiBasePath() + '/pipeline-element-templates', template);
+    return this.http.post(this.platformServicesCommons.apiBasePath + '/pipeline-element-templates', template);
   }
 
 
diff --git a/ui/src/app/platform-services/apis/pipeline-element.service.ts b/ui/src/app/platform-services/apis/pipeline-element.service.ts
index 1073385..a6b3fd4 100644
--- a/ui/src/app/platform-services/apis/pipeline-element.service.ts
+++ b/ui/src/app/platform-services/apis/pipeline-element.service.ts
@@ -60,22 +60,22 @@ export class PipelineElementService {
   }
 
   getDocumentation(appId) {
-    return this.http.get(this.platformServicesCommons.unauthenticatedBasePath
+    return this.http.get(this.platformServicesCommons.apiBasePath
         + '/pe/'
         + appId
         + '/assets/documentation', {responseType: 'text'});
   }
 
   private get dataProcessorsUrl(): string {
-    return this.platformServicesCommons.apiBasePath() + '/sepas';
+    return this.platformServicesCommons.apiBasePath + '/sepas';
   }
 
   private get dataStreamsUrl(): string {
-    return this.platformServicesCommons.apiBasePath() + '/streams';
+    return this.platformServicesCommons.apiBasePath + '/streams';
   }
 
   private get dataSinksUrl(): string {
-    return this.platformServicesCommons.apiBasePath() + '/actions';
+    return this.platformServicesCommons.apiBasePath + '/actions';
   }
 
 }
diff --git a/ui/src/app/platform-services/apis/pipeline-monitoring.service.ts b/ui/src/app/platform-services/apis/pipeline-monitoring.service.ts
index cf9e8f3..b8913cb 100644
--- a/ui/src/app/platform-services/apis/pipeline-monitoring.service.ts
+++ b/ui/src/app/platform-services/apis/pipeline-monitoring.service.ts
@@ -16,14 +16,12 @@
  *
  */
 
-import {Injectable} from "@angular/core";
-import {HttpClient} from "@angular/common/http";
-import {Observable} from "rxjs";
-import {
-  PipelineMonitoringInfo
-} from "../../core-model/gen/streampipes-model";
-import {PlatformServicesCommons} from "./commons.service";
-import {map} from "rxjs/operators";
+import { Injectable } from "@angular/core";
+import { HttpClient } from "@angular/common/http";
+import { Observable } from "rxjs";
+import { PipelineMonitoringInfo } from "../../core-model/gen/streampipes-model";
+import { PlatformServicesCommons } from "./commons.service";
+import { map } from "rxjs/operators";
 
 @Injectable()
 export class PipelineMonitoringService {
@@ -33,7 +31,7 @@ export class PipelineMonitoringService {
   }
 
   getPipelineMonitoringInfo(pipelineId: string): Observable<PipelineMonitoringInfo> {
-    return this.http.get(this.platformServicesCommons.apiBasePath()
+    return this.http.get(this.platformServicesCommons.apiBasePath
         + '/pipeline-monitoring/'
         + pipelineId)
         .pipe(map(response => PipelineMonitoringInfo.fromData(response as any)));
diff --git a/ui/src/app/platform-services/apis/pipeline.service.ts b/ui/src/app/platform-services/apis/pipeline.service.ts
index 3796bbc..7076b6f 100644
--- a/ui/src/app/platform-services/apis/pipeline.service.ts
+++ b/ui/src/app/platform-services/apis/pipeline.service.ts
@@ -105,7 +105,7 @@ export class PipelineService {
   }
 
   get apiBasePath() {
-    return this.platformServicesCommons.apiBasePath();
+    return this.platformServicesCommons.apiBasePath;
   }
 
 }
diff --git a/ui/src/app/platform-services/apis/semantic-types.service.ts b/ui/src/app/platform-services/apis/semantic-types.service.ts
index 5b6ee52..3373ec4 100644
--- a/ui/src/app/platform-services/apis/semantic-types.service.ts
+++ b/ui/src/app/platform-services/apis/semantic-types.service.ts
@@ -16,11 +16,11 @@
  *
  */
 
-import {Injectable} from "@angular/core";
-import {HttpClient} from "@angular/common/http";
-import {PlatformServicesCommons} from "./commons.service";
-import {map} from "rxjs/operators";
-import {Observable} from "rxjs";
+import { Injectable } from "@angular/core";
+import { HttpClient } from "@angular/common/http";
+import { PlatformServicesCommons } from "./commons.service";
+import { map } from "rxjs/operators";
+import { Observable } from "rxjs";
 
 @Injectable()
 export class SemanticTypesService {
@@ -31,7 +31,7 @@ export class SemanticTypesService {
   }
 
   getSemanticTypes(text: string): Observable<Array<string>> {
-    return this.http.get(this.platformServicesCommons.unauthenticatedBasePath + "/autocomplete/semantic-type?text=" + text).pipe(map(response => {
+    return this.http.get(this.platformServicesCommons.apiBasePath + "/autocomplete/semantic-type?text=" + text).pipe(map(response => {
       return response as Array<string>;
     }));
   }
diff --git a/ui/src/app/profile/components/basic-profile-settings.ts b/ui/src/app/profile/components/basic-profile-settings.ts
index 1bc1c00..5e98d6b 100644
--- a/ui/src/app/profile/components/basic-profile-settings.ts
+++ b/ui/src/app/profile/components/basic-profile-settings.ts
@@ -16,21 +16,23 @@
  *
  */
 
-import {ProfileService} from "../profile.service";
-import {User} from "../../core-model/gen/streampipes-model-client";
-import {Directive} from "@angular/core";
-import {AppConstants} from "../../services/app.constants";
+import { ProfileService } from '../profile.service';
+import { User } from '../../core-model/gen/streampipes-model-client';
+import { Directive } from '@angular/core';
+import { AppConstants } from '../../services/app.constants';
+import { JwtTokenStorageService } from '../../services/jwt-token-storage.service';
 
 @Directive()
 export abstract class BasicProfileSettings {
 
   userData: User;
-  profileLoaded: boolean = false;
-  profileUpdating: boolean = false;
+  profileLoaded = false;
+  profileUpdating = false;
   errorMessage: string;
 
   constructor(protected profileService: ProfileService,
-              public appConstants: AppConstants) {
+              public appConstants: AppConstants,
+              private tokenService: JwtTokenStorageService) {
 
   }
 
diff --git a/ui/src/app/profile/components/general/general-profile-settings.component.ts b/ui/src/app/profile/components/general/general-profile-settings.component.ts
index 1cf73ff..8cefffa 100644
--- a/ui/src/app/profile/components/general/general-profile-settings.component.ts
+++ b/ui/src/app/profile/components/general/general-profile-settings.component.ts
@@ -16,47 +16,49 @@
  *
  */
 
-import {Component, OnInit} from "@angular/core";
-import {ProfileService} from "../../profile.service";
-import {User} from "../../../core-model/gen/streampipes-model-client";
-import {BasicProfileSettings} from "../basic-profile-settings";
-import {AppConstants} from "../../../services/app.constants";
-import {AuthStatusService} from "../../../services/auth-status.service";
+import { Component, OnDestroy, OnInit } from '@angular/core';
+import { ProfileService } from '../../profile.service';
+import { BasicProfileSettings } from '../basic-profile-settings';
+import { AppConstants } from '../../../services/app.constants';
+import { AuthService } from '../../../services/auth.service';
+import { JwtTokenStorageService } from '../../../services/jwt-token-storage.service';
 
 @Component({
   selector: 'general-profile-settings',
   templateUrl: './general-profile-settings.component.html',
   styleUrls: ['./general-profile-settings.component.scss']
 })
-export class GeneralProfileSettingsComponent extends BasicProfileSettings implements OnInit {
+export class GeneralProfileSettingsComponent extends BasicProfileSettings implements OnInit, OnDestroy {
 
-  darkMode: boolean = false;
-  originalDarkMode: boolean = false;
-  darkModeChanged: boolean = false;
+  darkMode = false;
+  originalDarkMode = false;
+  darkModeChanged = false;
 
-  constructor(private authStatusService: AuthStatusService,
+  constructor(private authService: AuthService,
               profileService: ProfileService,
-              appConstants: AppConstants) {
-    super(profileService, appConstants);
+              appConstants: AppConstants,
+              tokenService: JwtTokenStorageService) {
+    super(profileService, appConstants, tokenService);
   }
 
   ngOnInit(): void {
-    this.darkMode = this.authStatusService.darkMode;
-    this.originalDarkMode = this.authStatusService.darkMode;
+    this.authService.darkMode$.subscribe(darkMode => this.darkMode = darkMode);
     this.receiveUserData();
   }
 
   ngOnDestroy(): void {
     if (!this.darkModeChanged) {
-      this.authStatusService.darkMode = this.originalDarkMode;
+      this.authService.darkMode$.next(this.originalDarkMode);
     }
   }
 
   changeModePreview(value: boolean) {
-    this.authStatusService.darkMode = value;
+    this.authService.darkMode$.next(value);
   }
 
   onUserDataReceived() {
+    this.originalDarkMode = this.userData.darkMode;
+    this.authService.darkMode$.next(this.userData.darkMode);
   }
 
   updateAppearanceMode() {
diff --git a/ui/src/app/profile/profile.service.ts b/ui/src/app/profile/profile.service.ts
index ca611a4..d77ec18 100644
--- a/ui/src/app/profile/profile.service.ts
+++ b/ui/src/app/profile/profile.service.ts
@@ -16,13 +16,13 @@
  *
  */
 
-import {Injectable} from "@angular/core";
-import {PlatformServicesCommons} from "../platform-services/apis/commons.service";
-import {HttpClient} from "@angular/common/http";
-import {RawUserApiToken, User} from "../core-model/gen/streampipes-model-client";
-import {Observable} from "rxjs";
-import {map} from "rxjs/operators";
-import {Message} from "../core-model/gen/streampipes-model";
+import { Injectable } from '@angular/core';
+import { PlatformServicesCommons } from '../platform-services/apis/commons.service';
+import { HttpClient } from '@angular/common/http';
+import { RawUserApiToken, User } from '../core-model/gen/streampipes-model-client';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { Message } from '../core-model/gen/streampipes-model';
 
 @Injectable()
 export class ProfileService {
@@ -33,27 +33,31 @@ export class ProfileService {
   }
 
   getUserProfile(): Observable<User> {
-    return this.http.get(this.platformServicesCommons.authUserBasePath()).pipe(map(response => {
+    return this.http.get(this.profilePath).pipe(map(response => {
       return User.fromData(response as any);
     }));
   }
 
   updateUserProfile(userData: User): Observable<Message> {
-    return this.http.put(this.platformServicesCommons.authUserBasePath(), userData).pipe(map(response => {
+    return this.http.put(this.profilePath, userData).pipe(map(response => {
       return Message.fromData(response as any);
-    }))
+    }));
   }
 
   updateAppearanceMode(darkMode: boolean): Observable<Message> {
-    return this.http.put(`${this.platformServicesCommons.authUserBasePath()}/appearance/mode/${darkMode}`, {}).pipe(map(response => {
+    return this.http.put(`${this.profilePath}/appearance/mode/${darkMode}`, {}).pipe(map(response => {
       return Message.fromData(response as any);
-    }))
+    }));
   }
 
   requestNewApiToken(baseToken: RawUserApiToken): Observable<RawUserApiToken> {
-    return this.http.post(this.platformServicesCommons.authUserBasePath() + "/tokens", baseToken)
+    return this.http.post(this.profilePath + '/tokens', baseToken)
         .pipe(map(response => {
           return RawUserApiToken.fromData(response as any);
-        }))
+        }));
+  }
+
+  private get profilePath(): string {
+    return this.platformServicesCommons.apiBasePath + '/users/profile';
   }
 }
diff --git a/ui/src/app/services/auth.service.ts b/ui/src/app/services/auth.service.ts
index 105757f..209747b 100644
--- a/ui/src/app/services/auth.service.ts
+++ b/ui/src/app/services/auth.service.ts
@@ -16,27 +16,73 @@
  *
  */
 
-import {RestApi} from "./rest-api.service";
-import {AuthStatusService} from "./auth-status.service";
-import {Inject, Injectable} from "@angular/core";
-import {Observable} from "rxjs";
+import { RestApi } from './rest-api.service';
+import { Injectable } from '@angular/core';
+import { BehaviorSubject, Observable, timer } from 'rxjs';
+import { JwtHelperService } from '@auth0/angular-jwt';
+import { JwtTokenStorageService } from './jwt-token-storage.service';
+import { UserInfo } from '../core-model/gen/streampipes-model-client';
+import { filter, map, switchMap, tap } from 'rxjs/operators';
+import { Router } from '@angular/router';
+import { LoginService } from '../login/services/login.service';
 
 @Injectable()
 export class AuthService {
 
-    constructor(private RestApi: RestApi,
-                private AuthStatusService: AuthStatusService) {
+    public authToken$: BehaviorSubject<string> = new BehaviorSubject<string>(undefined);
+    public user$: BehaviorSubject<any> = new BehaviorSubject<any>(undefined);
+    public isLoggedIn$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
+    public darkMode$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
+
+    constructor(private restApi: RestApi,
+                private tokenStorage: JwtTokenStorageService,
+                private router: Router,
+                private loginService: LoginService) {
+        if (this.authenticated()) {
+            this.authToken$.next(tokenStorage.getToken());
+            this.user$.next(tokenStorage.getUser());
+            this.isLoggedIn$.next(true);
+
+        } else {
+            this.logout();
+        }
+        this.scheduleTokenRenew();
+        this.watchTokenExpiration();
+    }
+
+    public login(data) {
+        this.tokenStorage.saveToken(data.accessToken);
+        this.tokenStorage.saveUser(data.userInfo);
+        this.authToken$.next(data.accessToken);
+        this.user$.next(data.userInfo);
+    }
+
+    public logout() {
+        this.tokenStorage.clearTokens();
+        this.authToken$.next(undefined);
+    }
+
+    public getCurrentUser(): UserInfo {
+        return this.tokenStorage.getUser();
+    }
+
+    public authenticated(): boolean {
+        const token = this.authToken$.getValue() || this.tokenStorage.getToken();
+        const jwtHelper: JwtHelperService = new JwtHelperService({});
+
+        return token !== null && token !== undefined && !jwtHelper.isTokenExpired(token);
+    }
+
+    public decodeJwtToken(token: string): any {
+        const jwtHelper: JwtHelperService = new JwtHelperService({});
+        return jwtHelper.decodeToken(token);
     }
 
     checkConfiguration(): Observable<boolean> {
-        return Observable.create((observer) => this.RestApi.configured().subscribe(response => {
+        return Observable.create((observer) => this.restApi.configured().subscribe(response => {
             if (response.configured) {
-                this.AuthStatusService.configured = true;
-                // TODO
-                //this.$rootScope.appConfig = response.data.appConfig;
                 observer.next(true);
             } else {
-                this.AuthStatusService.configured = false;
                 observer.next(false);
             }
         }, error => {
@@ -44,16 +90,28 @@ export class AuthService {
         }));
     }
 
-    checkAuthentication() {
-        return this.RestApi.getAuthc().subscribe(response => {
-            if (response.success) {
-                this.AuthStatusService.username = response.info.authc.principal.username;
-                this.AuthStatusService.email = response.info.authc.principal.email;
-                this.AuthStatusService.authenticated = true;
-                this.AuthStatusService.token = response.token;
-            } else {
-                this.AuthStatusService.authenticated = false;
+    scheduleTokenRenew() {
+        this.authToken$.pipe(
+            filter((token: any) => !!token),
+            map((token: any) => new JwtHelperService({}).getTokenExpirationDate(token)),
+            switchMap((expiresIn: Date) => timer(expiresIn.getTime() - Date.now() - 60000)),
+        ).subscribe(() => {
+            if (this.authenticated()) {
+                this.loginService.renewToken().subscribe(data => {
+                    this.login(data);
+                });
             }
-        })
+        });
+    }
+
+    watchTokenExpiration() {
+        this.authToken$.pipe(
+            filter((token: any) => !!token),
+            map((token: any) => new JwtHelperService({}).getTokenExpirationDate(token)),
+            switchMap((expiresIn: Date) => timer(expiresIn.getTime() - Date.now() + 1))
+        ).subscribe(() => {
+            this.logout();
+            this.router.navigate(['login']);
+        });
     }
-}
\ No newline at end of file
+}
diff --git a/ui/src/app/platform-services/apis/commons.service.ts b/ui/src/app/services/jwt-token-storage.service.ts
similarity index 54%
copy from ui/src/app/platform-services/apis/commons.service.ts
copy to ui/src/app/services/jwt-token-storage.service.ts
index 6ed5b73..f64eb2a 100644
--- a/ui/src/app/platform-services/apis/commons.service.ts
+++ b/ui/src/app/services/jwt-token-storage.service.ts
@@ -16,31 +16,34 @@
  *
  */
 
-import {AuthStatusService} from "../../services/auth-status.service";
-import {Injectable} from "@angular/core";
+import { UserInfo } from '../core-model/gen/streampipes-model-client';
 
-@Injectable()
-export class PlatformServicesCommons {
+const TOKEN_KEY = 'auth-token';
+const USER_KEY = 'auth-user';
 
-  constructor(private authStatusService: AuthStatusService) {
+export class JwtTokenStorageService {
 
-  }
+  constructor() { }
 
-  get basePath(): string {
-    return '/streampipes-backend';
+  clearTokens(): void {
+    window.localStorage.clear();
   }
 
-  apiBasePath() {
-    return this.basePath + '/api/v2';
+  public saveToken(token: string): void {
+    window.localStorage.removeItem(TOKEN_KEY);
+    window.localStorage.setItem(TOKEN_KEY, token);
   }
-  
-  authUserBasePath() {
-    return this.basePath + '/api/v2/users/' + this.authStatusService.email;
+
+  public getToken(): string {
+    return localStorage.getItem(TOKEN_KEY);
   }
 
-  get unauthenticatedBasePath() {
-    return this.basePath + '/api/v2';
+  public saveUser(user: UserInfo): void {
+    window.localStorage.removeItem(USER_KEY);
+    window.localStorage.setItem(USER_KEY, JSON.stringify(user));
   }
 
+  public getUser(): UserInfo {
+    return JSON.parse(localStorage.getItem(USER_KEY));
+  }
 }
-
diff --git a/ui/src/app/services/pipeline-icon.service.ts b/ui/src/app/services/pipeline-icon.service.ts
deleted file mode 100644
index 2abe21d..0000000
--- a/ui/src/app/services/pipeline-icon.service.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-export class PipelineElementIconService {
-
-    ImageChecker: any;
-    ElementIconText: any;
-
-    constructor(ImageChecker, ElementIconText) {
-        this.ImageChecker = ImageChecker;
-        this.ElementIconText = ElementIconText;
-    }
-
-    addImageOrTextIcon($element, json, small, type) {
-        let iconUrl = "";
-        if (type == 'block' && json.streams != null && typeof json.streams !== 'undefined') {
-            iconUrl = json.streams[0].iconUrl;
-        } else {
-            iconUrl = json.iconUrl;
-        }
-        this.ImageChecker.imageExists(iconUrl, exists => {
-            if (exists) {
-                let $img = $('<img>')
-                    .attr("src", iconUrl)
-                    .data("JSON", $.extend(true, {}, json));
-                if (type == 'draggable') {
-                    $img.addClass("draggable-img tt");
-                } else if (type == 'connectable') {
-                    $img.addClass('connectable-img tt');
-                } else if (type == 'block') {
-                    $img.addClass('block-img tt');
-                } else if (type == 'recommended') {
-                    $img.addClass('recommended-item-img tt');
-                }
-                $element.append($img);
-            } else {
-                let name = "";
-                if (type == 'block' && json.streams != null && typeof json.streams !== 'undefined') {
-                    name = json.streams[0].name;
-                } else {
-                    name = json.name;
-                }
-                let $span = $("<span>")
-                    .text(this.ElementIconText.getElementIconText(name) || "N/A")
-                    .attr(
-                        {
-                            "data-toggle": "tooltip",
-                            "data-placement": "top",
-                            "data-delay": '{"show": 1000, "hide": 100}',
-                            title: name
-                        })
-                    .data("JSON", $.extend(true, {}, json));
-                if (small) {
-                    $span.addClass("element-text-icon-small")
-                } else {
-                    $span.addClass("element-text-icon")
-                }
-                $element.append($span);
-            }
-        })
-    }
-
-}
-
-//PipelineElementIconService.$inject = ['ImageChecker', 'ElementIconText'];
\ No newline at end of file
diff --git a/ui/src/app/services/rest-api.service.ts b/ui/src/app/services/rest-api.service.ts
index db0d4c8..f537eeb 100644
--- a/ui/src/app/services/rest-api.service.ts
+++ b/ui/src/app/services/rest-api.service.ts
@@ -20,7 +20,6 @@
 
 
 import { Injectable } from '@angular/core';
-import { AuthStatusService } from './auth-status.service';
 import { PlatformServicesCommons } from '../platform-services/apis/commons.service';
 import { HttpClient } from '@angular/common/http';
 import { Observable } from 'rxjs';
@@ -30,21 +29,16 @@ export class RestApi {
 
     encodeURIComponent: any;
 
-    constructor (private authStatusService: AuthStatusService,
-                 private platformServicesCommons: PlatformServicesCommons,
+    constructor (private platformServicesCommons: PlatformServicesCommons,
                  private $http: HttpClient) {
     }
 
     getServerUrl() {
-        return this.platformServicesCommons.unauthenticatedBasePath;
-    }
-
-    urlBase() {
-        return this.platformServicesCommons.authUserBasePath();
+        return this.platformServicesCommons.apiBasePath;
     }
 
     urlApiBase() {
-        return this.platformServicesCommons.apiBasePath();
+        return this.platformServicesCommons.apiBasePath;
     }
 
     getAssetUrl(appId) {
@@ -52,56 +46,7 @@ export class RestApi {
     }
 
     updateUserDetails(user) {
-        return this.$http.put(this.urlBase(), user);
-    }
-
-    getBlocks() {
-        return this.$http.get(this.urlBase() + '/block');
-    }
-
-    getOwnActions() {
-        return this.$http.get(this.urlBase() + '/actions/own');
-    }
-
-    getAvailableActions() {
-        return this.$http.get(this.urlBase() + '/actions/available');
-    }
-
-    getPreferredActions() {
-        return this.$http.get(this.urlBase() + '/actions/favorites');
-    }
-
-    getOwnSepas() {
-        return this.$http.get(this.urlBase() + '/sepas/own');
-    }
-
-    getAvailableSepas() {
-        return this.$http.get(this.urlBase() + '/sepas/available');
-    }
-
-    getPreferredSepas() {
-        return this.$http.get(this.urlBase() + '/sepas/favorites');
-    }
-
-    getOwnSources(): Observable<any> {
-        return this.$http.get(this.urlBase() + '/sources/own');
-    }
-
-    getAvailableSources() {
-        return this.$http.get(this.urlBase() + '/sources/available');
-    }
-
-    getPreferredSources() {
-        return this.$http.get(this.urlBase() + '/sources/favorites');
-    }
-
-    getOwnStreams(source) {
-        return this.$http.get(this.urlBase() + '/sources/' + encodeURIComponent(source.uri) + '/streams');
-
-    }
-
-    jsonld(elementUri) {
-        return this.$http.get(this.urlApiBase() + '/element/' + encodeURIComponent(elementUri) + '/jsonld');
+        return this.$http.put(this.urlApiBase() + '/users/profile', user);
     }
 
     configured(): Observable<any> {
@@ -110,64 +55,10 @@ export class RestApi {
         });
     }
 
-    updateConfiguration(config) {
-        return this.$http.put(this.getServerUrl() + '/setup/configuration', config);
-        // return this.$http.get(this.getServerUrl() +"/semantic-epa-backend/api/v2/setup/configured");
-    }
-
-    getOwnPipelines(): Observable<any> {
-        return this.$http.get(this.urlBase() + '/pipelines/own');
-        // return this.$http.get("/semantic-epa-backend/api/pipelines");
-    }
-
-    storePipeline(pipeline) {
-        return this.$http.post(this.urlBase() + '/pipelines', pipeline);
-    }
-
-    updateStream(stream) {
-        return this.$http.post(this.urlBase() + '/streams/update', stream);
-    }
-
-    getPipelineCategories() {
-        return this.$http.get(this.urlBase() + '/pipelinecategories');
-    }
-
-    storePipelineCategory(pipelineCategory) {
-        return this.$http.post(this.urlBase() + '/pipelinecategories', pipelineCategory);
-    }
-
-    startPipeline(pipelineId) {
-        return this.$http.get(this.urlBase() + '/pipelines/' + pipelineId + '/start');
-    }
-
-    stopPipeline(pipelineId) {
-        return this.$http.get(this.urlBase() + '/pipelines/' + pipelineId + '/stop');
-    }
-
-    getPipelineById(pipelineId) {
-        return this.$http.get(this.urlBase() + '/pipelines/' + pipelineId);
-    }
-
-    getPipelineStatusById(pipelineId) {
-        return this.$http.get(this.urlBase() + '/pipelines/' + pipelineId + '/status');
-    }
-
-    getNotifications() {
-        return this.$http.get(this.urlApiBase() + '/notifications');
-    }
-
     getUnreadNotificationsCount(): Observable<any> {
         return this.$http.get(this.urlApiBase() + '/notifications/count');
     }
 
-    getUnreadNotifications() {
-        return this.$http.get(this.urlApiBase() + '/notifications/unread');
-    }
-
-    getSepaById(elementId) {
-        return this.$http.get(this.urlBase() + '/sepas/' + encodeURIComponent(elementId));
-    }
-
     getOntologyProperties() {
         return this.$http.get( this.getServerUrl() + '/ontology/properties');
     }
@@ -265,27 +156,6 @@ export class RestApi {
         return this.$http.get(this.getServerUrl() + '/categories/adapter');
     }
 
-    getAvailableApps(elementId) {
-        return this.$http.get(this.urlBase() + '/marketplace');
-    }
-
-    getTargetPods() {
-        return this.$http.get(this.urlBase() + '/marketplace/pods');
-    }
-
-
-    getAuthc(): Observable<any> {
-        return this.$http.get(this.getServerUrl() + '/admin/authc');
-    }
-
-    logout() {
-        return this.$http.get(this.getServerUrl() + '/admin/logout');
-    }
-
-    register(payload) {
-        return this.$http.post(this.getServerUrl() + '/admin/register', payload);
-    }
-
     getApplicationLinks() {
         return this.$http.get(this.getServerUrl() + '/applink');
     }
diff --git a/ui/src/app/services/route-transition-interceptor.service.ts b/ui/src/app/services/route-transition-interceptor.service.ts
deleted file mode 100644
index aa96ac9..0000000
--- a/ui/src/app/services/route-transition-interceptor.service.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import {AuthService} from "./auth.service";
-import {AuthStatusService} from "./auth-status.service";
-
-export class RouteTransitionInterceptorService {
-
-    AuthService: AuthService;
-    AuthStatusService: AuthStatusService;
-    $q: any;
-
-    publicPages: string[] = ["login", "register", "setup"];
-
-    constructor(AuthService, AuthStatusService, $q) {
-        this.AuthService = AuthService;
-        this.AuthStatusService = AuthStatusService;
-        this.$q = $q;
-    }
-
-    onTransitionStarted(transitionInfo) {
-        return new Promise(resolve => {
-            if (transitionInfo.$to().name !== "startup") {
-                this.AuthService.checkConfiguration().then(() => {
-                    if (this.AuthStatusService.configured) {
-                        this.AuthService.checkAuthentication().then(() => {
-                            if (this.isProtectedPage(transitionInfo.$to().name) && !(this.AuthStatusService.authenticated)) {
-                                resolve(transitionInfo.router.stateService.target('login'));
-                            } else {
-                                if (this.AuthStatusService.authenticated && (transitionInfo.$to().name === 'login'
-                                    || transitionInfo.$to().name === 'setup')) {
-                                    resolve(transitionInfo.router.stateService.target('streampipes'));
-                                } else {
-                                    if (transitionInfo.$to().name === 'setup') {
-                                        resolve(transitionInfo.router.stateService.target('streampipes'));
-                                    } else {
-                                        resolve(true);
-                                    }
-                                }
-                            }
-                        })
-                    } else {
-                        if (transitionInfo.$to().name == 'setup') {
-                            resolve(true);
-                        } else {
-                            resolve(transitionInfo.router.stateService.target('setup'));
-                        }
-                    }
-                }, (error) => {
-                    if (error.status === 504 || error.status === 502) {
-                        resolve(transitionInfo.router.stateService.target('startup'));
-                    }
-                });
-            } else {
-                resolve(true);
-            }
-        });
-    }
-
-    isProtectedPage(target) {
-        return !(this.publicPages.some(p => p === target));
-    }
-}
-RouteTransitionInterceptorService.$inject = ['AuthService', 'AuthStatusService', '$q'];
\ No newline at end of file
diff --git a/ui/src/app/services/services.module.ts b/ui/src/app/services/services.module.ts
index 93499c2..2b07170 100644
--- a/ui/src/app/services/services.module.ts
+++ b/ui/src/app/services/services.module.ts
@@ -16,15 +16,16 @@
  *
  */
 
-import {NgModule} from "@angular/core";
-import {RestApi} from "./rest-api.service";
-import {AuthService} from "./auth.service";
-import {ShepherdService} from "./tour/shepherd.service";
-import {TourProviderService} from "./tour/tour-provider.service";
-import {NotificationCountService} from "./notification-count-service";
-import {PropertySelectorService} from "./property-selector.service";
-import {ElementIconText} from "./get-element-icon-text.service";
-import {AppConstants} from "./app.constants";
+import { NgModule } from '@angular/core';
+import { RestApi } from './rest-api.service';
+import { AuthService } from './auth.service';
+import { ShepherdService } from './tour/shepherd.service';
+import { TourProviderService } from './tour/tour-provider.service';
+import { NotificationCountService } from './notification-count-service';
+import { PropertySelectorService } from './property-selector.service';
+import { ElementIconText } from './get-element-icon-text.service';
+import { AppConstants } from './app.constants';
+import { JwtTokenStorageService } from './jwt-token-storage.service';
 
 @NgModule({
   imports: [],
@@ -34,6 +35,7 @@ import {AppConstants} from "./app.constants";
     RestApi,
     AuthService,
     ElementIconText,
+    JwtTokenStorageService,
     ShepherdService,
     TourProviderService,
     NotificationCountService,