Skip to main content

Azure AD B2C SSO Integration

Overview

APEX uses Azure AD B2C as its identity provider for customer authentication. The system implements OAuth 2.0 and OpenID Connect protocols for secure authentication. This document provides detailed guidance on how to implement SSO with Azure AD B2C in your application.

Important: All Azure AD B2C configuration, tenant setup, and policy management is handled by the APEX team. Contact the APEX team at platform-dev@lightstone.co.za to request Azure configuration changes or to obtain your application's specific credentials.

Configuration Parameters

The Azure AD B2C configuration requires several key parameters that must be defined in your application's configuration. These parameters will be provided by the APEX team.

Parameter Descriptions

  • authority: The Azure AD B2C policy endpoint for sign-up/sign-in. This URL contains the Azure B2C tenant name and the user flow or custom policy to use for signing in.

    • Standard value: "https://login.lightstone.co.za/tfp/lsgb2c.onmicrosoft.com/B2C_1A_SIGNUPORSIGNINV2_TEST/"
  • passwordReset: The password reset policy endpoint. This URL points to a separate user flow configured for password reset operations.

    • Standard value: "https://login.lightstone.co.za/tfp/lsgb2c.onmicrosoft.com/B2C_1A_PASSWORDRESETV2_TEST/"
  • clientId: The application client ID registered in Azure AD B2C. This identifier is provided by the APEX team after they register your application in the Azure portal.

  • redirectUrl: The application redirect URL after successful authentication. Provide this URL to the APEX team to ensure it matches exactly what's registered in the Azure portal for your application.

  • logoutRedirectUrl: The URL to redirect to after logout. Provide this URL to the APEX team so they can configure Azure AD B2C to redirect users to this URL when they sign out.

  • scopes: The API permissions required by the application:

    • Standard values: ["openid", "profile"]
    • If your application needs access to specific APIs, discuss additional scopes with the APEX team
  • knownAuthorities: The list of trusted authority domains for authentication. Only these domains will be considered valid token issuers.

    • Standard values: ["lsgb2c.b2clogin.com", "login.lightstone.co.za"]

Implementation Guide

1. Application Registration

The APEX team will handle all Azure AD B2C tenant creation and application registration processes. To get your application registered:

  1. Contact the APEX team with the following information:
    • Your application name and description
    • Application type ("Web app / API" or "Single-page application")
    • Redirect URLs for authentication
    • Required API permissions and scopes
    • Any custom user attributes needed

The APEX team will provide you with the necessary clientId and other configuration parameters after registration.

2. User Flow Configuration

The APEX team manages all user flow configurations in Azure AD B2C, including:

  • Sign-up and sign-in: Combined flow that allows users to create new accounts or sign in
  • Password reset: Flow that handles the password recovery process
  • Profile editing: Optional flow that allows users to modify their profile information

If you need customizations to these flows, contact the APEX team with your specific requirements.

3. Client-Side Implementation

Implement the MSAL.js library in your application using the configuration provided by the APEX team:

import { PublicClientApplication } from "@azure/msal-browser";

const msalConfig = {
auth: {
clientId: "your-client-id", // Use the client ID provided by the APEX team
authority: "https://login.lightstone.co.za/tfp/lsgb2c.onmicrosoft.com/B2C_1A_SIGNUPORSIGNINV2_TEST/",
knownAuthorities: ["lsgb2c.b2clogin.com", "login.lightstone.co.za"],
redirectUri: "https://your-app.com/auth-redirect", // Your application's redirect URL
postLogoutRedirectUri: "https://your-app.com/logout-redirect" // Your application's logout redirect URL
},
cache: {
cacheLocation: "sessionStorage"
}
};

const msalInstance = new PublicClientApplication(msalConfig);

4. Authentication Flows

Sign-in

const loginRequest = {
scopes: ["openid", "profile"]
};

msalInstance.loginRedirect(loginRequest)
.catch(error => {
// Handle login errors
if (error.errorMessage.includes("AADB2C90118")) {
// Password reset error code - redirect to reset flow
msalInstance.loginRedirect({
authority: "https://login.lightstone.co.za/tfp/lsgb2c.onmicrosoft.com/B2C_1A_PASSWORDRESETV2_TEST/"
});
}
});

Token Acquisition

msalInstance.acquireTokenSilent(loginRequest)
.then(response => {
// Use the access token in the response to call your API
const accessToken = response.accessToken;
})
.catch(error => {
// Handle token acquisition errors
if (error instanceof InteractionRequiredAuthError) {
msalInstance.acquireTokenRedirect(loginRequest);
}
});

Sign-out

msalInstance.logout({
postLogoutRedirectUri: msalConfig.auth.postLogoutRedirectUri
});

Security Best Practices

  1. Token Validation: Always validate tokens on your server before granting access
  2. Secure Storage: Store tokens securely and never in local storage
  3. HTTPS Only: Ensure all communication happens over HTTPS
  4. State Parameter: Use state parameters to prevent CSRF attacks
  5. Scopes: Request only the scopes your application needs

Troubleshooting

Common issues and solutions:

IssueSolution
CORS errorsContact the APEX team to ensure your app's domain is registered in the Azure portal
Invalid redirect URIEnsure redirect URIs match what you provided to the APEX team
Token expiredImplement proper token refresh logic
Silent token acquisition failsFall back to interactive authentication
Configuration changes neededContact the APEX team for any Azure AD B2C configuration changes

Federation Integration

