My sample application work on local environment. But, it does not work on Java8 standard environment. The following project is the sample application project.
https://github.com/nosix/appengine-java8-spring-oauth2
The following error occurs in Java8 standard environment:
Authentication Failed: Could not obtain access token
I added logs to the source code of Spring OAuth and investigated the cause. The cause of the error seems to be that the session data has been lost.
It operated as follows:
preservedState is null in AuthorizationCodeAccessTokenProvider::getParametersForTokenRequest. So, InvalidRequestException is thrown. This is the cause of the error.
setPreservedState method is called in OAuth2RestTemplate::acquireAccessToken. At that time, preservedState is set to null.
DefaultOAuth2ClientContext instance has preservedState. preservedState of DefaultOAuth2ClientContext instance is null in Java8 standard environment. But, It is not null in the local environment.
DefaultOAuth2ClientContext instance are stored in the session. I understand that it is stored on memory in the local environment and in the data store in the standard environment.
From the above, I guessed that the session data was lost.
I was stuck in the investigation. Is there information that serves as a clue for solving?
I had the same issue. Finally I implemented a custom SessionRepository of Spring Session as follows: (see also this commit)
Repository class:
class MemcacheSessionRepository(private val memcacheService: MemcacheService) : SessionRepository<MemcacheSession> {
private val log = LoggerFactory.getLogger(javaClass)
private val maxInactiveIntervalInSeconds: Int = 3600
override fun createSession() = MemcacheSession().also { session ->
session.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds
log.debug("createSession() = {}", session.id)
}
override fun save(session: MemcacheSession) {
log.debug("save({}) with expiration {}", session.id, session.maxInactiveIntervalInSeconds)
memcacheService.put(session.id, session, Expiration.byDeltaSeconds(session.maxInactiveIntervalInSeconds))
}
override fun getSession(id: String): MemcacheSession? =
(memcacheService.get(id) as? MemcacheSession)?.also { session ->
session.setLastAccessedTimeToNow()
}.also { session ->
log.debug("getSession({}) = {}", id, session?.id)
}
override fun delete(id: String) {
log.debug("delete({})", id)
memcacheService.delete(id)
}
}
Entity class:
class MemcacheSession : ExpiringSession, Serializable {
companion object {
const val serialVersionUID: Long = 1
}
private val id: String = UUID.randomUUID().toString()
private val creationTime: Long = System.currentTimeMillis()
private var lastAccessedTime: Long = creationTime
private var maxInactiveIntervalInSeconds: Int = 3600
private val attributes: MutableMap<String, Any> = mutableMapOf()
override fun getId() = id
override fun getCreationTime() = creationTime
override fun getLastAccessedTime() = lastAccessedTime
override fun setLastAccessedTime(time: Long) {
lastAccessedTime = time
}
fun setLastAccessedTimeToNow() {
lastAccessedTime = System.currentTimeMillis()
}
override fun getMaxInactiveIntervalInSeconds() = maxInactiveIntervalInSeconds
override fun setMaxInactiveIntervalInSeconds(interval: Int) {
maxInactiveIntervalInSeconds = interval
}
override fun removeAttribute(key: String) {
attributes.remove(key)
}
override fun getAttributeNames() = attributes.keys
override fun <T> getAttribute(key: String): T? = attributes[key] as T?
override fun setAttribute(key: String, value: Any) {
attributes.put(key, value)
}
override fun isExpired() = false
}
This seems work well at this time but it uses only Memcache and needs to improve for high availability.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With