|
| 1 | +package com.algolia.client |
| 2 | + |
| 3 | +import com.algolia.client.api.AgentStudioClient |
| 4 | +import com.algolia.client.extensions.internal.encodeKeySHA256 |
| 5 | +import kotlin.io.encoding.Base64 |
| 6 | +import kotlin.io.encoding.ExperimentalEncodingApi |
| 7 | +import kotlin.test.Test |
| 8 | +import kotlin.test.assertEquals |
| 9 | +import kotlin.test.assertTrue |
| 10 | +import kotlinx.datetime.Clock |
| 11 | +import kotlinx.serialization.json.Json |
| 12 | +import kotlinx.serialization.json.JsonObject |
| 13 | +import kotlinx.serialization.json.jsonPrimitive |
| 14 | + |
| 15 | +@OptIn(ExperimentalEncodingApi::class) |
| 16 | +class TestForgeSecuredUserToken { |
| 17 | + |
| 18 | + @Test |
| 19 | + fun forgeSecuredUserToken() { |
| 20 | + val client = AgentStudioClient(appId = "appID", apiKey = "apiKey") |
| 21 | + |
| 22 | + val token = client.forgeSecuredUserToken("my-secret-key", "my-key-id", "user-123") |
| 23 | + |
| 24 | + val parts = token.split(".") |
| 25 | + assertEquals(3, parts.size) |
| 26 | + |
| 27 | + val headerJson = Base64.UrlSafe.decode(parts[0]).decodeToString() |
| 28 | + val header = Json.decodeFromString<JsonObject>(headerJson) |
| 29 | + assertEquals("HS256", header["alg"]!!.jsonPrimitive.content) |
| 30 | + assertEquals("JWT", header["typ"]!!.jsonPrimitive.content) |
| 31 | + assertEquals("my-key-id", header["kid"]!!.jsonPrimitive.content) |
| 32 | + |
| 33 | + val payloadJson = Base64.UrlSafe.decode(parts[1]).decodeToString() |
| 34 | + val payload = Json.decodeFromString<JsonObject>(payloadJson) |
| 35 | + assertEquals("user-123", payload["sub"]!!.jsonPrimitive.content) |
| 36 | + val exp = payload["exp"]!!.jsonPrimitive.content.toLong() |
| 37 | + val expectedExp = Clock.System.now().epochSeconds + 24 * 3600 |
| 38 | + assertTrue(kotlin.math.abs(exp - expectedExp) < 5, "exp $exp should be within 5s of $expectedExp") |
| 39 | + |
| 40 | + val expectedHmacHex = encodeKeySHA256(key = "my-secret-key", message = "${parts[0]}.${parts[1]}") |
| 41 | + val actualSigBytes = Base64.UrlSafe.decode(parts[2]) |
| 42 | + val actualSigHex = actualSigBytes.joinToString("") { "%02x".format(it) } |
| 43 | + assertEquals(expectedHmacHex, actualSigHex) |
| 44 | + } |
| 45 | + |
| 46 | + @Test |
| 47 | + fun forgeSecuredUserTokenCustomExpiry() { |
| 48 | + val client = AgentStudioClient(appId = "appID", apiKey = "apiKey") |
| 49 | + |
| 50 | + val token = client.forgeSecuredUserToken("my-secret-key", "my-key-id", "user-456", 3600) |
| 51 | + |
| 52 | + val parts = token.split(".") |
| 53 | + val payloadJson = Base64.UrlSafe.decode(parts[1]).decodeToString() |
| 54 | + val payload = Json.decodeFromString<JsonObject>(payloadJson) |
| 55 | + val exp = payload["exp"]!!.jsonPrimitive.content.toLong() |
| 56 | + val expectedExp = Clock.System.now().epochSeconds + 3600 |
| 57 | + assertTrue(kotlin.math.abs(exp - expectedExp) < 5, "exp $exp should be within 5s of $expectedExp") |
| 58 | + } |
| 59 | +} |
0 commit comments