Apex SSO supports two federation patterns:

  1. Your application as a client — your application accepts Apex B2C-issued JWTs. Users authenticate through the Apex sign-in page and your server validates tokens issued by B2C.
  2. Your identity provider as a federated IdP — your organisation's IdentityServer (or any OIDC-compatible IdP) is registered with Apex B2C. Users click a "Sign in with [Your Organisation]" button on the Apex login screen and authenticate through your IdP; Apex B2C trusts the resulting token.

Both patterns require contacting the APEX team to register your application. The sections below cover each case.

How Federation Works

When a user accesses a 3rd party application, they are redirected to Apex B2C for authentication. B2C either handles the login directly (local account or social IdP) or delegates to a registered federated identity provider. After authentication, B2C issues a JWT back to the 3rd party application. If the user is new to Apex, B2C automatically creates a contact record via the Apex SSO API before issuing the token.

Registering as a Federation Partner

Contact the APEX team at platform-dev@lightstone.co.za with the following information:

InformationNotes
Application / organisation nameUsed for display and internal tracking
Integration type"Client application" (your app uses Apex B2C as IdP) or "Identity provider" (your IdP is added to Apex B2C)
OIDC Discovery URLRequired for IdP integration — your /.well-known/openid-configuration endpoint
Client IDFor IdP integration: the client ID your IdP assigns to Apex B2C
Redirect URIsThe URL(s) Apex B2C redirects back to after authentication
Required scopesAny scopes beyond openid profile email
Display name for sign-in buttonHow your option appears on the Apex sign-in page

The APEX team will provide:

Server-Side Integration

If your application is server-side rather than a browser-only SPA, use your platform's OAuth2/OIDC middleware to handle the authentication flow.

Note on hostnames and URL format: The authority URL uses login.lightstone.co.za (the Apex custom domain), while the redirect URI registered with the APEX team uses lsgb2c.b2clogin.com (the native Azure AD B2C domain). Both hostnames resolve the same B2C tenant. Your OIDC middleware must trust both — include both in your knownAuthorities (MSAL) or equivalent allowed-issuers configuration.

Note on /v2.0/: The authority URL for server-side OIDC middleware includes the /v2.0/ suffix (e.g. ...B2C_1A_SIGNUPORSIGNINV2/v2.0/). This is required so the middleware can auto-discover the OIDC configuration at /.well-known/openid-configuration. The MSAL.js authority shown in the Configuration Parameters section above omits /v2.0/ — this is correct for that library but will not work for server-side middleware. Use the /v2.0/ form for all server-side frameworks.

// Program.cs
// using Microsoft.AspNetCore.Authentication.OpenIdConnect;
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddOpenIdConnect(options =>
{
options.Authority = "https://login.lightstone.co.za/tfp/lsgb2c.onmicrosoft.com/B2C_1A_SIGNUPORSIGNINV2/v2.0/";
options.ClientId = "your-client-id"; // Provided by APEX team
options.ClientSecret = "your-client-secret";
options.ResponseType = OpenIdConnectResponseType.Code;
options.SaveTokens = true;
options.Scope.Add("openid");
options.Scope.Add("profile");
options.MetadataAddress =
"https://login.lightstone.co.za/tfp/lsgb2c.onmicrosoft.com/B2C_1A_SIGNUPORSIGNINV2/v2.0/.well-known/openid-configuration";
});

Replace B2C_1A_SIGNUPORSIGNINV2 with the policy name provided by the APEX team.

Forcing a Specific Identity Provider

If your application uses a federated IdP registered with Apex B2C, you can bypass the Apex sign-in screen entirely and send users directly to your identity provider using the domain_hint parameter. The APEX team provides the correct domain_hint value for your provider at registration time.

info

The domain_hint value matches the domain configured in the Apex B2C policy for your provider. Using an incorrect value causes the normal sign-in screen to display rather than routing to your IdP.

const loginRequest = {
scopes: ["openid", "profile"],
extraQueryParameters: {
domain_hint: "your-provider-domain" // Dot-separated domain identifier — value provided by APEX team at registration
}
};

msalInstance.loginRedirect(loginRequest);
// or
await msalInstance.loginPopup(loginRequest);

Account Resolution Scenarios

When a user authenticates via a federated identity provider, Apex B2C resolves the user's identity using their email address. The following scenarios describe what happens depending on whether the user already exists in each system.

Scenario A — New to both Apex and the 3rd party system

The user has never accessed either system. They authenticate via the federated IdP for the first time.

Scenario B — New to Apex, existing in 3rd party system

The user already has an account with the partner's system but has never signed into Apex. This is the most common first-login pattern for federation rollouts.

Note: From B2C's perspective, Scenarios A and B are technically identical — B2C has no visibility into whether the user already has an account with the partner IdP. The B2C flow is the same in both cases; the scenarios differ only at the user-experience level (new vs. returning in the partner system).

Note: Email is the identity correlation key. B2C always creates a new B2C user account for first-time federated logins (the alternativeSecurityId not found → write new). Email-based deduplication of Apex contacts happens inside the /Identity/OnboardUser API call (Step 14), not in B2C itself. If the user's email matches an existing Apex contact, OnboardUser links the federated identity to that contact rather than creating a duplicate contact.

On API errors: If /Identity/LookupIdentity or /Identity/OnboardUser returns an error, B2C will abort the authentication flow and return an error response to the 3rd party application. The user will see a B2C error page and will not receive a JWT. Your application should handle OAuth2 error responses on the redirect callback accordingly.

Scenario C — Existing in both Apex and 3rd party system

The user has previously signed in to Apex via this federated provider. The B2C account already has the alternativeSecurityId for this IdP. No onboarding call is made.

Reference