In any application dealing with users, data privacy, or critical workflows, Role-Based Access Control (RBAC) is essential. With Micronaut, implementing RBAC is clean and powerful thanks to its built-in security framework and support for annotations.
This guide will walk you through implementing Role-Based Access Control in Micronaut, including custom roles, securing endpoints, and integrating with JWT authentication. We’ll use the package com.kscodes.micronaut.security for all the code examples.

🔎 What is Role-Based Access Control (RBAC)?
RBAC is a security mechanism where access permissions are granted based on the role assigned to a user. For example:
ROLE_USER: Can access their own data.ROLE_ADMIN: Can manage all users.ROLE_MANAGER: Can manage specific segments.
In Micronaut, roles are usually carried within JWT tokens and validated automatically using annotations like @Secured.
🛠 Project Setup
1. Add Required Dependencies
In your build.gradle:
dependencies {
implementation("io.micronaut.security:micronaut-security-jwt")
}
Or Maven:
io.micronaut.security
micronaut-security-jwt
⚙️ Configuration (application.yml)
micronaut:
application:
name: rbac-demo
security:
enabled: true
token:
jwt:
signatures:
secret:
generator:
secret: "kscodes-role-based-key"
authentication: bearer
👤 Creating a Custom Authentication Provider
File: com.kscodes.micronaut.security.RoleAuthProvider.java
package com.kscodes.micronaut.security;
import io.micronaut.security.authentication.*;
import jakarta.inject.Singleton;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import java.util.List;
@Singleton
public class RoleAuthProvider implements AuthenticationProvider {
@Override
public Publisher authenticate(AuthenticationRequest, ?> request) {
String username = request.getIdentity().toString();
String password = request.getSecret().toString();
if ("admin".equals(username) && "admin123".equals(password)) {
return Mono.just(AuthenticationResponse.success(username, List.of("ROLE_ADMIN")));
} else if ("user".equals(username) && "user123".equals(password)) {
return Mono.just(AuthenticationResponse.success(username, List.of("ROLE_USER")));
}
return Mono.just(new AuthenticationFailed());
}
}
🔑 Login Endpoint to Issue JWT
File: com.kscodes.micronaut.security.LoginController.java
package com.kscodes.micronaut.security;
import io.micronaut.http.annotation.*;
import io.micronaut.security.authentication.UsernamePasswordCredentials;
import io.micronaut.security.token.jwt.render.BearerAccessRefreshToken;
import io.micronaut.security.authentication.Authentication;
import io.micronaut.security.token.jwt.generator.JwtGeneratorConfiguration;
import io.micronaut.security.token.jwt.generator.JwtTokenGenerator;
import jakarta.inject.Inject;
import reactor.core.publisher.Mono;
@Controller("/auth")
public class LoginController {
@Inject
JwtTokenGenerator tokenGenerator;
@Post("/login")
public Mono login(@Body UsernamePasswordCredentials credentials) {
Authentication user = Authentication.build(credentials.getUsername(), List.of());
return Mono.just(
new BearerAccessRefreshToken("RBAC-Demo", credentials.getUsername(), null,
tokenGenerator.generateToken(user).orElse(""), null));
}
}
🔒 Securing Endpoints by Role
File: com.kscodes.micronaut.security.DashboardController.java
package com.kscodes.micronaut.security;
import io.micronaut.http.annotation.*;
import io.micronaut.security.annotation.Secured;
@Controller("/dashboard")
public class DashboardController {
@Secured("ROLE_ADMIN")
@Get("/admin")
public String adminDashboard() {
return "Welcome to Admin Dashboard";
}
@Secured("ROLE_USER")
@Get("/user")
public String userDashboard() {
return "Welcome to User Dashboard";
}
@Secured({"ROLE_ADMIN", "ROLE_USER"})
@Get("/common")
public String commonDashboard() {
return "Accessible to both Admin and User roles";
}
}
🧪 Testing RBAC in Micronaut
- Login with Admin User
curl -X POST http://localhost:8080/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "admin123"}'
Access /dashboard/admin with token
2. Login with Regular User
curl -X POST http://localhost:8080/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "user", "password": "user123"}'
3. Access /dashboard/user with user token
4. Try accessing /dashboard/admin with user token – should return 403 Forbidden
⚡ Advanced Tips
- Store roles in the JWT claims for efficiency.
- Use
@Securedat method or class level for fine-grained control. - For dynamic access logic, implement
SecurityRule. - Avoid hardcoding roles—use a database or external provider (e.g., OAuth2).
📚 External References
✅ Conclusion
Role-Based Access Control in Micronaut enables you to build robust, secure APIs with minimal boilerplate. Using the @Secured annotation and Micronaut’s JWT integration, you can enforce strict access rules based on user roles in a clean, declarative way.
With this guide, you’ve learned how to define roles, secure endpoints, generate JWTs, and apply real-world access control patterns using the com.kscodes.micronaut.security package.
Start small, scale securely—and let RBAC do the heavy lifting.