Last year, Micah Silverman wrote about integrating Spring Boot, Spring Security, and Stormpath. Today, I’m going to take you on a similar journey, except this time you’ll be using AngularJS and Stormpath’s AngularJS SDK for the UI. Along the way, you’ll learn how to create REST endpoints with Spring Data REST, configure Spring Boot to handle cross-domain requests, and use Stormpath to make authentication a breeze.

Get Started with AngularJS

To get started with AngularJS, I used to recommend cloning Angular’s angular-seed project. I wrote about developing a simple Angular app with angular-seed early last year. I followed that up with an article on testing your Angular app.

As part of a recent update to the JHipster mini-book, I created my own my angular-seed fork that uses UI-Router, Gulp, and Browsersync. This project will be the starting point for this tutorial. This tutorial assumes you have Node.js, Git and Gulp installed.

To begin, clone my fork of the angular-seed project and install all its dependencies:

TIP: You can also use Facebook’s yarn as an alternative to npm. It caches downloads and can be up to 11 times faster with a warm cache. I tried it on this project and found it took 20.63 seconds the first time I ran “yarn install”. The second time, it took 0.14 seconds! You can install yarn with npm using npm -g install yarn.

After you’ve performed these steps, your browser should launch and you should see a screen like this:

First view

You can modify one of its CSS files (e.g. app/css/app2.css) to add some body padding:

When you save the file, Browsersync will auto-reload your changes and things look a bit better.

First view with padding

Angular has a $resource service that allows you to easily make HTTP calls to a REST endpoint. In the following section, you’ll use $resource, and a JSON file to create an application that allows searching and editing. After that, you’ll change to use Spring Boot for that endpoint. Finally, we’ll integrate Stormpath to provide the following:

  1. Registration
  2. Login
  3. Logout
  4. Forgot Password
  5. Only allow admins to search

Add a Search Feature

The AngularJS code below might look a bit different than you’re used to. This code uses John Papa’s Angular 1 Style Guide. This guide promotes an opinionated way to write AngularJS 1.x applications; allowing you to worry less about syntax and naming conventions and more about your code.

To create a new feature, you’ll need a few different files:

  1. search.service.js to interact with your data
  2. search.controller.js to contain your controller logic
  3. search.html to display your rendered data
  4. search.state.js to contain routing information

Create app/search/search.service.js and populate it with the following JavaScript:

The $resource service is not included by default in angular-seed. To add it to your project, add "angular-resource": "~1.5.0" to your dependencies in bower.json, or run the following command:

To activate this service in your application, add a link to angular-resource.js in app/index.html.

And reference it as a dependency in app/app.js.

In addition to using $resource, SearchService reads from a people.json file. Create app/api/search/people.json with the following contents:

Now that the data and service are in place create app/search/search.html to search and display data.

In this file, there are two “vm” (a.k.a. view-model) variables that the template expects in its controller: vm.term and vm.searchResults. Create app/search/search.controller.js to expose these variables:

To make things look better, you can add some new CSS rules to app/css/app2.css:

Add a link to the search feature in app/index.html by adding a “search” menu item:

To make this link work, you need to create a search.state.js file in the search directory that configures the “search” state.

The final step to enabling search is making sure all the JavaScript files are referenced in app/index.html:

At this point, you should be able to run “gulp”, click on the search link and perform a search. For example, below is a screenshot after searching for “Von”.

Search for Von

If you’ve made it this far, congratulations! If you encountered issues along the way, see the add search feature commit to see what’s changed since cloning the original angular-seed project.

Add an Edit Feature

For the edit feature, you’ll create similar files to what you did for the search feature.

  1. edit.state.js to contain routing information
  2. edit.controller.js to contain your controller logic
  3. edit.html to display your rendered data

You’ll reuse the search.service.js and add a new fetch function for retrieving a single record.

Create app/edit/edit.state.js to route “/edit/{id}” URL to the EditController.

Create app/edit/edit.controller.js and create a simple controller that fetches a person’s record by the passed in identifier.

