Modern applications require secure ways to manage user identities and protect API endpoints. One of the most popular and efficient mechanisms is JWT (JSON Web Token) authentication. If you’re building cloud-native or microservice-based apps using Micronaut, securing your services with JWT Authentication with Micronaut is both straightforward and powerful.
In this guide, weβll explore how to configure JWT-based authentication in a Micronaut application. All examples will use the package: com.kscodes.micronaut.security
.

π¦ What is JWT?
JWT (JSON Web Token) is a compact, URL-safe means of representing claims transferred between two parties. Itβs commonly used for stateless authentication in APIs, and consists of:
- Header β metadata (type + signing algorithm)
- Payload β user claims (e.g.,
sub
,exp
,roles
) - Signature β verifies data integrity
Micronaut provides seamless JWT integration via its micronaut-security-jwt
module.
π Project Setup
1. Add Dependencies
For Gradle:
1 2 3 4 5 6 |
dependencies { implementation("io.micronaut.security:micronaut-security-jwt") } |
For Maven:
1 2 3 4 5 6 7 |
<dependency> <groupId>io.micronaut.security</groupId> <artifactId>micronaut-security-jwt</artifactId> </dependency> |
βοΈ JWT Configuration (application.yml
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
micronaut: application: name: jwt-auth-demo security: enabled: true authentication: bearer token: jwt: signatures: secret: generator: secret: "jwt-secret-key" |
authentication: bearer
: Enables JWT bearer token.
jwt-secret-key
: Change in production to something secure (or use Vault).
π€ Custom Authentication Provider
File: com.kscodes.micronaut.security.CustomAuthProvider.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
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 CustomAuthProvider implements AuthenticationProvider { @Override public Publisher<AuthenticationResponse> authenticate(AuthenticationRequest<?, ?> request) { String username = request.getIdentity().toString(); String password = request.getSecret().toString(); if ("user1".equals(username) && "pass123".equals(password)) { return Mono.just(AuthenticationResponse.success(username, List.of("ROLE_USER"))); } return Mono.just(new AuthenticationFailed()); } } |
π Creating a Login Endpoint to Issue JWT
File: com.kscodes.micronaut.security.LoginController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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.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<BearerAccessRefreshToken> login(@Body UsernamePasswordCredentials creds) { // In a real app, delegate to auth service if ("user1".equals(creds.getUsername()) && "pass123".equals(creds.getPassword())) { String token = tokenGenerator.generateToken(creds).orElse(""); return Mono.just(new BearerAccessRefreshToken("jwt-demo", creds.getUsername(), null, token, null)); } return Mono.error(new RuntimeException("Invalid credentials")); } } |
π Protecting Routes with JWT
File: com.kscodes.micronaut.security.SecureController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package com.kscodes.micronaut.security; import io.micronaut.http.annotation.*; import io.micronaut.security.annotation.Secured; @Controller("/secure") public class SecureController { @Secured("ROLE_USER") @Get("/profile") public String getProfile() { return "This is a protected profile endpoint!"; } } |
π Sample Request-Response Flow
- Login Request:
1 2 3 4 5 6 |
curl -X POST http://localhost:8080/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"user1","password":"pass123"}' |
2. Get Token from Response
3. Access Secured Endpoint:
1 2 3 4 |
curl -H "Authorization: Bearer <TOKEN>" http://localhost:8080/secure/profile |
β Tips for Production Use
- Use HTTPS to transmit JWTs securely.
- Store secrets in a secure store (Vault, AWS Secrets Manager).
- Use refresh tokens or short-lived tokens with auto-renewal.
- Add
exp
andiat
claims to control token lifecycle. - Donβt store sensitive info (like passwords) inside JWT.
π External References
π§© Conclusion
Implementing JWT Authentication with Micronaut is efficient, secure, and fits perfectly within microservice architectures. Youβve now seen how to set up JWT security, write custom authentication logic, issue tokens, and protect endpoints.
By using the package com.kscodes.micronaut.security
, this guide offers a solid foundation for real-world JWT-based authentication in Micronaut.
This post equips you to move forward confidently in building secure, scalable Micronaut applications with modern authentication techniques.