Java / Kotlin (Spring Boot)
Setup
// build.gradle.kts
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("com.nimbusds:nimbus-jose-jwt:9.40")
}
Spring Security filter
@Component
class JwtAuthFilter(
@Value("\${auth.url}") private val authUrl: String,
) : OncePerRequestFilter() {
private val jwksUrl by lazy { URL("$authUrl/.well-known/jwks.json") }
private val jwkSource by lazy {
JWKSourceBuilder.create<SecurityContext>(jwksUrl).cache(true).build()
}
override fun doFilterInternal(req: HttpServletRequest, res: HttpServletResponse, chain: FilterChain) {
val token = req.cookies?.firstOrNull { it.name == "identsphere_at" }?.value
?: req.getHeader("Authorization")?.removePrefix("Bearer ")
if (token != null) {
try {
val processor = DefaultJWTProcessor<SecurityContext>().apply {
jwsKeySelector = JWSVerificationKeySelector(JWSAlgorithm.RS256, jwkSource)
}
val claims = processor.process(token, null)
val auth = UsernamePasswordAuthenticationToken(
claims.subject, null, listOf(SimpleGrantedAuthority("ROLE_USER"))
)
SecurityContextHolder.getContext().authentication = auth
} catch (e: Exception) { /* drop, become anonymous */ }
}
chain.doFilter(req, res)
}
}
SecurityConfig
@Configuration
class SecurityConfig(private val jwtFilter: JwtAuthFilter) {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http
.csrf { it.disable() }
.authorizeHttpRequests { it
.requestMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
}
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter::class.java)
return http.build()
}
}
Proxying login
@RestController
@RequestMapping("/auth")
class AuthProxy(@Value("\${auth.url}") val authUrl: String) {
private val client = HttpClient.newHttpClient()
@PostMapping("/login")
fun login(@RequestBody body: String, response: HttpServletResponse): String {
val req = HttpRequest.newBuilder(URI.create("$authUrl/v1/auth/login"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build()
val upstream = client.send(req, HttpResponse.BodyHandlers.ofString())
upstream.headers().allValues("set-cookie").forEach {
response.addHeader("Set-Cookie", it)
}
response.status = upstream.statusCode()
return upstream.body()
}
}
Java (non-Kotlin)
Same flow with HttpServletRequest / HttpServletResponse. Use
com.nimbusds:nimbus-jose-jwt or io.jsonwebtoken:jjwt for JWT
verification.