Add app/edit/edit.html and populate it with the following HTML to display a person’s information.

Add a link to the edit state from app/search/search.html:

And add a link to the new JavaScript files you added in app/index.html:

TIP: If you get tired of adding <script> tags in your index.html, you can use gulp-inject to add new files automatically.

Finally, add some CSS in app/css/app2.css to make the form look a bit better.

After making all these changes, you should be able to search for a person, click on their name and view their information.

Edit Von

Get Started with Spring Boot and Stormpath

Spring Initializr is a project that makes it super easy to get started with Spring Boot. It’s deployed at https://start.spring.io by default and Stormpath has an instance deployed at http://start.stormpath.io. Our instance has Stormpath Spring Boot starters available, and they should be available soon on the default instance.

To create an application with Spring Boot and Stormpath, go to http://start.stormpath.io and select the following dependencies: Web, JPA, H2, Stormpath Default, and DevTools. DevTools is a handy plugin for Spring Boot that allows you to hot-reload the application when you recompile any Java files.

start.stormpath.io

Click “Generate Project” and download the resulting demo.zip file. Expand the file and copy its contents into the Angular project you created (e.g. angularjs-spring-boot-stormpath).

Because you’ve integrated Stormpath in this project, you’ll need a Stormpath account and API Keys to start the application. If you don’t have an account, go to https://api.stormpath.com/register and sign up. A developer account is free, with up to 10K API calls per month.

Register for Stormpath

You’ll receive an email to activate your account. Click on the activation link and login to your account.

Stormpath Activated

Click on the “Create API Key” button and copy the resulting file to ~/.stormpath/apiKey.properties.

Create API Keys

At this point, you should be able to start the Spring Boot app by running mvn spring-boot:run. When you open http://localhost:8080 in your browser, you’ll be prompted to login using basic authentication. You can turn off basic authentication if you want (using security.basic.enabled = false in src/main/resources/application.properties), but you can also integrate Stormpath with Spring Security instead.

To add Stormpath support to Spring Security, create src/main/java/com/example/SecurityConfiguration.java with the following code.

After recompiling this class and waiting for your application to reload, go to http://localhost:8080. You’ll be prompted to log in with Stormpath’s login form.

Thymeleaf Login

You won’t be able to log in because you haven’t created any accounts in your default application. Click on “Create Account” to create a new account. You can use the same email address as you did when you registered.

Thymeleaf Registration Form

After completing registration, you should be able to log in using the email and password you entered.

NOTE: The above steps are covered in Stormpath’s Spring Boot Quickstart Guide.

You’ll likely see a 404 page from Spring Boot after you’ve successfully logged in.

404 from Spring Boot

This is because Stormpath redirects to / by default. To make it so you don’t see an error, create a homepage at src/main/resources/static/index.html with the following HTML:

The auto-discovery of HTML files in this directory is covered in Spring Boot’s static content documentation. If you want to make your homepage dynamic, you have to create a Controller that serves up a Thymleaf template. Thymeleaf is enabled by default when using the Stormpath Spring Boot starter.

To see what this looks like, create src/main/java/com/example/HomeController.java with the following code.

Then create src/main/templates/index.html to say hello to the user with their name.

If you compile HelloController and DevTools reloads your application, you’ll likely see the following error:

Restarting your application manually will solve this issue, but a better solution is to configure the Spring Boot Maven plugin to add resources.

This setting will allow you to modify templates and see the changes immediately without restarting your server.

If you’re still logged in, you should be able to refresh your browser and see a page like the one below.

Hello Stormpath!

You might notice that clicking the “Logout” button will prompt you to log in again. If you’d prefer to show the homepage and allow users to click a link to log in, you can allow this in your Spring Security configuration. Simply update SecurityConfiguration.java to have the following. While you’re at it, add protection for the API endpoints you’re about to create.

For more information on the features that Stormpath provides for Spring Boot and Spring Security, see A Simple Web App with Spring Boot, Spring Security, and Stormpath – in 15 Minutes.

Add an API Endpoint

