Fork me on GitHub

Apache Shiro Logo Simple. Java. Security. Apache Software Foundation Event Banner

Apache Shiro Jakarta EE module makes it transparent to use Shiro features in Jakarta EE applications with minimal configuration. It makes annotations such as @RequiresRoles available in Jakarta EE (CDI, EJB, etc.) code.

Jakarta EE integration is available in Shiro 2.0 or later.
The module is compatible with Java EE 8 through Jakarta EE 10 or later. It may work with earlier versions of Jakarta EE but was not tested with those.


Include the shiro-jakarta-ee dependency in you application classpath (we recommend using a tool such as Apache Maven or Gradle to manage this).

compile 'org.apache.shiro:shiro-jakarta-ee:1.11.0'
libraryDependencies += "org.apache.shiro" % "shiro-jakarta-ee" % "1.11.0"
<dependency org="org.apache.shiro" name="shiro-jakarta-ee" rev="1.11.0"/>
[org.apache.shiro/shiro-jakarta-ee "1.11.0"]

Relationships between Jakarta EE and CDI / Jax-RS modules

Jakarta EE module depends on CDI and Jax-RS submodules to fully integrate with the complete Jakarta EE API (Web Profile). If that is not desired, CDI and Jax-RS submodules can be used separately.


Configure Shiro automatically with sensible defaults for Jakarta EE, with minimal, or no configuration aside from shiro.ini.

Use shiro.ini as usual to protect web application and Jax-RS paths and endpoints.

Forms are automatically saved if sessions expire and seamlessly submitted upon subsequent login.

Use Shiro-secured application behind a load balancer or an SSL-terminating proxy (haproxy, nginx, etc.) easily.

Use @Named CDI beans in shiro.ini.

Inject Shiro Subject, Principal, Session and SecurityManager into CDI, EJB beans and Jax-RS endpoints.

Use Shiro and Jakarta EE Security annotations (i.e. @RequiresRole) to protect:

  • CDI and EJB (local and remote) beans (part of CDI module)

  • Jax-RS endpoints (part of Jax-RS module)

Use Jakarta Faces (JSF) tags.

Make Shiro’s login flows Jakarta Faces (JSF) Ajax-aware.

Jakarta EE Security Annotations (JSR-250)

In addition to all Shiro annotations, Jakarta EE module allows to specify Jakarta EE security annotations such as @RolesAllowed, @DenyAll and @PermitAll on your beans

How to use Jakarta 9+ (jakarta.* namespace) - replace LATEST with the version number

Use the Shiro artifacts with Jakarta classifiers:






Import the Shiro BOM as seen below (replace LATEST with the version number):


CDI Features

Use Shiro and Jakarta Security annotations on any CDI bean, with no additional annotations required:

public class MyBean { }

public class MyRoleBean { }

Configuring CDI without Jakarta EE module or shiro.ini

Below is an example of Shiro configuration in Java code with CDI only (no shiro.ini):

public class MyBean {
    private DefaultSecurityManager securityManager;

