Embedded Frontend

Flowable Engage provides a dedicated JavaScript frontend that can either be deployed to any HTML capable server or run embedded directly within the Flowable Server.

To run the frontend embedded within the Flowable Server add the following dependency to the pom.xml file of the project:

<dependency>
    <groupId>com.flowable.work</groupId>
    <artifactId>flowable-work-frontend</artifactId>
</dependency>

The frontend provides user interfaces for both Flowable Work and Flowable Engage. The Engage interface can be deactivated if only Work features are made available.

In addition you need to provide the correct Spring Boot Security configuration to allow access to the embedded frontend. This is done by adding a class e.g. called SecurityConfiguration as a sibling of the Spring Boot Application class containing the following configuration:

import com.flowable.platform.common.security.SecurityConstants;
import com.flowable.platform.spring.security.web.authentication.AjaxAuthenticationFailureHandler;
import com.flowable.platform.spring.security.web.authentication.AjaxAuthenticationSuccessHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;

@Configuration
@Order(10)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .headers().frameOptions().sameOrigin()
            .and()
            .logout()
            .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
            .logoutUrl("/auth/logout")
            .and()
            .exceptionHandling()
            .defaultAuthenticationEntryPointFor(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED), AnyRequestMatcher.INSTANCE)
            .and()
            .formLogin()
            .loginProcessingUrl("/auth/login")
            .successHandler(new AjaxAuthenticationSuccessHandler())
            .failureHandler(new AjaxAuthenticationFailureHandler())
            .and()
            .authorizeRequests()
            .antMatchers("/analytics-api/**").hasAuthority(SecurityConstants.ACCESS_REPORTS_METRICS)
            .antMatchers("/template-api/**").hasAuthority(SecurityConstants.ACCESS_TEMPLATE_MANAGEMENT)
            .antMatchers("/work-object-api/**").hasAuthority(SecurityConstants.ACCESS_WORKOBJECT_API)
            // allow context root for all (it triggers the loading of the initial page)
            .antMatchers("/") .permitAll()
            .antMatchers(
                    "/**/*.svg", "/**/*.ico", "/**/*.png", "/**/*.woff2", "/**/*.css",
                    "/**/*.woff", "/**/*.html", "/**/*.js",
                    "/**/index.html").permitAll()
            .anyRequest().authenticated()
            .and()
            .httpBasic();
    }
}