To add an API for /people, you’re going to need some data first. Spring Boot’s Spring Data JPA provides an easy way to do this. You’ll need a JPA entity to represent your data, so create src/main/java/com/example/Person.java.

Create an Address.java class in the same directory.

Then create src/main/resources/data.sql to create sample data on startup.

Spring Data JPA provides JPA repositories that make it easy to CRUD an entity. The Spring Data REST project provides support for creating JPA repositories and exposing them as REST endpoints.

Add the Spring Boot starter for Spring Data REST to your pom.xml.

Create a PersonRepository.java file in src/main/java/com/example that utilizes Spring Data REST.

To make all Spring Data REST endpoints have an /api prefix, add the following to src/main/resources/application.properties.

Using HTTPie, you should be able to login via the command line using:

To see the data at /api/people, copy the access token from the result of the command above and use it in an Authorization header.

You can also login with your browser and navigate to http://localhost:8080/api/people.

People JSON in browser

In this example, there’s a PersonRespository#findByName method that allows you to search by a person’s full name. Below is an example call to this REST endpoint.

http://localhost:8080/api/people/search/findByName?name=Von%20Miller

You’ll notice this doesn’t provide full-text searching. Spring Data Elasticsearch is a good place to start if you’re looking for full-text searching.

Integrate AngularJS with Spring Boot

To integrate the AngularJS with Spring Boot, let’s first turn off Stormpath so you can access api/people without logging in. Modify SecurityConfiguration.java to remove the stormpath() hook and allow all requests.

Next, modify app/search/search.service.js to talk to http://localhost:8080/api/people, configure the ‘query’ function to not expect an array, and change the search function to handle the new data structure.

Fire up your Angular app using gulp, then try its search feature. You’ll see an error in your console when you try to search. This happens because of your browser’s same-origin policy.

SOP Error

Spring Boot supports Cross-Origin Resource Sharing (CORS) to help solve this issue. However, it only works for Spring MVC, not Spring Data REST (see DATAREST-573 for more information). The good news is the Spring Framework provides a CorsFilter you can use for filter-based frameworks. Add the following to SpringConfiguration.java.

After making these changes and waiting for your application to reload, you should be able to search people, just like you did before.

Enable Stormpath

To make everything work with Stormpath enabled, there’re several things that need to happen:

  1. Re-enable Stormpath in SecurityConfiguration.java
  2. Add Stormpath’s AngularJS SDK to the Angular app
  3. Create pages and controllers for Login, Logout, Registration, and Forgot Password

Revert the changes you made in SecurityConfiguration.java to allow all requests.

To add Stormpath’s AngularJS SDK to your project, you can use Bower.

Add these new files to app/index.html:

Open app/app.js and add these two Stormpath dependencies at the bottom of the list.

Modify the config block in this file to configure Stormpath to point to Spring Boot on http://localhost:8080.

In the same app.js file, add a run block, place it below the config block (make sure you move the semicolon from the config block to the run block):

This configures Stormpath to do the following:

  • Redirect users to the login view if they try to access a restricted view. After logging in, they are sent back to the view that they originally requested.
  • Send users to the view1 view after login if they have visited the login page directly (they did not try to access a restricted view first).

Modify app/index.html to adjust the menu so only logged in users can access view2 and the search feature. This code makes use of the if-user and if-not-user directives, which are documented in the AngularJS SDK docs.

NOTE: There is an issue in the Stormpath’s Java SDK where if-user-in-group=”ADMIN” doesn’t work. A fix will be available in a future release. In the meantime, there’s a workaround in Stormpath’s AngularJS SDK.

Since no “login” state exists yet, you’ll need to create one. Create app/login/login.state.js and populate it with the following.

No controller is needed because Stormpath provides the Controller for you. Create app/login/login.html and use the spLoginForm directive to render the login form.

Add login.state.js to index.html.

At this point, I noticed my console said I was not allowed to access http://localhost:8080/me because my origin (http://localhost:3000/me) was not supported. After debugging, I figured out this was because the main StormpathFilter comes before the CorsFilter. To fix this, add the following to application.properties.

