Search code examples
kotlinspring-securitykotlin-coroutines

Why SecurityContextHolder.getContext().authentication becomes equal null inside the Kotlin async method?


I'm new to Kotlin Coroutines and I want to call the API for each of my employees in asynchronous way. But I faced the problem that iside the new coroutine I'm unable to retrieve authentication from the SecurityContextHolder.getContext.

Can anybody explain please why SecurityContextHolder.getContext().authentication becomes equal null inside GlobalScope.async{...} block in Kotlin? Does a new coroutine have a separate security context? And how do I solve this issue? I there a way to avoid passing the authentication from the calling perform() function to the callApi() function?

Below you can find the code snippet:

fun perform() {
    // SecurityContextHolder.getContext().authentication contains some value!!!

    val deferred = employeesRepository.getEmployees().map { callApi(it) }

    runBlocking {
        deferred.forEach { it.await() }
    }

}

fun callApi(employee: EmployeeModel) = GlobalScope.async {
    // SecurityContextHolder.getContext().authentication is null here!!!
}

Solution

  • If I recall correctly the SecurityContextHolder.getContext() holds a thread-local reference to the authentication object. Using coroutines you actually switch to another thread (which does not have a thread-local authentication object).

    I think passing the authentication object could work, that was my first idea too when i started to read your question. Why do you want to avoid this?

    Perhaps you can create a coroutine context with auth object (or is there an existing one for this purpose?), but it's only a guess from me, i have no real experience with coroutines yet.

    edit: By a quick search i found this. You can find interesting ideas in this thread: https://github.com/Kotlin/kotlinx.coroutines/issues/119