Introduction

What if your Angular frontend relied on your Spring Boot backend to handle all of its authentication and authorisation responsibilities and API interactions?

The Backend for Frontend (BFF) design pattern is an architectural approach that a browser-based application can use to handle all of its authentication and authorisation responsibilities and API interactions, for example:

  • The BFF interacts with an OAuth 2.0 Authorization Server as a confidential OAuth 2.0 Client.

  • The BFF manages OAuth 2.0 access and refresh tokens in the context of a cookie-based session, avoiding the direct exposure of any tokens to the browser-based application.

  • The BFF forwards all requests to a OAuth 2.0 Resource Server, augmenting them with the correct access token before forwarding them to the resource server.

The OAuth 2.0 for Browser-Based Applications specification outlines the threats, attack consequences, security considerations and best practices that must be taken into account when developing browser-based applications. It also discusses how different architectural approaches can help address some of these challenges.

In this post we are going to look at some options for working with Angular and Spring Boot.

Note: At the time of writing, Angular is at version 19.x and Spring Boot is at version 3.4.2.

Spring Boot

Static Content

Static content can be served from your Spring Boot application if you place it in the right location. By default, Spring Boot serves static content from resources in the classpath at /static.

For example:

 ├── /serendipity
     └── /modules
        └── /web-bff
            └── /src
                └── /main
                    └── /java
                    └── /resources
                        └── /static
                            ├── 3rdpartylicenses.txt
                            ├── favicon.ico
                            ├── index.html
                            ├── main-2STXNAPZ.js
                            ├── polyfills-EQXJKH7W.js
                            ├── prerendered-routes.json
                            ├── styles-5INURTSO.css
                └── /test

The index.html resource is special because, if it exists, it is used as a 'welcome page', which means it is served up as the root ('/') resource (that is, at http://localhost:8080/).

For example:

Managing Routes

We also need to forward any requests, where the requested path doesn’t look like a static file, to Angular.

For example:

@Controller
public class AngularForwardController {

    @GetMapping("{path:^(?!api|public)[^\\.]*}/**")
    public String handleForward() {
        return "forward:/";
    }

}

Spring Boot handles static files and API requests. Angular handles everything else in the browser.

Maven Plugins

Maven Resources Plugin

You can use the maven-resources-plugin to copy your resources:

	<build>
		<plugins>

			<plugin>
				<artifactId>maven-resources-plugin</artifactId>
				<executions>
					<execution>
						<id>copy-resources</id>
						<phase>validate</phase>
						<goals>
							<goal>copy-resources</goal>
						</goals>
						<configuration>
							<outputDirectory>./target/classes/static/</outputDirectory>
							<resources>
								<resource>
									<directory>../../../frontend/dist/web-ui</directory>
								</resource>
							</resources>
						</configuration>
					</execution>
				</executions>
			</plugin>
            
            ...

		</plugins>
	</build>
Frontend Maven Plugin

Alternatively, you can place your Angular source code in your Backend for Frontend's /webapp directory:

For example:

 ├── /serendipity
     └── /modules
        └── /web-bff        
            └── /src
                └── /main
                    └── /java
                    └── /resources
                    └── /webapp
                        └── /app
                        └── /environments
                        ├── favicon.ico
                        ├── index.html
                        ├── main.ts
                        ├── styles.scss                        
                └── /test

Note: Spring Boot will ignore the src/main/webapp directory if your application is packaged as a fat (aka uber) jar.

And use the frontend-maven-plugin to run your Angular build:

    <build>
        <plugins>

            <plugin>
                <groupId>com.github.eirslett</groupId>
                <artifactId>frontend-maven-plugin</artifactId>
                <version>${frontend.maven.plugin.version}</version>
                <executions>
                    <execution>
                        <id>nodeAndNpmSetup</id>
                        <goals>
                            <goal>install-node-and-npm</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>npmInstall</id>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <configuration>
                            <arguments>install</arguments>
                        </configuration>
                    </execution>
                    <execution>
                        <id>npmRunBuild</id>
                        <goals>
                            <goal>npm</goal>
                        </goals>
                        <configuration>
                            <arguments>run build</arguments>
                        </configuration>
                    </execution>
                </executions>
                <configuration>
                    <nodeVersion>${node.version}</nodeVersion>
                </configuration>
            </plugin>
            
            ...

        </plugins>
    </build>

Don't forget to update the outputPath in your angular.json:

        ...
        
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          "options": {
            "outputPath": {
              "base": "./target/classes/static",
              "browser": ""
            },
            
        ...
References
OAuth 2.0
Spring