Using Spring Boot and ReactJs together is pretty common, so I think a lot of people coming to this repository might be looking to integrate the two.
The React SDK provided by FusionAuth sets HttpOnly cookies that are automatically submitted per-request, which may work well for other server libraries, but unless I'm mistaken, parsing a JWT from a cookie in Spring is a fairly manual process and grates against the "happy path" of using an Authorization header.
It would be great if there were sample code available for this integration, or for it to be called out in the tutorial / readme (happy to contribute). Because I'm new at Javascript and decent with Kotlin, I've opted to just make to with the HttpOnly cookie while using the React SDK as is (my attempt below).
package com.benjaminstammen.bfi.security
import com.nimbusds.jose.JWSAlgorithm
import com.nimbusds.jose.jwk.source.JWKSourceBuilder
import com.nimbusds.jose.proc.JWSKeySelector
import com.nimbusds.jose.proc.JWSVerificationKeySelector
import com.nimbusds.jose.proc.SecurityContext
import com.nimbusds.jose.proc.SimpleSecurityContext
import com.nimbusds.jwt.JWTClaimsSet
import com.nimbusds.jwt.SignedJWT
import com.nimbusds.jwt.proc.DefaultJWTProcessor
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.web.filter.OncePerRequestFilter
import java.net.URI
import java.util.*
class JwtAuthenticationFilter : OncePerRequestFilter() {
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
val jwt = getJwtFromCookie(request)
if (jwt != null && validateJwt(jwt)) {
val authentication = getAuthentication(jwt)
SecurityContextHolder.getContext().authentication = authentication
}
filterChain.doFilter(request, response)
}
private fun getJwtFromCookie(request: HttpServletRequest): String? {
val cookies = request.cookies ?: return null
val jwtCookie = cookies.firstOrNull { it.name == "app.at" }
return jwtCookie?.value
}
private fun validateJwt(jwt: String): Boolean {
// Parse the JWT
val signedJwt = SignedJWT.parse(jwt)
// Set up the JWK source
val jwkSetUrl = URI("http://localhost:9011/.well-known/jwks").toURL()
val keySource = JWKSourceBuilder
.create<SecurityContext>(jwkSetUrl)
.build();
val expectedJwsAlgorithm = JWSAlgorithm.RS256;
val keySelector: JWSKeySelector<SecurityContext> = JWSVerificationKeySelector(expectedJwsAlgorithm, keySource)
// Create a JWT processor for the access tokens
val jwtProcessor: DefaultJWTProcessor<SecurityContext> = DefaultJWTProcessor()
jwtProcessor.jwsKeySelector = keySelector
// Set the required claims that the token must contain - adjust this to match your requirements
val securityContext = SimpleSecurityContext()
jwtProcessor.process(signedJwt, securityContext)
// Obtain the JWT claims...
val claimsSet: JWTClaimsSet = signedJwt.jwtClaimsSet
if (claimsSet.issuer != "...") return false
if (!claimsSet.audience.contains("...")) return false
if (claimsSet.expirationTime.before(Date())) return false
return true // return true if valid, false otherwise
}
private fun getAuthentication(jwt: String): UsernamePasswordAuthenticationToken {
// Parse the JWT to extract authorities and other credentials
// Replace "user" and "emptyList()" with actual values after parsing the JWT
return UsernamePasswordAuthenticationToken("user", null, emptyList())
}
}
Using Spring Boot and ReactJs together is pretty common, so I think a lot of people coming to this repository might be looking to integrate the two.
The React SDK provided by FusionAuth sets HttpOnly cookies that are automatically submitted per-request, which may work well for other server libraries, but unless I'm mistaken, parsing a JWT from a cookie in Spring is a fairly manual process and grates against the "happy path" of using an Authorization header.
It would be great if there were sample code available for this integration, or for it to be called out in the tutorial / readme (happy to contribute). Because I'm new at Javascript and decent with Kotlin, I've opted to just make to with the HttpOnly cookie while using the React SDK as is (my attempt below).