EAF IAM Client SDK
The EAF IAM Client SDK provides seamless integration with the ACCI EAF Identity and Access Management (IAM) service, enabling Spring Boot applications to authenticate users, enforce role-based access control (RBAC), and maintain tenant context across multi-tenant environments.
Featuresโ
- ๐ JWT Token Validation: Automatic validation of EAF-issued JWT tokens
- ๐ข Multi-tenant Context: Automatic tenant context propagation
- ๐ก๏ธ Spring Security Integration: Seamless integration with Spring Security
- ๐ Role-Based Access Control: Support for
@PreAuthorize
annotations and programmatic role checking - โ๏ธ Auto-Configuration: Zero-configuration setup with Spring Boot auto-configuration
- ๐งช Test Support: Comprehensive testing utilities and examples
Quick Startโ
1. Add Dependencyโ
Add the EAF IAM Client SDK to your Spring Boot project:
dependencies {
implementation("com.axians.eaf:eaf-iam-client")
}
2. Configure Propertiesโ
Add the following properties to your application.yml
:
eaf:
iam:
enabled: true
base-url: 'http://localhost:8080'
issuer-uri: 'http://localhost:8080'
audience: 'eaf-services'
3. Secure Your Endpointsโ
Use Spring Security annotations to protect your endpoints:
@RestController
@RequestMapping("/api/products")
class ProductController {
@GetMapping
@PreAuthorize("hasRole('TENANT_USER')")
fun getProducts(): List<Product> {
// Your business logic here
return productService.findAll()
}
@PostMapping
@PreAuthorize("hasRole('TENANT_ADMIN')")
fun createProduct(@RequestBody product: Product): Product {
return productService.create(product)
}
}
4. Access User Contextโ
Access the current user and tenant context in your services:
@Service
class ProductService {
fun findAll(): List<Product> {
val authentication = SecurityContextHolder.getContext().authentication as EafAuthentication
val tenantId = authentication.tenantId
val userId = authentication.principal.userId
// Use tenant context for data isolation
return productRepository.findByTenantId(tenantId)
}
}
Configuration Propertiesโ
Property | Description | Default | Required |
---|---|---|---|
eaf.iam.enabled | Enable/disable EAF IAM integration | true | No |
eaf.iam.base-url | Base URL of the IAM service | - | Yes |
eaf.iam.issuer-uri | JWT token issuer URI | - | Yes |
eaf.iam.audience | Expected JWT audience | - | Yes |
Authentication Flowโ
sequenceDiagram
participant Client
participant App as Your Application
participant Filter as JwtAuthenticationFilter
participant IAM as IAM Service
Client->>App: Request with JWT token
App->>Filter: Process request
Filter->>Filter: Extract JWT from Authorization header
Filter->>IAM: Validate token via /api/v1/auth/introspect
IAM->>Filter: Return user details and roles
Filter->>Filter: Create EafAuthentication object
Filter->>App: Set SecurityContext
App->>Client: Process request with user context
Role Mappingโ
The SDK automatically maps IAM service roles to Spring Security authorities:
IAM Role | Spring Authority | Description |
---|---|---|
TENANT_ADMIN | ROLE_TENANT_ADMIN | Full administrative access within tenant |
TENANT_USER | ROLE_TENANT_USER | Standard user access within tenant |
SUPER_ADMIN | ROLE_SUPER_ADMIN | System-wide administrative access |
Programmatic Role Checkingโ
Beyond annotations, you can check roles programmatically:
@Service
class BusinessService {
fun performSensitiveOperation() {
val authentication = SecurityContextHolder.getContext().authentication as EafAuthentication
val principal = authentication.principal as EafPrincipal
when {
principal.hasRole("TENANT_ADMIN") -> {
// Admin-specific logic
}
principal.hasRole("TENANT_USER") -> {
// User-specific logic
}
else -> {
throw AccessDeniedException("Insufficient permissions")
}
}
}
}
Error Handlingโ
The SDK provides comprehensive error handling:
Common Error Scenariosโ
Scenario | HTTP Status | Response |
---|---|---|
Missing token | 401 | {"error": "unauthorized", "message": "No authentication token provided"} |
Invalid token | 401 | {"error": "invalid_token", "message": "Token validation failed"} |
Expired token | 401 | {"error": "token_expired", "message": "Authentication token has expired"} |
Insufficient permissions | 403 | {"error": "access_denied", "message": "Insufficient permissions"} |
Custom Error Handlingโ
You can customize error responses by providing your own AuthenticationEntryPoint
:
@Configuration
class SecurityConfig {
@Bean
fun authenticationEntryPoint(): AuthenticationEntryPoint {
return AuthenticationEntryPoint { request, response, authException ->
response.contentType = "application/json"
response.status = HttpServletResponse.SC_UNAUTHORIZED
response.writer.write("""{"error": "custom_unauthorized", "message": "${authException.message}"}""")
}
}
}
Testingโ
Unit Testingโ
Test your secured endpoints using Spring Security test utilities:
@WebMvcTest(ProductController::class)
class ProductControllerTest {
@Autowired
private lateinit var mockMvc: MockMvc
@Test
@WithMockUser(roles = ["TENANT_USER"])
fun `should allow access to users with TENANT_USER role`() {
mockMvc.perform(get("/api/products"))
.andExpect(status().isOk)
}
@Test
@WithMockUser(roles = ["TENANT_ADMIN"])
fun `should allow product creation for admins`() {
mockMvc.perform(
post("/api/products")
.contentType(MediaType.APPLICATION_JSON)
.content("""{"name": "Test Product"}""")
).andExpect(status().isCreated)
}
}
Integration Testingโ
For integration tests, you can mock the IAM service or use test containers:
@SpringBootTest
@TestPropertySource(properties = [
"eaf.iam.base-url=http://localhost:8080",
"eaf.iam.issuer-uri=http://localhost:8080",
"eaf.iam.audience=test-audience"
])
class ProductIntegrationTest {
@Test
fun `should authenticate valid JWT token`() {
// Your integration test logic
}
}
Troubleshootingโ
Common Issuesโ
Issue: NoSuchBeanDefinitionException
for security components Solution: Ensure
@EnableWebSecurity
is present and auto-configuration is not excluded
Issue: Token validation fails with 401 Solution: Verify IAM service URL and ensure the service is accessible
Issue: Roles not recognized in @PreAuthorize
Solution: Check role mapping and ensure roles
are prefixed with ROLE_
Debug Loggingโ
Enable debug logging to troubleshoot authentication issues:
logging:
level:
com.axians.eaf.iam.client: DEBUG
org.springframework.security: DEBUG
Architectureโ
The EAF IAM Client SDK follows clean architecture principles:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Your Application โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ EAF IAM Client SDK โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ Security โ โ Auto Config โ โ
โ โ Filter โ โ โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Spring Security โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ IAM Service โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Best Practicesโ
- Always validate tenant context: Ensure data isolation by checking tenant ID
- Use method-level security: Prefer
@PreAuthorize
over URL-based security - Handle authentication errors gracefully: Provide meaningful error messages
- Test security configurations: Include security tests in your test suite
- Monitor authentication metrics: Track authentication success/failure rates
Migration Guideโ
If you're migrating from a custom authentication solution:
- Replace custom filters with EAF IAM Client SDK auto-configuration
- Update role checks to use Spring Security authorities
- Migrate user context access to use
EafAuthentication
andEafPrincipal
- Update tests to use Spring Security test utilities
Related Documentationโ
- Security Context Access Guide
- Spring Boot Integration Testing
- IAM Service API Reference (Coming Soon)
Supportโ
For issues and questions:
- Check the troubleshooting section above
- Review the integration tests for examples
- Consult the EAF documentation for broader context