    void configureSecurityManager(@Observes @Initialized(ApplicationScoped.class) Object nothing) {
        var realm = new SimpleAccountRealm();
        securityManager = new DefaultSecurityManager(realm);
        realm.addAccount("powerful", "awesome", "admin");
        realm.addAccount("regular", "meh", "user");

    void destroySecurityManager(@Observes @Destroyed(ApplicationScoped.class) Object nothing) {

Injecting Shiro components and APIs

Shiro APIs can be @Inject into CDI and EJB beans:

public class MyBean {
    SecurityManager manager;

    Subject subject;

    Optional<MyUserAccount> userAccount;

    Session session;

    Session optionalSession;

Subject, Session and @Principal are always treated as Request-Scoped beans.
If Session is annotated with @NoSessionCreation and if there is no existing session, InvalidSessionException is thrown when accessing the Injected session. Any Shiro Principal can be injected if annotated by @Principal. It must be injected as a Java optional, and may not be present if Shiro cannot retrieve it.

Jakarta EE Integration Module

Jakarta EE integration module was inspired by this OmniFaces article and brings everything together to seamlessly create secure Jakarta EE applications easily and with minimal configuration. The module works "the Shiro way" and uses shiro.ini in a straight-forward and intuitive way.


Enabling RememberMe functionality

RememberMe functionality is disabled by default. You can enable it easily by adding the below to shiro.ini:

authc.useRemembered = true

Automatic delay when login failed

When user fails to log in, Shiro will automatically delay the failure response for a number of seconds. This can be one of the strategies to prevent brute force attacks.

Be careful utilizing this technique, as it could be a vector for a denial-of-service attack. Servers with virtual thread support (Project Loom) will not be affected by the DDOS vector.

Add the below to shiro.ini:

authc.loginFailedWaitTime = 5


No configuration is required. The module is bootstrapped automatically. To disable automatic bootstrapping, add the following to web.xml:


The module adds ShiroFilter to the Servlet configuration. For most cases, the filter ordering works correctly out of the box. However, some cases require to reorder filters. Filter ordering follows the order of <filter-mapping> elements in web.xml:

<!-- Enforce Filter Ordering (Optional) -->
... other filters ...
... other filters ...

Shiro.ini file locations

The module finds shiro.ini in the same manner as Web Configuration (WEB-INF/shiro.ini by default). Additionally, configuration is enhanced to merge two separate configuration files:

    <param-value>classpath:META-INF/shiro.ini, classpath:META-INF/shiro2.ini</param-value>

Only two files are supported. More than two file will result in an error.

Custom WebEnvironment class

Custom class is supported, provided it’s inherited from or has the same functionality.

Enhanced SSL filter

By default, Shiro enforces a specific ssl port number where the requests go to. However, if the application is behind a load balancer or a proxy (such as haproxy or nginx), the ports may be different for different instances. In this case, port filter can be turned off to allow SSL traffic to go to any port. To disable port filter, put the following in your shiro.ini:

ssl.enablePortFilter = false

SSL filter is only enabled in Jakarta Faces production mode (default) and is disabled in Development mode. However, if SSL filter always needs to be enabled, put the following into your shiro.ini:

ssl.alwaysEnabled = true

Using Enhanced SSL filter with HAProxy or other load balancers

When behind SSL-terminating proxy, Shiro may not be able to determine if SSL was used. X-Forwarded-Proto header can mitigate this. You can configure your proxy set this header to https to tell Shiro when SSL is used. Below is an haproxy configuration excerpt:

frontend tcp-in
    http-request set-header X-Forwarded-Proto https if { ssl_fc }

Using CDI Beans in shiro.ini

Below is an example of using a CDI bean and assign it’s property to a variable in shiro.ini

public class MyBean {
    public boolean getMyValue() {
        return true;
myBeanInstance = myBean
myVariable = $myBeanInstance.myValue

Using CDI for custom RememberMe cipher key generation

Use CDI bean that implements CipherKeySupplier interface to create a custom logic for generating the cipher key. For convenience, String data type is used, If the String that’s returned is null or blank (just spaces), the default cipher key generating mechanism is used.

For example, you can use MicroProfile Config to get the cipher key:

public class CipherKeySource implements CipherKeySupplier {
    @ConfigProperty(name = "my.config.source.cipher-key")
    String cipherKey;

    public String get() {
        return cipherKey;

Enhanced login flow and smart fallback pages

Shiro always tries to redirect back to a previous page when a login or logout flow was successful. However, in some cases this may not be desired, such as when the previous page was a login page itself. In such cases, a fallback page is provided in shiro.ini (usually index or root page), and it is used even if the previous page is available. Logic is provided by implementing the FallbackPredicate interface.
Here we use the path check. If previous page is part of the auth folder, fallback path (index / root) page will always be used:

public class UseFallback implements FallbackPredicate {
    public boolean useFallback(String path, HttpServletRequest request) {
        return path.contains("shiro/auth/");
fallbackType = useFallback
authc.loginFallbackType = $fallbackType
authc.logoutFallbackType = $fallbackType

Automatic form submit upon subsequent login

The module will automatically submit forms upon session expiration and subsequent re-login. To disable this behavior, add the following to web.xml:


Configuring for Tomcat / Jetty (or without Jakarta Faces)

If Jakarta Faces (JSF) is not available in your environment, you need to put the following into your web.xml to enable proper OmniFaces initialization:


Principal Propagation (Jakarta EE)

By default, Shiro will propagate the Subject to, which may not always be desired. For example, if calling remote EJBs, the container security mechanism might interpret the principal and will error the remote EJB call as unauthenticated. To disable this behavior, you can put the following in your web.xml:


Security Annotations (Shiro and EE)

The module works transparently to enable Shiro (@RequiresRole) and Jakarta Security (@RolesAllowed) annotations, without any additional annotations or configuration.

Automatic form resubmit when logged out and subsequently logged in

Users get frustrated when they lose data. For example, while filling out a complicated form, the user get side-tracked with another browser tab or window. Then lunch. After getting back to the form, they will fill out the rest of the form and submit it. However, since it took a long time, they are now thrown back to the login screen. Once they log in, all their data entry vanished!
There are few workarounds for his issue, like a periodic ping of the back-end or something similar, but that causes unnecessary load and memory pressure on the server. These methods are also very brittle.
Jakarta EE module will automatically save the form data into Shiro cache when a user is redirected to a login screen. The cache is encrypted. And when the user subsequently logs back in, the form is automatically submitted and the data entry is never lost.
Form resubmission works with JSP, Jakarta Faces partial page rendering (Ajax) and with PrimeFaces components.

Using CDI @SessionScoped and @ViewScoped beans

Both CDI and OmniFaces Session and ViewScoped beans work correctly and transparently with both web container and Shiro native sessions.

Jakarta Faces (JSF) features

When using Shiro with Jakarta Faces, login and logout flow works transparently and correctly without worrying about ViewExpiredException. This works for both Ajax and standard events.
Both server and client state saving methods are supported.
Shiro’s FormAuthenticationFilter (authc by default) in shiro.ini works the same way in Faces as it does in JSP.
It takes named Faces components and uses them to authenticate. Below, elements named by id are automatically used to authenticate, and any command button without explicit action will trigger the login.

<h:form prependId="false" id="form">
    Username: <h:inputText id="username" p:autofocus="true" title="Username: " required="true" />
    Password: <h:inputText id="password" title="Password: " required="true"/>
    Remember Me: <h:selectBooleanCheckbox id="rememberMe" title="Remember Me: "/>
    <h:commandButton id="login" value="Login ..."/>

Logout can be specified via shiro.ini, without having any additional pages or code:

/shiro/auth/logout* = ssl, logout
<h:outputLink value="#{request.contextPath}/shiro/auth/logout">Logout</h:outputLink>

Jakarta Faces variables and actions

Below are actions and variables available within Facelets. All actions have zero-argument versions that execute sensible defaults.

<div jsf:rendered="#{authc.sessionExpired}">
    Your Session Has Expired
<div jsf:rendered="#{authc.loginFailure}">
    Login Failed
<h:commandButton value="Login ..." action="#{authc.login}"/>
<h:commandButton value="Login ..." action="#{authc.login(bean.username, bean.password)}"/>
<h:commandButton value="Login ..." action="#{authc.login(bean.username, bean.password, bean.rememberMe)}"/>
<h:commandButton value="Login ..." action="#{authc.redirectIfLoggedIn('page')}"/>

Forms API

Forms class has external-faces API that can be accessed directly from code. See javadoc for further info.


Jakarta EE module uses Jax-RS module to provide support for non-CDI and non-EJB beans.
See Jax-RS documentation for more details.

Principal Propagation (Jax-RS)

Propagation is enabled or disabled for Jax-RS by the Jakarta EE module. See Jax-RS Principal Propagation