Integrating Auth0 with Java Spring Boot
Integrating Auth0 with Java Spring Boot
Authentication and authorization are critical components to my Boothmark project. In this blog post, we'll explore how to integrate Auth0 with Java 21 + Spring Boot to secure your APIs and applications.
Why Auth0?
Auth0 is a cloud-based authentication and authorization platform that provides a simple and secure way to add authentication and authorization to your Spring Boot applications. With Auth0, I don't have to worry about implementing and maintaining authentication and authorization logic myself. I can focus on building my application and let Auth0 handle the security.
Setting Up Your Spring Boot Application
Dependencies
First, add the required dependencies to your pom.xml:
12345678<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>Configuration
Configure Auth0 in your application.yml:
12345678910auth0:
domain: ${AUTH0_DOMAIN}
audience: ${AUTH0_AUDIENCE}
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://${auth0.domain}/Security Configuration
Create a comprehensive security configuration that defines which endpoints require authentication:
123456789101112131415161718192021@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
)
.cors(withDefaults())
.csrf(csrf -> csrf.disable())
.build();
}
// ... additional configuration
}This configuration:
- Permits all requests to
/api/public/** - Requires authentication for all other requests
- Configures JWT token validation
- Enables CORS for frontend integration
- Disables CSRF for stateless APIs
1234567891011121314151617181920## Creating Protected Endpoints
With authentication configured, you can now create controllers that automatically receive user information:
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/protected/profile")
public ResponseEntity<Map<String, Object>> getProfile(@AuthenticationPrincipal Jwt jwt) {
String userId = jwt.getSubject();
String email = jwt.getClaim("email");
String name = jwt.getClaim("name");
Map<String, Object> response = new HashMap<>();
response.put("userId", userId);
response.put("email", email);
response.put("name", name);
return ResponseEntity.ok(response);
}
}User Service Integration
Create a service to handle user data and integrate with your database:
1234567891011121314151617@Service
public class UserService {
@Transactional
public User findOrCreateUser(String auth0Id, String email, String name) {
User existingUser = userRepository.findByAuth0Id(auth0Id);
if (existingUser != null) {
// Update user info in case it changed in Auth0
existingUser.setEmail(email);
existingUser.setName(name);
return userRepository.save(existingUser);
}
// Create new user with default roles
return createNewUser(auth0Id, email, name);
}
}Authentication Helper Service
Create a utility service to extract user information from JWT tokens:
1234567891011121314151617@Service
public class AuthService {
public String getCurrentUserId(Authentication auth) {
if (auth instanceof JwtAuthenticationToken jwt) {
return jwt.getToken().getSubject();
}
return null;
}
public String getCurrentUserEmail(Authentication auth) {
if (auth instanceof JwtAuthenticationToken jwt) {
return jwt.getToken().getClaim("email");
}
return null;
}
}Best Practices
1. Environment-Specific Configuration
Always use environment-specific configuration for sensitive information like Auth0 credentials. Avoid hardcoding them in your application.
12345678910111213spring:
profiles:
active: ${SPRING_PROFILES_ACTIVE:dev}
---
spring:
config:
activate:
on-profile: production
security:
oauth2:
resourceserver:
jwt:
issuer-uri: ${AUTH0_ISSUER_URI}2. CORS Configuration
Properly configure CORS for your frontend applications:
123456789101112@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("https://yourdomain.com"));
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(List.of("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}3. JWT Claims Validation
Configure additional JWT validation for enhanced security:
123456789@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(jwt -> {
// Extract and convert authorities from JWT claims
return extractAuthorities(jwt);
});
return converter;
}Testing Your Secured Endpoints
Spring Boot provides excellent testing support for secured endpoints:
12345678910111213@WebMvcTest(UserController.class)
class SecurityTests {
@Autowired
private MockMvc mvc;
@Test
@WithMockUser(roles = "USER")
void testProtectedEndpoint() throws Exception {
mvc.perform(get("/api/protected/profile"))
.andExpect(status().isOk());
}
}Frontend Integration
Your frontend application will need to:
- Redirect users to Auth0 for authentication
- Receive the JWT token after successful authentication
- Include the token in API requests via the Authorization header:
1234567const token = localStorage.getItem('access_token');
const response = await fetch('/api/protected/profile', {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});Conclusion
Integrating Auth0 with Spring Boot provides a robust, scalable solution for API security. The combination offers:
- Simplified Authentication: Auth0 handles the complexity of user authentication
- JWT-Based Security: Stateless authentication perfect for APIs
- Flexible Authorization: Easy to implement role-based access control
- Developer Experience: Spring Security's annotations make securing endpoints straightforward
This setup provides a solid foundation for building secure, modern web applications.
Remember to always follow security best practices, keep your dependencies up to date, and regularly review your security configuration as you application evolves.