1
0

refactor: implement partial JWT authentication; migrate to reactive spring/mongodb

Signed-off-by: Alan Brault <alan.brault@visus.io>
This commit is contained in:
2026-03-15 11:37:15 -04:00
parent 9f5c48fffc
commit 240964ea1d
34 changed files with 642 additions and 72 deletions
@@ -0,0 +1,15 @@
package io.visus.demos.kotlinapi.api.dto
import io.swagger.v3.oas.annotations.media.Schema
@Schema(description = "Authentication response containing tokens and user information")
data class AuthResponse(
@Schema(description = "JWT access token", example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
val accessToken: String,
@Schema(description = "JWT refresh token", example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
val refreshToken: String,
@Schema(description = "Token type", example = "Bearer")
val tokenType: String = "Bearer",
@Schema(description = "Access token expiration time in seconds", example = "3600")
val expiresIn: Long,
)
@@ -0,0 +1,16 @@
package io.visus.demos.kotlinapi.api.dto
import io.swagger.v3.oas.annotations.media.Schema
import java.time.Instant
@Schema(description = "Error response")
data class ErrorResponse(
@Schema(description = "HTTP status code", example = "403")
val status: Int,
@Schema(description = "Error message", example = "Forbidden: You don't have permission to access this resource")
val message: String,
@Schema(description = "Timestamp of the error occurrence", example = "2024-01-01T12:00:00Z")
val timestamp: Instant = Instant.now(),
@Schema(description = "Request path", example = "/api/v1/users/me")
val path: String? = null,
)
@@ -0,0 +1,16 @@
package io.visus.demos.kotlinapi.api.dto
import io.swagger.v3.oas.annotations.media.Schema
import jakarta.validation.constraints.Email
import jakarta.validation.constraints.NotBlank
@Schema(description = "Login request")
data class LoginRequest(
@field:Email(message = "Invalid email format")
@field:NotBlank(message = "Email is required")
@Schema(description = "User email address", example = "user@example.com")
val email: String,
@field:NotBlank(message = "Password is required")
@Schema(description = "User password", example = "P@ssw0rd!")
val password: String,
)
@@ -0,0 +1,11 @@
package io.visus.demos.kotlinapi.api.dto
import io.swagger.v3.oas.annotations.media.Schema
import jakarta.validation.constraints.NotBlank
@Schema(description = "Refresh token request")
data class RefreshTokenRequest(
@field:NotBlank(message = "Refresh token is required")
@Schema(description = "JWT refresh token", example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
val refreshToken: String,
)
@@ -0,0 +1,13 @@
package io.visus.demos.kotlinapi.api.dto
import io.swagger.v3.oas.annotations.media.Schema
@Schema(description = "User information")
data class UserDto(
@Schema(description = "Unique identifier of the user", example = "507f1f77bcf86cd799439011")
val id: String,
@Schema(description = "User email address", example = "user@example.com")
val email: String,
@Schema(description = "User role", example = "ROLE_USER")
val role: String,
)
@@ -5,10 +5,11 @@ import io.visus.demos.kotlinapi.domain.model.HealthStatus
import tech.mappie.api.ObjectMappie
object HealthResponseMapper : ObjectMappie<HealthStatus, HealthResponse>() {
override fun map(from: HealthStatus): HealthResponse = mapping {
HealthResponse::status fromProperty HealthStatus::status transform { it.name }
HealthResponse::components fromProperty HealthStatus::components transform {
it.mapValues { (_, value) -> ComponentHealthDtoMapper.map(value) }
override fun map(from: HealthStatus): HealthResponse =
mapping {
HealthResponse::status fromProperty HealthStatus::status transform { it.name }
HealthResponse::components fromProperty HealthStatus::components transform {
it.mapValues { (_, value) -> ComponentHealthDtoMapper.map(value) }
}
}
}
}