I have an issue with the sign-out in Azure B2C.
I have configured the login 1 year ago and it’s working pretty well (and it was pretty straight forward with the documentation available here
For the sign-out I was following the documentation available here but even if it looks like it is working (I’m redirected to the configured URL), if I click again on the link to login via Azure SSO, it will not ask for my login and password and connect me directly.
I guess it’s an issue with the configuration but since there is not that many stuff that can be changed regarding the sign-out, I really don’t see what is the issue.
Here is my code (my project is in java for the backend):
1- Building the login URL:
public String buildAuthorisationUrl(final String nonce, final Item item)
{
final ExternalSystemConfigData azureConfig = retrieveAzureConfig(item);
final String tenantId = azureConfig.getPropertyValue(Azure.TENANT_ID_KEY);
final String policy = azureConfig.getPropertyValue(Azure.POLICY_KEY);
final String clientId = azureConfig.getPropertyValue(Azure.CLIENT_ID_KEY);
final String redirectUrl = azureConfig.getPropertyValue(Azure.REDIRECT_URL_KEY);
try
{
return "https://" + tenantId + ".b2clogin.com/" + tenantId + ".onmicrosoft.com/" + policy + "/oauth2/v2.0/authorize?" //
+ "client_id=" + clientId //
+ "&redirect_uri=" + URLEncoder.encode(redirectUrl, "UTF-8") //
+ "&response_mode=form_post" //
+ "&response_type=code" //
+ "&scope=" + clientId //
+ "&nonce=" + nonce;
}
catch (final UnsupportedEncodingException e)
{
LogUtil.error(getClass(), e, "Error when encoding redirect URL. Redirect-url=" + redirectUrl);
}
return null;
}
2- Redirect endpoint from Azure login redirect URL:
@ResponseBody
@RequestMapping(value = "/login-redirect", method = RequestMethod.POST)
public ModelAndView azureLoginRedirection(final HttpServletRequest request)
{
try
{
// we need to rebuild the URL to get an Azure Authentication Response
final Map<String, List<String>> params = request.getParameterMap().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> Collections.singletonList(e.getValue()[0])));
final AuthenticationResponse authResponse = AuthenticationResponseParser.parse(new URI(request.getRequestURL().toString()), params);
if (authResponse instanceof AuthenticationSuccessResponse) // successful authentication
{
final AuthenticationSuccessResponse oidcResponse = (AuthenticationSuccessResponse) authResponse;
// validate that OIDC Auth Response matches Code Flow (contains only requested artifacts)
validateAuthRespMatchesAuthCodeFlow(oidcResponse);
final IAuthenticationResult result = azureConnectionService.retrieveAuthResultByAuthCode(request, oidcResponse.getAuthorizationCode(),
requestContextService.getContextSchool());
// validate nonce to prevent reply attacks (code maybe substituted to one with broader access)
final String nonce = getNonceClaimValueFromIdToken(result.idToken());
final SessionInfos sessionInfos = requestContextService.getSessionInfos();
final String bid = sessionInfos.getBid();
if (DkObjectUtils.nullSafeEquals(bid, nonce))
{
LogUtil.info(getClass(), "ID Token : " + result.idToken());
sessionInfos.setIdToken(result.idToken());
final String email = getEmailFromIdToken(result.idToken());
LogUtil.info(getClass(), String.format("User %s has been authenticated successfully by AZURE.", email));
// Redirect to home page for user
return controllerService.getRedirectViewExternal(urlService.getClientLoginUrl(sessionInfos.getUniqueConnectionId()));
}
else
{
LogUtil.error(getClass(), "The parameter 'nonce' can't be validated. BID=[{}] nonce=[{}]", bid, nonce);
}
}
else
{
final AuthenticationErrorResponse oidcResponse = (AuthenticationErrorResponse) authResponse;
LogUtil.error(getClass(), String.format("Request for auth code failed: %s - %s", oidcResponse.getErrorObject().getCode(),
oidcResponse.getErrorObject().getDescription()));
}
}
catch (final Throwable e)
{
LogUtil.error(getClass(), e, e.getMessage());
}
// default redirection to login page with an error
return controllerService.getRedirectViewExternal(urlService.getClientLoginUrl(ClientRedirectionErrorCodeEnum.LOGIN_EXTERNAL_CONNECTION_FAILURE));
}
3- Building the logout URL:
public String buildLogoutUrl(final Item item, final String idToken)
{
final ExternalSystemConfigData azureConfig = retrieveAzureConfig(item);
final String tenantId = azureConfig.getPropertyValue(Azure.TENANT_ID_KEY);
final String policy = azureConfig.getPropertyValue(Azure.POLICY_KEY);
final String redirectUrl = azureConfig.getPropertyValue(Azure.REDIRECT_LOGOUT_URL_KEY);
try
{
return "https://" + tenantId + ".b2clogin.com/" + tenantId + ".onmicrosoft.com/" + policy + "/oauth2/v2.0/logout?" //
+ "&id_token_hint=" + idToken //
+ "&post_logout_redirect_uri=" + URLEncoder.encode(redirectUrl, "UTF-8");
}
catch (final UnsupportedEncodingException e)
{
LogUtil.error(getClass(), e, "Error when encoding redirect URL. Redirect-url=" + urlService.getClientUrl());
}
return null;
}
4- Redirect endpoint from Azure logout redirect URL:
@ResponseBody
@RequestMapping(value = "/logout-redirect", method = RequestMethod.GET)
public ModelAndView azureLogoutRedirection()
{
connectionService.disconnect();
return controllerService.getRedirectViewExternal(urlService.getClientUrl());
}
And finally here you can see my Azure configuration for the Authentication:
- In 1 you have my 2 redirect URLs (if I don’t put the sign-out URL here, I got an error saying that "the redirect URL provided in the request is not registered for the client id").
- In 2, I put the sign-out URL but not sure it is used in the end since I had to put it as well in 1.
Do you see what I did wrong?
2
Answers
So actually I got an answer from the microsoft Azure forum where I put my question as well.
So if someone is looking for the answer, the issue was simply that I forgot to add this in the buildAuthorisationUrl method:
In the end of the request. Then it works perfectly.
Please check if you can redirect to signout redirect with http context in configure services of start up class.
and please check if you could add controller to sign out this way > azure-b2c-logout-implementation-in-asp-net-core
Reference:
AzureADB2C.UI doesn’t allow customizing post-logout redirect URI ·
· GitHub