skip to Main Content

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:
enter image description here

  • 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


  1. Chosen as BEST ANSWER

    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:

    + "&prompt=login";
    

    In the end of the request. Then it works perfectly.


  2. Please check if you can redirect to signout redirect with http context in configure services of start up class.

    options.Events.OnSignedOutCallbackRedirect = async context =>
    {
        context.HttpContext.Response.Redirect(context.Options.SignedOutRedirectUri);
        context.HandleResponse();
    };
    

    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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search