title: On a successful login, SecurityContext.authenticate() returns AuthenticationStatus.SEND_CONTINUE instead of AuthenticationStatus.SUCCESS
body: <ul>
  <li>Jakarta EE 8</li>
  <li>Wildfly 21</li>
  <li>Java 11</li>
  </ul>
  <p>Using <em>Java EE Security</em>, I'm trying custom form authentication in a simple application.</p>
  <p>These are the relevant files (the description of the problem is below the files):</p>
  <p><strong>CustomFormAuthenticationConfig.java</strong></p>
  <pre><code>package br.dev.authentication.view;
  
  import javax.enterprise.context.ApplicationScoped;
  import javax.faces.annotation.FacesConfig;
  import javax.security.enterprise.authentication.mechanism.http.CustomFormAuthenticationMechanismDefinition;
  import javax.security.enterprise.authentication.mechanism.http.LoginToContinue;
  
  @CustomFormAuthenticationMechanismDefinition(
      loginToContinue = @LoginToContinue(
          loginPage = &quot;/login.xhtml&quot;,
          useForwardToLogin = false,
          errorPage = &quot;&quot;
      )
  )
  @FacesConfig
  @ApplicationScoped
  public class CustomFormAuthenticationConfig
  {
  }
  </code></pre>
  <p><strong>UserAuthenticator.java</strong></p>
  <pre><code>package br.dev.authentication.view;
  
  import java.util.Set;
  
  import javax.enterprise.context.ApplicationScoped;
  import javax.security.enterprise.credential.Credential;
  import javax.security.enterprise.credential.UsernamePasswordCredential;
  import javax.security.enterprise.identitystore.CredentialValidationResult;
  import javax.security.enterprise.identitystore.IdentityStore;
  
  @ApplicationScoped
  public class UserAuthenticator implements IdentityStore
  {
      @Override
      public CredentialValidationResult validate(Credential credencial)
      {
          var userCredentials = (UsernamePasswordCredential) credencial;
          var userName = userCredentials.getCaller();
          var password = userCredentials.getPasswordAsString();
  
          if (userName.equals(&quot;1&quot;) &amp;&amp; password.equals(&quot;1&quot;))
          {
              return new CredentialValidationResult(userName, Set.of(&quot;USER&quot;));
          }
          else
          {
              return CredentialValidationResult.INVALID_RESULT;
          }
      }
  }
  </code></pre>
  <p><strong>login.xhtml</strong></p>
  <pre><code>&lt;ui:composition template=&quot;/templates/layout.xhtml&quot;
      xmlns=&quot;http://www.w3.org/1999/xhtml&quot;
      xmlns:ui=&quot;http://xmlns.jcp.org/jsf/facelets&quot;
      xmlns:f=&quot;http://xmlns.jcp.org/jsf/core&quot;
      xmlns:h=&quot;http://xmlns.jcp.org/jsf/html&quot;
      xmlns:au=&quot;http://dev.br/authentication&quot;&gt;
  
      &lt;ui:define name=&quot;title&quot;&gt;
          Login
      &lt;/ui:define&gt;
  
      &lt;ui:define name=&quot;content&quot;&gt;
          &lt;au:errors /&gt;
          &lt;div id=&quot;fields&quot;&gt;
              &lt;h:outputLabel value=&quot;User name:&quot; for=&quot;userName&quot; /&gt;
              &lt;h:inputText id=&quot;userName&quot; value=&quot;#{login.userName}&quot; /&gt;
  
              &lt;h:outputLabel value=&quot;Password:&quot; for=&quot;password&quot; /&gt;
              &lt;h:inputSecret id=&quot;password&quot; value=&quot;#{login.password}&quot; /&gt;
  
              &lt;h:commandButton value=&quot;Enter&quot; action=&quot;#{login.authenticateUser}&quot; /&gt;
          &lt;/div&gt;
      &lt;/ui:define&gt;
  &lt;/ui:composition&gt;
  </code></pre>
  <p><strong>Login.java</strong></p>
  <pre><code>package br.dev.authentication.view;
  
  import java.io.IOException;
  
  import javax.enterprise.context.RequestScoped;
  import javax.faces.application.FacesMessage;
  import javax.faces.context.ExternalContext;
  import javax.faces.context.FacesContext;
  import javax.inject.Inject;
  import javax.inject.Named;
  import javax.security.enterprise.AuthenticationStatus;
  import javax.security.enterprise.SecurityContext;
  import javax.security.enterprise.authentication.mechanism.http.AuthenticationParameters;
  import javax.security.enterprise.credential.UsernamePasswordCredential;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.validation.constraints.NotBlank;
  
  @RequestScoped
  @Named
  public class Login
  {
      private String _userName;
      private String _password;
  
      @Inject
      private FacesContext _facesContext;
      
      @Inject
      private ExternalContext _externalContext;
  
      @Inject
      private SecurityContext _securityContext;
      
      @NotBlank(message = &quot;User name is required.&quot;)
      public String getUserName()
      {
          return _userName;
      }
      
      public void setUserName(String userName)
      {
          _userName = userName;
      }
      
      @NotBlank(message = &quot;Password is required.&quot;)
      public String getPassword()
      {
          return _password;
      }
      
      public void setPassword(String password)
      {
          _password = password;
      }
      
      public void authenticateUser() throws IOException
      {
          // After a successful login (username and password correct),
          // executeUserAuthentication() returns AuthenticationStatus.SEND_CONTINUE, 
          // and not AuthenticationStatus.SUCCESS.
          // Why?
          // As a result, the code in the AuthenticationStatus.SUCCESS branch above is not executed.
          AuthenticationStatus result = executeUserAuthentication();
          if (result == AuthenticationStatus.SUCCESS)
          {
              _externalContext.redirect(_externalContext.getRequestContextPath() + &quot;/start.xhtml&quot;);
          }
          else if (result == AuthenticationStatus.SEND_CONTINUE)
          {
              _facesContext.responseComplete();
          }
          else if (result == AuthenticationStatus.SEND_FAILURE)
          {
              _facesContext.addMessage(null, new FacesMessage(
                  FacesMessage.SEVERITY_ERROR, &quot;Invalid user name and/or password.&quot;, null));
          }
      }
      
      private AuthenticationStatus executeUserAuthentication()
      {
          return _securityContext.authenticate(
              (HttpServletRequest) _externalContext.getRequest(),
              (HttpServletResponse) _externalContext.getResponse(),
              AuthenticationParameters.withParams().credential(
                  new UsernamePasswordCredential(_userName, _password))
          );
      }   
  }
  </code></pre>
  <p>The problem is that, after a successful login (user name and password correct), as you saw in the comments in <em>Login</em> class above, the method <code>executeUserAuthentication()</code> returns <code>AuthenticationStatus.SEND_CONTINUE</code> instead of <code>AuthenticationStatus.SUCCESS</code>. Below is an image of the application running in debug mode in the moment of execution to show this:</p>
  <p><a href="https://i.stack.imgur.com/c5k3o.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/c5k3o.png" alt="enter image description here" /></a></p>
  <p>As a result, the browser address bar is not updated with the real url (<em>start.xhtml</em>) because the <code>AuthenticationStatus.SUCCESS</code> branch in the code above was not executed:</p>
  <p><a href="https://i.stack.imgur.com/pIAAb.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/pIAAb.png" alt="enter image description here" /></a></p>
  <p>I thought I was doing something wrong, but then I decided to clone this simple application from @ArjanTijms that uses the same authentication logic:</p>
  <p><a href="https://github.com/rieckpil/blog-tutorials/tree/master/jsf-simple-login-with-java-ee-security-api" rel="nofollow noreferrer">https://github.com/rieckpil/blog-tutorials/tree/master/jsf-simple-login-with-java-ee-security-api</a></p>
  <p>His application is explained in this post:</p>
  <p><a href="https://rieckpil.de/howto-simple-form-based-authentication-for-jsf-2-3-with-java-ee-8-security-api/" rel="nofollow noreferrer">https://rieckpil.de/howto-simple-form-based-authentication-for-jsf-2-3-with-java-ee-8-security-api/</a></p>
  <p>And the results were the same of my application: the <code>AuthenticationStatus.SEND_CONTINUE</code> branch was executed instead of the <code>AuthenticationStatus.SUCCESS</code> branch:</p>
  <p><a href="https://i.stack.imgur.com/AtJLi.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/AtJLi.png" alt="enter image description here" /></a></p>
  <p>No updated address bar too:</p>
  <p><a href="https://i.stack.imgur.com/m6aqB.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/m6aqB.png" alt="enter image description here" /></a></p>
  <p>So, what's going on here? Is this a problem in the applications, Wildfly, is this correct behaviour (if so, what's the use of the <code>AuthenticationStatus.SUCCESS</code> enum, when will it be used?)? I just want to be able to execute the redirect by myself.</p>
  <p><strong>UPDATE 1</strong></p>
  <p>For your information, after the <code>executeUserAuthentication()</code> the user is already authenticated: <code>((HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest()).getUserPrincipal()</code> is not null.</p>
  <p>Some other files in the application:</p>
  <p><strong>web.xml</strong></p>
  <pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
  &lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns=&quot;http://xmlns.jcp.org/xml/ns/javaee&quot; xsi:schemaLocation=&quot;http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd&quot; version=&quot;4.0&quot;&gt;
      &lt;display-name&gt;autenticacao-visao&lt;/display-name&gt;
  
      &lt;!-- ========== JSF ========== --&gt;
  
      &lt;servlet&gt;
          &lt;servlet-name&gt;Faces Servlet&lt;/servlet-name&gt;
          &lt;servlet-class&gt;javax.faces.webapp.FacesServlet&lt;/servlet-class&gt;
          &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
      &lt;/servlet&gt;
      &lt;servlet-mapping&gt;
          &lt;servlet-name&gt;Faces Servlet&lt;/servlet-name&gt;
          &lt;url-pattern&gt;*.xhtml&lt;/url-pattern&gt;
      &lt;/servlet-mapping&gt;
      
      &lt;context-param&gt;
          &lt;param-name&gt;javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL&lt;/param-name&gt;
          &lt;param-value&gt;true&lt;/param-value&gt;
      &lt;/context-param&gt;
      
      &lt;!-- ========== Security ========== --&gt;
      
      &lt;security-constraint&gt;
          &lt;web-resource-collection&gt;
              &lt;web-resource-name&gt;restrict&lt;/web-resource-name&gt;
              &lt;url-pattern&gt;/app/*&lt;/url-pattern&gt;
          &lt;/web-resource-collection&gt;
          &lt;auth-constraint&gt;
              &lt;role-name&gt;USER&lt;/role-name&gt;
          &lt;/auth-constraint&gt;
      &lt;/security-constraint&gt;
      &lt;security-constraint&gt;
          &lt;web-resource-collection&gt;
              &lt;web-resource-name&gt;allowed&lt;/web-resource-name&gt;
              &lt;url-pattern&gt;/app/resources/*&lt;/url-pattern&gt;
          &lt;/web-resource-collection&gt;
      &lt;/security-constraint&gt;
  
      &lt;security-role&gt;
          &lt;role-name&gt;USER&lt;/role-name&gt;
      &lt;/security-role&gt;
  
      &lt;!-- ========== Resources ========== --&gt;
      
      &lt;context-param&gt;
          &lt;param-name&gt;dev.br.RESOURCES&lt;/param-name&gt;
          &lt;param-value&gt;resources&lt;/param-value&gt;
      &lt;/context-param&gt;
  
      &lt;!-- ========== Start page ========== --&gt;
    
      &lt;welcome-file-list&gt;
          &lt;welcome-file&gt;app/start.xhtml&lt;/welcome-file&gt;
      &lt;/welcome-file-list&gt;
  &lt;/web-app&gt;
  </code></pre>
  <p><strong>jboss-app.xml</strong></p>
  <pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
  &lt;jboss-app&gt;
      &lt;security-domain&gt;jaspitest&lt;/security-domain&gt;
  &lt;/jboss-app&gt;
  </code></pre>
  <p><strong>start.xhtml</strong></p>
  <pre><code>&lt;ui:composition template=&quot;/templates/layout.xhtml&quot;
      xmlns=&quot;http://www.w3.org/1999/xhtml&quot;
      xmlns:ui=&quot;http://xmlns.jcp.org/jsf/facelets&quot;
      xmlns:f=&quot;http://xmlns.jcp.org/jsf/core&quot;
      xmlns:h=&quot;http://xmlns.jcp.org/jsf/html&quot;&gt;
  
      &lt;ui:define name=&quot;title&quot;&gt;
          Início
      &lt;/ui:define&gt;
      
      &lt;ui:define name=&quot;content&quot;&gt;
          #{start.loggedInMessage}
          &lt;br /&gt;
          &lt;h:commandButton value=&quot;Execute&quot; /&gt;
      &lt;/ui:define&gt;
  &lt;/ui:composition&gt;
  </code></pre>
  <p><strong>Start.java</strong></p>
  <pre><code>package br.dev.authentication.view;
  
  import java.security.Principal;
  
  import javax.enterprise.context.RequestScoped;
  import javax.faces.context.ExternalContext;
  import javax.faces.context.FacesContext;
  import javax.inject.Inject;
  import javax.inject.Named;
  import javax.servlet.http.HttpServletRequest;
  
  @RequestScoped
  @Named
  public class Start
  {
      @Inject
      private ExternalContext _externalContext;
      
      public String getLoggedInMessage()
      {
          Principal user = ((HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest()).getUserPrincipal();
          if (user != null)
          {
              return &quot;Logged in: &quot; + user.getName();
          }
          else
          {
              return &quot;Not logged in&quot;;
          }
      }
  }
  </code></pre>
  <p><strong>UPDATE 2</strong></p>
  <p>After lots of tests, I noticed (at least in my application) that sometimes <code>SecurityContext.authenticate()</code> returns <code>AuthenticationStatus.SEND_CONTINUE</code> and sometimes returns <code>AuthenticationStatus.SUCCESS</code>. Until now, I haven't figured out the reason why.</p>
  <p>So, for the time being, I decided to solve the problem with a hack for the cases when <code>AuthenticationStatus.SEND_CONTINUE</code> would be returned. So, basically, what I'm doing is redirecting to the <em>start</em> page manually. The hack is below:</p>
  <p><strong>web.xml</strong> (changed the welcome page to <em>redirectortostart.xhtml</em>)</p>
  <pre><code>&lt;welcome-file-list&gt;
      &lt;welcome-file&gt;app/redirectortostart.xhtml&lt;/welcome-file&gt;
  &lt;/welcome-file-list&gt;
  </code></pre>
  <p><strong>redirectortostart.xhtml</strong></p>
  <pre><code>&lt;ui:composition template=&quot;/templates/layout.xhtml&quot;
      xmlns=&quot;http://www.w3.org/1999/xhtml&quot;
      xmlns:ui=&quot;http://xmlns.jcp.org/jsf/facelets&quot;
      xmlns:f=&quot;http://xmlns.jcp.org/jsf/core&quot;&gt;
  
      &lt;ui:define name=&quot;metadados&quot;&gt;
          &lt;f:event type=&quot;preRenderView&quot; listener=&quot;#{redirectorToStart.goToStart}&quot; /&gt;
      &lt;/ui:define&gt;
  &lt;/ui:composition&gt;
  </code></pre>
  <p><strong>RedirectorToStart.java</strong></p>
  <pre><code>package br.dev.authentication.view;
  
  import java.io.IOException;
  
  import javax.enterprise.context.RequestScoped;
  import javax.faces.context.ExternalContext;
  import javax.inject.Inject;
  import javax.inject.Named;
  
  @RequestScoped
  @Named
  public class RedirectorToStart
  {
      @Inject
      private ExternalContext _externalContext;
  
      public void goToStart() throws IOException
      {
          _externalContext.redirect(_externalContext.getRequestContextPath() + &quot;/app/start.xhtml&quot;);
      }
  }
  </code></pre>
  <p>It's not elegant, but for the time being it solves my problem. Hope someday some of you have a clue about what really could be happening with my application and could give a hint to me.</p>