Mastering Single Sign‑On: Principles, Architecture, and Java Implementation

This article explains the fundamentals of HTTP's stateless nature, session handling in single‑system web apps, the challenges of multi‑system environments, and presents a detailed walkthrough of Single Sign‑On concepts, token‑based authentication flow, global versus local sessions, deployment considerations, and a step‑by‑step Java implementation with code examples.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Mastering Single Sign‑On: Principles, Architecture, and Java Implementation

Single System Login Mechanism

Web applications use a browser/server model where HTTP is a stateless protocol; each request is processed independently, which means the server cannot associate requests without an explicit mechanism.

To protect resources, the server and browser must share state, which is achieved through a session mechanism. When the browser first requests the server, the server creates a session and returns a session ID (e.g., JSESSIONID) to the browser. The browser stores this ID and includes it in subsequent requests, allowing the server to recognize the same user.

Two common ways for the browser to send the session ID are as a request parameter or via a cookie. Cookies automatically attach to HTTP requests for matching domains, making them the preferred method.

Login State in a Single System

When a user submits credentials, the server validates them against a database. Upon success, the server marks the session as logged in, for example:

HttpSession session = request.getSession();</code>
<code>session.setAttribute("isLogin", true);

Later requests retrieve the flag to determine if the user is authenticated:

HttpSession session = request.getSession();</code>
<code>session.getAttribute("isLogin");

Multi‑System Complexity

Modern web applications consist of many subsystems. Requiring users to log in to each subsystem separately is impractical. Ideally, a user should authenticate once and gain access to the entire application suite.

Sharing cookies across subsystems would require a common top‑level domain and identical server technologies, which is rarely feasible and introduces security concerns.

Therefore, a dedicated Single Sign‑On (SSO) solution is needed.

Single Sign‑On Overview

SSO (Single Sign‑On) allows a user to log in to one system and obtain authorization for all other systems without re‑entering credentials. It consists of two parts: single sign‑on (login) and single sign‑off (logout).

SSO Login Flow

User accesses a protected resource in System 1.

System 1 detects no session and redirects the user to the SSO authentication server, passing its own URL as a parameter.

The SSO server presents a login page.

User submits username and password; the SSO server validates them.

Upon success, the SSO server creates a global session and generates an authorization token.

The SSO server redirects back to System 1 with the token.

System 1 sends the token to the SSO server for verification.

If verification succeeds, System 1 creates a local session marked as logged in.

User later accesses System 2, which also redirects to the SSO server.

The SSO server sees the existing global session, redirects back to System 2 with the same token.

System 2 verifies the token and creates its own local session.

Global vs. Local Sessions

A local session can exist only if a global session exists.

A global session may exist without any local sessions.

When the global session is destroyed, all associated local sessions must be destroyed.

Deployment Diagram

The SSO architecture consists of an SSO authentication server (the central authority) and multiple SSO clients embedded in each subsystem. Communication between them exchanges tokens, validates tokens, and propagates logout requests.

Java Implementation Details

SSO Client (Filter)

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {</code>
<code>    HttpServletRequest req = (HttpServletRequest) request;</code>
<code>    HttpServletResponse res = (HttpServletResponse) response;</code>
<code>    HttpSession session = req.getSession();</code>
<code>    if (session.getAttribute("isLogin") != null) {</code>
<code>        chain.doFilter(request, response);</code>
<code>        return;</code>
<code>    }</code>
<code>    // Redirect to SSO server</code>
<code>    res.sendRedirect("sso-server-url-with-system-url");</code>
<code>}

When the SSO server redirects back with a token parameter, the filter verifies it:

// Request carries token parameter</code>
<code>String token = req.getParameter("token");</code>
<code>if (token != null) {</code>
<code>    boolean verifyResult = this.verify("sso-server-verify-url", token);</code>
<code>    if (!verifyResult) {</code>
<code>        res.sendRedirect("sso-server-url");</code>
<code>        return;</code>
<code>    }</code>
<code>    session.setAttribute("isLogin", true);</code>
<code>    chain.doFilter(request, response);</code>
<code>}

Token Generation (SSO Server) String token = UUID.randomUUID().toString(); Tokens and the list of registered subsystems are stored in a key‑value store such as Redis, which also handles token expiration.

Logout Process

When a user logs out from any subsystem, the client sends a logout request (including the token) to the SSO server. The SSO server invalidates the global session, looks up all registered subsystems for that token, and issues logout requests to each.

String logout = req.getParameter("logout");</code>
<code>if (logout != null) {</code>
<code>    this.ssoServer.logout(token);</code>
<code>}

The SSO server’s logout endpoint clears the HTTP session:

@RequestMapping("/logout")</code>
<code>public String logout(HttpServletRequest req) {</code>
<code>    HttpSession session = req.getSession();</code>
<code>    if (session != null) {</code>
<code>        session.invalidate(); // triggers LogoutListener</code>
<code>    }</code>
<code>    return "redirect:/";</code>
<code>}

A LogoutListener monitors global session destruction and notifies all registered subsystems to clear their local sessions:

public class LogoutListener implements HttpSessionListener {</code>
<code>    @Override</code>
<code>    public void sessionCreated(HttpSessionEvent event) {}</code>
<code>    @Override</code>
<code>    public void sessionDestroyed(HttpSessionEvent event) {</code>
<code>        // Use HttpClient to send logout requests to all registered systems</code>
<code>    }</code>
<code>}

By following these steps, a developer can build a functional SSO solution that provides seamless authentication across multiple web applications while maintaining clear separation between the global authentication authority and individual subsystem clients.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaAuthenticationWeb SecuritySession ManagementSSOSingle Sign-On
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.