Skip to content
This repository was archived by the owner on Dec 10, 2025. It is now read-only.

Commit bfb0d9d

Browse files
authored
Merge pull request #58 from SLNE-Development/54-add-bearer-token-authentication-for-web-api
feat: add bearer token authentication and update Ktor server configuration
2 parents b2c06d2 + 694366d commit bfb0d9d

File tree

3 files changed

+45
-13
lines changed

3 files changed

+45
-13
lines changed

gradle/libs.versions.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ ktor-server-resources = { module = "io.ktor:ktor-server-resources" }
5454
kotlin-css = { module = "org.jetbrains.kotlin-wrappers:kotlin-css" }
5555
ktor-server-websockets = { module = "io.ktor:ktor-server-websockets" }
5656
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json" }
57+
ktor-server-auth = { module = "io.ktor:ktor-server-auth" }
5758
bson-kotlinx = { module = "org.mongodb:bson-kotlinx", version.ref = "bson-kotlinx" }
5859
aspectjweaver = { module = "org.aspectj:aspectjweaver" }
5960
aspectjrt = { module = "org.aspectj:aspectjrt" }
@@ -87,5 +88,5 @@ jackson-api-common = ["jackson-core", "jackson-databind", "jackson-module-kotlin
8788
exposed-api-server = ["exposed-spring-boot-starter", "exposed-java-time", "exposed-migration"]
8889
maven-libraries = ["maven-impl", "maven-resolver"]
8990
console-api = ["jline", "brigadier", "terminalconsoleappender"]
90-
ktor-api-server = ["ktor-server-core-jvm", "ktor-server-netty", "ktor-server-core", "ktor-server-html-builder", "kotlin-css", "ktor-server-websockets", "ktor-serialization-kotlinx-json", "ktor-server-resources"]
91+
ktor-api-server = ["ktor-server-core-jvm", "ktor-server-netty", "ktor-server-core", "ktor-server-html-builder", "kotlin-css", "ktor-server-websockets", "ktor-serialization-kotlinx-json", "ktor-server-resources", "ktor-server-auth"]
9192
flyway = ["flyway-core", "flyway-mysql"]

surf-cloud-standalone/src/main/kotlin/dev/slne/surf/cloud/standalone/config/StandaloneConfig.kt

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package dev.slne.surf.cloud.standalone.config
33
import dev.slne.surf.cloud.core.common.coreCloudInstance
44
import dev.slne.surf.surfapi.core.api.config.createSpongeYmlConfig
55
import dev.slne.surf.surfapi.core.api.config.surfConfigApi
6+
import dev.slne.surf.surfapi.core.api.util.random
67
import org.spongepowered.configurate.objectmapping.ConfigSerializable
78
import org.spongepowered.configurate.objectmapping.meta.Comment
89
import org.spongepowered.configurate.objectmapping.meta.Setting
10+
import java.util.Base64
911

1012

1113
val standaloneConfig: StandaloneConfig by lazy {
@@ -35,8 +37,24 @@ data class StandaloneConfig(
3537
@ConfigSerializable
3638
data class KtorConfig(
3739
val port: Int = 8080,
38-
val host: String = "0.0.0.0"
39-
)
40+
val host: String = "0.0.0.0",
41+
val bearerToken: String = generateBearerToken()
42+
) {
43+
companion object {
44+
private fun generateBearerToken(length: Int = 32): String {
45+
// The default token length of 32 provides a good balance between security and usability.
46+
// A minimum length of 16 is enforced to ensure sufficient entropy for security purposes.
47+
require(length >= 16) { "Token should be at least 16 characters long" }
48+
49+
val randomBytes = ByteArray(length)
50+
random.nextBytes(randomBytes)
51+
52+
// Base64 encoding is used to make the token URL-safe and compact while preserving randomness.
53+
val token = Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes)
54+
return token
55+
}
56+
}
57+
}
4058

4159
@ConfigSerializable
4260
data class LoggingConfig(

surf-cloud-standalone/src/main/kotlin/dev/slne/surf/cloud/standalone/ktor/KtorServer.kt

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ import dev.slne.surf.cloud.standalone.config.standaloneConfig
99
import dev.slne.surf.cloud.standalone.ktor.routes.punish.punishRoutes
1010
import io.ktor.http.*
1111
import io.ktor.server.application.*
12+
import io.ktor.server.auth.*
1213
import io.ktor.server.engine.*
1314
import io.ktor.server.html.*
1415
import io.ktor.server.netty.*
1516
import io.ktor.server.plugins.*
1617
import io.ktor.server.plugins.statuspages.*
17-
import io.ktor.server.resources.Resources
18+
import io.ktor.server.resources.*
1819
import io.ktor.server.routing.*
19-
import io.ktor.server.websocket.*
2020
import kotlinx.coroutines.launch
2121
import kotlinx.html.*
2222
import org.springframework.core.annotation.Order
2323
import org.springframework.stereotype.Component
24-
import kotlin.time.Duration.Companion.seconds
24+
import java.security.MessageDigest
2525

2626
@Component
2727
@Order(CloudLifecycleAware.KTOR_SERVER_PRIORITY)
@@ -46,21 +46,34 @@ class KtorServer : CloudLifecycleAware {
4646

4747
server = embeddedServer(Netty, port = port, host = host) {
4848
install(StatusPages) { configure() }
49-
install(WebSockets) {
50-
pingPeriod = 15.seconds
51-
}
49+
// install(WebSockets) {
50+
// pingPeriod = 15.seconds
51+
// }
5252
install(Resources)
53+
authentication {
54+
bearer {
55+
realm = "Access to the '/' path"
56+
authenticate {tokenCredential ->
57+
if (MessageDigest.isEqual(tokenCredential.token.toByteArray(), standaloneConfig.ktor.bearerToken.toByteArray())) {
58+
UserIdPrincipal("Bearer")
59+
} else {
60+
null
61+
}
62+
}
63+
}
64+
}
5365

5466
for (plugin in plugins) {
5567
plugin.apply { configure() }
5668
}
5769

5870
routing {
59-
for (plugin in plugins) {
60-
plugin.apply { installRoutes() }
71+
authenticate {
72+
for (plugin in plugins) {
73+
plugin.apply { installRoutes() }
74+
}
75+
punishRoutes()
6176
}
62-
63-
punishRoutes()
6477
}
6578
}
6679
server.start(wait = true)

0 commit comments

Comments
 (0)