Custom OAuth2 Integration for Flowable Work: User Attribute Mapping

Flowable Work is a business process automation and case management platform. It enables organizations to model, deploy, and execute workflows efficiently. As such, it is widely used in enterprise applications to streamline processes and integrate with existing IT ecosystems. In my current project, I have been tasked with enabling Single Sign-On (SSO) for the Flowable Work application by integrating it with Microsoft ADFS. While Flowable provides documentation on OAuth2 client registration (Flowable Documentation), the integration required additional customization to ensure correct user attribute mapping. This article will focus on the security integration aspect, particularly handling user attributes in OAuth2 authentication.

OAuth2 Configuration

Following the Flowable documentation, I configured the OAuth2 client registration by setting the OAuth2 client provider issuer URI, along with the client ID and client secret. This initial step worked as expected. Additionally, I mapped the user definition key for the essential user-admin Flowable user-definition-key. However, configuring this via ArgoCD presented challenges due to YAML key syntax, which I will discuss in a separate article.

With OAuth2 integration enabled, I was able to receive OAuth2 tokens from ADFS, confirmed by logs such as:

SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=Name: [<redacted-email>], Granted Authorities: [[OIDC_USER, SCOPE_openid]], User Attributes: [{sub=OZ94FhIfCdgNpGKAAFCIEcVvD3xVp77Qug7Yw2+DE6Y=, scp=openid, ver=1.0, pwd_exp=14162373, ...}]

This log confirms that the authentication process was successful, as the OAuth2AuthenticationToken is populated with the expected user attributes from ADFS. If these logs are absent or incomplete, it may indicate an issue with the OAuth2 flow or token retrieval, which can help with troubleshooting authentication failures.

However, an issue arose where the user’s first name, last name, and email were stored in non-standard claims (FLOW_FirstnameFLOW_LastnameFLOW_Mail). As a result, Flowable Work displayed the user as Anonymous, which was undesirable.

Handling Non-Standard Claims

Flowable does not support these claims by default because the platform’s OAuth2 implementation is designed to work with standard OpenID Connect (OIDC) claims such as given_namefamily_name, and email. Non-standard claims, such as FLOW_Firstname and FLOW_Lastname, are often used by organizations that have custom attribute mappings in their identity provider (in this case, ADFS). This can be a common issue in OAuth2 integrations, especially when dealing with custom claim names or configurations that differ from the default OIDC schema. Understanding this is essential when troubleshooting or customizing the integration.

Flowable provides configuration properties for user attributes:

flowable.control.app.security.oauth2.current-user.first-name-attribute=given_name
flowable.control.app.security.oauth2.current-user.last-name-attribute=family_name
flowable.control.app.security.oauth2.current-user.display-name-attribute=name
flowable.control.app.security.oauth2.current-user.email-attribute=email

However, these settings only apply when using OpenID Connect (OIDC), not plain OAuth2. Since our setup used OAuth2, we had to take an alternative approach.

Implementing a Custom CurrentUserEnhancer

To resolve this, I implemented a custom CurrentUserEnhancer to map the non-standard claims:

@Service
public class AdfsUserEnhancer implements CurrentUserEnhancer, Ordered {

    private static final Logger log = LoggerFactory.getLogger(AdfsUserEnhancer.class);

    public AdfsUserEnhancer() {
        log.info("AdfsUserEnhancer started.");
    }

    @Override
    public int getOrder() {
        return 8;
    }

    @Override
    public void enhanceCurrentUser(CurrentUserResponse currentUserResponse) {
        log.info("Enhancing the current user for: {}", currentUserResponse);

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        log.info("Authentication: {}", authentication);

        if (authentication instanceof OAuth2AuthenticationToken) {
            OAuth2User user = (OAuth2User) authentication.getPrincipal();
            log.info("OAuth2 user: {}", user);

            if (user.getAttributes().containsKey("FLOW_Firstname")) {
                currentUserResponse.setFirstName(user.getAttribute("FLOW_Firstname"));
            }
            if (user.getAttributes().containsKey("FLOW_Lastname")) {
                currentUserResponse.setLastName(user.getAttribute("FLOW_Lastname"));
            }
            if (user.getAttributes().containsKey("FLOW_Mail")) {
                currentUserResponse.setEmail(user.getAttribute("FLOW_Mail"));
            }
        }
    }
}

The CurrentUserEnhancer must be instantiated as a Spring bean using the following configuration:

@AutoConfiguration
public class AdfsUserEnhancerConfiguration {

    @Bean
    public AdfsUserEnhancer adfsUserEnhancer() {
        return new AdfsUserEnhancer();
    }
}

To ensure the enhancer is picked up by Spring Boot, I created a file at: src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports with the following content

ch.bkb.il.flowable.sso.AdfsUserEnhancer

With the custom CurrentUserEnhancer implemented, the final step was to package the class as a JAR and include it in the Flowable Work container’s classpath. I will cover this deployment process in a follow-up article using Flowable’s /additional-classpath mechanism.

Conclusion

This article covered the integration of Flowable Work with Microsoft ADFS, focusing on handling non-standard claims in OAuth2 authentication. By implementing a custom CurrentUserEnhancer, we successfully mapped user attributes and resolved the issue of users appearing as “Anonymous.” Stay tuned for the next post, where I will discuss deploying this solution efficiently.