How to implement SAML SSO in Java with Spring Boot
If you’re reading this blog post, you probably need to support SAML single sign-on in a Java web application. And if you’re anything like most software developers, you’ve never worked with SAML before. This post will help you get started.
SAML in Java (Spring Boot): getting started
Before you actually ship SAML support, you’ll probably want to acquaint yourself with SAML. SAML introduces a bunch of new concepts and some jargon that can be challenging to navigate.
We at SSOReady put a few resources together that should help a bit:
-
A gentle introduction to SAML: This is an overview of SAML that skips the details. We wrote it to help readers generally understand SAML. You might find it useful if you’re totally overwhelmed.
-
SAML, a technical primer: This resource spends more time deep in the details of SAML. If you want to develop practical mastery of SAML single sign-on, you should read this at least once.
But I’ll assume that you’re a little bit like me and don’t want to read those.
SAML defines a protocol that software applications can use to authenticate users indirectly. Instead of challenging users to present, say, a username and password, a software application will rely on claims it receives from another software application.
In practice, this just means that SAML single sign-on enables enterprise customers to access all of their software applications through a single software application, an identity provider like Microsoft Entra ID or Okta.
It’s kind of a convoluted process that looks like this:
This article focuses on a simplified SAML implementation that uses SSOReady, an open source middleware that abstracts away all the complicated details.
Here’s what it looks like to use SSOReady:
You don’t have to handle any cryptography, you don’t have to handle any XML, you don’t need to worry about differences between SAML identity providers. You just need to set up two endpoints.
SAML in Java (Spring Boot): getting started with an example application
If you simply want to get started with an example application that implements SAML in Java, you can visit our example app on GitHub.
This app implements SAML using SSOReady’s middleware service.
You can also just run the following:
git clone https://github.com/ssoready/ssoready-example-app-java-spring-boot-saml
cd ssoready-example-app-java-spring-boot-saml
./gradlew dependencies
./gradlew bootRun
SAML in Java (Spring Boot): the SSOReady Java SDK
The example app that I linked above uses SSOReady’s Java SDK. Find it on GitHub here for installation instructions.
SAML in Java (Spring Boot): SAML in two endpoints
I’m going to gloss over some details here and just focus on the two core endpoints that interface with SSOReady. In essence, you need one endpoint that initiates SAML logins; we call this the SAML Redirect endpoint. And then you need another endpoint that processes incoming SAML logins; we call this the Callback endpoint.
Here’s what the Redirect endpoint looks like:
@GetMapping("/saml-redirect")
public RedirectView samlRedirect(@RequestParam(value = "email") String email) {
String redirectUrl = this.ssoready.saml().getSamlRedirectUrl(
GetSamlRedirectUrlRequest
.builder()
// converts "john.doe@example.com" into "example.com"
.organizationExternalId(email.split("@")[1])
.build()
).getRedirectUrl().orElseThrow();
return new RedirectView(redirectUrl);
}
The Redirect endpoint does basically two things:
- It asks SSOReady for a ‘redirect URL’ that points at a corporate identity provider (e.g. Okta, Entra, etc.)
- It redirects the user to visit that redirect URL for authentication
If this doesn’t make sense to you, check out the general explanations of SAML that I linked above!
Upon arriving at the redirect URL – i.e., at a corporate identity provider – the user will sign in with a username and a password. The identity provider will then relay claims about the user back (to SSOReady) in a SAML message. SSOReady processes the SAML message and associates it with a saml_access_code
. SSOReady continues the user’s redirect back to the Callback endpoint, passing the saml_access_code
as a query parameter.
The app’s Callback endpoint needs to receive the user’s redirect and collect the saml_access_code
. It passes the saml_access_code
back to SSOReady to get the user’s details. Once it gets user details from SSOReady, the app establishes a session for the user.
Here’s what the Callback endpoint looks like:
@GetMapping("/ssoready-callback")
public RedirectView ssoreadyCallback(HttpServletResponse response, @RequestParam(value = "saml_access_code") String samlAccessCode) {
String email = this.ssoready.saml().redeemSamlAccessCode(
RedeemSamlAccessCodeRequest
.builder()
.samlAccessCode(samlAccessCode)
.build()
).getEmail().orElseThrow();
Cookie cookie = new Cookie("email", email);
cookie.setMaxAge(3600);
response.addCookie(cookie);
return new RedirectView("/");
}
This will seem a little overwhelming at first, but it’s by far the easiest and most secure way to set up SAML in your app.
If you need a more detailed overview, check out the SSOReady docs at https://ssoready.com/docs.