diff --git a/CONFIGURATION.md b/CONFIGURATION.md
index d4f26e43e80320c4eafeaa1a5d9628031c89d58f..a82a147edef4a2e29f8f1a282c9aeeffe09cf44d 100644
--- a/CONFIGURATION.md
+++ b/CONFIGURATION.md
@@ -6,6 +6,8 @@ Configuration may be set using SpringBoot's configuration file (`application.pro
 
 | Variable                            | Default                                     | Description                                                                                                            |
 |-------------------------------------|---------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
+| **Application**                     |                                             |                                                                                                                        |
+|                                     |                                             |                                                                                                                        |
 | NAMING_DATABASE_URL                 | jdbc:postgresql://postgres:5432/discs_names | JDBC URL for the database connection                                                                                   |
 | NAMING_DATABASE_USERNAME            | discs_names                                 | user name for the database connection                                                                                  |
 | NAMING_DATABASE_PASSWORD            | discs_names                                 | password for the database connection                                                                                   |
@@ -22,4 +24,17 @@ Configuration may be set using SpringBoot's configuration file (`application.pro
 | NAMING_SMTP_PORT                    | 587                                         | port to use for SMTP, 587 for SMTP Secure                                                                              |
 | NAMING_SMTP_USERNAME                |                                             | username for SMTP server                                                                                               |
 | NAMING_SMTP_PASSWORD                |                                             | password for SMTP server                                                                                               |
+|                                     |                                             |                                                                                                                        |
+| **Springdoc, Swagger**              |                                             |                                                                                                                        |
+|                                     |                                             |                                                                                                                        |
 | NAMING_SWAGGER_URL                  | http://localhost:8080/swagger-ui.html       | default url for Swagger UI                                                                                             |
+| API_DOCS_PATH                       | /api-docs                                   | custom path of the OpenAPI documentation in JSON                                                                       |
+| SWAGGER_UI_PATH                     | /swagger-ui.html                            | custom path of the swagger-ui documentation in HTML                                                                    |
+|                                     |                                             |                                                                                                                        |
+| **Security**                        |                                             |                                                                                                                        |
+|                                     |                                             |                                                                                                                        |
+| NAMING_SECURITY_ENABLED             | false                                       | enable security for application                                                                                        |
+| AES_KEY                             | aes_secret_key                              | secret that is used to hash the tokens in the JWT token                                                                |
+| JWT_SECRET                          | secret_password_to_hash_token               | secret that is used sign the JWT token                                                                                 |
+| JWT_EXP_MIN                         | 240                                         | time interval until the JWT token is valid (in minutes)                                                                |
+| RBAC_SERVER_ADDRESS                 |                                             | RBAC server address used for log in users if NAMING_SECURITY_ENABLED is enabled                                        |
diff --git a/pom.xml b/pom.xml
index 7b58ad2f093e2a5b6e272764707f6d72aed9142e..c8e4c652732f8d325234a858b2a1907e73ed1f08 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,6 +24,10 @@
       <groupId>javax.persistence</groupId>
       <artifactId>javax.persistence-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-security</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
@@ -59,6 +63,28 @@
       <artifactId>springdoc-openapi-ui</artifactId>
       <version>1.8.0</version>
     </dependency>
+    <dependency>
+      <groupId>org.springdoc</groupId>
+      <artifactId>springdoc-openapi-security</artifactId>
+      <version>1.8.0</version>
+    </dependency>
+    <dependency>
+      <groupId>io.fusionauth</groupId>
+      <artifactId>fusionauth-jwt</artifactId>
+      <version>5.3.2</version>
+    </dependency>
+    <dependency>
+      <groupId>com.squareup.okhttp3</groupId>
+      <artifactId>okhttp</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.dataformat</groupId>
+      <artifactId>jackson-dataformat-xml</artifactId>
+    </dependency>
 
     <dependency>
       <groupId>com.github.spotbugs</groupId>
diff --git a/src/main/java/org/openepics/names/NamingApplication.java b/src/main/java/org/openepics/names/NamingApplication.java
index 379b5211c3b06bafea38e27f0058a8fff16ae1e1..3277fb7aad41972148c70951f035f861c391dd50 100644
--- a/src/main/java/org/openepics/names/NamingApplication.java
+++ b/src/main/java/org/openepics/names/NamingApplication.java
@@ -22,6 +22,8 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.annotation.Bean;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 import io.swagger.v3.oas.models.ExternalDocumentation;
 import io.swagger.v3.oas.models.OpenAPI;
@@ -67,4 +69,18 @@ public class NamingApplication {
                         .version(appVersion));
     }
 
+    @Bean
+    public WebMvcConfigurer corsConfigurer() {
+        return new WebMvcConfigurer() {
+            @Override
+            public void addCorsMappings(CorsRegistry registry) {
+                registry
+                .addMapping("/**")
+                .allowedOriginPatterns("*")
+                .allowCredentials(true)
+                .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE");
+            }
+        };
+    }
+
 }
