diff --git a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AccessToken.kt b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AccessToken.kt index ed2a5e6ce..c456dfd7c 100644 --- a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AccessToken.kt +++ b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AccessToken.kt @@ -17,7 +17,7 @@ suspend fun SupabaseClient.resolveAccessToken( jwtToken: String? = null, keyAsFallback: Boolean = true ): String? { - val key = if(keyAsFallback) supabaseKey else null + val key = if(keyAsFallback && isApiKeyJWT) supabaseKey else null return jwtToken ?: accessToken?.invoke() ?: pluginManager.getPluginOrNull(Auth)?.currentAccessTokenOrNull() ?: key } diff --git a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthenticatedSupabaseApi.kt b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthenticatedSupabaseApi.kt index aca2fd113..a86271c69 100644 --- a/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthenticatedSupabaseApi.kt +++ b/Auth/src/commonMain/kotlin/io/github/jan/supabase/auth/AuthenticatedSupabaseApi.kt @@ -21,9 +21,9 @@ class AuthenticatedSupabaseApi @SupabaseInternal constructor( ): SupabaseApi(resolveUrl, parseErrorResponse, supabaseClient) { override suspend fun rawRequest(url: String, builder: HttpRequestBuilder.() -> Unit): HttpResponse { - val accessToken = supabaseClient.resolveAccessToken(jwtToken) ?: error("No access token available") + val accessToken = supabaseClient.resolveAccessToken(jwtToken) return super.rawRequest(url) { - bearerAuth(accessToken) + accessToken?.let { bearerAuth(it) } builder() defaultRequest?.invoke(this) } diff --git a/Auth/src/commonTest/kotlin/AccessTokenTest.kt b/Auth/src/commonTest/kotlin/AccessTokenTest.kt index ad6647495..d0aa53f2c 100644 --- a/Auth/src/commonTest/kotlin/AccessTokenTest.kt +++ b/Auth/src/commonTest/kotlin/AccessTokenTest.kt @@ -2,6 +2,7 @@ import io.github.jan.supabase.auth.Auth import io.github.jan.supabase.auth.auth import io.github.jan.supabase.auth.minimalSettings import io.github.jan.supabase.auth.resolveAccessToken +import io.github.jan.supabase.testing.TEST_JWT import io.github.jan.supabase.testing.createMockedSupabaseClient import kotlinx.coroutines.test.runTest import kotlin.test.Test @@ -20,7 +21,7 @@ class AccessTokenTest { } } ) - client.auth.importAuthToken("myAuth") //this should be ignored as per plugin tokens override the used access token + client.auth.importAuthToken(TEST_JWT) //this should be ignored as per plugin tokens override the used access token assertEquals("myJwtToken", client.resolveAccessToken("myJwtToken")) } } @@ -28,8 +29,16 @@ class AccessTokenTest { @Test fun testAccessTokenWithKeyAsFallback() { runTest { - val client = createMockedSupabaseClient(supabaseKey = "myKey") - assertEquals("myKey", client.resolveAccessToken()) + val client = createMockedSupabaseClient(supabaseKey = TEST_JWT) + assertEquals(TEST_JWT, client.resolveAccessToken()) + } + } + + @Test + fun testAccessTokenWithKeyAsFallbackWithInvalidKey() { + runTest { + val client = createMockedSupabaseClient(supabaseKey = "not_a_jwt") + assertNull(client.resolveAccessToken()) } } @@ -65,8 +74,8 @@ class AccessTokenTest { } } ) - client.auth.importAuthToken("myAuth") - assertEquals("myAuth", client.resolveAccessToken()) + client.auth.importAuthToken(TEST_JWT) + assertEquals(TEST_JWT, client.resolveAccessToken()) } } diff --git a/Auth/src/commonTest/kotlin/AdminApiTest.kt b/Auth/src/commonTest/kotlin/AdminApiTest.kt index 1e899e027..59819fad4 100644 --- a/Auth/src/commonTest/kotlin/AdminApiTest.kt +++ b/Auth/src/commonTest/kotlin/AdminApiTest.kt @@ -7,6 +7,7 @@ import io.github.jan.supabase.auth.auth import io.github.jan.supabase.auth.minimalSettings import io.github.jan.supabase.auth.user.UserInfo import io.github.jan.supabase.auth.user.UserMfaFactor +import io.github.jan.supabase.testing.TEST_JWT import io.github.jan.supabase.testing.assertMethodIs import io.github.jan.supabase.testing.assertPathIs import io.github.jan.supabase.testing.createMockedSupabaseClient @@ -39,7 +40,7 @@ class AdminApiTest { @Test fun testSignOut() { runTest { - val jwt = "jwt" + val jwt = TEST_JWT val scope = SignOutScope.LOCAL val client = createMockedSupabaseClient( configuration = configuration diff --git a/Auth/src/commonTest/kotlin/AuthApiTest.kt b/Auth/src/commonTest/kotlin/AuthApiTest.kt index e87b4238c..3c31a2c9c 100644 --- a/Auth/src/commonTest/kotlin/AuthApiTest.kt +++ b/Auth/src/commonTest/kotlin/AuthApiTest.kt @@ -13,6 +13,7 @@ import io.github.jan.supabase.auth.providers.builtin.IDToken import io.github.jan.supabase.auth.providers.builtin.OTP import io.github.jan.supabase.auth.providers.builtin.Phone import io.github.jan.supabase.auth.status.SessionSource +import io.github.jan.supabase.testing.TEST_JWT import io.github.jan.supabase.testing.assertMethodIs import io.github.jan.supabase.testing.assertPathIs import io.github.jan.supabase.testing.createMockedSupabaseClient @@ -615,7 +616,7 @@ class AuthRequestTest { @Test fun testRetrieveUser() { runTest { - val expectedJWT = "token" + val expectedJWT = TEST_JWT val client = createMockedSupabaseClient(configuration = configuration) { assertMethodIs(HttpMethod.Get, it.method) assertPathIs("/user", it.url.pathAfterVersion()) @@ -677,7 +678,7 @@ class AuthRequestTest { private fun sampleUserSession() = """ { - "access_token": "token", + "access_token": "$TEST_JWT", "refresh_token": "refresh", "token_type": "bearer", "expires_in": 3600 diff --git a/Auth/src/commonTest/kotlin/AuthTest.kt b/Auth/src/commonTest/kotlin/AuthTest.kt index eeb0ee5b8..365f54785 100644 --- a/Auth/src/commonTest/kotlin/AuthTest.kt +++ b/Auth/src/commonTest/kotlin/AuthTest.kt @@ -8,6 +8,7 @@ import io.github.jan.supabase.auth.status.SessionStatus import io.github.jan.supabase.auth.user.Identity import io.github.jan.supabase.auth.user.UserInfo import io.github.jan.supabase.auth.user.UserSession +import io.github.jan.supabase.testing.TEST_JWT import io.github.jan.supabase.testing.createMockedSupabaseClient import io.github.jan.supabase.testing.pathAfterVersion import io.github.jan.supabase.testing.respondJson @@ -185,7 +186,7 @@ class AuthTest { identities = expectedIdentities ) val session = UserSession( - accessToken = "accessToken", + accessToken = TEST_JWT, refreshToken = "refreshToken", expiresIn = 3600, tokenType = "Bearer", @@ -216,7 +217,7 @@ class AuthTest { } -fun userSession(customToken: String = "accessToken", expiresIn: Long = 3600, user: UserInfo? = null) = UserSession( +fun userSession(customToken: String = TEST_JWT, expiresIn: Long = 3600, user: UserInfo? = null) = UserSession( accessToken = customToken, refreshToken = "refreshToken", expiresIn = expiresIn, diff --git a/Auth/src/commonTest/kotlin/AuthenticatedSupabaseApiTest.kt b/Auth/src/commonTest/kotlin/AuthenticatedSupabaseApiTest.kt new file mode 100644 index 000000000..f3e98f8fb --- /dev/null +++ b/Auth/src/commonTest/kotlin/AuthenticatedSupabaseApiTest.kt @@ -0,0 +1,27 @@ +import io.github.jan.supabase.auth.AuthenticatedSupabaseApi +import io.github.jan.supabase.testing.createMockedSupabaseClient +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertFailsWith + +class AuthenticatedSupabaseApiTest { + + @Test + fun testFailureIfInvalidAuthorizationHeader() { + val supabase = createMockedSupabaseClient( + supabaseKey = "myKey", + supabaseUrl = "https://example.com" + ) + val api = AuthenticatedSupabaseApi( + resolveUrl = { "https://example.com/$it" }, + supabaseClient = supabase, + jwtToken = "myToken" + ) + assertFailsWith { + runTest { + api.get("test") + } + } + } + +} \ No newline at end of file diff --git a/Auth/src/commonTest/kotlin/MfaApiTest.kt b/Auth/src/commonTest/kotlin/MfaApiTest.kt index 67571e6af..17fb112e7 100644 --- a/Auth/src/commonTest/kotlin/MfaApiTest.kt +++ b/Auth/src/commonTest/kotlin/MfaApiTest.kt @@ -10,6 +10,7 @@ import io.github.jan.supabase.auth.providers.builtin.Phone import io.github.jan.supabase.auth.user.UserInfo import io.github.jan.supabase.auth.user.UserMfaFactor import io.github.jan.supabase.auth.user.UserSession +import io.github.jan.supabase.testing.TEST_JWT import io.github.jan.supabase.testing.assertMethodIs import io.github.jan.supabase.testing.assertPathIs import io.github.jan.supabase.testing.createMockedSupabaseClient @@ -165,7 +166,7 @@ class MfaApiTest { ) { respondJson(UserInfo(id = "id", aud = "aud", factors = listOf(expectedFactor))) } - client.auth.importAuthToken("token") + client.auth.importAuthToken(TEST_JWT) val factors = client.auth.mfa.retrieveFactorsForCurrentUser() assertEquals(1, factors.size) assertEquals(expectedFactor, factors.first()) @@ -212,7 +213,8 @@ class MfaApiTest { val data = buildJsonObject { put("aal", currentAAL.name.lowercase()) } - val token = "ignore.${data.toString().encodeBase64()}" + val encoded = data.toString().encodeBase64() + val token = "$encoded.$encoded.$encoded" val client = createMockedSupabaseClient( configuration = configuration ) { @@ -230,7 +232,8 @@ class MfaApiTest { val data = buildJsonObject { put("aal", current.name.lowercase()) } - val token = "ignore.${data.toString().encodeBase64()}" + val encoded = data.toString().encodeBase64() + val token = "$encoded.$encoded.$encoded" val client = createMockedSupabaseClient( configuration = configuration ) { diff --git a/Functions/src/commonTest/kotlin/FunctionsTest.kt b/Functions/src/commonTest/kotlin/FunctionsTest.kt index 50ffc5116..fbbed2609 100644 --- a/Functions/src/commonTest/kotlin/FunctionsTest.kt +++ b/Functions/src/commonTest/kotlin/FunctionsTest.kt @@ -5,6 +5,7 @@ import io.github.jan.supabase.auth.minimalSettings import io.github.jan.supabase.functions.FunctionRegion import io.github.jan.supabase.functions.Functions import io.github.jan.supabase.functions.functions +import io.github.jan.supabase.testing.TEST_JWT import io.github.jan.supabase.testing.createMockedSupabaseClient import io.github.jan.supabase.testing.pathAfterVersion import io.github.jan.supabase.testing.toJsonElement @@ -28,7 +29,7 @@ class FunctionsTest { @Test fun testAuthorizationHeaderAuth() { runTest { - val expectedJWT = "jwt" + val expectedJWT = TEST_JWT val supabase = createMockedSupabaseClient( configuration ={ install(Auth) { @@ -51,7 +52,7 @@ class FunctionsTest { @Test fun testAuthorizationHeaderCustomToken() { runTest { - val expectedJWT = "jwt" + val expectedJWT = TEST_JWT val supabase = createMockedSupabaseClient( configuration = { install(Functions) { diff --git a/Realtime/src/commonTest/kotlin/RealtimeChannelTest.kt b/Realtime/src/commonTest/kotlin/RealtimeChannelTest.kt index 5079b8475..97466114b 100644 --- a/Realtime/src/commonTest/kotlin/RealtimeChannelTest.kt +++ b/Realtime/src/commonTest/kotlin/RealtimeChannelTest.kt @@ -18,6 +18,7 @@ import io.github.jan.supabase.realtime.broadcastFlow import io.github.jan.supabase.realtime.channel import io.github.jan.supabase.realtime.postgresChangeFlow import io.github.jan.supabase.realtime.realtime +import io.github.jan.supabase.testing.TEST_JWT import io.github.jan.supabase.testing.assertPathIs import io.github.jan.supabase.testing.pathAfterVersion import io.github.jan.supabase.testing.toJsonElement @@ -142,7 +143,7 @@ class RealtimeChannelTest { @Test fun testSendingPayloadWithAuthJWT() { - val expectedAuthToken = "authToken" + val expectedAuthToken = TEST_JWT runTest { createTestClient( wsHandler = { i, _ -> diff --git a/Storage/src/commonTest/kotlin/StorageTest.kt b/Storage/src/commonTest/kotlin/StorageTest.kt index ab972775f..ddc538b62 100644 --- a/Storage/src/commonTest/kotlin/StorageTest.kt +++ b/Storage/src/commonTest/kotlin/StorageTest.kt @@ -5,6 +5,7 @@ import io.github.jan.supabase.auth.minimalSettings import io.github.jan.supabase.storage.Storage import io.github.jan.supabase.storage.resumable.MemoryResumableCache import io.github.jan.supabase.storage.storage +import io.github.jan.supabase.testing.TEST_JWT import io.github.jan.supabase.testing.assertMethodIs import io.github.jan.supabase.testing.assertPathIs import io.github.jan.supabase.testing.createMockedSupabaseClient @@ -193,7 +194,7 @@ class StorageTest { @Test fun testAuthHeaderWhenAuthInstalled() { runTest { - val key = "test-key" + val key = TEST_JWT val client = createMockedSupabaseClient( configuration = { install(Storage) { diff --git a/Supabase/src/commonMain/kotlin/io/github/jan/supabase/SupabaseClient.kt b/Supabase/src/commonMain/kotlin/io/github/jan/supabase/SupabaseClient.kt index 4d5a97d2f..02c40fffb 100644 --- a/Supabase/src/commonMain/kotlin/io/github/jan/supabase/SupabaseClient.kt +++ b/Supabase/src/commonMain/kotlin/io/github/jan/supabase/SupabaseClient.kt @@ -19,17 +19,17 @@ import io.ktor.client.engine.HttpClientEngine sealed interface SupabaseClient { /** - * The supabase url with either a http or https scheme. + * The Supabase url with either an HTTP or HTTPs scheme. */ val supabaseHttpUrl: String /** - * The base supabase url without any scheme + * The base Supabase url without any scheme */ val supabaseUrl: String /** - * The api key for interacting with the supabase api + * The api key for interacting with the Supabase API */ val supabaseKey: String @@ -39,7 +39,7 @@ sealed interface SupabaseClient { val pluginManager: PluginManager /** - * The http client used to interact with the Supabase api + * The http client used to interact with the Supabase API */ val httpClient: KtorSupabaseHttpClient @@ -59,6 +59,12 @@ sealed interface SupabaseClient { @SupabaseInternal val accessToken: AccessTokenProvider? + /** + * Whether the api key is a JWT token. This property only exists to not re-check the api key type every time it is needed. + */ + @SupabaseInternal + val isApiKeyJWT: Boolean + /** * Releases all resources held by the [httpClient] and all plugins the [pluginManager] */ @@ -110,6 +116,16 @@ internal class SupabaseClientImpl( "http://$supabaseUrl" } + override val isApiKeyJWT: Boolean = isJwt(supabaseKey) + + init { + if (!isApiKeyJWT) { + SupabaseClient.LOGGER.i { + "The Supabase API key is not a JWT token. It will not be used for authentication." + } + } + } + // override val coroutineContext = Dispatchers.Default + SupervisorJob() @OptIn(SupabaseInternal::class) diff --git a/Supabase/src/commonMain/kotlin/io/github/jan/supabase/Utils.kt b/Supabase/src/commonMain/kotlin/io/github/jan/supabase/Utils.kt index ff8d0c108..02711fd66 100644 --- a/Supabase/src/commonMain/kotlin/io/github/jan/supabase/Utils.kt +++ b/Supabase/src/commonMain/kotlin/io/github/jan/supabase/Utils.kt @@ -64,4 +64,21 @@ suspend inline fun HttpResponse.bodyOrNull(): T? { } catch(e: Exception) { null } +} + +val BASE64URL_REGEX = "^([a-z0-9_-]{4})*(\$|[a-z0-9_-]{3}\$|[a-z0-9_-]{2}\$)".toRegex(RegexOption.IGNORE_CASE) + +@SupabaseInternal +fun isJwt(value: String): Boolean { + val value = if(value.startsWith("Bearer ")) value.substring("Bearer ".length).trim() else value.trim() + if(value.isEmpty()) return false + + val parts = value.split(".") + + if(parts.size != 3) return false + + for(part in parts) { + if(part.length < 4 || !BASE64URL_REGEX.matches(part)) return false + } + return true } \ No newline at end of file diff --git a/Supabase/src/commonMain/kotlin/io/github/jan/supabase/network/KtorSupabaseHttpClient.kt b/Supabase/src/commonMain/kotlin/io/github/jan/supabase/network/KtorSupabaseHttpClient.kt index b86c9bf2f..c22a48196 100644 --- a/Supabase/src/commonMain/kotlin/io/github/jan/supabase/network/KtorSupabaseHttpClient.kt +++ b/Supabase/src/commonMain/kotlin/io/github/jan/supabase/network/KtorSupabaseHttpClient.kt @@ -5,6 +5,7 @@ import io.github.jan.supabase.BuildConfig import io.github.jan.supabase.SupabaseClient import io.github.jan.supabase.annotations.SupabaseInternal import io.github.jan.supabase.exceptions.HttpRequestException +import io.github.jan.supabase.isJwt import io.github.jan.supabase.logging.d import io.github.jan.supabase.logging.e import io.github.jan.supabase.supabaseJson @@ -55,6 +56,7 @@ class KtorSupabaseHttpClient @SupabaseInternal constructor( url(url) builder() } + checkAuthorizationHeader(request) val endPoint = request.url.encodedPath SupabaseClient.LOGGER.d { "Starting ${request.method.value} request to endpoint $endPoint" } @@ -100,6 +102,13 @@ class KtorSupabaseHttpClient @SupabaseInternal constructor( fun close() = httpClient.close() + private fun checkAuthorizationHeader(requestBuilder: HttpRequestBuilder) { + val authHeader = requestBuilder.headers["Authorization"] ?: return + if(!isJwt(authHeader.substringAfter("Bearer "))) { + error("The Authorization header must be a JWT token") + } + } + private fun HttpClientConfig<*>.applyDefaultConfiguration(modifiers: List.() -> Unit>) { install(DefaultRequest) { headers { diff --git a/plugins/ApolloGraphQL/src/commonMain/kotlin/io/github/jan/supabase/graphql/ApolloHttpInterceptor.kt b/plugins/ApolloGraphQL/src/commonMain/kotlin/io/github/jan/supabase/graphql/ApolloHttpInterceptor.kt index 608d37fd7..fdca2352a 100644 --- a/plugins/ApolloGraphQL/src/commonMain/kotlin/io/github/jan/supabase/graphql/ApolloHttpInterceptor.kt +++ b/plugins/ApolloGraphQL/src/commonMain/kotlin/io/github/jan/supabase/graphql/ApolloHttpInterceptor.kt @@ -16,9 +16,11 @@ internal class ApolloHttpInterceptor(private val supabaseClient: SupabaseClient, chain: HttpInterceptorChain ): ApolloHttpResponse { GraphQL.logger.d { "Intercepting Apollo request with url ${request.url}" } - val accessToken = supabaseClient.resolveAccessToken(config.jwtToken) ?: error("Access token should not be null") + val accessToken = supabaseClient.resolveAccessToken(config.jwtToken) val newRequest = request.newBuilder().apply { - addHeader(HttpHeaders.Authorization, "Bearer $accessToken") + accessToken?.let { + addHeader(HttpHeaders.Authorization, "Bearer $it") + } } return chain.proceed(newRequest.build()) } diff --git a/plugins/ApolloGraphQL/src/commonTest/kotlin/ApolloHttpInterceptorTest.kt b/plugins/ApolloGraphQL/src/commonTest/kotlin/ApolloHttpInterceptorTest.kt index 27d500de5..862f5cbde 100644 --- a/plugins/ApolloGraphQL/src/commonTest/kotlin/ApolloHttpInterceptorTest.kt +++ b/plugins/ApolloGraphQL/src/commonTest/kotlin/ApolloHttpInterceptorTest.kt @@ -11,6 +11,7 @@ import io.github.jan.supabase.auth.minimalSettings import io.github.jan.supabase.graphql.ApolloHttpInterceptor import io.github.jan.supabase.graphql.GraphQL import io.github.jan.supabase.graphql.graphql +import io.github.jan.supabase.testing.TEST_JWT import io.github.jan.supabase.testing.createMockedSupabaseClient import kotlinx.coroutines.test.runTest import kotlin.test.Test @@ -22,12 +23,12 @@ class ApolloHttpInterceptorTest { fun testApolloHttpInterceptorWithApiKey() { runTest { val supabaseClient = createMockedSupabaseClient( - supabaseKey = "testkey", + supabaseKey = TEST_JWT, configuration = { install(GraphQL) } ) - testInterceptor(supabaseClient, "testkey") + testInterceptor(supabaseClient, TEST_JWT) } } @@ -42,8 +43,8 @@ class ApolloHttpInterceptorTest { } } ) - supabaseClient.auth.importAuthToken("testtoken") - testInterceptor(supabaseClient, "testtoken") + supabaseClient.auth.importAuthToken(TEST_JWT) + testInterceptor(supabaseClient, TEST_JWT) } } @@ -54,11 +55,11 @@ class ApolloHttpInterceptorTest { configuration = { install(GraphQL) accessToken = { - "testtoken" + TEST_JWT } } ) - testInterceptor(supabaseClient, "testtoken") + testInterceptor(supabaseClient, TEST_JWT) } } @@ -68,11 +69,11 @@ class ApolloHttpInterceptorTest { val supabaseClient = createMockedSupabaseClient( configuration = { install(GraphQL) { - jwtToken = "testtoken" + jwtToken = TEST_JWT } } ) - testInterceptor(supabaseClient, "testtoken") + testInterceptor(supabaseClient, TEST_JWT) } } diff --git a/plugins/ApolloGraphQL/src/commonTest/kotlin/GraphQLTest.kt b/plugins/ApolloGraphQL/src/commonTest/kotlin/GraphQLTest.kt index bc9baf677..8b4a5c048 100644 --- a/plugins/ApolloGraphQL/src/commonTest/kotlin/GraphQLTest.kt +++ b/plugins/ApolloGraphQL/src/commonTest/kotlin/GraphQLTest.kt @@ -3,6 +3,7 @@ import io.github.jan.supabase.BuildConfig import io.github.jan.supabase.graphql.ApolloHttpInterceptor import io.github.jan.supabase.graphql.GraphQL import io.github.jan.supabase.graphql.graphql +import io.github.jan.supabase.testing.TEST_JWT import io.github.jan.supabase.testing.createMockedSupabaseClient import kotlin.test.Test import kotlin.test.assertContains @@ -16,7 +17,7 @@ class GraphQLTest { fun testCreatedGraphQLClient() { val supabaseClient = createMockedSupabaseClient( supabaseUrl = "https://test.supabase.co", - supabaseKey = "testkey", + supabaseKey = TEST_JWT, configuration = { install(GraphQL) { apolloConfiguration { @@ -28,7 +29,7 @@ class GraphQLTest { val client = supabaseClient.graphql.apolloClient assertEquals("https://test.supabase.co/graphql/v1", client.newBuilder().httpServerUrl) assertNotNull(client.httpHeaders) - assertContains(client.httpHeaders!!, HttpHeader("apikey", "testkey")) + assertContains(client.httpHeaders!!, HttpHeader("apikey", TEST_JWT)) assertContains(client.httpHeaders!!, HttpHeader("X-Client-Info", "supabase-kt/${BuildConfig.PROJECT_VERSION}")) assertTrue { client.newBuilder().httpInterceptors.any { it is ApolloHttpInterceptor } } assertEquals(1000, client.newBuilder().webSocketIdleTimeoutMillis) diff --git a/test-common/src/commonMain/kotlin/io/github/jan/supabase/testing/SupabaseClientMock.kt b/test-common/src/commonMain/kotlin/io/github/jan/supabase/testing/SupabaseClientMock.kt index 6ec774f9a..ddce9b3a3 100644 --- a/test-common/src/commonMain/kotlin/io/github/jan/supabase/testing/SupabaseClientMock.kt +++ b/test-common/src/commonMain/kotlin/io/github/jan/supabase/testing/SupabaseClientMock.kt @@ -11,7 +11,7 @@ import io.ktor.client.request.HttpResponseData fun createMockedSupabaseClient( supabaseUrl: String = "https://projectref.supabase.co", - supabaseKey: String = "project-anon-key", + supabaseKey: String = TEST_JWT, configuration: SupabaseClientBuilder.() -> Unit = {}, requestHandler: suspend MockRequestHandleScope.(HttpRequestData) -> HttpResponseData = { respond("") }, ): SupabaseClient { diff --git a/test-common/src/commonMain/kotlin/io/github/jan/supabase/testing/TestUtils.kt b/test-common/src/commonMain/kotlin/io/github/jan/supabase/testing/TestUtils.kt index c819d1986..8694a4652 100644 --- a/test-common/src/commonMain/kotlin/io/github/jan/supabase/testing/TestUtils.kt +++ b/test-common/src/commonMain/kotlin/io/github/jan/supabase/testing/TestUtils.kt @@ -3,6 +3,8 @@ package io.github.jan.supabase.testing import io.ktor.http.HttpMethod import kotlin.test.assertEquals +const val TEST_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" + fun assertMethodIs(expected: HttpMethod, actual: HttpMethod) { assertEquals(expected, actual, "Method should be $expected") }