While trying to figure out how to test my Micronaut 2.x application, I couldn’t find any examples integration testing with OpenID Connect. I wanted to mock the token validation part, so that it didn’t need to talk an external OpenID Connect session. Eventually, I found a solution to mocking OpenID Connect in Micronaut Integration Tests. This post should help those find the same thing I spent a long time looking for.
The solution is remarkably simple, provide a mock TokenAuthenticationFetcher. My implementation that is based on the Keycloak response follows.
package `is`.kow.documentmanager2 import `is`.kow.documentmanager2.entities.UserInformation import io.micronaut.context.annotation.Replaces import io.micronaut.http.HttpRequest import io.micronaut.security.authentication.Authentication import io.micronaut.security.filters.AuthenticationFetcher import io.micronaut.security.token.TokenAuthenticationFetcher import io.micronaut.security.token.reader.TokenResolver import io.reactivex.rxjava3.core.Flowable import mu.KotlinLogging import org.reactivestreams.Publisher import javax.inject.Inject import javax.inject.Singleton @Replaces(value = TokenAuthenticationFetcher::class) @Singleton class MockTokenAuthenticationFetcher @Inject constructor( private val resolver: TokenResolver ) : AuthenticationFetcher { override fun fetchAuthentication(request: HttpRequest?): Publisher { // My user info is parsed from keycloaks token response // return UserInformation( // username = attrs["preferred_username"] as String, // surname = attrs["family_name"] as String, // email = attrs["email"] as String, // commonName = attrs["given_name"] as String, // issuer = attrs["iss"] as String // ) return Flowable.fromOptional(resolver.resolveToken(request)) .flatMap { token -> when (token) { "authorizedToken" -> Flowable.just(object : Authentication { override fun getName(): String { return "Authenticated User" } override fun getAttributes(): MutableMap { return mutableMapOf( "preferred_username" to "authenticated", "family_name" to "User", "email" to "[email protected]", "given_name" to "Authenticated", "iss" to "TestToken" ) } }) else -> Flowable.empty() } } } }
Providing this in a test scope, or in the test classpath, replaces the existing one. Now, it’s absolutely trivial to map a token to whatever Authentication Information you want. All the roles parsing, and other parsing remains the same. This is really all it takes for mocking OpenID Connect in Micronaut Integration Tests. Hope it proves useful to you!