After making this change, you should be able to hit http://localhost:3000 and click the Login link.

AngularJS Login

It doesn’t look great by default, but that’s because the default template expects Bootstrap to be one of the CSS files. Add Bootstrap with Bower (bower install bootstrap --save), add a <link> in app/index.html, and the form becomes a lot prettier.

Bootstrap Login

You should be able to login with the username and password combination you registered with earlier.

NOTE: There’s an issue when trying to logout cross-domain with the Stormpath’s Spring Boot integration. We hope to have a fix soon. In the meantime, refreshing your browser after clicking the Logout link will show you have successfully logged out.

Unlike the Spring Boot Thymeleaf templates, the AngularJS spLoginForm directive does not include a link to register. You can add this above the form by modifying app/login/login.html and adding the following HTML at the top.

After making this change, the login form looks more like the Thymeleaf version.

Login with Create Account

However, the “Create Account” link won’t work since there is no “register” state yet. To create it, add app/register/register.state.js:

Create a register.html file in the same directory.

TIP: Wrapping the template in a .container-fluid class removes the horizontal scrolling you can see in the previous screenshot.

Add a reference to register.state.js in app/index.html.

Now clicking on the “Create Account” link should render a registration form.

AngularJS Registration Form

When I first tried to register using this form, I received a strange error.

To fix this, I had to modify app/app.js and set the form content type to application/json.

There is an open issue to remove this extra step in Stormpath’s AngularJS SDK.

The last step is to configure the state for the Forgot Password feature. Create app/forgot/forgot.state.js and populate it with the following code.

Create forgot.html in the same directory and use the spPasswordResetRequestForm directive in it.

Don’t forget to add a reference to this new state in app/index.html.

Now, you should be able to click the Forgot Password link in the Login form. However, the current release of Stormpath’s AngularJS SDK doesn’t support Angular’s hashbang mode and expects HTML5 mode. The Forgot Password link doesn’t work in hashbang mode.

The easy way to workaround this is to pass in a $locationProvider to the config block in app/app.js and set HTML5 mode to true.

You’ll also need to add <base href="/"> to the <head> of app/index.html to make HTML5 mode work. This does cause issues with Browsersync reloading; I haven’t figured out a solution for that yet.

If you don’t want to use HTML5 mode in your AngularJS application, you can override the templates to provide relative links. For example, you can change login.html to point to your customized template.

Then you can create app/stormpath/login.tpl and tweak the default template so the registration link uses UI Router’s ui-sref directive.

Both methods will allow you to navigate to the “forgot” state when clicking on the “Forgot Password” link.

AngularJS Forgot Password

Summary

I hope you’ve enjoyed this tour of AngularJS, Spring Boot, and Stormpath. I showed you how to do a number of things in this article:

  1. Create a simple AngularJS application with a search feature
  2. Create a Spring Boot application with Stormpath integrated
  3. Communicate between the AngularJS and Spring Boot apps cross-domain
  4. Add login, registration, and forgot password features to the AngularJS application

The source code for the completed application referenced here is available at https://github.com/stormpath/stormpath-angularjs-spring-boot-example.

In future posts, I’ll talk about how the Stormpath’s AngularJS SDK can be used to prevent access to certain states and hide links to different groups. I also plan to show you how to integrate Stormpath into JHipster.

As far as Stormpath’s Angular 2 support—we’re working on it! We hope to have something for you to experiment with by Thanksgiving (November 24). Update: We released a beta version of our Angular 2 support on November 14!

If you have any questions, don’t hesitate to leave a comment or hit me up on Twitter at @mraible.

References

The good Dr. Dave Syer wrote an excellent blog series in 2015 on integrating AngularJS with Spring Boot and Spring Security.

  1. Spring and Angular JS: A Secure Single Page Application
  2. The Login Page: Angular JS and Spring Security Part II
  3. The Resource Server: Angular JS and Spring Security Part III
  4. The API Gateway Pattern: Angular JS and Spring Security Part IV
  5. SSO with OAuth2: Angular JS and Spring Security Part V