CustomOAuth2SuccessHandler.kt

package delta.codecharacter.server.auth.oauth2

import delta.codecharacter.server.auth.AuthService
import delta.codecharacter.server.exception.CustomException
import delta.codecharacter.server.user.LoginType
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Lazy
import org.springframework.security.core.Authentication
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
import org.springframework.stereotype.Component
import java.time.Instant
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

@Component
class CustomOAuth2SuccessHandler(@Lazy @Autowired private val authService: AuthService) :
    AuthenticationSuccessHandler {

    @Value("\${base-url}") private val baseUrl: String = ""
    @Value("\${frontend-domain}") private val frontendDomain: String = ""

    private val logger: Logger = LoggerFactory.getLogger(CustomOAuth2SuccessHandler::class.java)

    override fun onAuthenticationSuccess(
        request: HttpServletRequest?,
        response: HttpServletResponse?,
        authentication: Authentication?
    ) {
        val principal = authentication?.principal
        if (principal is OAuth2AuthenticatedPrincipal) {
            val attributes = principal.attributes
            val email = attributes["email"] as String
            val provider = attributes["provider"] as String?
            val loginType = LoginType.valueOf(provider ?: "GOOGLE")
            try {
                val token = authService.oAuth2Login(email, loginType)
                val instant = Instant.now()
                val zoneId = ZoneId.of("GMT")
                val zonedDateTimePlus = ZonedDateTime.ofInstant(instant.plusSeconds(60), zoneId)
                val plusOneSecond = zonedDateTimePlus.format(DateTimeFormatter.RFC_1123_DATE_TIME)
                if (baseUrl.contains("https")) {
                    response?.setHeader(
                        "Set-Cookie",
                        "bearer-token=$token; Domain=$frontendDomain; Path=/; Expires=$plusOneSecond; Secure; SameSite=None"
                    )
                } else {
                    response?.setHeader(
                        "Set-Cookie",
                        "bearer-token=$token; Domain=$frontendDomain; Expires=$plusOneSecond; Path=/; SameSite=false"
                    )
                }
                response?.sendRedirect("$baseUrl/#/dashboard")
            } catch (e: CustomException) {
                response?.sendRedirect("$baseUrl/#/login?error=${e.message}")
            } catch (e: Exception) {
                logger.error("Unexpected error", e)
                response?.sendRedirect("$baseUrl/#/login?error=Internal Server Error")
            }
        } else {
            response?.sendRedirect("$baseUrl/#/login?error=Invalid login, please try again")
        }
    }
}