diff --git a/src/main/java/org/openepics/names/configuration/SecurityConfiguration.java b/src/main/java/org/openepics/names/configuration/SecurityConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..b2c8b8431550d824eb61d4a02322fce280872cf6
--- /dev/null
+++ b/src/main/java/org/openepics/names/configuration/SecurityConfiguration.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2024 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.configuration;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.openepics.names.rest.filter.JwtRequestFilter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Role;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
+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.WebSecurityCustomizer;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.security.web.firewall.HttpFirewall;
+import org.springframework.security.web.firewall.StrictHttpFirewall;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Set up security configuration for Naming backend.
+ *
+ * @author Lars Johansson
+ */
+@Configuration
+@EnableWebSecurity
+@EnableMethodSecurity(prePostEnabled = false)
+public class SecurityConfiguration {
+
+    // note
+    //     ability to run application with and without security
+    //     spring and swagger work together
+    //     spring
+    //         @EnableMethodSecurity
+    //         @PreAuthorize
+    //         +
+    //         AuthorizationManagerBeforeMethodInterceptor
+    //         SecurityFilterChain
+    //     swagger
+    //         @SecurityRequirement
+
+    private static final String API_V1_AUTHENTICATION   = "/api/v1/authentication";
+    private static final String API_V1_NAMES            = "/api/v1/names";
+    private static final String API_V1_NAMES_PATHS      = "/api/v1/names/*";
+    private static final String API_V1_STRUCTURES       = "/api/v1/structures";
+    private static final String API_V1_STRUCTURES_PATHS = "/api/v1/structures/*";
+    private static final String API_V1_PV_NAMES         = "/api/v1/pvNames";
+    private static final String API_V1_CONVERT          = "/api/v1/convert";
+
+    private static final String ACTUATOR                = "/actuator";
+    private static final String ACTUATOR_PATHS          = "/actuator/**";
+    private static final String HEALTHCHECK             = "/healthcheck";
+    private static final String REPORT_PATHS            = "/report/**";
+
+    public static final String ROLE_ADMINISTRATOR       = "NamingAdministrator";
+    public static final String ROLE_USER                = "NamingUser";
+    public static final String IS_ADMINISTRATOR         = "hasAuthority('" + ROLE_ADMINISTRATOR + "')";
+    public static final String IS_USER                  = "hasAuthority('" + ROLE_USER + "')";
+    public static final String IS_ADMINISTRATOR_OR_USER = IS_ADMINISTRATOR + " or " + IS_USER;
+
+    private static final List<String> ALLOWED_ROLES_TO_LOGIN =
+            Arrays.asList(
+                    SecurityConfiguration.ROLE_ADMINISTRATOR,
+                    SecurityConfiguration.ROLE_USER);
+
+    @Value("${naming.security.enabled:false}")
+    private boolean namingSecurityEnabled;
+    @Value("${springdoc.api-docs.path}")
+    private String apiDocsPath;
+    @Value("${springdoc.swagger-ui.path}")
+    private String swaggerUiPath;
+
+    private final UserDetailsService jwtUserDetailsService;
+    private final JwtRequestFilter jwtRequestFilter;
+
+    @Autowired
+    public SecurityConfiguration(
+            UserDetailsService jwtUserDetailsService,
+            JwtRequestFilter jwtRequestFilter) {
+        this.jwtUserDetailsService = jwtUserDetailsService;
+        this.jwtRequestFilter = jwtRequestFilter;
+    }
+
+    public static List<String> getAllowedRolesToLogin() {
+        return ImmutableList.copyOf(ALLOWED_ROLES_TO_LOGIN);
+    }
+
+    @Bean
+    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+    @ConditionalOnProperty(name = "naming.security.enabled", havingValue = "true")
+    static AuthorizationManagerBeforeMethodInterceptor preAuthorizeAuthorizationMethodInterceptor() {
+        return AuthorizationManagerBeforeMethodInterceptor.preAuthorize();
+    }
+
+    @Autowired
+    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+      // configure AuthenticationManager so that it knows from where to load
+      // user for matching credentials
+      // Use BCryptPasswordEncoder
+      auth.userDetailsService(jwtUserDetailsService);
+    }
+
+    @Bean
+    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+        // disable csrf since internal
+        // authentication and authorization
+        //     create, read, update, delete
+        //     not needed for read but needed for others, user for names, admin for structures
+        //     accept requests to
+        //         openapi, swagger
+        //         healthcheck
+        //         login, logout
+        // patterns that are not mentioned are to be authenticated
+        // stateless session as session not used to store user's state
+
+        // TODO naming-convention-tool
+        //     about
+        //         paths to be removed when such functionality is removed
+        //         /verification to verify data migration
+        //         /rest rest api for comparison
+        //     paths
+        //         /verification/**
+        //         /rest/deviceNames/**
+        //         /rest/healthcheck
+        //         /rest/history/**
+        //         /rest/parts/**
+
+        http
+            .csrf().disable()
+            .cors();
+
+        if (namingSecurityEnabled) {
+            http
+                .authorizeRequests()
+                    // api docs, swagger
+                    // authentication - login, logout
+                    // names - read
+                    // structures - read
+                    // other
+                    .mvcMatchers("/v3/api-docs/**", apiDocsPath + "/**", "/api/swagger-ui/**", "/swagger-ui/**", swaggerUiPath).permitAll()
+                    .mvcMatchers(HttpMethod.POST,   API_V1_AUTHENTICATION + "/login").permitAll()
+                    .mvcMatchers(HttpMethod.GET,    API_V1_NAMES, API_V1_NAMES_PATHS).permitAll()
+                    .mvcMatchers(HttpMethod.GET,    API_V1_STRUCTURES, API_V1_STRUCTURES_PATHS).permitAll()
+                    .mvcMatchers(HttpMethod.GET,    API_V1_PV_NAMES).permitAll()
+                    .mvcMatchers(HttpMethod.GET,    API_V1_CONVERT).permitAll()
+                    .mvcMatchers(HttpMethod.GET,    REPORT_PATHS).permitAll()
+                    .mvcMatchers(HttpMethod.GET,    HEALTHCHECK).permitAll()
+                    .mvcMatchers(HttpMethod.GET,    ACTUATOR, ACTUATOR_PATHS).permitAll()
+                    // naming-convention-tool
+                    .mvcMatchers(HttpMethod.GET,    "/verification/**").permitAll()
+                    .mvcMatchers(HttpMethod.GET,    "/rest/deviceNames/**").permitAll()
+                    .mvcMatchers(HttpMethod.GET,    "/rest/healthcheck").permitAll()
+                    .mvcMatchers(HttpMethod.GET,    "/rest/history/**").permitAll()
+                    .mvcMatchers(HttpMethod.GET,    "/rest/parts/**").permitAll()
+                    // any other requests to be authenticated
+                    .anyRequest().authenticated()
+                // add a filter to validate the tokens with every request
+                .and()
+                .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)
+                // make sure we use stateless session; session won't be used to store user's state.
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
+        }
+
+        return http.build();
+    }
+
+    @Bean
+    public WebSecurityCustomizer webSecurityCustomizer() {
+        // allow % that is URL encoded %25 may be in path
+        // see org.springframework.security.web.firewall.StrictHttpFirewall
+        return web -> web.httpFirewall(allowUrlEncodedPercenthHttpFirewall());
+    }
+
+    private HttpFirewall allowUrlEncodedPercenthHttpFirewall() {
+        StrictHttpFirewall firewall = new StrictHttpFirewall();
+        firewall.setAllowUrlEncodedPercent(true);
+        return firewall;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/configuration/SwaggerConfiguration.java b/src/main/java/org/openepics/names/configuration/SwaggerConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..f1cdf2b291f97f00ce180d1827787d08d09c6c9d
--- /dev/null
+++ b/src/main/java/org/openepics/names/configuration/SwaggerConfiguration.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.configuration;
+
+import org.springdoc.core.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
+import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
+import io.swagger.v3.oas.annotations.security.SecurityScheme;
+import io.swagger.v3.oas.annotations.security.SecuritySchemes;
+
+/**
+ * Set up Swagger configuration for Naming backend.
+ *
+ * @author Lars Johansson
+ */
+@Configuration
+@SecuritySchemes(value = {
+        @SecurityScheme(
+                name = "bearerAuth",
+                type = SecuritySchemeType.HTTP,
+                in = SecuritySchemeIn.HEADER,
+                bearerFormat = "JWT",
+                scheme = "bearer")
+})
+public class SwaggerConfiguration {
+
+    @Bean
+    public GroupedOpenApi v1Api() {
+        return GroupedOpenApi.builder().group("api-v1").pathsToMatch("/api/v1/**").build();
+    }
+
+    @Bean
+    public GroupedOpenApi base() {
+        return GroupedOpenApi.builder().group("base").pathsToMatch("/report/**", "/healthcheck").build();
+    }
+
+
+}
diff --git a/src/main/java/org/openepics/names/exception/ServiceException.java b/src/main/java/org/openepics/names/exception/ServiceException.java
index a0bf606cf81acbb1ce5b6985ec983ec8877049cf..9bab827afbc406877ec8d1b9854ee09bb937aa70 100644
--- a/src/main/java/org/openepics/names/exception/ServiceException.java
+++ b/src/main/java/org/openepics/names/exception/ServiceException.java
@@ -33,6 +33,17 @@ public class ServiceException extends RuntimeException {
     private final String details;
     private final String field;
 
+    /**
+     * Public constructor.
+     *
+     * @param message message
+     */
+    public ServiceException(String message) {
+        super(message);
+        this.details = null;
+        this.field = null;
+    }
+
     /**
      * Public constructor.
      *
diff --git a/src/main/java/org/openepics/names/exception/handler/GlobalControllerExceptionHandler.java b/src/main/java/org/openepics/names/exception/handler/GlobalControllerExceptionHandler.java
index a7c60a99b2d6047d7fae98db2ec43c4f277e796a..f18b7b52f4b628c32f44ea904d1778f1f9ce9a8e 100644
--- a/src/main/java/org/openepics/names/exception/handler/GlobalControllerExceptionHandler.java
+++ b/src/main/java/org/openepics/names/exception/handler/GlobalControllerExceptionHandler.java
@@ -31,6 +31,10 @@ import org.openepics.names.exception.InputNotCorrectException;
 import org.openepics.names.exception.InputNotEmptyException;
 import org.openepics.names.exception.InputNotValidException;
 import org.openepics.names.exception.ServiceException;
+import org.openepics.names.exception.security.AuthenticationException;
+import org.openepics.names.exception.security.EntityNotFoundException;
+import org.openepics.names.exception.security.RemoteException;
+import org.openepics.names.exception.security.UnauthorizedException;
 import org.openepics.names.rest.beans.response.Response;
 import org.openepics.names.util.TextUtil;
 import org.springframework.http.HttpStatus;
@@ -46,10 +50,13 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
  * Note
  * <ul>
  * <li>400 {@link HttpStatus#BAD_REQUEST}</li>
+ * <li>401 {@link HttpStatus#UNAUTHORIZED}</li>
+ * <li>403 {@link HttpStatus#FORBIDDEN}</li>
  * <li>404 {@link HttpStatus#NOT_FOUND}</li>
  * <li>409 {@link HttpStatus#CONFLICT}</li>
  * <li>422 {@link HttpStatus#UNPROCESSABLE_ENTITY}</li>
  * <li>500 {@link HttpStatus#INTERNAL_SERVER_ERROR}</li>
+ * <li>503 {@link HttpStatus#SERVICE_UNAVAILABLE}</li>
  * </ul>
 *
  * @author Lars Johansson
@@ -58,7 +65,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
 public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHandler {
 
     @ExceptionHandler
-    protected ResponseEntity<Response> handleConflict(RuntimeException ex, WebRequest request) {
+    public ResponseEntity<Response> handleConflict(RuntimeException ex, WebRequest request) {
         Response response = new Response("", "", "");
         response.setMessage(TextUtil.OPERATION_COULD_NOT_BE_PERFORMED);
 
@@ -71,15 +78,17 @@ public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHan
 
             // HttpStatus.BAD_REQUEST handled by Spring
 
-            if (ex instanceof InputNotAvailableException
-                    || ex instanceof InputNotCorrectException
-                    || ex instanceof InputNotEmptyException
-                    || ex instanceof InputNotValidException) {
-                resultStatus = HttpStatus.UNPROCESSABLE_ENTITY;
+            if (ex instanceof AuthenticationException) {
+                resultStatus = HttpStatus.UNAUTHORIZED;
+            }
+
+            if (ex instanceof UnauthorizedException) {
+                resultStatus = HttpStatus.FORBIDDEN;
             }
 
             if (ex instanceof DataNotAvailableException
-                    || ex instanceof DataNotFoundException) {
+                    || ex instanceof DataNotFoundException
+                    || ex instanceof EntityNotFoundException) {
                 resultStatus = HttpStatus.NOT_FOUND;
             }
 
@@ -90,9 +99,17 @@ public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHan
                  resultStatus = HttpStatus.CONFLICT;
             }
 
-            if (ex instanceof DataNotCorrectException) {
+            if (ex instanceof InputNotAvailableException
+                    || ex instanceof InputNotCorrectException
+                    || ex instanceof InputNotEmptyException
+                    || ex instanceof InputNotValidException
+                    || ex instanceof DataNotCorrectException) {
                 resultStatus = HttpStatus.UNPROCESSABLE_ENTITY;
             }
+
+            if (ex instanceof RemoteException) {
+                resultStatus = HttpStatus.SERVICE_UNAVAILABLE;
+            }
         }
 
         return new ResponseEntity<>(response, Response.getHeaderJson(), resultStatus);
diff --git a/src/main/java/org/openepics/names/exception/security/AuthenticationException.java b/src/main/java/org/openepics/names/exception/security/AuthenticationException.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec1ad8e0521707b25455147693d519be3bd878c7
--- /dev/null
+++ b/src/main/java/org/openepics/names/exception/security/AuthenticationException.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.exception.security;
+
+import org.openepics.names.exception.ServiceException;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+public class AuthenticationException extends ServiceException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -5434486411943794281L;
+
+    private static final String ERROR = "Authentication error";
+
+    public AuthenticationException(String description) {
+        super(ERROR, description, null, null);
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/exception/security/EntityNotFoundException.java b/src/main/java/org/openepics/names/exception/security/EntityNotFoundException.java
new file mode 100644
index 0000000000000000000000000000000000000000..f8780d711e79ca45d9b2c8a5b8e16997a50acc51
--- /dev/null
+++ b/src/main/java/org/openepics/names/exception/security/EntityNotFoundException.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.exception.security;
+
+import org.openepics.names.exception.ServiceException;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+public class EntityNotFoundException extends ServiceException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 564746316436100483L;
+
+    private static final String ENTITY_NOT_FOUND = "Entity not found";
+
+    public EntityNotFoundException(String entityType, long entityId) {
+        super(ENTITY_NOT_FOUND, entityType + " (ID: " + entityId + ") not found", null, null);
+    }
+
+    public EntityNotFoundException(String entityType, String name) {
+        super(ENTITY_NOT_FOUND, entityType + " (name: " + name + ") not found", null, null);
+    }
+
+    public EntityNotFoundException(String message) {
+        super(ENTITY_NOT_FOUND, message, null, null);
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/exception/security/ParseException.java b/src/main/java/org/openepics/names/exception/security/ParseException.java
new file mode 100644
index 0000000000000000000000000000000000000000..0df3e3ff07db0544652388929e89d3a0089961c9
--- /dev/null
+++ b/src/main/java/org/openepics/names/exception/security/ParseException.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.exception.security;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+public class ParseException extends Exception {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 7711905654503012121L;
+
+    public ParseException() {}
+
+    public ParseException(String message) {
+        super(message);
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/exception/security/RemoteException.java b/src/main/java/org/openepics/names/exception/security/RemoteException.java
new file mode 100644
index 0000000000000000000000000000000000000000..c54cf6ac2d96a20c135d4d547507dd5b5869383a
--- /dev/null
+++ b/src/main/java/org/openepics/names/exception/security/RemoteException.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.exception.security;
+
+import org.openepics.names.exception.ServiceException;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+public class RemoteException extends ServiceException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -1202935975436997437L;
+
+    public RemoteException(String error, String description) {
+        super(error, description, null, null);
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/exception/security/RemoteServiceException.java b/src/main/java/org/openepics/names/exception/security/RemoteServiceException.java
new file mode 100644
index 0000000000000000000000000000000000000000..efdb01a788267642bc8b7551237e3b7a1b3ec8c1
--- /dev/null
+++ b/src/main/java/org/openepics/names/exception/security/RemoteServiceException.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.exception.security;
+
+/**
+ * @author <a href="mailto:zoltan.runyo@ess.eu">Zoltan Runyo</a>
+ */
+public class RemoteServiceException extends Exception {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 3744513029294293528L;
+
+    public RemoteServiceException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public RemoteServiceException(String message) {
+        super(message);
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/exception/security/UnauthorizedException.java b/src/main/java/org/openepics/names/exception/security/UnauthorizedException.java
new file mode 100644
index 0000000000000000000000000000000000000000..3128be98001febc704c34900d059315651dc270d
--- /dev/null
+++ b/src/main/java/org/openepics/names/exception/security/UnauthorizedException.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.exception.security;
+
+import org.openepics.names.exception.ServiceException;
+
+/**
+ * @author <a href="mailto:zoltan.runyo@ess.eu">Zoltan Runyo</a>
+ */
+public class UnauthorizedException extends ServiceException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -3051588358017181877L;
+
+    public UnauthorizedException(String description) {
+        super("Operation forbidden", description, null, null);
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/rest/api/v1/IAuthentication.java b/src/main/java/org/openepics/names/rest/api/v1/IAuthentication.java
new file mode 100644
index 0000000000000000000000000000000000000000..612fb1fe37aef887ed0d3f7915aef906cee6effb
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/api/v1/IAuthentication.java
@@ -0,0 +1,113 @@
+package org.openepics.names.rest.api.v1;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import org.openepics.names.exception.ServiceException;
+import org.openepics.names.rest.beans.security.Login;
+import org.openepics.names.rest.beans.security.LoginResponse;
+import org.openepics.names.service.security.dto.UserDetails;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * @author <a href="mailto:zoltan.runyo@ess.eu">Zoltan Runyo</a>
+ */
+@RequestMapping("/api/v1/authentication")
+@Tag(name = "5. Authentication")
+public interface IAuthentication {
+
+    @Operation(
+            summary     = "Login user and acquire JWT token",
+            description = "Login user with username, and password in order to acquire JWT token")
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200",
+                    description  = "Ok",
+                    content = @Content(schema = @Schema(implementation = LoginResponse.class))),
+            @ApiResponse(
+                    responseCode = "401",
+                    description  = "Bad username, and/or password",
+                    content = @Content(schema = @Schema(implementation = ServiceException.class))),
+            @ApiResponse(
+                    responseCode = "403",
+                    description  = "User doesn't have permission to log in",
+                    content = @Content(schema = @Schema(implementation = ServiceException.class))),
+            @ApiResponse(
+                    responseCode = "503",
+                    description  = "Login server unavailable",
+                    content = @Content(schema = @Schema(implementation = ServiceException.class))),
+            @ApiResponse(
+                    responseCode = "500",
+                    description  = "Service exception",
+                    content = @Content(schema = @Schema(implementation = ServiceException.class)))
+    })
+    @PostMapping(
+            value = "/login",
+            produces = {"application/json"},
+            consumes = {"application/json"})
+    ResponseEntity<LoginResponse> login(@RequestBody Login loginInfo);
+
+    @Operation(
+            summary     = "Renewing JWT token",
+            description = "Renewing valid, non-expired JWT token",
+            security    = {@SecurityRequirement(name = "bearerAuth")})
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200",
+                    description  = "Ok",
+                    content = @Content(schema = @Schema(implementation = LoginResponse.class))),
+            @ApiResponse(
+                    responseCode = "401",
+                    description  = "Unauthorized",
+                    content = @Content(schema = @Schema(implementation = ServiceException.class))),
+            @ApiResponse(
+                    responseCode = "403",
+                    description  = "Permission denied",
+                    content = @Content(schema = @Schema(implementation = ServiceException.class))),
+            @ApiResponse(
+                    responseCode = "503",
+                    description  = "Login server unavailable",
+                    content = @Content(schema = @Schema(implementation = ServiceException.class))),
+            @ApiResponse(
+                    responseCode = "500",
+                    description  = "Service exception",
+                    content = @Content(schema = @Schema(implementation = ServiceException.class)))
+    })
+    @PostMapping(
+            value = "/renew",
+            produces = {"application/json"})
+    ResponseEntity<LoginResponse> tokenRenew(@AuthenticationPrincipal UserDetails user);
+
+    @Operation(
+            summary     = "Logout",
+            description = "Logging out the user",
+            security    = {@SecurityRequirement(name = "bearerAuth")})
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200",
+                    description  = "Ok"),
+            @ApiResponse(
+                    responseCode = "500",
+                    description  = "Service exception",
+                    content = @Content(schema = @Schema(implementation = ServiceException.class))),
+            @ApiResponse(
+                    responseCode = "503",
+                    description  = "Login server unavailable or remote error",
+                    content = @Content(schema = @Schema(implementation = ServiceException.class)))
+    })
+    @DeleteMapping(
+            value = "/logout",
+            produces = {"application/json"})
+    ResponseEntity<Object> logout(@AuthenticationPrincipal UserDetails user);
+
+}
diff --git a/src/main/java/org/openepics/names/rest/api/v1/INames.java b/src/main/java/org/openepics/names/rest/api/v1/INames.java
index 9dab9f0eaddb356447295de9a585abaf4e65207c..7626cb87baf74056d3dfdb6975bb07bc16dc092f 100644
--- a/src/main/java/org/openepics/names/rest/api/v1/INames.java
+++ b/src/main/java/org/openepics/names/rest/api/v1/INames.java
@@ -20,6 +20,7 @@ package org.openepics.names.rest.api.v1;
 
 import java.util.List;
 
+import org.openepics.names.configuration.SecurityConfiguration;
 import org.openepics.names.rest.beans.FieldName;
 import org.openepics.names.rest.beans.element.NameElement;
 import org.openepics.names.rest.beans.element.NameElementCommandConfirm;
@@ -29,7 +30,10 @@ import org.openepics.names.rest.beans.response.Response;
 import org.openepics.names.rest.beans.response.ResponseBoolean;
 import org.openepics.names.rest.beans.response.ResponseBooleanList;
 import org.openepics.names.rest.beans.response.ResponsePageNameElements;
