Building Custom AutoLogin Module for Liferay Integration with Azure AD B2C
Source: Dev.to
Azure AD B2C + Liferay Integration
Azure AD B2C provides a robust, cloud‑based identity management solution that offers secure authentication, multi‑factor authentication support, and seamless integration with enterprise systems. When combined with Liferay’s flexible portal capabilities, you get a powerful platform that can handle complex authentication scenarios while maintaining a great user experience.
The Solution: Custom AutoLogin Module
The approach involves creating a custom AutoLogin component that intercepts the authentication flow, validates tokens from Azure B2C, and automatically logs users into Liferay.
Step 1 – Create the AutoLogin Class
Create a class that extends BaseAutoLogin. This class will handle the authentication logic:
public class WebsiteAutoLogin extends BaseAutoLogin {
@Reference
private UserLocalService userLocalService;
private RestTemplate restTemplate;
@Activate
public void activateComponent() {
restTemplate = new RestTemplate();
}
}@Referenceinjects Liferay’sUserLocalService, which we’ll use to look up users.RestTemplateis initialized during component activation and will be used for HTTP calls to Azure B2C.
Step 2 – Implement the doLogin Method
The core authentication logic resides in the doLogin method:
public String[] doLogin(HttpServletRequest request,
HttpServletResponse response) throws AutoLoginException {
// 1) Extract the ID token from the request
String code = ParamUtil.getString(request, "id_token");
// 2) Exchange code for ID token – call the B2C REST API
String tokenEncodedString = retrieveAzureToken(code);
// 3) Decode the JWT payload
JSONObject payload = decodeJWTToken(tokenEncodedString);
// 4) Extract user identifier from the token
String screenName = payload.getString("MatchingScreenName");
try {
long companyId = PortalUtil.getCompanyId(request);
// 5) Fetch existing user by screen name
User user = userLocalService.fetchUserByScreenName(companyId, screenName);
// 6) Return credentials for auto‑login
return new String[] {
String.valueOf(user.getUserId()),
user.getPassword(),
Boolean.TRUE.toString()
};
} catch (Exception e) {
logger.error("Error during user login or creation: " + e.getMessage(), e);
return null;
}
}What the method does
- Extracts the authorization code or ID token from the incoming request.
- Exchanges this code with Azure B2C to obtain a valid token.
- Decodes the JWT token to extract user information.
- Looks up the corresponding Liferay user.
- Returns the authentication credentials for automatic login.
Step 3 – Token Retrieval from Azure B2C
retrieveAzureToken handles communication with Azure B2C’s token endpoint:
private String retrieveAzureToken(String authorizationCode) {
try {
// Get the token endpoint URL
String tokenEndpoint = getTokenEndpoint();
// Create HTTP headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// Encode the redirect URI
String redirectUri = URLEncoder.encode("YOUR_REDIRECT_URL", "UTF-8");
// Build form parameters
MultiValueMap formParams = new LinkedMultiValueMap<>();
formParams.add("client_id", B2C_AZURE_CLIENT_ID);
formParams.add("client_secret", B2C_AZURE_CLIENT_SECRET);
formParams.add("code", authorizationCode);
formParams.add("grant_type", AUTH_GRANT_TYPE);
formParams.add("redirect_uri", redirectUri);
// Create and send the request
HttpEntity> requestEntity =
new HttpEntity<>(formParams, headers);
ResponseEntity response = restTemplate.postForEntity(
tokenEndpoint,
requestEntity,
String.class
);
// Parse and return the ID token
JSONObject jsonObject = JSONFactoryUtil.createJSONObject(response.getBody());
return jsonObject.getString("id_token");
} catch (Exception e) {
logger.error("Exception occurred on B2C Azure Token Request: " + e);
}
return null;
}Step 4 – JWT Token Decoding
The JWT token returned by Azure B2C must be decoded to extract user claims:
public static JSONObject decodeJWTToken(String token) {
try {
if (Validator.isNull(token)) {
return null;
}
// Split the token into header, payload, and signature
String[] parts = token.split("\\.");
// Decode the payload (second part) from Base64
return JSONFactoryUtil.createJSONObject(decode(parts[1]));
} catch (Exception e) {
logger.error("Exception occurred while decoding the JSON token: " + e.getMessage());
}
return null;
}Configuration Requirements
Azure AD B2C
- Register your application in Azure AD B2C.
- Configure the redirect URIs.
- Note the Client ID and Client Secret.
- Set up the appropriate user flows (sign‑in, sign‑up).
Liferay
- Deploy the custom AutoLogin module.
- Configure the module with your Azure B2C credentials (via Liferay’s secure configuration).
- Ensure users exist in Liferay with matching screen names.
Security Considerations
When implementing this solution, keep these best practices in mind:
| Concern | Recommendation |
|---|---|
| Credential storage | Store Azure B2C client secrets in Liferay’s encrypted configuration (e.g., portal-ext.properties with portal.security.manager.enabled=true) – never hard‑code them. |
| Token validation | Verify the JWT signature using Azure B2C’s public keys and check exp, nbf, and iss claims before trusting the token. |
| HTTPS | All communication with Azure B2C must occur over HTTPS. |
| Least‑privilege | Grant the Azure B2C app only the permissions it needs (e.g., openid, profile). |
| Logging | Avoid logging sensitive data such as tokens or passwords. Use masked logs if necessary. |
| Error handling | Do not expose stack traces to end‑users; log them securely and return generic error messages. |
Following these guidelines will help you build a secure, maintainable integration between Azure AD B2C and Liferay.
usting its claims
- HTTPS only: Ensure all communication happens over HTTPS.
- Error handling: Implement proper error handling to avoid exposing sensitive information.
- Logging: Log authentication events for auditing, but never log sensitive token data.
Conclusion
Integrating Azure AD B2C with Liferay through a custom AutoLogin module provides a secure and seamless authentication experience. This approach leverages Azure’s enterprise‑grade identity management while maintaining Liferay’s flexibility and extensibility.
The complete implementation gives you a foundation that can be extended to support additional features like user provisioning, role mapping based on Azure AD groups, and multi‑factor authentication.