Abstract
Single Sign-On (SSO) allows a user to authenticate once and gain access to multiple related systems. Modern SSO often uses JSON Web Tokens (JWTs) or similar tokens, enabling stateless identity across domains. This report analyzes a token-based SSO implementation built with React (using React Router), Axios and a REST API backend. We dissect the login and registration pages (client components) and the underlying flows- detecting existing sessions, redirecting to a central auth service, issuing JWTs and returning the user to the original app. JWT, cookies, BroadcastChannel and security mechanisms (cookie flags, redirect whitelisting) are explained. Real-world SSO examples (Google, Microsoft) provide context.
Introduction
Single Sign-On (SSO) schemes let users log in once and access multiple applications without re-entering credentials. This improves user productivity by reducing password fatigue and help-desk overhead. For example, a corporate login can grant seamless access to email, calendars and intranet tools. In a microfrontend or multi-domain setup (e.g. several apps under unifyed.tech), a central auth service can issue a token that all sub-apps trust. Our stack uses React on the client (React Router for navigation) and Axios for API calls to a RESTful identity backend. SSO typically relies on a shared identity provider (IdP) and specific protocols. Enterprise systems often use SAML for SSO. Cloud and consumer apps commonly use OAuth 2.0.
Real-World SSO Architectures
Major platforms exemplify SSO in action. Google's ecosystem shares authentication cookies on *.google.com, so logging in at accounts.google.com signs you into Gmail, Drive, etc. Microsoft's Azure AD or ADFS provides SAML/OIDC identities for Office 365 and corporate apps. Identity-as-a-Service vendors (Okta, Auth0) centralize user management and support SAML/OIDC flows for many clients. These solutions share a common pattern- a centralized login domain issues a signed token (often a JWT) that client apps validate. Companies like Okta and Auth0 build platforms so developers can easily enable SSO with these standards. In all cases, the goal is one authentication step to access to all connected apps.
Architectural Overview
In our example, we have,
- Auth Domain- auth.unifyed.tech (handles login, registration, token issuance).
- Subdomain Apps: e.g. cpanel.unifyed.tech, dash.unifyed.tech (protected resources).
All domains share the parent domain .unifyed.tech. A JWT is issued by auth.unifyed.tech and stored in a cookie scoped to Domain=.unifyed.tech. That cookie is automatically sent with requests to any subdomain. The flow is as follows,
-
A user attempts to load cpanel.unifyed.tech. The app's initialization script checks for the authToken cookie (scoped to.unifyed.tech).
-
If no valid cookie is found, the app redirects the user to the login page on the auth service, including a redirect parameter (the original app URL).
-
On auth.unifyed.tech, the server inspects the redirect URL (verifying it matches *.unifyed.tech to avoid open-redirect attacks). If the user already has a valid session cookie, they are sent straight back. Otherwise, the login form is shown.
-
After successful login, the server generates a JWT (with user info) and sets it in an HttpOnly, Secure cookie on Domain=.unifyed.tech. The server then redirects the browser back to the original app (the redirect URL).
-
The subdomain app (cpanel.unifyed.tech) now sees the cookie and can call /validate-token on the backend to fetch user details. Since the cookie is HttpOnly, the browser sends it automatically in the request header.
This design ensures all sub-apps trust a single identity source. The shared cookie eliminates the need for client-side polling of other subdomain storage. Upon each app load or route change, the front-end code checks for authentication state and either allows access or invokes the redirect flow.
SSO Flow
Consider the user journey in detail,
User Visits Protected App, The user navigates to cpanel.unifyed.tech/dashboard.
- The app's startup code runs and reads the authToken cookie (if any).
- If a token cookie is present, the app calls GET /validate-token on the backend.
- Valid Cookie- Server confirms the JWT signature and expiration, returns user info. App displays dashboard.
- Invalid or No Cookie- The app triggers a redirect,
window.location.href = `https://auth.unifyed.tech/login?redirect=${encodeURIComponent(
currentURL
)}`;
This sends the user to the centralized auth service, carrying the original URL as a parameter.
Auth Service Handles Redirect- At auth.unifyed.tech/login?redirect=cpanel.unifyed.tech/dashboard,
- Server first validates the redirect param against a whitelist regex (e.g. ^https?://[^/]+.unifyed.tech). This prevents attackers from injecting external URLs.
- If the user already has a valid authToken cookie (perhaps from a prior login), the auth service skips the form and immediately redirects back to the redirect URL (preserving session).
- If not logged in, the login page is shown. The user enters credentials.
User Logs In-
- The login handler (Login.jsx) sends a POST /login with the user's credentials.
- On success, the backend issues a JWT and responds with it.
- The client JavaScript sets a cookie.
document.cookie = `authToken=${token}; Domain=.unifyed.tech; Path=/; Secure; HttpOnly; SameSite=None`;
This cookie is flagged Secure (HTTPS only), HttpOnly (inaccessible to JS) and SameSite=None to allow cross-site sending.
Finally, window.location.href is set to the original redirect URL (e.g. cpanel.unifyed.tech/dashboard). The token itself need not go in the URL, since the cookie will be automatically attached on the next request.
Single Sign-Out (Logout)- If the user clicks "Logout" in any sub-app,
- The app clears the authToken cookie:
document.cookie = "authToken=; Domain=.unifyed.tech; Path=/; Max-Age=0";
- It also call POST auth.unifyed.tech/logout to invalidate the session server-side.
Broadcast Logout to Others
To synchronize all open tabs/services, the code emits a logout signal.
const bc = new BroadcastChannel("auth");
bc.postMessage({ cmd: "logout" });
Other tabs who are listening,
const bc = new BroadcastChannel("auth");
bc.onmessage = (event) => {
if (event.data?.cmd === "logout") {
// perform logout actions
}
};
Any listening script in other tabs or sub-apps receives this message and triggers its own logout (clearing any UI state and redirecting to login). The BroadcastChannel API is designed for same-origin communication between browsing contexts. In effect, one click logs the user out everywhere. The SSO principle of single logout (SLO) means a single action terminates access across all services.
In summary, this flow resembles an OAuth2 implicit style SSO within a controlled domain. A single JWT (cookie) is handed to the browser and each application trusts that cookie with server-side validation. Users feel like they're only logging in once; under the hood, the token is passed seamlessly.
Core Technologies
React & React Router used for the frontend app structure. The router provides hooks like useLocation, useNavigate to read query params (redirect) and navigate programmatically.
Frontend uses Axios to call backend endpoints. The token is included via the browser cookie or Authorization header.
The JWT is stored in a cookie on Domain=.unifyed.tech. The HttpOnly flag (per OWASP) prevents JavaScript from reading the cookie, mitigating XSS-based token theft . The Secure flag ensures it is only sent over HTTPS and SameSite=None allows the cookie to be sent in cross-site requests (since subdomains count as cross-site).
For session state synchronization, we use these browser features. The BroadcastChannel API lets scripts on the same origin (e.g. auth.unifyed.tech and *.unifyed.tech) send messages to each other. We broadcast a {cmd: 'logout'} message so all listeners (other tabs or apps) can react. As Chrome's docs note, this is useful when the user logs out in another open tab on the same site.
The auth server enforces that the redirect URL belongs to our unifyed.tech domain. This avoids open-redirect vulnerabilities. In practice we implement a regex like ^https?://[^/]+.unifyed.tech to validate the target.
Modern SSO also considers tokens, OAuth scopes and third-party providers. In our internal SSO, we did not implement refresh tokens (JWT expiry is short and a fresh login can be done). We assume a monolithic IdP (auth.unifyed.tech) so we bypass federated identity complexity. But the pattern easily extends, replacing the login form with an OIDC or SAML IdP login, for example, would integrate external identity providers.
Token Storage and Security
In our design, the JWT lives in an HttpOnly cookie on the auth subdomain. Unlike storing tokens in localStorage, cookies with HttpOnly cannot be read or written by JavaScript. This is a critical defense as OWASP explains, setting the HttpOnly flag on a cookie helps mitigate the risk of client-side script accessing the protected cookie. Even if a cross-site scripting flaw existed, the cookie cannot be stolen by malicious scripts. Thus, the auth system does not expose tokens to the browser runtime. Sub-apps simply rely on the browser to send the cookie in requests. Because we use Domain=.unifyed.tech, this cookie is sent to all subdomains (e.g. cpanel.unifyed.tech, dash.unifyed.tech, etc.) whenever the browser makes an HTTP request to them. Upon receiving a request with that cookie, each service validates the JWT server-side. If the token were stored in localStorage, it would be confined to one origin and vulnerable to XSS attacks jwt.io. By contrast, our cookie approach follows best practices for sensitive tokens.
Security Highlights
No Embedded Secrets- Client applications (the React front-ends) do not embed any secrets. Only the auth server holds the signing key for JWTs. All validation of tokens happens on trusted servers.
Conclusion
This token-based SSO implementation provides a seamless login experience across multiple subdomain apps. By centralizing authentication (auth.unifyed.tech), issuing a JWT in a secure cookie and broadcasting logout events, we achieve key SSO goals like one login unlocks all services and one logout clears all sessions. The design follows best practices– restricting redirect targets, using HttpOnly cookies and validating tokens on every request. While we built this for a specific React+REST ecosystem, the principles apply broadly. This SSO is a robust foundation. It exemplifies how modern web technologies (JWTs, BroadcastChannel, secure cookies) can replicate the conveniences of enterprise SSO in a custom application stack.