+import org.openepics.names.service.security.dto.UserDetails;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -48,6 +52,7 @@ import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import io.swagger.v3.oas.annotations.tags.Tag;
 
 /**
@@ -142,7 +147,8 @@ public interface INames {
 
                           Note
                           - Uuid is created by Naming
-                          """)
+                          """,
+            security = {@SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(
                     responseCode = "201",
@@ -154,6 +160,14 @@ public interface INames {
                     responseCode = "400",
                     description  = "Bad request. Reason and information such as message, details, field are available.",
                     content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
+            @ApiResponse(
+                    responseCode = "401",
+                    description  = "Unauthorized. Reason and information such as message, details, field are available.",
+                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
+            @ApiResponse(
+                    responseCode = "403",
+                    description  = "Forbidden. Reason and information such as message, details, field are available.",
+                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
             @ApiResponse(
                     responseCode = "404",
                     description  = "Not Found. Reason and information such as message, details, field are available.",
@@ -174,7 +188,9 @@ public interface INames {
     @PostMapping(
             produces = {"application/json"},
             consumes = {"application/json"})
+    @PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR_OR_USER)
     public ResponseEntity<List<NameElement>> createNames(
+            @AuthenticationPrincipal UserDetails user,
             @Parameter(
                     in = ParameterIn.DEFAULT,
                     description = "array of name elements",
@@ -664,7 +680,8 @@ public interface INames {
                           Optional attributes:
                           - parentDeviceStructure
                           - index
-                          """)
+                          """,
+            security = {@SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(
                     responseCode = "200",
@@ -676,6 +693,14 @@ public interface INames {
                     responseCode = "400",
                     description  = "Bad request. Reason and information such as message, details, field are available.",
                     content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
+            @ApiResponse(
+                    responseCode = "401",
+                    description  = "Unauthorized. Reason and information such as message, details, field are available.",
+                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
+            @ApiResponse(
+                    responseCode = "403",
+                    description  = "Forbidden. Reason and information such as message, details, field are available.",
+                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
             @ApiResponse(
                     responseCode = "404",
                     description  = "Not Found. Reason and information such as message, details, field are available.",
@@ -696,7 +721,9 @@ public interface INames {
     @PutMapping(
             produces = {"application/json"},
             consumes = {"application/json"})
+    @PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR_OR_USER)
     public List<NameElement> updateNames(
+            @AuthenticationPrincipal UserDetails user,
             @Parameter(
                     in = ParameterIn.DEFAULT,
                     description = "array of name elements",
@@ -725,7 +752,8 @@ public interface INames {
 
                           Required attributes:
                           - uuid
-                          """)
+                          """,
+            security = {@SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(
                     responseCode = "204",
@@ -734,6 +762,14 @@ public interface INames {
                     responseCode = "400",
                     description  = "Bad request. Reason and information such as message, details, field are available.",
                     content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
+            @ApiResponse(
+                    responseCode = "401",
+                    description  = "Unauthorized. Reason and information such as message, details, field are available.",
+                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
+            @ApiResponse(
+                    responseCode = "403",
+                    description  = "Forbidden. Reason and information such as message, details, field are available.",
+                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
             @ApiResponse(
                     responseCode = "404",
                     description  = "Not Found. Reason and information such as message, details, field are available.",
@@ -750,7 +786,9 @@ public interface INames {
     @DeleteMapping(
             produces = {"application/json"},
             consumes = {"application/json"})
+    @PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR_OR_USER)
     public ResponseEntity<Response> deleteNames(
+            @AuthenticationPrincipal UserDetails user,
             @Parameter(
                     in = ParameterIn.DEFAULT,
                     description = "array of name elements",
diff --git a/src/main/java/org/openepics/names/rest/api/v1/IStructures.java b/src/main/java/org/openepics/names/rest/api/v1/IStructures.java
index fed8d373a414f4c9e9b8a6be5908c8dae9e0ba8e..fa9b542e42123288228d99b379cb5bcfd87adf4c 100644
--- a/src/main/java/org/openepics/names/rest/api/v1/IStructures.java
+++ b/src/main/java/org/openepics/names/rest/api/v1/IStructures.java
@@ -20,6 +20,7 @@ package org.openepics.names.rest.api.v1;
 
 import java.util.List;
 
+import org.openepics.names.configuration.SecurityConfiguration;
 import org.openepics.names.rest.beans.FieldStructure;
 import org.openepics.names.rest.beans.Type;
 import org.openepics.names.rest.beans.element.StructureElement;
@@ -30,7 +31,10 @@ import org.openepics.names.rest.beans.response.Response;
 import org.openepics.names.rest.beans.response.ResponseBoolean;
 import org.openepics.names.rest.beans.response.ResponseBooleanList;
 import org.openepics.names.rest.beans.response.ResponsePageStructureElements;
+import org.openepics.names.service.security.dto.UserDetails;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -49,6 +53,7 @@ import io.swagger.v3.oas.annotations.media.Content;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import io.swagger.v3.oas.annotations.tags.Tag;
 
 /**
@@ -146,7 +151,8 @@ public interface IStructures {
                           - Uuid is created by Naming
                           - Parent is required for System, Subsystem, DeviceGroup, DeviceType
                           - Mnemonic is required for System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup
-                          """)
+                          """,
+            security = {@SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(
                     responseCode = "201",
@@ -158,6 +164,14 @@ public interface IStructures {
                     responseCode = "400",
                     description  = "Bad request. Reason and information such as message, details, field are available.",
                     content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
+            @ApiResponse(
+                    responseCode = "401",
+                    description  = "Unauthorized. Reason and information such as message, details, field are available.",
+                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
+            @ApiResponse(
+                    responseCode = "403",
+                    description  = "Forbidden. Reason and information such as message, details, field are available.",
+                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
             @ApiResponse(
                     responseCode = "404",
                     description  = "Not Found. Reason and information such as message, details, field are available.",
@@ -178,7 +192,9 @@ public interface IStructures {
     @PostMapping(
             produces = {"application/json"},
             consumes = {"application/json"})
+    @PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR)
     public ResponseEntity<List<StructureElement>> createStructures(
+            @AuthenticationPrincipal UserDetails user,
             @Parameter(
                     in = ParameterIn.DEFAULT,
                     description = "array of structure elements",
@@ -726,7 +742,8 @@ public interface IStructures {
                           Note
                           - Parent is required for System, Subsystem, DeviceGroup, DeviceType
                           - Mnemonic is required for System, Subsystem, Discipline, DeviceType, may be set for SystemGroup, not allowed for DeviceGroup
-                          """)
+                          """,
+            security = {@SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(
                     responseCode = "200",
@@ -738,6 +755,14 @@ public interface IStructures {
                     responseCode = "400",
                     description  = "Bad request. Reason and information such as message, details, field are available.",
                     content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
+            @ApiResponse(
+                    responseCode = "401",
+                    description  = "Unauthorized. Reason and information such as message, details, field are available.",
+                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
+            @ApiResponse(
+                    responseCode = "403",
+                    description  = "Forbidden. Reason and information such as message, details, field are available.",
+                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
             @ApiResponse(
                     responseCode = "404",
                     description  = "Not Found. Reason and information such as message, details, field are available.",
@@ -758,7 +783,9 @@ public interface IStructures {
     @PutMapping(
             produces = {"application/json"},
             consumes = {"application/json"})
+    @PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR)
     public List<StructureElement> updateStructures(
+            @AuthenticationPrincipal UserDetails user,
             @Parameter(
                     in = ParameterIn.DEFAULT,
                     description = "array of structure elements",
@@ -788,7 +815,8 @@ public interface IStructures {
                           Required attributes:
                           - uuid
                           - type
-                          """)
+                          """,
+            security = {@SecurityRequirement(name = "bearerAuth")})
     @ApiResponses(value = {
             @ApiResponse(
                     responseCode = "204",
@@ -797,6 +825,14 @@ public interface IStructures {
                     responseCode = "400",
                     description  = "Bad request. Reason and information such as message, details, field are available.",
                     content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
+            @ApiResponse(
+                    responseCode = "401",
+                    description  = "Unauthorized. Reason and information such as message, details, field are available.",
+                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
+            @ApiResponse(
+                    responseCode = "403",
+                    description  = "Forbidden. Reason and information such as message, details, field are available.",
+                    content = @Content(mediaType = "application/json", schema = @Schema(implementation = Response.class))),
             @ApiResponse(
                     responseCode = "404",
                     description  = "Not Found. Reason and information such as message, details, field are available.",
@@ -813,7 +849,9 @@ public interface IStructures {
     @DeleteMapping(
             produces = {"application/json"},
             consumes = {"application/json"})
+    @PreAuthorize(SecurityConfiguration.IS_ADMINISTRATOR)
     public ResponseEntity<Response> deleteStructures(
+            @AuthenticationPrincipal UserDetails user,
             @Parameter(
                     in = ParameterIn.DEFAULT,
                     description = "array of structure elements",
diff --git a/src/main/java/org/openepics/names/rest/beans/security/Login.java b/src/main/java/org/openepics/names/rest/beans/security/Login.java
new file mode 100644
index 0000000000000000000000000000000000000000..6beba544bd486d8979ef75b32a1de46fa61abc32
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/beans/security/Login.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.rest.beans.security;
+
+/**
+ * Class is used for sending Login request trough REST API.
+ *
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+public class Login {
+
+    private String username;
+    private String password;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/rest/beans/security/LoginResponse.java b/src/main/java/org/openepics/names/rest/beans/security/LoginResponse.java
new file mode 100644
index 0000000000000000000000000000000000000000..498b02564df3b0c5bcd723f622dc1912a74b2c83
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/beans/security/LoginResponse.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.rest.beans.security;
+
+/**
+ * Class used for sending back JWT token in response to the client if login was successful.
+ *
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+public class LoginResponse {
+
+    private String token;
+
+    /**
+     * Setting the JWT token for the Login response
+     *
+     * @param token the JWT token that will be used for the communication
+     */
+    public LoginResponse(String token) {
+        this.token = token;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/rest/controller/AuthenticationController.java b/src/main/java/org/openepics/names/rest/controller/AuthenticationController.java
new file mode 100644
index 0000000000000000000000000000000000000000..21a31a0d99fab9f79ecc016eaccdc5bf2c7129da
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/controller/AuthenticationController.java
@@ -0,0 +1,129 @@
+package org.openepics.names.rest.controller;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.openepics.names.exception.ServiceException;
+
+import org.openepics.names.exception.security.AuthenticationException;
+import org.openepics.names.exception.security.RemoteException;
+import org.openepics.names.exception.security.UnauthorizedException;
+import org.openepics.names.rest.api.v1.IAuthentication;
+import org.openepics.names.rest.beans.security.Login;
+import org.openepics.names.rest.beans.security.LoginResponse;
+import org.openepics.names.service.LogService;
+import org.openepics.names.service.security.AuthenticationService;
+import org.openepics.names.service.security.dto.UserDetails;
+import org.openepics.names.service.security.util.SecurityTextUtil;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.ResponseCookie;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author <a href="mailto:zoltan.runyo@ess.eu">Zoltan Runyo</a>
+ */
+@RestController
+public class AuthenticationController implements IAuthentication {
+
+    private static final Logger LOGGER = Logger.getLogger(AuthenticationController.class.getName());
+
+    private final AuthenticationService authenticationService;
+    private final LogService logService;
+
+    @Autowired
+    public AuthenticationController(
+            AuthenticationService authenticationService,
+            LogService logService) {
+        this.authenticationService = authenticationService;
+        this.logService = logService;
+    }
+
+    @Override
+    public ResponseEntity<LoginResponse> login(Login loginInfo) {
+        try {
+            LoginResponse login =
+                    authenticationService.login(loginInfo.getUsername(), loginInfo.getPassword());
+
+            ResponseCookie loginCookie =
+                    ResponseCookie.from(SecurityTextUtil.COOKIE_AUTH_HEADER, login.getToken())
+                    .httpOnly(true)
+                    .secure(true)
+                    .path("/")
+                    .build();
+
+            return ResponseEntity.ok()
+                    .header(HttpHeaders.SET_COOKIE, loginCookie.toString())
+                    .body(login);
+        } catch (UnauthorizedException e) {
+            logService.logServiceException(LOGGER, Level.WARNING, e, "User doesn't have permission to log in");
+            throw e;
+        } catch (AuthenticationException e) {
+            logService.logServiceException(LOGGER, Level.WARNING, e, "Error while user tried to log in");
+            throw e;
+        } catch (RemoteException e) {
+            logService.logServiceException(LOGGER, Level.WARNING, e, "Remote exception while user tried to log in");
+            throw e;
+        } catch (Exception e) {
+            logService.logException(LOGGER, Level.WARNING, e, "Error while trying to log in user");
+            throw e;
+        }
+    }
+
+    @Override
+    public ResponseEntity<LoginResponse> tokenRenew(UserDetails user) {
+        try {
+            LoginResponse renew = authenticationService.renewToken(user);
+
+            ResponseCookie renewCookie =
+                    ResponseCookie.from(SecurityTextUtil.COOKIE_AUTH_HEADER, renew.getToken())
+                    .httpOnly(true)
+                    .secure(true)
+                    .path("/")
+                    .build();
+
+            return ResponseEntity.ok()
+                    .header(HttpHeaders.SET_COOKIE, renewCookie.toString())
+                    .body(renew);
+        } catch (UnauthorizedException e) {
+            logService.logServiceException(LOGGER, Level.WARNING, e, "Authorization error while trying to renew token");
+            throw e;
+        } catch (RemoteException e) {
+            logService.logServiceException(LOGGER, Level.WARNING, e, "Remote exception while trying to renew token");
+            throw e;
+        } catch (Exception e) {
+            logService.logException(LOGGER, Level.WARNING, e, "Error while trying to renew token");
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+    @Override
+    public ResponseEntity<Object> logout(UserDetails user) {
+        try {
+            authenticationService.logout(user);
+
+            ResponseCookie deleteSpringCookie =
+                    ResponseCookie.from(SecurityTextUtil.COOKIE_AUTH_HEADER, null)
+                    .path("/")
+                    .httpOnly(true)
+                    .secure(true)
+                    .build();
+
+            return ResponseEntity.ok()
+                    .header(HttpHeaders.SET_COOKIE, deleteSpringCookie.toString())
+                    .build();
+        } catch (RemoteException e) {
+            logService.logServiceException(LOGGER, Level.WARNING, e);
+            throw e;
+        } catch (ServiceException e) {
+            logService.logServiceException(LOGGER, Level.WARNING, e);
+            throw e;
+        } catch (Exception e) {
+            logService.logException(LOGGER, Level.WARNING, e, "Error while trying to logout user");
+            throw new ServiceException(e.getMessage());
+        }
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/rest/controller/HealthcheckController.java b/src/main/java/org/openepics/names/rest/controller/HealthcheckController.java
index 524d885640975b749170e506823318105aaab951..93cd1f64dd3f800b48576258319635ef8810cb80 100644
--- a/src/main/java/org/openepics/names/rest/controller/HealthcheckController.java
+++ b/src/main/java/org/openepics/names/rest/controller/HealthcheckController.java
@@ -38,7 +38,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
  *
  * @author Lars Johansson
  */
-@Tag(name        = "6. Healthcheck",
+@Tag(name        = "Healthcheck",
      description = "perform healthcheck for Naming application")
 @RestController
 @RequestMapping("/healthcheck")
diff --git a/src/main/java/org/openepics/names/rest/controller/NamesController.java b/src/main/java/org/openepics/names/rest/controller/NamesController.java
index 33569e4aaff56c9168b5c045a0c5c15a5ae68ce8..2e0eb347b8293ba1a343ac95aab49662e30f3822 100644
--- a/src/main/java/org/openepics/names/rest/controller/NamesController.java
+++ b/src/main/java/org/openepics/names/rest/controller/NamesController.java
@@ -36,6 +36,8 @@ import org.openepics.names.rest.beans.response.ResponseBooleanList;
 import org.openepics.names.rest.beans.response.ResponsePageNameElements;
 import org.openepics.names.service.LogService;
 import org.openepics.names.service.NamesService;
+import org.openepics.names.service.security.dto.UserDetails;
+import org.openepics.names.service.security.util.SecurityUtil;
 import org.openepics.names.util.NameElementUtil;
 import org.openepics.names.util.TextUtil;
 import org.openepics.names.util.ValidateNameElementUtil;
@@ -76,7 +78,8 @@ public class NamesController implements INames {
     }
 
     @Override
-    public ResponseEntity<List<NameElement>> createNames(List<NameElementCommandCreate> nameElementCommands) {
+    public ResponseEntity<List<NameElement>> createNames(UserDetails user,
+            List<NameElementCommandCreate> nameElementCommands) {
         // validate authority - user & admin
         // convert
         // validate
@@ -85,7 +88,7 @@ public class NamesController implements INames {
         try {
             List<NameElementCommand> commands = NameElementUtil.convertCommandCreate2Command(nameElementCommands);
             namesService.validateNamesCreate(commands);
-            return new ResponseEntity<>(namesService.createNames(commands, TextUtil.TEST_WHO), Response.getHeaderJson(), HttpStatus.CREATED);
+            return new ResponseEntity<>(namesService.createNames(commands, SecurityUtil.getUsername(user)), Response.getHeaderJson(), HttpStatus.CREATED);
         } catch (ServiceException e) {
             logService.logServiceException(LOGGER, Level.WARNING, e);
             throw e;
@@ -346,7 +349,8 @@ public class NamesController implements INames {
     // ----------------------------------------------------------------------------------------------------
 
     @Override
-    public List<NameElement> updateNames(List<NameElementCommandUpdate> nameElementCommands) {
+    public List<NameElement> updateNames(UserDetails user,
+            List<NameElementCommandUpdate> nameElementCommands) {
         // validate authority - user & admin
         // convert
         // validate
@@ -355,7 +359,7 @@ public class NamesController implements INames {
         try {
             List<NameElementCommand> commands = NameElementUtil.convertCommandUpdate2Command(nameElementCommands);
             namesService.validateNamesUpdate(commands);
-            return namesService.updateNames(commands, TextUtil.TEST_WHO);
+            return namesService.updateNames(commands, SecurityUtil.getUsername(user));
         } catch (ServiceException e) {
             logService.logServiceException(LOGGER, Level.WARNING, e);
             throw e;
@@ -368,7 +372,8 @@ public class NamesController implements INames {
     // ----------------------------------------------------------------------------------------------------
 
     @Override
-    public ResponseEntity<Response> deleteNames(List<NameElementCommandConfirm> nameElementCommands) {
+    public ResponseEntity<Response> deleteNames(UserDetails user,
+            List<NameElementCommandConfirm> nameElementCommands) {
         // validate authority - user & admin
         // convert
         // validate
@@ -377,7 +382,7 @@ public class NamesController implements INames {
         try {
             List<NameElementCommand> commands = NameElementUtil.convertCommandConfirm2Command(nameElementCommands);
             namesService.validateNamesDelete(commands);
-            namesService.deleteNames(commands, TextUtil.TEST_WHO);
+            namesService.deleteNames(commands, SecurityUtil.getUsername(user));
             return new ResponseEntity<>(HttpStatus.NO_CONTENT);
         } catch (ServiceException e) {
             logService.logServiceException(LOGGER, Level.WARNING, e);
diff --git a/src/main/java/org/openepics/names/rest/controller/ReportController.java b/src/main/java/org/openepics/names/rest/controller/ReportController.java
index 292f4da94b7b5819344180490c81ec5f93db20e3..f3cb13134ce51a152418eeedaef73a966030ba47 100644
--- a/src/main/java/org/openepics/names/rest/controller/ReportController.java
+++ b/src/main/java/org/openepics/names/rest/controller/ReportController.java
@@ -61,7 +61,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
  *
  * @author Lars Johansson
  */
-@Tag(name        = "5. Report",
+@Tag(name        = "Report",
      description = "provide reports for Naming application")
 @RestController
 @RequestMapping("/report")
diff --git a/src/main/java/org/openepics/names/rest/controller/StructuresController.java b/src/main/java/org/openepics/names/rest/controller/StructuresController.java
index 5b7fe1697829c76dcecf9318b905b2c630d0aac7..32c51cfc47ac9a1d677217d56a8ab9a3443da82b 100644
--- a/src/main/java/org/openepics/names/rest/controller/StructuresController.java
+++ b/src/main/java/org/openepics/names/rest/controller/StructuresController.java
@@ -37,6 +37,8 @@ import org.openepics.names.rest.beans.response.ResponseBooleanList;
 import org.openepics.names.rest.beans.response.ResponsePageStructureElements;
 import org.openepics.names.service.LogService;
 import org.openepics.names.service.StructuresService;
+import org.openepics.names.service.security.dto.UserDetails;
+import org.openepics.names.service.security.util.SecurityUtil;
 import org.openepics.names.util.StructureElementUtil;
 import org.openepics.names.util.TextUtil;
 import org.openepics.names.util.ValidateStructureElementUtil;
@@ -77,7 +79,8 @@ public class StructuresController implements IStructures {
     }
 
     @Override
-    public ResponseEntity<List<StructureElement>> createStructures(List<StructureElementCommandCreate> structureElementCommands) {
+    public ResponseEntity<List<StructureElement>> createStructures(UserDetails user,
+            List<StructureElementCommandCreate> structureElementCommands) {
         // validate authority - user & admin
         // convert
         // validate
@@ -86,7 +89,7 @@ public class StructuresController implements IStructures {
         try {
             List<StructureElementCommand> commands = StructureElementUtil.convertCommandCreate2Command(structureElementCommands);
             structuresService.validateStructuresCreate(commands);
-            return new ResponseEntity<>(structuresService.createStructures(commands, TextUtil.TEST_WHO), Response.getHeaderJson(), HttpStatus.CREATED);
+            return new ResponseEntity<>(structuresService.createStructures(commands, SecurityUtil.getUsername(user)), Response.getHeaderJson(), HttpStatus.CREATED);
         } catch (ServiceException e) {
             logService.logServiceException(LOGGER, Level.WARNING, e);
             throw e;
@@ -347,7 +350,8 @@ public class StructuresController implements IStructures {
     // ----------------------------------------------------------------------------------------------------
 
     @Override
-    public List<StructureElement> updateStructures(List<StructureElementCommandUpdate> structureElementCommands) {
+    public List<StructureElement> updateStructures(UserDetails user,
+            List<StructureElementCommandUpdate> structureElementCommands) {
         // validate authority - user & admin
         // convert
         // validate
@@ -356,7 +360,7 @@ public class StructuresController implements IStructures {
         try {
             List<StructureElementCommand> commands = StructureElementUtil.convertCommandUpdate2Command(structureElementCommands);
             structuresService.validateStructuresUpdate(commands);
-            return structuresService.updateStructures(commands, TextUtil.TEST_WHO);
+            return structuresService.updateStructures(commands, SecurityUtil.getUsername(user));
         } catch (ServiceException e) {
             logService.logServiceException(LOGGER, Level.WARNING, e);
             throw e;
@@ -369,7 +373,8 @@ public class StructuresController implements IStructures {
     // ----------------------------------------------------------------------------------------------------
 
     @Override
-    public ResponseEntity<Response> deleteStructures(List<StructureElementCommandConfirm> structureElementCommands) {
+    public ResponseEntity<Response> deleteStructures(UserDetails user,
+            List<StructureElementCommandConfirm> structureElementCommands) {
         // validate authority - user & admin
         // convert
         // validate
@@ -378,7 +383,7 @@ public class StructuresController implements IStructures {
         try {
             List<StructureElementCommand> commands = StructureElementUtil.convertCommandConfirm2Command(structureElementCommands);
             structuresService.validateStructuresDelete(commands);
-            structuresService.deleteStructures(commands, TextUtil.TEST_WHO);
+            structuresService.deleteStructures(commands, SecurityUtil.getUsername(user));
             return new ResponseEntity<>(HttpStatus.NO_CONTENT);
         } catch (ServiceException e) {
             logService.logServiceException(LOGGER, Level.WARNING, e);
diff --git a/src/main/java/org/openepics/names/rest/filter/JwtRequestFilter.java b/src/main/java/org/openepics/names/rest/filter/JwtRequestFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ccc4cd6c4927a7041b7ad0d53bca8ce57e80061
--- /dev/null
+++ b/src/main/java/org/openepics/names/rest/filter/JwtRequestFilter.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2021 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.rest.filter;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.openepics.names.exception.handler.GlobalControllerExceptionHandler;
+import org.openepics.names.rest.beans.response.Response;
+import org.openepics.names.service.LogService;
+import org.openepics.names.service.security.JwtTokenService;
+import org.openepics.names.service.security.JwtUserDetailsService;
+import org.openepics.names.service.security.dto.UserDetails;
+import org.openepics.names.service.security.util.EncryptUtil;
+import org.openepics.names.service.security.util.SecurityTextUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.ServletWebRequest;
+import org.springframework.web.filter.OncePerRequestFilter;
+import org.springframework.web.util.WebUtils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.fusionauth.jwt.JWTExpiredException;
+
+/**
+ * Purpose of class to intercept rest calls and handle cookies and tokens in uniformed manner.
+ *
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+@Component
+public class JwtRequestFilter extends OncePerRequestFilter {
+
+    private static final Logger LOGGER = Logger.getLogger(JwtRequestFilter.class.getName());
+
+    private final JwtUserDetailsService jwtUserDetailsService;
+    private final JwtTokenService jwtTokenService;
+    private final EncryptUtil encryptUtil;
+    private final GlobalControllerExceptionHandler globalControllerExceptionHandler;
+    private final LogService logService;
+
+    @Autowired
+    public JwtRequestFilter(
+            JwtUserDetailsService jwtUserDetailsService,
+            JwtTokenService jwtTokenService,
+            EncryptUtil encryptUtil,
+            GlobalControllerExceptionHandler globalControllerExceptionHandler,
+            LogService logService) {
+        this.jwtUserDetailsService = jwtUserDetailsService;
+        this.jwtTokenService = jwtTokenService;
+        this.encryptUtil = encryptUtil;
+        this.globalControllerExceptionHandler = globalControllerExceptionHandler;
+        this.logService = logService;
+    }
+
+    private static class TokenInfo {
+        private String userName;
+        private String rbacToken;
+
+        public String getUserName() {
+            return userName;
+        }
+
+        public void setUserName(String userName) {
+            this.userName = userName;
+        }
+
+        public String getRbacToken() {
+            return rbacToken;
+        }
+
+        public void setRbacToken(String rbacToken) {
+            this.rbacToken = rbacToken;
+        }
+    }
+
+    private TokenInfo extractTokenInfo(String jwtToken) {
+        TokenInfo result = new TokenInfo();
+        try {
+            result.setUserName(jwtTokenService.getUsernameFromToken(jwtToken));
+            result.setRbacToken(encryptUtil.decrypt(jwtTokenService.getRBACTokenFromToken(jwtToken)));
+        } catch (JWTExpiredException e) {
+            // not log as it may be considerable amount of exceptions
+            // otherwise message: JWT Token has expired
+            logService.logException(LOGGER, Level.WARNING, e, "JWT Token has expired");
+            return null;
+        } catch (Exception e) {
+            logService.logException(LOGGER, Level.WARNING, e, "Unable to get info from JWT Token");
+            return null;
+        }
+
+        return result;
+    }
+
+    @Override
+    protected void doFilterInternal(
+            HttpServletRequest httpServletRequest,
+            HttpServletResponse httpServletResponse,
+            FilterChain filterChain)
+                    throws ServletException, IOException {
+
+        final String requestTokenHeader = httpServletRequest.getHeader("Authorization");
+
+        String jwtToken = null;
+        TokenInfo tokenInfo = null;
+        try {
+            // JWT Token is in the form "Bearer token". Remove Bearer word and get
+            // only the Token
+            if (requestTokenHeader != null) {
+                if (requestTokenHeader.startsWith(SecurityTextUtil.AUTHENTICATION_HEADER_PREFIX)) {
+                    jwtToken = requestTokenHeader.substring(SecurityTextUtil.AUTHENTICATION_HEADER_PREFIX.length());
+                } else {
+                    jwtToken = requestTokenHeader;
+                }
+
+                tokenInfo = extractTokenInfo(jwtToken);
+            } else {
+                Cookie cookie = WebUtils.getCookie(httpServletRequest, SecurityTextUtil.COOKIE_AUTH_HEADER);
+
+                if (cookie != null) {
+                    String cookieValue = cookie.getValue();
+                    if (StringUtils.isNotEmpty(cookieValue)) {
+                        jwtToken = cookieValue;
+                        tokenInfo = extractTokenInfo(cookieValue);
+                    }
+                }
+            }
+
+            // Once we get the token validate it.
+            if (tokenInfo != null
+                    && tokenInfo.getRbacToken() != null
+                    && SecurityContextHolder.getContext().getAuthentication() == null) {
+
+                UserDetails userDetails = this.jwtUserDetailsService.loadUserByToken(tokenInfo.getRbacToken());
+
+                // if token is valid configure Spring Security to manually set
+                // authentication
+                if (jwtTokenService.validateToken(jwtToken, userDetails)) {
+
+                    UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
+                            new UsernamePasswordAuthenticationToken(
+                                    userDetails, null, userDetails.getAuthorities());
+                    usernamePasswordAuthenticationToken.setDetails(
+                            new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
+                    // After setting the Authentication in the context, we specify
+                    // that the current user is authenticated. So it passes the
+                    // Spring Security Configurations successfully.
+                    SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
+                }
+            }
+        } catch (RuntimeException e) {
+            // MyObject is whatever the output of the below method
+            ResponseEntity<Response> objectResponseEntity = null;
+            try {
+                objectResponseEntity = globalControllerExceptionHandler.handleConflict(e, new ServletWebRequest(httpServletRequest));
+
+                // set the response object
+                httpServletResponse.setStatus(objectResponseEntity.getStatusCode().value());
+                httpServletResponse.setContentType("application/json");
+
+                // pass down the actual obj that exception handler normally send
+                ObjectMapper mapper = new ObjectMapper();
+                PrintWriter out = httpServletResponse.getWriter();
+                out.print(mapper.writeValueAsString(objectResponseEntity.getBody()));
+                out.flush();
+
+                return;
+            } catch (Exception ex) {
+                logService.logException(LOGGER, Level.WARNING, ex, "JWT Request filter processing error");
+            }
+        }
+        filterChain.doFilter(httpServletRequest, httpServletResponse);
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/AuthenticationService.java b/src/main/java/org/openepics/names/service/security/AuthenticationService.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3e8619e7e6ed29ded626c92a41a22f64da2451f
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/AuthenticationService.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security;
+
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.openepics.names.configuration.SecurityConfiguration;
+import org.openepics.names.exception.ServiceException;
+import org.openepics.names.exception.security.AuthenticationException;
+import org.openepics.names.exception.security.UnauthorizedException;
+import org.openepics.names.rest.beans.security.LoginResponse;
+import org.openepics.names.service.security.dto.LoginTokenDto;
+import org.openepics.names.service.security.dto.UserDetails;
+import org.openepics.names.service.security.util.EncryptUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+@Service
+public class AuthenticationService {
+
+    private static final Logger LOGGER = Logger.getLogger(AuthenticationService.class.getName());
+
+    @Value("${jwt.expire.in.minutes}")
+    private Integer tokenExpiration;
+
+    private final UserService userService;
+    private final JwtTokenService jwtTokenService;
+    private final EncryptUtil encryptUtil;
+
+    @Autowired
+    public AuthenticationService(
+            UserService userService, JwtTokenService jwtTokenService, EncryptUtil encryptUtil) {
+        this.userService = userService;
+        this.jwtTokenService = jwtTokenService;
+        this.encryptUtil = encryptUtil;
+    }
+
+    /**
+     * Checks if user has permission in RBAC, and if has, logs in. Successful login will result in
+     * creating a JWT for the REST API communication
+     *
+     * @param userName The login name for the user
+     * @param password The password for the user
+     * @return After successful login the backend will generate a JWT that can be user for the REST
+     *     API communication
+     * @throws AuthenticationException If user has bad username/password, or doesn't have permission
+     *     to log in
+     */
+    public LoginResponse login(String userName, String password) throws AuthenticationException {
+        LoginTokenDto tokenDto = userService.loginUser(userName, password);
+        // checking user roles in RBAC
+        checkUserRights(tokenDto.getRoles(), userName);
+
+        UserDetails userDetails = new UserDetails();
+        userDetails.setUserName(userName);
+        userDetails.setToken(encryptUtil.encrypt(tokenDto.getToken()));
+        userDetails.setRoles(tokenDto.getRoles());
+
+        long tokenExpiresIn = Math.min(tokenExpiration, tokenDto.getExpirationDuration());
+
+        return new LoginResponse(jwtTokenService.generateToken(userDetails, tokenExpiresIn));
+    }
+
+    /**
+     * Checks if user has roles in RBAC at the beginning of the login process
+     *
+     * @param userRoles The roles of the user according to RBAC
+     * @param userName The name of the user
+     * @throws UnauthorizedException If user doesn't have permissions in RBAC
+     */
+    private void checkUserRights(List<String> userRoles, String userName) throws UnauthorizedException {
+        List<String> rolesUserHas =
+                userRoles.stream()
+                .filter(SecurityConfiguration.getAllowedRolesToLogin()::contains)
+                .toList();
+
+        if (rolesUserHas.isEmpty()) {
+            LOGGER.log(Level.WARNING, "User ({}) doesn't have permission to log in", userName);
+            throw new UnauthorizedException("You don't have permission to log in");
+        }
+    }
+
+    public LoginResponse renewToken(UserDetails user) {
+        LoginTokenDto token = userService.renewToken(user.getToken());
+        user.setToken(encryptUtil.encrypt(user.getToken()));
+
+        long tokenExpiresIn = Math.min(tokenExpiration, token.getExpirationDuration());
+
+        return new LoginResponse(jwtTokenService.generateToken(user, tokenExpiresIn));
+    }
+
+    public void logout(UserDetails user) throws ServiceException {
+        userService.logoutUser(user.getToken());
+    }
+
+    public List<String> getUserRoles(UserDetails user) {
+        UserDetails userInfo = userService.getUserInfoFromToken(user.getToken());
+        return userInfo.getRoles();
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/JwtTokenService.java b/src/main/java/org/openepics/names/service/security/JwtTokenService.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a04701358c3719634314b14a855a195cbfa1047
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/JwtTokenService.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security;
+
+import io.fusionauth.jwt.Signer;
+import io.fusionauth.jwt.Verifier;
+import io.fusionauth.jwt.domain.JWT;
+import io.fusionauth.jwt.hmac.HMACSigner;
+import io.fusionauth.jwt.hmac.HMACVerifier;
+
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.Date;
+
+import org.openepics.names.service.security.dto.UserDetails;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+@Service
+public class JwtTokenService {
+
+    private static final String TOKEN = "token";
+    private static final String ROLES = "roles";
+
+    @Value("${jwt.secret}")
+    private String secret;
+
+    /**
+     * Retrieves userName from JWT token.
+     *
+     * @param token the JWT token.
+     * @return the userName from the JWT token.
+     */
+    public String getUsernameFromToken(String token) {
+        return decodeJWT(token).subject;
+    }
+
+    public String getRBACTokenFromToken(String token) {
+        return decodeJWT(token).getAllClaims().get(TOKEN).toString();
+    }
+
+    // check if the token has expired
+    private Boolean isTokenExpired(String token) {
+        return decodeJWT(token).isExpired();
+    }
+
+    /**
+     * Retrieving a field value from the JWT token.
+     *
+     * @param token The JWT token.
+     * @return The decoded value of the JWT token.
+     */
+    public JWT decodeJWT(String token) {
+        Verifier verifier = HMACVerifier.newVerifier(secret);
+        return JWT.getDecoder().decode(token, verifier);
+    }
+
+    /**
+     * Generates JWT token from userInformation, and expiration interval.
+     *
+     * @param userDetails Information about the user.
+     * @param tokenExpiration JWT token expiration interval.
+     * @return The generated JWT token.
+     */
+    // while creating the token -
+    // 1. Define  claims of the token, like Issuer, Expiration, Subject, and the ID
+    // 2. Sign the JWT using the HS512 algorithm and secret key.
+    // 3. According to JWS Compact
+    // Serialization(https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-3.1)
+    //   compaction of the JWT to a URL-safe string
+    public String generateToken(UserDetails userDetails, long tokenExpiration) {
+        Date jwtTokenValidity = new Date(System.currentTimeMillis() + tokenExpiration * 60 * 1000);
+        Signer signer = HMACSigner.newSHA512Signer(secret);
+        JWT jwt =
+                new JWT()
+                .setIssuer("Naming-tool")
+                .setIssuedAt(ZonedDateTime.now(ZoneOffset.UTC))
+                .setSubject(userDetails.getUserName())
+                .addClaim(TOKEN, userDetails.getToken())
+                .addClaim(ROLES, userDetails.getRoles())
+                .setExpiration(ZonedDateTime.ofInstant(jwtTokenValidity.toInstant(), ZoneId.systemDefault()));
+
+        return JWT.getEncoder().encode(jwt, signer);
+    }
+
+    // validate token
+
+    /**
+     * Checks if the JWT token is valid.
+     *
+     * @param token The JWT token that has to be checked.
+     * @param userDetails The users details.
+     * @return <code>true</code> if the JWT token is valid <code>false</code> if the JWT token is not
+     *     valid
+     */
+    public Boolean validateToken(String token, UserDetails userDetails) {
+        final String username = getUsernameFromToken(token);
+        return (username.equals(userDetails.getUserName()) && !isTokenExpired(token));
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/JwtUserDetailsService.java b/src/main/java/org/openepics/names/service/security/JwtUserDetailsService.java
new file mode 100644
index 0000000000000000000000000000000000000000..822e7d885cd168b1fa202ea1b3ab2d057b13863d
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/JwtUserDetailsService.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security;
+
+import org.openepics.names.service.security.dto.UserDetails;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+@Service
+public class JwtUserDetailsService implements UserDetailsService {
+
+    private final UserService userService;
+
+    @Autowired
+    public JwtUserDetailsService(UserService userService) {
+        this.userService = userService;
+    }
+
+    public UserDetails loadUserByToken(String token) {
+        return userService.getUserInfoFromToken(token);
+    }
+
+    @Override
+    public org.springframework.security.core.userdetails.UserDetails loadUserByUsername(String s)
+            throws UsernameNotFoundException {
+        return null;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/RBACService.java b/src/main/java/org/openepics/names/service/security/RBACService.java
new file mode 100644
index 0000000000000000000000000000000000000000..a44877b32cd1336ffdc85533f26d2611576ba32e
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/RBACService.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security;
+
+import java.util.Base64;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.openepics.names.exception.security.AuthenticationException;
+import org.openepics.names.exception.security.EntityNotFoundException;
+import org.openepics.names.exception.security.ParseException;
+import org.openepics.names.exception.security.RemoteException;
+import org.openepics.names.exception.security.RemoteServiceException;
+import org.openepics.names.exception.security.UnauthorizedException;
+import org.openepics.names.service.LogService;
+import org.openepics.names.service.security.rbac.RBACToken;
+import org.openepics.names.service.security.rbac.RBACUserInfo;
+import org.openepics.names.service.security.rbac.RBACUserRoles;
+import org.openepics.names.service.security.util.HttpClientService;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Service;
+
+import okhttp3.Headers;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+@Service
+public class RBACService {
+
+    private static final Logger LOGGER = Logger.getLogger(RBACService.class.getName());
+
+    private static final String RBAC_SERVER_BASEURL = "rbac.server.address";
+    private static final String AUTH_PATH = "auth";
+    private static final String TOKEN_PATH = AUTH_PATH + "/token";
+
+    private static final String AUTHENTICATION_EXCEPTION = "Authentication Exception";
+
+    private final Environment env;
+    private final HttpClientService httpClientService;
+    private final LogService logService;
+
+    @Autowired
+    public RBACService(Environment env, HttpClientService httpClientService, LogService logService) {
+        this.env = env;
+        this.httpClientService = httpClientService;
+        this.logService = logService;
+    }
+
+    /**
+     * Tries to log in user with specific parameters into RBAC, and if successful then give back
+     * userInformation, and a token.
+     *
+     * @param userName the loginName for the user
+     * @param password the password for the user
+     * @return userInformation, and token for the successfully logged in user
+     * @throws AuthenticationException if authentication fails
+     */
+    public RBACToken loginUser(String userName, String password) throws RemoteException, AuthenticationException {
+        String secretHeader = Base64.getEncoder().encodeToString((userName + ":" + password).getBytes());
+        Headers headers = new Headers.Builder().add("Authorization", "BASIC " + secretHeader).build();
+
+        // trying to log in
+        try {
+            HttpClientService.ServiceResponse<RBACToken> rbacTokenServiceResponse =
+                    httpClientService.executePostRequest(
+                            headers,
+                            env.getProperty(RBAC_SERVER_BASEURL) + TOKEN_PATH,
+                            null,
+                            HttpClientService.XML_MEDIA_TYPE,
+                            RBACToken.class);
+
+            // successful login
+            if (HttpClientService.isSuccessHttpStatusCode(rbacTokenServiceResponse.getStatusCode())) {
+                return rbacTokenServiceResponse.getEntity();
+            }
+        } catch (ParseException | RemoteServiceException e) {
+            logService.logException(LOGGER, Level.WARNING, e, "Login error");
+            throw new RemoteException(AUTHENTICATION_EXCEPTION, "Error while trying to log in to RBAC");
+        }
+
+        throw new AuthenticationException("Bad username/password");
+    }
+
+    /**
+     * Gathers information about the logged in user.
+     *
+     * @param token the token for the logged in user.
+     * @return information about the logged in user.
+     * @throws UnauthorizedException if the token is not valid
+     */
+    public RBACToken userInfoFromToken(String token) throws UnauthorizedException, RemoteException {
+        Headers headers = new Headers.Builder().build();
+
+        try {
+            HttpClientService.ServiceResponse<RBACToken> rbacTokenServiceResponse =
+                    httpClientService.executeGetRequest(
+                            headers,
+                            env.getProperty(RBAC_SERVER_BASEURL) + TOKEN_PATH + "/" + token,
+                            HttpClientService.XML_MEDIA_TYPE,
+                            RBACToken.class);
+
+            // token check was successful
+            if (HttpClientService.isSuccessHttpStatusCode(rbacTokenServiceResponse.getStatusCode())) {
+                return rbacTokenServiceResponse.getEntity();
+            }
+        } catch (RemoteServiceException | ParseException e) {
+            throw new RemoteException(AUTHENTICATION_EXCEPTION, "Error while trying to getting token info from RBAC");
+        }
+
+        throw new UnauthorizedException("Token error");
+    }
+
+    /**
+     * Can be used to renew a valid client token in RBAC.
+     *
+     * @param token the token for the logged in user.
+     * @return the renewed token, and user information.
+     * @throws UnauthorizedException if token was not valid for renewing.
+     */
+    public RBACToken renewToken(String token) throws UnauthorizedException, RemoteException {
+        Headers headers = new Headers.Builder().build();
+
+        try {
+            HttpClientService.ServiceResponse<RBACToken> rbacTokenServiceResponse =
+                    httpClientService.executePostRequest(
+                            headers,
+                            env.getProperty(RBAC_SERVER_BASEURL) + TOKEN_PATH + "/" + token + "/renew",
+                            null,
+                            HttpClientService.XML_MEDIA_TYPE,
+                            RBACToken.class);
+
+            // token renewal was successful
+            if (HttpClientService.isSuccessHttpStatusCode(rbacTokenServiceResponse.getStatusCode())) {
+                return rbacTokenServiceResponse.getEntity();
+            }
+        } catch (RemoteServiceException | ParseException e) {
+            throw new RemoteException(AUTHENTICATION_EXCEPTION, "Error while trying to renew token in RBAC");
+        }
+
+        throw new UnauthorizedException("Token renewal error");
+    }
+
+    /**
+     * Can be used to log out a user from RBAC (deletes the token).
+     *
+     * @param token the token for the logged in user.
+     * @throws RemoteException if token was not valid, or already deleted
+     */
+    public void deleteToken(String token) throws RemoteException {
+        Headers headers = new Headers.Builder().build();
+
+        try {
+            Integer respCode =
+                    httpClientService.executeDeleteRequest(
+                            headers, env.getProperty(RBAC_SERVER_BASEURL) + TOKEN_PATH + "/" + token);
+
+            // deleting token was successful
+            if (HttpClientService.isSuccessHttpStatusCode(respCode)) {
+                return;
+            }
+            LOGGER.log(Level.WARNING, "Failed to delete RBAC token, response code: {}", respCode);
+            throw new RemoteException(
+                    "RBAC error", "Failed to delete RBAC token, response code: " + respCode);
+        } catch (RemoteServiceException | ParseException e) {
+            logService.logException(LOGGER, Level.WARNING, e, "Failed to delete RBAC token");
+            throw new RemoteException("RBAC error", "Failed to delete RBAC token: " + e.getMessage());
+        }
+    }
+
+    public RBACUserInfo fetchUsersByRole(String role) throws AuthenticationException, RemoteException {
+        Headers headers = new Headers.Builder().build();
+
+        try {
+            HttpClientService.ServiceResponse<RBACUserInfo> rbacTokenServiceResponse =
+                    httpClientService.executeGetRequest(
+                            headers,
+                            env.getProperty(RBAC_SERVER_BASEURL) + AUTH_PATH + "/" + role + "/users",
+                            HttpClientService.XML_MEDIA_TYPE,
+                            RBACUserInfo.class);
+
+            // fetching users was successful
+            if (HttpClientService.isSuccessHttpStatusCode(rbacTokenServiceResponse.getStatusCode())) {
+                return rbacTokenServiceResponse.getEntity();
+            }
+
+            if (HttpStatus.NOT_FOUND.value() == rbacTokenServiceResponse.getStatusCode()) {
+                throw new EntityNotFoundException("RBAC role", role);
+            }
+        } catch (RemoteServiceException | ParseException e) {
+            throw new RemoteException(AUTHENTICATION_EXCEPTION, "Error while trying get users from RBAC");
+        }
+
+        throw new UnauthorizedException("Getting user info error");
+    }
+
+    /**
+     * Fetching roles from RBAC based on username.
+     *
+     * @param username The login name to fetch the user roles.
+     * @throws RemoteException When error occurs when trying to fetch roles from RBAC
+     * @return List of roles that is associated to the user in RBAC
+     */
+    public RBACUserRoles fetchRolesByUsername(String username) throws AuthenticationException, RemoteException {
+        Headers headers = new Headers.Builder().build();
+
+        try {
+            HttpClientService.ServiceResponse<RBACUserRoles> rbacTokenServiceResponse =
+                    httpClientService.executeGetRequest(
+                            headers,
+                            env.getProperty(RBAC_SERVER_BASEURL) + AUTH_PATH + "/" + username + "/role",
+                            HttpClientService.XML_MEDIA_TYPE,
+                            RBACUserRoles.class);
+
+            // fetching users was successful
+            if (HttpClientService.isSuccessHttpStatusCode(rbacTokenServiceResponse.getStatusCode())) {
+                return rbacTokenServiceResponse.getEntity();
+            }
+        } catch (RemoteServiceException | ParseException e) {
+            throw new RemoteException(AUTHENTICATION_EXCEPTION, "Error while trying get roles by username from RBAC");
+        }
+
+        throw new RemoteException(AUTHENTICATION_EXCEPTION, "Error while trying to fetch user-roles");
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/UserService.java b/src/main/java/org/openepics/names/service/security/UserService.java
new file mode 100644
index 0000000000000000000000000000000000000000..140f2f113fc2c5d242d0570da1b135279c105906
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/UserService.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.openepics.names.exception.ServiceException;
+import org.openepics.names.exception.security.AuthenticationException;
+import org.openepics.names.exception.security.UnauthorizedException;
+import org.openepics.names.service.LogService;
+import org.openepics.names.service.security.dto.LoginTokenDto;
+import org.openepics.names.service.security.dto.UserDetails;
+import org.openepics.names.service.security.rbac.RBACToken;
+import org.openepics.names.service.security.util.SecurityUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+@Service
+public class UserService {
+
+    private static final Logger LOGGER = Logger.getLogger(UserService.class.getName());
+
+    private final RBACService rbacService;
+    private final LogService logService;
+
+    @Autowired
+    public UserService(RBACService rbacService, LogService logService) {
+        this.rbacService = rbacService;
+        this.logService = logService;
+    }
+
+    /**
+     * Logs in user with username/password in RBAC, and if successful, generates JWT token
+     *
+     * @param userName The user's login name
+     * @param password The user's password
+     * @return LoginTokenDto with roles that can be user for generating JWT token
+     * @throws AuthenticationException When user tries to log in with bad username/password
+     * @throws ServiceException If _other_ error occurs during the authentication process
+     */
+    public LoginTokenDto loginUser(String userName, String password)
+            throws ServiceException, AuthenticationException {
+
+        try {
+            RBACToken rbacToken = rbacService.loginUser(userName, password);
+
+            LocalDateTime createTime = LocalDateTime.ofInstant(rbacToken.getCreationTime().toInstant(), ZoneId.systemDefault());
+            LocalDateTime expirationTime = LocalDateTime.ofInstant(rbacToken.getExpirationTime().toInstant(), ZoneId.systemDefault());
+
+            Duration duration = Duration.between(createTime, expirationTime);
+            long expireInMinutes = Math.abs(duration.toMinutes());
+
+            return new LoginTokenDto(rbacToken.getId(), expireInMinutes, rbacToken.getRoles());
+        } catch (AuthenticationException e) {
+            logService.logServiceException(LOGGER, Level.WARNING, e, "Error while trying to log in user to RBAC");
+            throw e;
+        } catch (ServiceException e) {
+            logService.logServiceException(LOGGER, Level.WARNING, e, "Error while trying to log in user to RBAC");
+            throw e;
+        }
+    }
+
+    /**
+     * Extracting user-info from RBAC using the token they have
+     *
+     * @param token The user's login token
+     * @return The user-information stored in RBAC
+     */
+    public UserDetails getUserInfoFromToken(String token) {
+        return SecurityUtil.convertToUserDetails(rbacService.userInfoFromToken(token));
+    }
+
+    /**
+     * Trying to renew user's token in RBAC.
+     *
+     * @param token The user's login token.
+     * @return Information about the renewed token (including the new expiration date)
+     * @throws ServiceException When unexpected error occurs during the renewal process
+     * @throws UnauthorizedException When RBAC gives error during the token renewal process
+     */
+    public LoginTokenDto renewToken(String token) throws ServiceException, UnauthorizedException {
+        RBACToken rbacToken = rbacService.renewToken(token);
+
+        LocalDateTime createTime = LocalDateTime.ofInstant(rbacToken.getCreationTime().toInstant(), ZoneId.systemDefault());
+        LocalDateTime expirationTime = LocalDateTime.ofInstant(rbacToken.getExpirationTime().toInstant(), ZoneId.systemDefault());
+
+        Duration duration = Duration.between(createTime, expirationTime);
+        long expireInMinutes = Math.abs(duration.toMinutes());
+
+        return new LoginTokenDto(rbacToken.getId(), expireInMinutes, rbacToken.getRoles());
+    }
+
+    /**
+     * Trying to log out user from RBAC. This will result in deleting token from the system.
+     *
+     * @param token The user's token that has to be deleted from RBAC
+     * @throws ServiceException When error occurs during the token logout process
+     */
+    public void logoutUser(String token) throws ServiceException {
+        rbacService.deleteToken(token);
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/dto/LoginTokenDto.java b/src/main/java/org/openepics/names/service/security/dto/LoginTokenDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..5a64ece4472d4e1bd382fc8f5474b57ce18a361c
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/dto/LoginTokenDto.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security.dto;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+public class LoginTokenDto {
+
+    private String token;
+    private long expirationDuration;
+    private List<String> roles;
+
+    public LoginTokenDto(String token, long expirationDuration, List<String> roles) {
+        this.token = token;
+        this.expirationDuration = expirationDuration;
+        this.roles = roles;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public long getExpirationDuration() {
+        return expirationDuration;
+    }
+
+    public List<String> getRoles() {
+        return roles;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/dto/RoleAuthority.java b/src/main/java/org/openepics/names/service/security/dto/RoleAuthority.java
new file mode 100644
index 0000000000000000000000000000000000000000..cbc4a2f0b4ca74090e690c2044050ff856cd9317
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/dto/RoleAuthority.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security.dto;
+
+import org.springframework.security.core.GrantedAuthority;
+
+/**
+ * @author <a href="mailto:zoltan.runyo@ess.eu">Zoltan Runyo</a>
+ */
+public class RoleAuthority implements GrantedAuthority {
+
+    private static final long serialVersionUID = -47836193761080412L;
+
+    private String role;
+
+    public RoleAuthority(String role) {
+        this.role = role;
+    }
+
+    @Override
+    public String getAuthority() {
+        return role;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/dto/UserDetails.java b/src/main/java/org/openepics/names/service/security/dto/UserDetails.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c26717e459cf5bbf420f94bed3b855ad278e391
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/dto/UserDetails.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security.dto;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+import org.springframework.security.core.GrantedAuthority;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+public class UserDetails {
+
+    private String userName;
+    private String fullName;
+    private String token;
+    private Collection<RoleAuthority> authorities;
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public String getFullName() {
+        return fullName;
+    }
+
+    public void setFullName(String fullName) {
+        this.fullName = fullName;
+    }
+
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return authorities;
+    }
+
+    public List<String> getRoles() {
+        return authorities != null
+                ? authorities.stream().map(RoleAuthority::getAuthority).collect(Collectors.toList())
+                        : Collections.emptyList();
+    }
+
+    public void setRoles(List<String> roles) {
+        this.authorities =
+                roles != null
+                ? roles.stream().map(RoleAuthority::new).collect(Collectors.toList())
+                        : Collections.emptyList();
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/rbac/RBACToken.java b/src/main/java/org/openepics/names/service/security/rbac/RBACToken.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c246a3e8928f4f4161a23899f78209f4f3e46e2
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/rbac/RBACToken.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security.rbac;
+
+import java.util.Date;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class RBACToken {
+
+    private String id;
+
+    @JsonProperty("username")
+    private String userName;
+    private String firstName;
+    private String lastName;
+    private Date creationTime;
+    private Date expirationTime;
+    private String ip;
+    private List<String> roles;
+    private String signature;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getFirstName() {
+        return firstName;
+    }
+
+    public void setFirstName(String firstName) {
+        this.firstName = firstName;
+    }
+
+    public String getLastName() {
+        return lastName;
+    }
+
+    public void setLastName(String lastName) {
+        this.lastName = lastName;
+    }
+
+    public Date getCreationTime() {
+        return RBACToken.cloneDate(creationTime);
+    }
+
+    public void setCreationTime(Date creationTime) {
+        this.creationTime = RBACToken.cloneDate(creationTime);
+    }
+
+    public Date getExpirationTime() {
+        return RBACToken.cloneDate(expirationTime);
+    }
+
+    public void setExpirationTime(Date expirationTime) {
+        this.expirationTime = RBACToken.cloneDate(expirationTime);
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public List<String> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(List<String> roles) {
+        this.roles = roles;
+    }
+
+    public String getSignature() {
+        return signature;
+    }
+
+    public void setSignature(String signature) {
+        this.signature = signature;
+    }
+
+    /**
+     * Clones a Date to make object immutable.
+     *
+     * @param dateToClone the date that has to be cloned.
+     * @return <code>null</code>, if date was null <code>cloned date</code>, if date was not null
+     */
+    public static Date cloneDate(Date dateToClone) {
+      return dateToClone == null ? null : new Date(dateToClone.getTime());
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/rbac/RBACUserInfo.java b/src/main/java/org/openepics/names/service/security/rbac/RBACUserInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..553642552e417b4e0525896b62d466886648df07
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/rbac/RBACUserInfo.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security.rbac;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:zoltan.runyo@ess.eu">Zoltan Runyo</a>
+ */
+public class RBACUserInfo {
+
+    private String role;
+    private List<String> users;
+
+    public String getRole() {
+        return role;
+    }
+
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    public List<String> getUsers() {
+        return users;
+    }
+
+    public void setUsers(List<String> users) {
+        this.users = users;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/rbac/RBACUserRoles.java b/src/main/java/org/openepics/names/service/security/rbac/RBACUserRoles.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4fe1b8c7432ae7b5a0eab2c89b66716327bcfc9
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/rbac/RBACUserRoles.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security.rbac;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+public class RBACUserRoles {
+
+    private String username;
+    private List<String> roles;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public List<String> getRoles() {
+        return roles;
+    }
+
+    public void setRoles(List<String> roles) {
+        this.roles = roles;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/util/EncryptUtil.java b/src/main/java/org/openepics/names/service/security/util/EncryptUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..9520e91558163ef81c2eb6d975b4a2dcf15e9361
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/util/EncryptUtil.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security.util;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * Encryption utility.
+ *
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+@Component
+public class EncryptUtil {
+
+    private static final Logger LOGGER = Logger.getLogger(EncryptUtil.class.getName());
+
+    @Value("${aes.key}")
+    private String secret;
+
+    private static SecretKeySpec secretKey;
+    private static final String ALGORITHM = "AES";
+
+    private void prepareSecretKey(String myKey) {
+        MessageDigest sha = null;
+        try {
+            byte[] key = myKey.getBytes(StandardCharsets.UTF_8);
+            sha = MessageDigest.getInstance("SHA-1");
+            key = sha.digest(key);
+            key = Arrays.copyOf(key, 16);
+            secretKey = new SecretKeySpec(key, ALGORITHM);
+        } catch (NoSuchAlgorithmException e) {
+            LOGGER.log(Level.WARNING, SecurityTextUtil.ALGORITHM_NOT_FOUND, e);
+        }
+    }
+
+    /**
+     * String encryption wrapper.
+     *
+     * @param strToEncrypt string to encrypt
+     * @return encrypted string
+     */
+    public String encrypt(String strToEncrypt) {
+        try {
+            prepareSecretKey(secret);
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+            return Base64.getEncoder()
+                    .encodeToString(cipher.doFinal(strToEncrypt.getBytes(StandardCharsets.UTF_8)));
+        } catch (Exception e) {
+            LOGGER.log(Level.WARNING, SecurityTextUtil.ERROR_WHILE_ENCRYPTING, e);
+        }
+        return null;
+    }
+
+    /**
+     * String decryption wrapper.
+     *
+     * @param strToDecrypt string to decrypt
+     * @return decrypted string
+     */
+    public String decrypt(String strToDecrypt) {
+        try {
+            prepareSecretKey(secret);
+            Cipher cipher = Cipher.getInstance(ALGORITHM);
+            cipher.init(Cipher.DECRYPT_MODE, secretKey);
+            return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
+        } catch (Exception e) {
+            LOGGER.log(Level.WARNING, SecurityTextUtil.ERROR_WHILE_DECRYPTING, e);
+        }
+        return null;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/util/HttpClientService.java b/src/main/java/org/openepics/names/service/security/util/HttpClientService.java
new file mode 100644
index 0000000000000000000000000000000000000000..b93f95cf29c00295a5f6ce0509b6fd4fdbba09f7
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/util/HttpClientService.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security.util;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+
+import org.openepics.names.exception.security.ParseException;
+import org.openepics.names.exception.security.RemoteServiceException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import okhttp3.Headers;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+
+/**
+ * @author <a href="mailto:zoltan.runyo@ess.eu">Zoltan Runyo</a>
+ */
+@Service
+public class HttpClientService {
+
+    public static final MediaType JSON_MEDIA_TYPE = MediaType.get("application/json; charset=utf-8");
+    public static final MediaType XML_MEDIA_TYPE  = MediaType.get("application/xml; charset=utf-8");
+
+    private static final String UNABLE_TO_CALL_SERVICE = "Unable to call service";
+
+    private final OkHttpClient okHttpClient;
+
+    @Autowired
+    public HttpClientService(OkHttpClient okHttpClient) {
+        this.okHttpClient = okHttpClient;
+    }
+
+    public static class ServiceResponse<T> {
+        private final T entity;
+        private final int statusCode;
+        private final String errorMessage;
+        private final Headers headers;
+
+        public ServiceResponse(T entity, int statusCode, Headers headers) {
+            this.entity = entity;
+            this.statusCode = statusCode;
+            this.errorMessage = null;
+            this.headers = headers;
+        }
+
+        public ServiceResponse(int statusCode, String errorMessage, Headers headers) {
+            this.entity = null;
+            this.statusCode = statusCode;
+            this.errorMessage = errorMessage;
+            this.headers = headers;
+        }
+
+        public T getEntity() {
+            return entity;
+        }
+
+        public int getStatusCode() {
+            return statusCode;
+        }
+
+        public String getErrorMessage() {
+            return errorMessage;
+        }
+
+        public Headers getHeaders() {
+            return headers;
+        }
+    }
+
+    public <T> ServiceResponse<T> executeGetRequest(
+            Headers headers, String url, Class<T> responseClass) throws RemoteServiceException {
+        return executeGetRequest(headers, url, responseClass, null);
+    }
+
+    public <T> ServiceResponse<T> executeGetRequest(
+            Headers headers, String url, Class<T> responseClass, String formatDate)
+                    throws RemoteServiceException {
+        Request request;
+        request = new Request.Builder().headers(headers).url(url).build();
+
+        try (Response response = okHttpClient.newCall(request).execute()) {
+            if (isSuccessHttpStatusCode(response.code())) {
+                Gson gson = new Gson();
+                if (formatDate != null) {
+                    gson = new GsonBuilder().setDateFormat(formatDate).create();
+                }
+                return new ServiceResponse<>(
+                        gson.fromJson(response.body().string(), responseClass),
+                        response.code(),
+                        response.headers());
+            }
+            return new ServiceResponse<>(null, response.code(), response.headers());
+        } catch (IOException e) {
+            throw new RemoteServiceException(UNABLE_TO_CALL_SERVICE, e);
+        }
+    }
+
+    public <T> ServiceResponse<T> executeGetRequest(
+            Headers headers, String url, Type type, String formatDate) throws RemoteServiceException {
+        Request request;
+        request = new Request.Builder().headers(headers).url(url).build();
+
+        try (Response response = okHttpClient.newCall(request).execute()) {
+            if (isSuccessHttpStatusCode(response.code())) {
+                return new ServiceResponse<>(
+                        new GsonBuilder()
+                        .setDateFormat(formatDate)
+                        .create()
+                        .fromJson(response.body().string(), type),
+                        response.code(),
+                        response.headers());
+            }
+            return new ServiceResponse<>(null, response.code(), response.headers());
+        } catch (IOException e) {
+            throw new RemoteServiceException(UNABLE_TO_CALL_SERVICE, e);
+        }
+    }
+
+    public <T> ServiceResponse<T> executeGetRequest(Headers headers, String url, Type type)
+            throws RemoteServiceException {
+        Request request;
+        request = new Request.Builder().headers(headers).url(url).build();
+
+        try (Response response = okHttpClient.newCall(request).execute()) {
+            if (isSuccessHttpStatusCode(response.code())) {
+                return new ServiceResponse<>(
+                        new GsonBuilder().create().fromJson(response.body().string(), type),
+                        response.code(),
+                        response.headers());
+            }
+            return new ServiceResponse<>(null, response.code(), response.headers());
+        } catch (IOException e) {
+            throw new RemoteServiceException(UNABLE_TO_CALL_SERVICE, e);
+        }
+    }
+
+    public <T> ServiceResponse<T> executeGetRequest(
+            Headers headers, String url, MediaType mediaType, Class<T> responseClass)
+                    throws RemoteServiceException, ParseException {
+
+        if (JSON_MEDIA_TYPE.equals(mediaType)) {
+            return executeGetRequest(headers, url, responseClass);
+        }
+
+        Request request;
+
+        request = new Request.Builder().headers(headers).url(url).build();
+
+        try (Response response = okHttpClient.newCall(request).execute()) {
+            if (isSuccessHttpStatusCode(response.code())) {
+                return new ServiceResponse<>(
+                        new XmlMapper().readValue(response.body().string(), responseClass),
+                        response.code(),
+                        response.headers());
+            }
+            return new ServiceResponse<>(null, response.code(), response.headers());
+        } catch (IOException e) {
+            throw new RemoteServiceException("Unable to call service with GET method", e);
+        }
+    }
+
+    public ServiceResponse<String> executePlainGetRequest(Headers headers, String url)
+            throws RemoteServiceException {
+        Request request;
+        request = new Request.Builder().headers(headers).url(url).build();
+
+        try (Response response = okHttpClient.newCall(request).execute()) {
+            if (isSuccessHttpStatusCode(response.code())) {
+                return new ServiceResponse<>(response.body().string(), response.code(), response.headers());
+            }
+            return new ServiceResponse<>(null, response.code(), response.headers());
+        } catch (IOException e) {
+            throw new RemoteServiceException(UNABLE_TO_CALL_SERVICE, e);
+        }
+    }
+
+    public <T> ServiceResponse<T> executePostRequest(
+            Headers headers, String url, Object requestBody, Class<T> responseClass)
+                    throws RemoteServiceException {
+        RequestBody body = RequestBody.create(new Gson().toJson(requestBody), JSON_MEDIA_TYPE);
+        Request request;
+        request = new Request.Builder().headers(headers).url(url).post(body).build();
+
+        try (Response response = okHttpClient.newCall(request).execute()) {
+            if (isSuccessHttpStatusCode(response.code())) {
+                return new ServiceResponse<>(
+                        new Gson().fromJson(response.body().string(), responseClass),
+                        response.code(),
+                        response.headers());
+            }
+            return new ServiceResponse<>(
+                    response.code(),
+                    response.body() != null ? response.body().string() : null,
+                            response.headers());
+        } catch (IOException e) {
+            throw new RemoteServiceException(UNABLE_TO_CALL_SERVICE, e);
+        }
+    }
+
+    public ServiceResponse<String> executePlainPostRequest(
+            Headers headers, String url, Object requestBody) throws RemoteServiceException {
+        RequestBody body = RequestBody.create(new Gson().toJson(requestBody), JSON_MEDIA_TYPE);
+        Request request;
+        request = new Request.Builder().headers(headers).url(url).post(body).build();
+
+        try (Response response = okHttpClient.newCall(request).execute()) {
+            if (isSuccessHttpStatusCode(response.code())) {
+                return new ServiceResponse<>(response.body().string(), response.code(), response.headers());
+            }
+            return new ServiceResponse<>(null, response.code(), response.headers());
+        } catch (IOException e) {
+            throw new RemoteServiceException(UNABLE_TO_CALL_SERVICE, e);
+        }
+    }
+
+    public <T> ServiceResponse<T> executePostRequest(
+            Headers headers, String url, Object requestBody, MediaType mediaType, Class<T> responseClass)
+                    throws RemoteServiceException, ParseException {
+        if (JSON_MEDIA_TYPE.equals(mediaType)) {
+            return executePostRequest(headers, url, requestBody, responseClass);
+        }
+
+        Request request;
+
+        try {
+            RequestBody body =
+                    RequestBody.create(new XmlMapper().writeValueAsString(requestBody), XML_MEDIA_TYPE);
+
+            request = new Request.Builder().headers(headers).url(url).post(body).build();
+        } catch (JsonProcessingException e) {
+            throw new ParseException("Unable to parse object");
+        }
+
+        try (Response response = okHttpClient.newCall(request).execute()) {
+            if (isSuccessHttpStatusCode(response.code())) {
+                return new ServiceResponse<>(
+                        new XmlMapper().readValue(response.body().string(), responseClass),
+                        response.code(),
+                        response.headers());
+            }
+            return new ServiceResponse<>(null, response.code(), response.headers());
+        } catch (IOException e) {
+            throw new RemoteServiceException("Unable to call service with POST method", e);
+        }
+    }
+
+    public Integer executeDeleteRequest(Headers headers, String url)
+            throws RemoteServiceException, ParseException {
+
+        Request request;
+
+        request = new Request.Builder().headers(headers).url(url).delete().build();
+
+        try (Response response = okHttpClient.newCall(request).execute()) {
+            return response.code();
+        } catch (IOException e) {
+            throw new RemoteServiceException("Unable to call service with POST method", e);
+        }
+    }
+
+    public static boolean isSuccessHttpStatusCode(int code) {
+        return code >= 200 && code < 300;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/util/OkHttpConfiguration.java b/src/main/java/org/openepics/names/service/security/util/OkHttpConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9fbdf5b2763350a95ebe95012175c3d619fb6f5
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/util/OkHttpConfiguration.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2022 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security.util;
+
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.commons.lang3.BooleanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+
+import okhttp3.ConnectionPool;
+import okhttp3.OkHttpClient;
+
+/**
+ * @author <a href="mailto:imre.toth@ess.eu">Imre Toth</a>
+ */
+@Configuration
+public class OkHttpConfiguration {
+
+    public static final String ALLOW_UNTRUSTED_CERTS = "allow.untrusted.certs";
+
+    private final Environment env;
+
+    @Autowired
+    public OkHttpConfiguration(Environment env) {
+        this.env = env;
+    }
+
+    @Bean
+    public OkHttpClient okHttpClient() {
+
+        OkHttpClient.Builder clientBuilder =
+                new OkHttpClient.Builder()
+                .connectTimeout(10, TimeUnit.SECONDS)
+                .readTimeout(10, TimeUnit.SECONDS)
+                .writeTimeout(10, TimeUnit.SECONDS)
+                .connectionPool(pool());
+
+        boolean allowUntrusted = BooleanUtils.toBoolean(env.getProperty(ALLOW_UNTRUSTED_CERTS));
+
+        if (allowUntrusted) {
+            final X509TrustManager trustManager =
+                    new X509TrustManager() {
+                @Override
+                public X509Certificate[] getAcceptedIssuers() {
+                    return new X509Certificate[0];
+                }
+
+                @Override
+                public void checkServerTrusted(final X509Certificate[] chain, final String authType) {}
+
+                @Override
+                public void checkClientTrusted(final X509Certificate[] chain, final String authType) {}
+            };
+
+            SSLContext sslContext = null;
+            try {
+                sslContext = SSLContext.getInstance("SSL");
+                sslContext.init(null, new TrustManager[] {trustManager}, new java.security.SecureRandom());
+            } catch (NoSuchAlgorithmException | KeyManagementException e) {
+                return null;
+            }
+
+            clientBuilder.sslSocketFactory(sslContext.getSocketFactory(), trustManager);
+
+            HostnameVerifier hostnameVerifier = (hostname, session) -> true;
+            clientBuilder.hostnameVerifier(hostnameVerifier);
+        }
+
+        return clientBuilder.build();
+    }
+
+    @Bean
+    public ConnectionPool pool() {
+        return new ConnectionPool(40, 10, TimeUnit.SECONDS);
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/util/SecurityTextUtil.java b/src/main/java/org/openepics/names/service/security/util/SecurityTextUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a389269674f97b08549744da9811ded35e2ab8f
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/util/SecurityTextUtil.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 European Spallation Source ERIC.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+package org.openepics.names.service.security.util;
+
+/**
+ * Utility class to assist in handling of text, in particular for security related matters.
+ *
+ * @author Lars Johansson
+ */
+public class SecurityTextUtil {
+
+    // authentication & authorization
+
+    public static final String AUTHENTICATION_HEADER_PREFIX    = "Bearer ";
+    public static final String COOKIE_AUTH_HEADER              = "naming-auth";
+
+    // encryption
+
+    public static final String ALGORITHM_NOT_FOUND             = "Algorithm not found";
+    public static final String ERROR_WHILE_DECRYPTING          = "Error while decrypting";
+    public static final String ERROR_WHILE_ENCRYPTING          = "Error while encrypting";
+
+    /**
+     * This class is not to be instantiated.
+     */
+    private SecurityTextUtil() {
+        throw new IllegalStateException("Utility class");
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/service/security/util/SecurityUtil.java b/src/main/java/org/openepics/names/service/security/util/SecurityUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..cfca9311278b4a50ded3afcd496a4b4b4f4a955b
--- /dev/null
+++ b/src/main/java/org/openepics/names/service/security/util/SecurityUtil.java
@@ -0,0 +1,50 @@
+package org.openepics.names.service.security.util;
+
+import org.openepics.names.service.security.dto.UserDetails;
+import org.openepics.names.service.security.rbac.RBACToken;
+
+/**
+ * @author <a href="mailto:zoltan.runyo@ess.eu">Zoltan Runyo</a>
+ * @author Lars Johansson
+ */
+public class SecurityUtil {
+
+    /**
+     * This class is not to be instantiated.
+     */
+    private SecurityUtil() {
+        throw new IllegalStateException("Utility class");
+    }
+
+    /**
+     * Converts RBAC token to user details DTO
+     *
+     * @param rbacInfo RBAC token descriptor
+     * @return User details DTO
+     */
+    public static UserDetails convertToUserDetails(RBACToken rbacInfo) {
+        UserDetails result = null;
+
+        if (rbacInfo != null) {
+            result = new UserDetails();
+
+            result.setUserName(rbacInfo.getUserName());
+            result.setFullName(rbacInfo.getFirstName() + " " + rbacInfo.getLastName());
+            result.setToken(rbacInfo.getId());
+            result.setRoles(rbacInfo.getRoles());
+        }
+
+        return result;
+    }
+
+    /**
+     * Return username for a user.
+     *
+     * @param userDetails user details
+     * @return username
+     */
+    public static String getUsername(UserDetails userDetails) {
+        return userDetails != null ? userDetails.getUserName() : null;
+    }
+
+}
diff --git a/src/main/java/org/openepics/names/util/TextUtil.java b/src/main/java/org/openepics/names/util/TextUtil.java
index b47222d11f7dd6417713a40006f8e10a71761601..b5a972c7b0efa04d98bff8b9c010f279e5102e4c 100644
--- a/src/main/java/org/openepics/names/util/TextUtil.java
+++ b/src/main/java/org/openepics/names/util/TextUtil.java
@@ -132,9 +132,6 @@ public class TextUtil {
     public static final String ATTACHMENT_FILENAME_NAME_ELEMENT_XLSX      = "attachment; filename=NameElement.xlsx";
     public static final String ATTACHMENT_FILENAME_STRUCTURE_ELEMENT_XLSX = "attachment; filename=StructureElement.xlsx";
 
-    // test
-    public static final String TEST_WHO                                = "test who";
-
     // log
     public static final String DESCRIPTION_NUMBER_ELEMENTS        = "{0}, # elements: {1}";
     public static final String DESCRIPTION_NUMBER_ELEMENTS_IN_OUT = "{0}, # elements (in): {1}, # elements (out): {2}";
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 7655d823cc097f1c3522300c22f53f23f814f69f..17f3c225302b1d861aee3a62fab86a6a8bd155f1 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -17,6 +17,18 @@ logging.level.org.springframework.web=INFO
 logging.level.org.hibernate.SQL=INFO
 spring.http.log-request-details=true
 
+# security
+#     enable
+#         disabled by default - allow run of application without association to particular way of authentication & authorization
+#     encryption
+#     token
+#     rbac
+naming.security.enabled=${NAMING_SECURITY_ENABLED:false}
+aes.key=${AES_KEY:aes_secret_key}
+jwt.secret=${JWT_SECRET:secret_password_to_hash_token}
+jwt.expire.in.minutes=${JWT_EXP_MIN:240}
+rbac.server.address=${RBAC_SERVER_ADDRESS}
+
 # mail, notification
 #     administrator mail - comma-separated list of email addresses
 #     notification  mail - comma-separated list of email addresses
@@ -75,6 +87,8 @@ openapi.info.title=Naming REST API
 #     api
 #     swagger
 #         url used for notification
+springdoc.api-docs.path=${API_DOCS_PATH:/api-docs}
+springdoc.swagger-ui.path=${SWAGGER_UI_PATH:/swagger-ui.html}
 springdoc.swagger-ui.tagsSorter=alpha
 springdoc.swagger-ui.operationsSorter=method
 naming.swagger.url=${NAMING_SWAGGER_URL:http://localhost:8080/swagger-ui.html}
diff --git a/src/test/java/org/openepics/names/docker/NamesIT.java b/src/test/java/org/openepics/names/docker/NamesIT.java
index 049ad1f2ab9c30260bf2145305601e1fdcb0905a..b2b142d1d97f5bf96624bd4bfb0e057201bf3a76 100644
--- a/src/test/java/org/openepics/names/docker/NamesIT.java
+++ b/src/test/java/org/openepics/names/docker/NamesIT.java
@@ -678,16 +678,8 @@ class NamesIT {
         ITUtilNames.assertRead("?description=updated description%",                 1, -1);
         ITUtilNames.assertRead("?description=updated description again",            1);
 
-        ITUtilNames.assertRead("?who=test who",                                    13, -1);
+        ITUtilNames.assertRead("?who=",                                            13, -1);
         ITUtilNames.assertRead("?who=test",                                         0);
-        ITUtilNames.assertRead("?who=who",                                          0);
-        ITUtilNames.assertRead("?who=test%",                                       13, -1);
-        ITUtilNames.assertRead("?who=%who",                                        13, -1);
-        ITUtilNames.assertRead("?who=%est%",                                       13, -1);
-        ITUtilNames.assertRead("?who=%wh%",                                        13, -1);
-        ITUtilNames.assertRead("?who=wh%",                                          0);
-        ITUtilNames.assertRead("?who=asdf",                                         0);
-        ITUtilNames.assertRead("?who=%asdf%",                                       0);
 
         ITUtilNames.assertRead("?deviceStructure=EMR-FS&index=003",                 1);
 
diff --git a/src/test/java/org/openepics/names/docker/StructuresDeviceGroupIT.java b/src/test/java/org/openepics/names/docker/StructuresDeviceGroupIT.java
index 6286303a3e49ba77f5e52e34dbc9162caa0d50f4..64f88b73e26deb95fe0bf93a8055f40bb7d10250 100644
--- a/src/test/java/org/openepics/names/docker/StructuresDeviceGroupIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresDeviceGroupIT.java
@@ -864,16 +864,8 @@ class StructuresDeviceGroupIT {
         ITUtilStructures.assertRead("?type=DEVICEGROUP&description=%sc%",                                                         30, -1);
         ITUtilStructures.assertRead("?type=DEVICEGROUP&description=description",                                                  10, -1);
 
-        ITUtilStructures.assertRead("?type=DEVICEGROUP&who=test who",                                                             30, -1);
+        ITUtilStructures.assertRead("?type=DEVICEGROUP&who=",                                                                     30, -1);
         ITUtilStructures.assertRead("?type=DEVICEGROUP&who=test",                                                                  0);
-        ITUtilStructures.assertRead("?type=DEVICEGROUP&who=who",                                                                   0);
-        ITUtilStructures.assertRead("?type=DEVICEGROUP&who=test%",                                                                30, -1);
-        ITUtilStructures.assertRead("?type=DEVICEGROUP&who=%who",                                                                 30, -1);
-        ITUtilStructures.assertRead("?type=DEVICEGROUP&who=%est%",                                                                30, -1);
-        ITUtilStructures.assertRead("?type=DEVICEGROUP&who=%wh%",                                                                 30, -1);
-        ITUtilStructures.assertRead("?type=DEVICEGROUP&who=wh%",                                                                   0);
-        ITUtilStructures.assertRead("?type=DEVICEGROUP&who=asdf",                                                                  0);
-        ITUtilStructures.assertRead("?type=DEVICEGROUP&who=%asdf%",                                                                0);
 
         // order by
         //     avoid
diff --git a/src/test/java/org/openepics/names/docker/StructuresDeviceTypeIT.java b/src/test/java/org/openepics/names/docker/StructuresDeviceTypeIT.java
index a512138db27f4d3de7ce105ddb6c466158ff7baf..279460882ed465361d3dcedcbe94a48a6cc36e06 100644
--- a/src/test/java/org/openepics/names/docker/StructuresDeviceTypeIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresDeviceTypeIT.java
@@ -872,16 +872,8 @@ class StructuresDeviceTypeIT {
         ITUtilStructures.assertRead("?type=DEVICETYPE&description=%sc%",                                                     30, -1);
         ITUtilStructures.assertRead("?type=DEVICETYPE&description=description",                                              10, -1);
 
-        ITUtilStructures.assertRead("?type=DEVICETYPE&who=test who",                                                         30, -1);
+        ITUtilStructures.assertRead("?type=DEVICETYPE&who=",                                                                 30, -1);
         ITUtilStructures.assertRead("?type=DEVICETYPE&who=test",                                                              0);
-        ITUtilStructures.assertRead("?type=DEVICETYPE&who=who",                                                               0);
-        ITUtilStructures.assertRead("?type=DEVICETYPE&who=test%",                                                            30, -1);
-        ITUtilStructures.assertRead("?type=DEVICETYPE&who=%who",                                                             30, -1);
-        ITUtilStructures.assertRead("?type=DEVICETYPE&who=%est%",                                                            30, -1);
-        ITUtilStructures.assertRead("?type=DEVICETYPE&who=%wh%",                                                             30, -1);
-        ITUtilStructures.assertRead("?type=DEVICETYPE&who=wh%",                                                               0);
-        ITUtilStructures.assertRead("?type=DEVICETYPE&who=asdf",                                                              0);
-        ITUtilStructures.assertRead("?type=DEVICETYPE&who=%asdf%",                                                            0);
 
         // order by
         //     avoid
diff --git a/src/test/java/org/openepics/names/docker/StructuresDisciplineIT.java b/src/test/java/org/openepics/names/docker/StructuresDisciplineIT.java
index 510df00a0860f20b058cbddff05a6f5dd7eed62c..1d36c322a47563464710779dc930fd0789cffb77 100644
--- a/src/test/java/org/openepics/names/docker/StructuresDisciplineIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresDisciplineIT.java
@@ -766,16 +766,8 @@ class StructuresDisciplineIT {
         ITUtilStructures.assertRead("?type=DISCIPLINE&description=%sc%",                                                     30, -1);
         ITUtilStructures.assertRead("?type=DISCIPLINE&description=description",                                              10, -1);
 
-        ITUtilStructures.assertRead("?type=DISCIPLINE&who=test who",                                                         30, -1);
+        ITUtilStructures.assertRead("?type=DISCIPLINE&who=",                                                                 30, -1);
         ITUtilStructures.assertRead("?type=DISCIPLINE&who=test",                                                              0);
-        ITUtilStructures.assertRead("?type=DISCIPLINE&who=who",                                                               0);
-        ITUtilStructures.assertRead("?type=DISCIPLINE&who=test%",                                                            30, -1);
-        ITUtilStructures.assertRead("?type=DISCIPLINE&who=%who",                                                             30, -1);
-        ITUtilStructures.assertRead("?type=DISCIPLINE&who=%est%",                                                            30, -1);
-        ITUtilStructures.assertRead("?type=DISCIPLINE&who=%wh%",                                                             30, -1);
-        ITUtilStructures.assertRead("?type=DISCIPLINE&who=wh%",                                                               0);
-        ITUtilStructures.assertRead("?type=DISCIPLINE&who=asdf",                                                              0);
-        ITUtilStructures.assertRead("?type=DISCIPLINE&who=%asdf%",                                                            0);
 
         // order by
         //     avoid
diff --git a/src/test/java/org/openepics/names/docker/StructuresSubsystemIT.java b/src/test/java/org/openepics/names/docker/StructuresSubsystemIT.java
index eb3c04b4a20b8767d8b471b4d11c960be29681bb..cef336b790f3b87c11f445bcbe0ab89e53ffd5a5 100644
--- a/src/test/java/org/openepics/names/docker/StructuresSubsystemIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresSubsystemIT.java
@@ -908,16 +908,8 @@ class StructuresSubsystemIT {
         ITUtilStructures.assertRead("?type=SUBSYSTEM&description=%sc%",                                                     30, -1);
         ITUtilStructures.assertRead("?type=SUBSYSTEM&description=description",                                              10, -1);
 
-        ITUtilStructures.assertRead("?type=SUBSYSTEM&who=test who",                                                         30, -1);
+        ITUtilStructures.assertRead("?type=SUBSYSTEM&who=",                                                                 30, -1);
         ITUtilStructures.assertRead("?type=SUBSYSTEM&who=test",                                                              0);
-        ITUtilStructures.assertRead("?type=SUBSYSTEM&who=who",                                                               0);
-        ITUtilStructures.assertRead("?type=SUBSYSTEM&who=test%",                                                            30, -1);
-        ITUtilStructures.assertRead("?type=SUBSYSTEM&who=%who",                                                             30, -1);
-        ITUtilStructures.assertRead("?type=SUBSYSTEM&who=%est%",                                                            30, -1);
-        ITUtilStructures.assertRead("?type=SUBSYSTEM&who=%wh%",                                                             30, -1);
-        ITUtilStructures.assertRead("?type=SUBSYSTEM&who=wh%",                                                               0);
-        ITUtilStructures.assertRead("?type=SUBSYSTEM&who=asdf",                                                              0);
-        ITUtilStructures.assertRead("?type=SUBSYSTEM&who=%asdf%",                                                            0);
 
         // order by
         //     avoid
diff --git a/src/test/java/org/openepics/names/docker/StructuresSystemGroupIT.java b/src/test/java/org/openepics/names/docker/StructuresSystemGroupIT.java
index e284a557275a2c9989053baefdbfdb63e87feda6..b4b05e973ebe4a7f3f8b676cb33cf364ef816add 100644
--- a/src/test/java/org/openepics/names/docker/StructuresSystemGroupIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresSystemGroupIT.java
@@ -813,16 +813,8 @@ class StructuresSystemGroupIT {
         ITUtilStructures.assertRead("?type=SYSTEMGROUP&description=%sc%",                                                     30, -1);
         ITUtilStructures.assertRead("?type=SYSTEMGROUP&description=description",                                              10, -1);
 
-        ITUtilStructures.assertRead("?type=SYSTEMGROUP&who=test who",                                                         30, -1);
+        ITUtilStructures.assertRead("?type=SYSTEMGROUP&who=",                                                                 30, -1);
         ITUtilStructures.assertRead("?type=SYSTEMGROUP&who=test",                                                              0);
-        ITUtilStructures.assertRead("?type=SYSTEMGROUP&who=who",                                                               0);
-        ITUtilStructures.assertRead("?type=SYSTEMGROUP&who=test%",                                                            30, -1);
-        ITUtilStructures.assertRead("?type=SYSTEMGROUP&who=%who",                                                             30, -1);
-        ITUtilStructures.assertRead("?type=SYSTEMGROUP&who=%est%",                                                            30, -1);
-        ITUtilStructures.assertRead("?type=SYSTEMGROUP&who=%wh%",                                                             30, -1);
-        ITUtilStructures.assertRead("?type=SYSTEMGROUP&who=wh%",                                                               0);
-        ITUtilStructures.assertRead("?type=SYSTEMGROUP&who=asdf",                                                              0);
-        ITUtilStructures.assertRead("?type=SYSTEMGROUP&who=%asdf%",                                                            0);
 
         // order by
         //     avoid
diff --git a/src/test/java/org/openepics/names/docker/StructuresSystemIT.java b/src/test/java/org/openepics/names/docker/StructuresSystemIT.java
index e307784abc6da007861b60526d3024704b0b1cb4..9afadef27c0cfd0bb16ed6d2bd1427d8d8514ace 100644
--- a/src/test/java/org/openepics/names/docker/StructuresSystemIT.java
+++ b/src/test/java/org/openepics/names/docker/StructuresSystemIT.java
@@ -852,16 +852,8 @@ class StructuresSystemIT {
         ITUtilStructures.assertRead("?type=SYSTEM&description=%sc%",                                                     30, -1);
         ITUtilStructures.assertRead("?type=SYSTEM&description=description",                                              10, -1);
 
-        ITUtilStructures.assertRead("?type=SYSTEM&who=test who",                                                         30, -1);
+        ITUtilStructures.assertRead("?type=SYSTEM&who=",                                                                 30, -1);
         ITUtilStructures.assertRead("?type=SYSTEM&who=test",                                                              0);
-        ITUtilStructures.assertRead("?type=SYSTEM&who=who",                                                               0);
-        ITUtilStructures.assertRead("?type=SYSTEM&who=test%",                                                            30, -1);
-        ITUtilStructures.assertRead("?type=SYSTEM&who=%who",                                                             30, -1);
-        ITUtilStructures.assertRead("?type=SYSTEM&who=%est%",                                                            30, -1);
-        ITUtilStructures.assertRead("?type=SYSTEM&who=%wh%",                                                             30, -1);
-        ITUtilStructures.assertRead("?type=SYSTEM&who=wh%",                                                               0);
-        ITUtilStructures.assertRead("?type=SYSTEM&who=asdf",                                                              0);
-        ITUtilStructures.assertRead("?type=SYSTEM&who=%asdf%",                                                            0);
 
         // order by
         //     avoid
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
index fc49f4c13c7a21160da0ed3b37bbbb9a41703334..4f1fdda9658f60e7c1c1d273b32a438ed590ff70 100644
--- a/src/test/resources/application.properties
+++ b/src/test/resources/application.properties
@@ -17,6 +17,18 @@ logging.level.org.springframework.web=INFO
 logging.level.org.hibernate.SQL=INFO
 spring.http.log-request-details=true
 
+# security
+#     enable
+#         disabled by default - allow run of application without association to particular way of authentication & authorization
+#     encryption
+#     token
+#     rbac
+naming.security.enabled=${NAMING_SECURITY_ENABLED:false}
+aes.key=${AES_KEY:aes_secret_key}
+jwt.secret=${JWT_SECRET:secret_password_to_hash_token}
+jwt.expire.in.minutes=${JWT_EXP_MIN:240}
+rbac.server.address=${RBAC_SERVER_ADDRESS}
+
 # mail, notification
 #     administrator mail - comma-separated list of email addresses
 #     notification  mail - comma-separated list of email addresses
@@ -76,6 +88,8 @@ openapi.info.title=Naming REST API
 #     api
 #     swagger
 #         url used for notification
+springdoc.api-docs.path=${API_DOCS_PATH:/api-docs}
+springdoc.swagger-ui.path=${SWAGGER_UI_PATH:/swagger-ui.html}
 springdoc.swagger-ui.tagsSorter=alpha
 springdoc.swagger-ui.operationsSorter=method
 naming.swagger.url=${NAMING_SWAGGER_URL:http://localhost:8080/swagger-ui.html}