From 13f615717e49be92016bb10f53230d7139653cdf Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 2 Dec 2023 17:46:36 +0100 Subject: [PATCH 01/12] Initial commit --- .../github/jan/supabase/gotrue/Utils.apple.kt | 9 ++++++++ .../io/github/jan/supabase/gotrue/Auth.kt | 12 +++++++++- .../io/github/jan/supabase/gotrue/AuthImpl.kt | 22 +++++++++++++++---- .../io/github/jan/supabase/gotrue/Utils.kt | 5 ++++- .../jan/supabase/gotrue/user/Identity.kt | 13 ++++++----- .../io/github/jan/supabase/gotrue/Utils.js.kt | 8 +++++++ .../github/jan/supabase/gotrue/Utils.jvm.kt | 14 ++++++++++++ .../github/jan/supabase/gotrue/Utils.linux.kt | 8 +++++++ .../github/jan/supabase/gotrue/Utils.mingw.kt | 11 ++++++++++ 9 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/Utils.apple.kt create mode 100644 GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/Utils.js.kt create mode 100644 GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.jvm.kt create mode 100644 GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/Utils.linux.kt create mode 100644 GoTrue/src/mingwMain/kotlin/io/github/jan/supabase/gotrue/Utils.mingw.kt diff --git a/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/Utils.apple.kt b/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/Utils.apple.kt new file mode 100644 index 00000000..fcf16f8e --- /dev/null +++ b/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/Utils.apple.kt @@ -0,0 +1,9 @@ +package io.github.jan.supabase.gotrue + +import io.github.jan.supabase.SupabaseClient +import io.github.jan.supabase.gotrue.providers.openUrl +import platform.Foundation.NSURL + +internal actual suspend fun SupabaseClient.openExternalUrl(url: String) { + openUrl(NSURL(url)) +} \ No newline at end of file diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt index 06db6178..a167a1c0 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt @@ -125,6 +125,16 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { config: (C.() -> Unit)? = null ) + suspend fun linkIdentity( + provider: OAuthProvider, + redirectUrl: String? = null, + config: ExternalAuthConfigDefaults.() -> Unit = {} + ) + + suspend fun unlinkIdentity( + identityId: String + ) + /** * Retrieves the sso url for the specified [type] * @param redirectUrl The redirect url to use @@ -294,7 +304,7 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { * @param provider The provider to use * @param redirectUrl The redirect url to use */ - fun oAuthUrl(provider: OAuthProvider, redirectUrl: String? = null, additionalConfig: ExternalAuthConfigDefaults.() -> Unit = {}): String + fun oAuthUrl(provider: OAuthProvider, redirectUrl: String? = null, url: String = "authorize", additionalConfig: ExternalAuthConfigDefaults.() -> Unit = {}): String /** * Stops auto-refreshing the current session diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt index 36dbb5c1..fa6ac514 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt @@ -110,6 +110,19 @@ internal class AuthImpl( importSession(it) }, redirectUrl, config) + override suspend fun linkIdentity( + provider: OAuthProvider, + redirectUrl: String?, + config: ExternalAuthConfigDefaults.() -> Unit + ) { + val url = oAuthUrl(provider, redirectUrl, "user/identities/authorize", config) + supabaseClient.openExternalUrl(url) //TODO: Add server callback on the JVM + } + + override suspend fun unlinkIdentity(identityId: String) { + TODO("Not yet implemented") + } + override suspend fun retrieveSSOUrl( redirectUrl: String?, config: SSO.Config.() -> Unit @@ -141,10 +154,10 @@ internal class AuthImpl( put("code_challenge", it) put("code_challenge_method", "s256") } - createdConfig?.domain.let { + createdConfig.domain?.let { put("domain", it) } - createdConfig?.providerId.let { + createdConfig.providerId?.let { put("provider_id", it) } }).body() @@ -184,7 +197,7 @@ internal class AuthImpl( return userInfo } - suspend fun resend(type: String, body: JsonObjectBuilder.() -> Unit) { + private suspend fun resend(type: String, body: JsonObjectBuilder.() -> Unit) { api.postJson("resend", buildJsonObject { put("type", type) putJsonObject(buildJsonObject(body)) @@ -459,6 +472,7 @@ internal class AuthImpl( override fun oAuthUrl( provider: OAuthProvider, redirectUrl: String?, + url: String, additionalConfig: ExternalAuthConfigDefaults.() -> Unit ): String { val config = ExternalAuthConfigDefaults().apply(additionalConfig) @@ -471,7 +485,7 @@ internal class AuthImpl( config.queryParams["code_challenge_method"] = "S256" } return resolveUrl(buildString { - append("authorize?provider=${provider.name}&redirect_to=$redirectUrl") + append("$url?provider=${provider.name}&redirect_to=$redirectUrl") if (config.scopes.isNotEmpty()) append("&scopes=${config.scopes.joinToString("+")}") if (config.queryParams.isNotEmpty()) { for ((key, value) in config.queryParams) { diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt index 63fb0993..bc207b29 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt @@ -1,6 +1,7 @@ package io.github.jan.supabase.gotrue import co.touchlab.kermit.Logger +import io.github.jan.supabase.SupabaseClient import io.github.jan.supabase.annotations.SupabaseInternal import io.github.jan.supabase.gotrue.user.UserSession import io.ktor.client.request.HttpRequestBuilder @@ -24,4 +25,6 @@ fun HttpRequestBuilder.redirectTo(url: String) { this.url.parameters["redirect_to"] = url } -internal fun invalidArg(message: String): Nothing = throw IllegalArgumentException(message) \ No newline at end of file +internal fun invalidArg(message: String): Nothing = throw IllegalArgumentException(message) + +internal expect suspend fun SupabaseClient.openExternalUrl(url: String) \ No newline at end of file diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/user/Identity.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/user/Identity.kt index c70aa527..a7c3ce72 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/user/Identity.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/user/Identity.kt @@ -5,21 +5,24 @@ package io.github.jan.supabase.gotrue.user import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject @Serializable data class Identity( - @SerialName("created_at") - val createdAt: String, @SerialName("id") val id: String, @SerialName("identity_data") - val identityData: Map, + val identityData: JsonObject, + @SerialName("identity_id") + val identityId: String, @SerialName("last_sign_in_at") val lastSignInAt: String? = null, + @SerialName("updated_at") + val updatedAt: String? = null, + @SerialName("created_at") + val createdAt: String? = null, @SerialName("provider") val provider: String, - @SerialName("updated_at") - val updatedAt: String, @SerialName("user_id") val userId: String ) \ No newline at end of file diff --git a/GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/Utils.js.kt b/GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/Utils.js.kt new file mode 100644 index 00000000..cec38b30 --- /dev/null +++ b/GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/Utils.js.kt @@ -0,0 +1,8 @@ +package io.github.jan.supabase.gotrue + +import io.github.jan.supabase.SupabaseClient +import kotlinx.browser.window + +internal actual suspend fun SupabaseClient.openExternalUrl(url: String) { + window.location.href = url +} \ No newline at end of file diff --git a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.jvm.kt b/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.jvm.kt new file mode 100644 index 00000000..164b4895 --- /dev/null +++ b/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.jvm.kt @@ -0,0 +1,14 @@ +package io.github.jan.supabase.gotrue + +import io.github.jan.supabase.SupabaseClient +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import java.awt.Desktop +import java.net.URI + +internal actual suspend fun SupabaseClient.openExternalUrl(url: String) { + withContext(Dispatchers.IO) { + Desktop.getDesktop() + .browse(URI(url)) + } +} \ No newline at end of file diff --git a/GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/Utils.linux.kt b/GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/Utils.linux.kt new file mode 100644 index 00000000..4580f900 --- /dev/null +++ b/GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/Utils.linux.kt @@ -0,0 +1,8 @@ +package io.github.jan.supabase.gotrue + +import io.github.jan.supabase.SupabaseClient +import platform.posix.system + +internal actual suspend fun SupabaseClient.openExternalUrl(url: String) { + system("xdg-open $url") +} \ No newline at end of file diff --git a/GoTrue/src/mingwMain/kotlin/io/github/jan/supabase/gotrue/Utils.mingw.kt b/GoTrue/src/mingwMain/kotlin/io/github/jan/supabase/gotrue/Utils.mingw.kt new file mode 100644 index 00000000..b741c818 --- /dev/null +++ b/GoTrue/src/mingwMain/kotlin/io/github/jan/supabase/gotrue/Utils.mingw.kt @@ -0,0 +1,11 @@ +package io.github.jan.supabase.gotrue + +import io.github.jan.supabase.SupabaseClient +import kotlinx.cinterop.ExperimentalForeignApi +import platform.windows.SW_SHOWNORMAL +import platform.windows.ShellExecuteW + +@OptIn(ExperimentalForeignApi::class) +internal actual suspend fun SupabaseClient.openExternalUrl(url: String) { + ShellExecuteW(null, "open", url, null, null, SW_SHOWNORMAL); +} \ No newline at end of file From 590dc2fc92f7d18286e01a55e99d157939cc5c52 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 2 Dec 2023 17:57:31 +0100 Subject: [PATCH 02/12] Add unlinking --- .../kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt | 11 +++++++++-- .../io/github/jan/supabase/gotrue/user/Identity.kt | 3 +-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt index fa6ac514..493157eb 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt @@ -27,6 +27,7 @@ import io.ktor.client.call.body import io.ktor.client.request.parameter import io.ktor.client.statement.HttpResponse import io.ktor.client.statement.bodyAsText +import io.ktor.http.HttpMethod import io.ktor.http.HttpStatusCode import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -37,10 +38,12 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.datetime.Clock +import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObjectBuilder import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.encodeToJsonElement import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.put import kotlinx.serialization.json.putJsonObject import kotlin.math.floor @@ -116,11 +119,15 @@ internal class AuthImpl( config: ExternalAuthConfigDefaults.() -> Unit ) { val url = oAuthUrl(provider, redirectUrl, "user/identities/authorize", config) - supabaseClient.openExternalUrl(url) //TODO: Add server callback on the JVM + val data = api.rawRequest(url) { + method = HttpMethod.Get + }.body() + val newUrl = data["url"]?.jsonPrimitive?.content ?: error("No url found in response") + supabaseClient.openExternalUrl(newUrl) //TODO: Add server callback on JVM and fix Android } override suspend fun unlinkIdentity(identityId: String) { - TODO("Not yet implemented") + api.delete("user/identities/${identityId}") } override suspend fun retrieveSSOUrl( diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/user/Identity.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/user/Identity.kt index a7c3ce72..d6f1d71b 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/user/Identity.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/user/Identity.kt @@ -4,7 +4,6 @@ package io.github.jan.supabase.gotrue.user import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject @Serializable @@ -14,7 +13,7 @@ data class Identity( @SerialName("identity_data") val identityData: JsonObject, @SerialName("identity_id") - val identityId: String, + val identityId: String? = null, @SerialName("last_sign_in_at") val lastSignInAt: String? = null, @SerialName("updated_at") From 089e550b91c79930e28b1b40ea9f24df1a819662 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 2 Dec 2023 22:48:50 +0100 Subject: [PATCH 03/12] Refactor opening urls --- GoTrue/build.gradle.kts | 10 +++- .../github/jan/supabase/gotrue/RedirectUrl.kt | 15 +++--- .../supabase/gotrue/compose/ComposeUtils.kt | 2 - .../github/jan/supabase/gotrue/RedirectUrl.kt | 15 +++--- .../gotrue/providers/OAuthProvider.kt | 48 ------------------- .../gotrue/providers/builtin/loginWithSSO.kt | 20 -------- .../io/github/jan/supabase/gotrue/Auth.kt | 14 +++--- .../io/github/jan/supabase/gotrue/AuthImpl.kt | 3 +- .../github/jan/supabase/gotrue/RedirectUrl.kt | 2 +- .../gotrue/providers/ExternalAuthConfig.kt | 2 +- .../providers/builtin/DefaultAuthProvider.kt | 7 +-- .../supabase/gotrue/providers/builtin/OTP.kt | 4 +- .../github/jan/supabase/gotrue/RedirectUrl.kt | 4 +- .../gotrue/providers/builtin/loginWithSSO.kt | 16 ------- .../github/jan/supabase/gotrue/RedirectUrl.kt | 2 +- .../gotrue/providers/OAuthProvider.kt | 18 +++---- .../gotrue/providers/builtin/loginWithSSO.kt | 16 +++++-- .../supabase/gotrue/generateRedirectUrl.kt | 2 +- .../gotrue/providers/OAuthProvider.kt | 41 ---------------- .../supabase/gotrue/generateRedirectUrl.kt | 2 +- .../gotrue/providers/OAuthProvider.kt | 43 ----------------- .../gotrue/providers/builtin/loginWithSSO.kt | 19 -------- .../gotrue/providers/OAuthProvider.nonJvm.kt} | 16 +++---- .../supabase/gotrue/providers/builtin/SSO.kt} | 4 +- 24 files changed, 69 insertions(+), 256 deletions(-) delete mode 100644 GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/compose/ComposeUtils.kt delete mode 100644 GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt delete mode 100644 GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt delete mode 100644 GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt delete mode 100644 GoTrue/src/mingwX64Main/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt delete mode 100644 GoTrue/src/mingwX64Main/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt rename GoTrue/src/{jsMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt => nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.nonJvm.kt} (70%) rename GoTrue/src/{linuxMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt => nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/SSO.kt} (82%) diff --git a/GoTrue/build.gradle.kts b/GoTrue/build.gradle.kts index 94484678..5b063822 100644 --- a/GoTrue/build.gradle.kts +++ b/GoTrue/build.gradle.kts @@ -63,6 +63,9 @@ kotlin { // api(libs.cache4k) } } + val nonJvmMain by creating { + dependsOn(commonMain) + } val nonLinuxMain by creating { dependsOn(commonMain) dependencies { @@ -89,14 +92,19 @@ kotlin { } val mingwX64Main by getting { dependsOn(nonLinuxMain) + dependsOn(nonJvmMain) } val appleMain by getting { dependsOn(nonLinuxMain) + dependsOn(nonJvmMain) } val jsMain by getting { dependsOn(nonLinuxMain) + dependsOn(nonJvmMain) + } + val linuxMain by getting { + dependsOn(nonJvmMain) } - val linuxMain by getting } } diff --git a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt index 7ce0a8d1..ae5008e8 100644 --- a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt +++ b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt @@ -3,17 +3,18 @@ package io.github.jan.supabase.gotrue import io.github.jan.supabase.annotations.SupabaseInternal @SupabaseInternal -actual fun Auth.generateRedirectUrl(fallbackUrl: String?): String? { - if(fallbackUrl != null) return fallbackUrl - val scheme = config.scheme ?: return null - val host = config.host ?: return null - this as AuthImpl - return "${scheme}://${host}" -} +actual fun Auth.generateRedirectUrl(): String? = config.deepLinkOrNull internal val AuthConfig.deepLink: String get() { val scheme = scheme ?: noDeeplinkError("scheme") val host = host ?: noDeeplinkError("host") return "${scheme}://${host}" + } + +internal val AuthConfig.deepLinkOrNull: String? + get() { + val scheme = scheme ?: return null + val host = host ?: return null + return "${scheme}://${host}" } \ No newline at end of file diff --git a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/compose/ComposeUtils.kt b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/compose/ComposeUtils.kt deleted file mode 100644 index 1dbf54f9..00000000 --- a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/compose/ComposeUtils.kt +++ /dev/null @@ -1,2 +0,0 @@ -package io.github.jan.supabase.gotrue.compose - diff --git a/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt b/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt index 7ce0a8d1..2b371da6 100644 --- a/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt +++ b/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt @@ -3,17 +3,18 @@ package io.github.jan.supabase.gotrue import io.github.jan.supabase.annotations.SupabaseInternal @SupabaseInternal -actual fun Auth.generateRedirectUrl(fallbackUrl: String?): String? { - if(fallbackUrl != null) return fallbackUrl - val scheme = config.scheme ?: return null - val host = config.host ?: return null - this as AuthImpl - return "${scheme}://${host}" -} +actual fun Auth.defaultRedirectUrl(): String? = config.deepLinkOrNull internal val AuthConfig.deepLink: String get() { val scheme = scheme ?: noDeeplinkError("scheme") val host = host ?: noDeeplinkError("host") return "${scheme}://${host}" + } + +internal val AuthConfig.deepLinkOrNull: String? + get() { + val scheme = scheme ?: return null + val host = host ?: return null + return "${scheme}://${host}" } \ No newline at end of file diff --git a/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt b/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt index 20d42514..cabdc494 100644 --- a/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt +++ b/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt @@ -1,53 +1,5 @@ package io.github.jan.supabase.gotrue.providers -import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.deepLink -import io.github.jan.supabase.gotrue.user.UserSession import platform.Foundation.NSURL -/** - * Represents an OAuth provider. - */ -actual abstract class OAuthProvider : AuthProvider { - - /** - * The name of the provider. - */ - actual abstract val name: String - - actual override suspend fun login( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (ExternalAuthConfig.() -> Unit)? - ) { - val externalConfig = ExternalAuthConfig().apply(config ?: {}) - openOAuth(redirectUrl, supabaseClient, externalConfig) - } - - actual override suspend fun signUp( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (ExternalAuthConfig.() -> Unit)? - ) = login(supabaseClient, onSuccess, redirectUrl, config = config) - - private fun openOAuth( - redirectUrl: String? = null, - supabaseClient: SupabaseClient, - externalConfig: ExternalAuthConfig - ) { - val gotrue = supabaseClient.auth - val url = NSURL(string = supabaseClient.auth.oAuthUrl(this, redirectUrl ?: gotrue.config.deepLink) { - scopes.addAll(externalConfig.scopes) - queryParams.putAll(externalConfig.queryParams) - }) - openUrl(url) - } - - actual companion object - -} - internal expect fun openUrl(url: NSURL) \ No newline at end of file diff --git a/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt b/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt deleted file mode 100644 index 23ffd7f0..00000000 --- a/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt +++ /dev/null @@ -1,20 +0,0 @@ -package io.github.jan.supabase.gotrue.providers.builtin - -import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.deepLink -import io.github.jan.supabase.gotrue.providers.openUrl -import io.github.jan.supabase.gotrue.user.UserSession -import platform.Foundation.NSURL - -internal actual suspend fun SSO.loginWithSSO( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (SSO.Config.() -> Unit)? -) { - val auth = supabaseClient.auth - val result = supabaseClient.auth.retrieveSSOUrl(redirectUrl ?: auth.config.deepLink) { config?.invoke(this) } - val url = NSURL(string = result.url) - openUrl(url) -} \ No newline at end of file diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt index a167a1c0..46d94371 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt @@ -95,7 +95,7 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { */ suspend fun > signUpWith( provider: Provider, - redirectUrl: String? = null, + redirectUrl: String? = supabaseClient.defaultRedirectUrl(), config: (C.() -> Unit)? = null ): R? @@ -121,13 +121,13 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { */ suspend fun > signInWith( provider: Provider, - redirectUrl: String? = null, + redirectUrl: String? = supabaseClient.defaultRedirectUrl(), config: (C.() -> Unit)? = null ) suspend fun linkIdentity( provider: OAuthProvider, - redirectUrl: String? = null, + redirectUrl: String? = supabaseClient.defaultRedirectUrl(), config: ExternalAuthConfigDefaults.() -> Unit = {} ) @@ -140,7 +140,7 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { * @param redirectUrl The redirect url to use * @param config The configuration to use */ - suspend fun retrieveSSOUrl(redirectUrl: String? = null, config: SSO.Config.() -> Unit): SSO.Result + suspend fun retrieveSSOUrl(redirectUrl: String? = supabaseClient.defaultRedirectUrl(), config: SSO.Config.() -> Unit): SSO.Result /** * Modifies the current user @@ -152,7 +152,7 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { */ suspend fun modifyUser( updateCurrentUser: Boolean = true, - redirectUrl: String? = null, + redirectUrl: String? = supabaseClient.defaultRedirectUrl(), config: UserUpdateBuilder.() -> Unit ): UserInfo @@ -186,7 +186,7 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { * @throws HttpRequestTimeoutException if the request timed out * @throws HttpRequestException on network related issues */ - suspend fun sendRecoveryEmail(email: String, redirectUrl: String? = null, captchaToken: String? = null) + suspend fun sendRecoveryEmail(email: String, redirectUrl: String? = supabaseClient.defaultRedirectUrl(), captchaToken: String? = null) /** * Sends a nonce to the user's email (preferred) or phone @@ -304,7 +304,7 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { * @param provider The provider to use * @param redirectUrl The redirect url to use */ - fun oAuthUrl(provider: OAuthProvider, redirectUrl: String? = null, url: String = "authorize", additionalConfig: ExternalAuthConfigDefaults.() -> Unit = {}): String + fun oAuthUrl(provider: OAuthProvider, redirectUrl: String? = defaultRedirectUrl(), url: String = "authorize", additionalConfig: ExternalAuthConfigDefaults.() -> Unit = {}): String /** * Stops auto-refreshing the current session diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt index 493157eb..074e459e 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt @@ -239,7 +239,6 @@ internal class AuthImpl( redirectUrl: String?, captchaToken: String? ) { - val finalRedirectUrl = generateRedirectUrl(redirectUrl) val body = buildJsonObject { put("email", email) captchaToken?.let { @@ -249,7 +248,7 @@ internal class AuthImpl( } }.toString() api.postJson("recover", body) { - finalRedirectUrl?.let { url.encodedParameters.append("redirect_to", it) } + redirectUrl?.let { url.encodedParameters.append("redirect_to", it) } } } diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt index bdb94591..0aec2e8d 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt @@ -3,4 +3,4 @@ package io.github.jan.supabase.gotrue import io.github.jan.supabase.annotations.SupabaseInternal @SupabaseInternal -expect fun Auth.generateRedirectUrl(fallbackUrl: String?): String? \ No newline at end of file +expect fun Auth.defaultRedirectUrl(): String? \ No newline at end of file diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/ExternalAuthConfig.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/ExternalAuthConfig.kt index 04e2878b..3a7c89a2 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/ExternalAuthConfig.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/ExternalAuthConfig.kt @@ -3,7 +3,7 @@ package io.github.jan.supabase.gotrue.providers /** * Configuration for external authentication providers like Google, Twitter, etc. */ -expect class ExternalAuthConfig: ExternalAuthConfigDefaults +expect class ExternalAuthConfig(): ExternalAuthConfigDefaults /** * The default values for [ExternalAuthConfig] diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/DefaultAuthProvider.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/DefaultAuthProvider.kt index af744705..7267f22a 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/DefaultAuthProvider.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/DefaultAuthProvider.kt @@ -8,7 +8,6 @@ import io.github.jan.supabase.gotrue.FlowType import io.github.jan.supabase.gotrue.auth import io.github.jan.supabase.gotrue.generateCodeChallenge import io.github.jan.supabase.gotrue.generateCodeVerifier -import io.github.jan.supabase.gotrue.generateRedirectUrl import io.github.jan.supabase.gotrue.providers.AuthProvider import io.github.jan.supabase.gotrue.redirectTo import io.github.jan.supabase.gotrue.user.UserSession @@ -56,11 +55,10 @@ sealed interface DefaultAuthProvider : AuthProvider { ) { require(config != null) { "Credentials are required" } val encodedCredentials = encodeCredentials(config) - val finalRedirectUrl = supabaseClient.auth.generateRedirectUrl(redirectUrl) val gotrue = supabaseClient.auth as AuthImpl val url = "token?grant_type=$grantType" val response = gotrue.api.postJson(url, encodedCredentials) { - finalRedirectUrl?.let { redirectTo(it) } + redirectUrl?.let { redirectTo(it) } } response.body().also { onSuccess(it) @@ -75,7 +73,6 @@ sealed interface DefaultAuthProvider : AuthProvider { config: (C.() -> Unit)? ): R? { require(config != null) { "Credentials are required" } - val finalRedirectUrl = supabaseClient.auth.generateRedirectUrl(redirectUrl) val body = encodeCredentials(config) val gotrue = supabaseClient.auth as AuthImpl var codeChallenge: String? = null @@ -96,7 +93,7 @@ sealed interface DefaultAuthProvider : AuthProvider { put("code_challenge_method", "s256") } }) { - finalRedirectUrl?.let { redirectTo(it) } + redirectUrl?.let { redirectTo(it) } } val json = response.body() if(json.containsKey("access_token")) { diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/OTP.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/OTP.kt index 6a521862..cfd5fc01 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/OTP.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/OTP.kt @@ -9,7 +9,6 @@ import io.github.jan.supabase.gotrue.FlowType import io.github.jan.supabase.gotrue.auth import io.github.jan.supabase.gotrue.generateCodeChallenge import io.github.jan.supabase.gotrue.generateCodeVerifier -import io.github.jan.supabase.gotrue.generateRedirectUrl import io.github.jan.supabase.gotrue.providers.AuthProvider import io.github.jan.supabase.gotrue.user.UserSession import io.github.jan.supabase.putJsonObject @@ -65,7 +64,6 @@ data object OTP: AuthProvider { require((otpConfig.email != null && otpConfig.email!!.isNotBlank()) || (otpConfig.phone != null && otpConfig.phone!!.isNotBlank())) { "You need to provide either an email or a phone number" } require(!(otpConfig.email != null && otpConfig.phone != null)) { "You can only provide either an email or a phone number" } - val finalRedirectUrl = supabaseClient.auth.generateRedirectUrl(redirectUrl) val body = buildJsonObject { put("create_user", otpConfig.createUser) otpConfig.data?.let { @@ -90,7 +88,7 @@ data object OTP: AuthProvider { put("code_challenge_method", "s256") } }) { - finalRedirectUrl?.let { url.parameters.append("redirect_to", it) } + redirectUrl?.let { url.parameters.append("redirect_to", it) } } } diff --git a/GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt b/GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt index e13aa7ac..9940d023 100644 --- a/GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt +++ b/GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt @@ -4,6 +4,4 @@ import io.github.jan.supabase.annotations.SupabaseInternal import kotlinx.browser.window @SupabaseInternal -actual fun Auth.generateRedirectUrl(fallbackUrl: String?): String? { - return window.location.origin -} \ No newline at end of file +actual fun Auth.defaultRedirectUrl(): String? = window.location.origin \ No newline at end of file diff --git a/GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt b/GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt deleted file mode 100644 index 68f8c9c9..00000000 --- a/GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt +++ /dev/null @@ -1,16 +0,0 @@ -package io.github.jan.supabase.gotrue.providers.builtin - -import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.user.UserSession -import kotlinx.browser.window - -internal actual suspend fun SSO.loginWithSSO( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (SSO.Config.() -> Unit)? -) { - val result = supabaseClient.auth.retrieveSSOUrl(redirectUrl ?: window.location.origin) { config?.invoke(this) } - window.location.href = result.url -} \ No newline at end of file diff --git a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt b/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt index f15b15ac..3b09669b 100644 --- a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt +++ b/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt @@ -3,4 +3,4 @@ package io.github.jan.supabase.gotrue import io.github.jan.supabase.annotations.SupabaseInternal @SupabaseInternal -actual fun Auth.generateRedirectUrl(fallbackUrl: String?): String? = fallbackUrl \ No newline at end of file +actual fun Auth.defaultRedirectUrl(): String? = null \ No newline at end of file diff --git a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt b/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt index d753bd57..d99cae61 100644 --- a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt +++ b/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt @@ -2,18 +2,16 @@ package io.github.jan.supabase.gotrue.providers import io.github.jan.supabase.SupabaseClient import io.github.jan.supabase.gotrue.auth +import io.github.jan.supabase.gotrue.openExternalUrl import io.github.jan.supabase.gotrue.user.UserSession import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import java.awt.Desktop -import java.net.URI /** * Represents an OAuth provider. */ -actual abstract class OAuthProvider : AuthProvider { - +actual abstract class OAuthProvider actual constructor() : AuthProvider { /** * The name of the provider. */ @@ -28,11 +26,10 @@ actual abstract class OAuthProvider : AuthProvider { val externalConfig = ExternalAuthConfig().apply { config?.invoke(this) } withContext(Dispatchers.IO) { if(redirectUrl != null) { - Desktop.getDesktop() - .browse(URI(supabaseClient.auth.oAuthUrl(this@OAuthProvider, redirectUrl) { - scopes.addAll(externalConfig.scopes) - queryParams.putAll(externalConfig.queryParams) - })) + supabaseClient.openExternalUrl(supabaseClient.auth.oAuthUrl(this@OAuthProvider, redirectUrl) { + scopes.addAll(externalConfig.scopes) + queryParams.putAll(externalConfig.queryParams) + }) return@withContext } launch { @@ -51,9 +48,8 @@ actual abstract class OAuthProvider : AuthProvider { onSuccess: suspend (UserSession) -> Unit, redirectUrl: String?, config: (ExternalAuthConfig.() -> Unit)? - ) = login(supabaseClient, onSuccess, redirectUrl, config = config) + ) = login(supabaseClient, onSuccess, redirectUrl, config) actual companion object - } \ No newline at end of file diff --git a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt b/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt index d296a655..0389c052 100644 --- a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt +++ b/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt @@ -2,6 +2,7 @@ package io.github.jan.supabase.gotrue.providers.builtin import io.github.jan.supabase.SupabaseClient import io.github.jan.supabase.gotrue.auth +import io.github.jan.supabase.gotrue.openExternalUrl import io.github.jan.supabase.gotrue.providers.createServer import io.github.jan.supabase.gotrue.user.UserSession import kotlinx.coroutines.Dispatchers @@ -15,11 +16,16 @@ internal actual suspend fun SSO.loginWithSSO( config: (SSO.Config.() -> Unit)? ) { withContext(Dispatchers.IO) { - launch { - createServer({ - val result = supabaseClient.auth.retrieveSSOUrl(redirectUrl ?: it) { config?.invoke(this) } - result.url - }, supabaseClient.auth, onSuccess) + if(redirectUrl == null) { + launch { + createServer({ + val result = supabaseClient.auth.retrieveSSOUrl(it) { config?.invoke(this) } + result.url + }, supabaseClient.auth, onSuccess) + } + } else { + val result = supabaseClient.auth.retrieveSSOUrl(redirectUrl) { config?.invoke(this) } + supabaseClient.openExternalUrl(result.url) } } } \ No newline at end of file diff --git a/GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/generateRedirectUrl.kt b/GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/generateRedirectUrl.kt index f15b15ac..3b09669b 100644 --- a/GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/generateRedirectUrl.kt +++ b/GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/generateRedirectUrl.kt @@ -3,4 +3,4 @@ package io.github.jan.supabase.gotrue import io.github.jan.supabase.annotations.SupabaseInternal @SupabaseInternal -actual fun Auth.generateRedirectUrl(fallbackUrl: String?): String? = fallbackUrl \ No newline at end of file +actual fun Auth.defaultRedirectUrl(): String? = null \ No newline at end of file diff --git a/GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt b/GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt deleted file mode 100644 index bf382e5f..00000000 --- a/GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.jan.supabase.gotrue.providers - -import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.user.UserSession -import platform.posix.system - -/** - * Represents an OAuth provider. - */ -actual abstract class OAuthProvider : AuthProvider { - - /** - * The name of the provider. - */ - actual abstract val name: String - - actual override suspend fun login( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (ExternalAuthConfig.() -> Unit)? - ) { - val externalConfig = ExternalAuthConfig().apply { config?.invoke(this) } - val url = supabaseClient.auth.oAuthUrl(this@OAuthProvider, redirectUrl) { - scopes.addAll(externalConfig.scopes) - queryParams.putAll(externalConfig.queryParams) - } - system("xdg-open $url") - } - - actual override suspend fun signUp( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (ExternalAuthConfig.() -> Unit)? - ) = login(supabaseClient, onSuccess, redirectUrl, config = config) - - actual companion object - -} \ No newline at end of file diff --git a/GoTrue/src/mingwX64Main/kotlin/io/github/jan/supabase/gotrue/generateRedirectUrl.kt b/GoTrue/src/mingwX64Main/kotlin/io/github/jan/supabase/gotrue/generateRedirectUrl.kt index f15b15ac..3b09669b 100644 --- a/GoTrue/src/mingwX64Main/kotlin/io/github/jan/supabase/gotrue/generateRedirectUrl.kt +++ b/GoTrue/src/mingwX64Main/kotlin/io/github/jan/supabase/gotrue/generateRedirectUrl.kt @@ -3,4 +3,4 @@ package io.github.jan.supabase.gotrue import io.github.jan.supabase.annotations.SupabaseInternal @SupabaseInternal -actual fun Auth.generateRedirectUrl(fallbackUrl: String?): String? = fallbackUrl \ No newline at end of file +actual fun Auth.defaultRedirectUrl(): String? = null \ No newline at end of file diff --git a/GoTrue/src/mingwX64Main/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt b/GoTrue/src/mingwX64Main/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt deleted file mode 100644 index abeb495d..00000000 --- a/GoTrue/src/mingwX64Main/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.github.jan.supabase.gotrue.providers - -import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.user.UserSession -import kotlinx.cinterop.ExperimentalForeignApi -import platform.windows.SW_SHOWNORMAL -import platform.windows.ShellExecuteW - -/** - * Represents an OAuth provider. - */ -@OptIn(ExperimentalForeignApi::class) -actual abstract class OAuthProvider actual constructor() : AuthProvider { - /** - * The name of the provider. - */ - actual abstract val name: String - - actual override suspend fun login( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (ExternalAuthConfig.() -> Unit)? - ) { - val externalConfig = ExternalAuthConfig().apply { config?.invoke(this) } - val url = supabaseClient.auth.oAuthUrl(this@OAuthProvider, redirectUrl) { - scopes.addAll(externalConfig.scopes) - queryParams.putAll(externalConfig.queryParams) - } - ShellExecuteW(null, "open", url, null, null, SW_SHOWNORMAL); - } - - actual override suspend fun signUp( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (ExternalAuthConfig.() -> Unit)? - ) = login(supabaseClient, onSuccess, redirectUrl, config = config) - - actual companion object - -} \ No newline at end of file diff --git a/GoTrue/src/mingwX64Main/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt b/GoTrue/src/mingwX64Main/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt deleted file mode 100644 index 084863d4..00000000 --- a/GoTrue/src/mingwX64Main/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt +++ /dev/null @@ -1,19 +0,0 @@ -package io.github.jan.supabase.gotrue.providers.builtin - -import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.user.UserSession -import kotlinx.cinterop.ExperimentalForeignApi -import platform.windows.SW_SHOWNORMAL -import platform.windows.ShellExecuteW - -@OptIn(ExperimentalForeignApi::class) -internal actual suspend fun SSO.loginWithSSO( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (SSO.Config.() -> Unit)? -) { - val result = supabaseClient.auth.retrieveSSOUrl(redirectUrl) { config?.invoke(this) } - ShellExecuteW(null, "open", result.url, null, null, SW_SHOWNORMAL); -} \ No newline at end of file diff --git a/GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt b/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.nonJvm.kt similarity index 70% rename from GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt rename to GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.nonJvm.kt index 2dff6dea..ce4a0067 100644 --- a/GoTrue/src/jsMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt +++ b/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.nonJvm.kt @@ -2,14 +2,13 @@ package io.github.jan.supabase.gotrue.providers import io.github.jan.supabase.SupabaseClient import io.github.jan.supabase.gotrue.auth +import io.github.jan.supabase.gotrue.openExternalUrl import io.github.jan.supabase.gotrue.user.UserSession -import kotlinx.browser.window /** * Represents an OAuth provider. */ actual abstract class OAuthProvider actual constructor() : AuthProvider { - /** * The name of the provider. */ @@ -21,13 +20,14 @@ actual abstract class OAuthProvider actual constructor() : AuthProvider Unit)? ) { - val authConfig = ExternalAuthConfig().apply { + val builtConfig = ExternalAuthConfig().apply { config?.invoke(this) } - window.location.href = supabaseClient.auth.oAuthUrl(this, redirectUrl ?: authConfig.redirectUrl) { - scopes.addAll(authConfig.scopes) - queryParams.putAll(authConfig.queryParams) + val url = supabaseClient.auth.oAuthUrl(this, redirectUrl) { + scopes.addAll(builtConfig.scopes) + queryParams.putAll(builtConfig.queryParams) } + supabaseClient.openExternalUrl(url) } actual override suspend fun signUp( @@ -35,9 +35,7 @@ actual abstract class OAuthProvider actual constructor() : AuthProvider Unit, redirectUrl: String?, config: (ExternalAuthConfig.() -> Unit)? - ) { - login(supabaseClient, onSuccess, redirectUrl, config) - } + ) = login(supabaseClient, onSuccess, redirectUrl, config) actual companion object diff --git a/GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt b/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/SSO.kt similarity index 82% rename from GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt rename to GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/SSO.kt index 3b978901..1fb9341d 100644 --- a/GoTrue/src/linuxMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt +++ b/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/SSO.kt @@ -2,8 +2,8 @@ package io.github.jan.supabase.gotrue.providers.builtin import io.github.jan.supabase.SupabaseClient import io.github.jan.supabase.gotrue.auth +import io.github.jan.supabase.gotrue.openExternalUrl import io.github.jan.supabase.gotrue.user.UserSession -import platform.posix.system internal actual suspend fun SSO.loginWithSSO( supabaseClient: SupabaseClient, @@ -12,5 +12,5 @@ internal actual suspend fun SSO.loginWithSSO( config: (SSO.Config.() -> Unit)? ) { val result = supabaseClient.auth.retrieveSSOUrl(redirectUrl) { config?.invoke(this) } - system("xdg-open ${result.url}") + supabaseClient.openExternalUrl(result.url) } \ No newline at end of file From d9753a2b98cca098fbbfe6c99b6e5a53d4d312d7 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 2 Dec 2023 22:50:03 +0100 Subject: [PATCH 04/12] Fix default redirect url --- .../kotlin/io/github/jan/supabase/gotrue/Auth.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt index 46d94371..48cd6716 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt @@ -95,7 +95,7 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { */ suspend fun > signUpWith( provider: Provider, - redirectUrl: String? = supabaseClient.defaultRedirectUrl(), + redirectUrl: String? = defaultRedirectUrl(), config: (C.() -> Unit)? = null ): R? @@ -121,13 +121,13 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { */ suspend fun > signInWith( provider: Provider, - redirectUrl: String? = supabaseClient.defaultRedirectUrl(), + redirectUrl: String? = defaultRedirectUrl(), config: (C.() -> Unit)? = null ) suspend fun linkIdentity( provider: OAuthProvider, - redirectUrl: String? = supabaseClient.defaultRedirectUrl(), + redirectUrl: String? = defaultRedirectUrl(), config: ExternalAuthConfigDefaults.() -> Unit = {} ) @@ -140,7 +140,7 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { * @param redirectUrl The redirect url to use * @param config The configuration to use */ - suspend fun retrieveSSOUrl(redirectUrl: String? = supabaseClient.defaultRedirectUrl(), config: SSO.Config.() -> Unit): SSO.Result + suspend fun retrieveSSOUrl(redirectUrl: String? = defaultRedirectUrl(), config: SSO.Config.() -> Unit): SSO.Result /** * Modifies the current user @@ -152,7 +152,7 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { */ suspend fun modifyUser( updateCurrentUser: Boolean = true, - redirectUrl: String? = supabaseClient.defaultRedirectUrl(), + redirectUrl: String? = defaultRedirectUrl(), config: UserUpdateBuilder.() -> Unit ): UserInfo @@ -186,7 +186,7 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { * @throws HttpRequestTimeoutException if the request timed out * @throws HttpRequestException on network related issues */ - suspend fun sendRecoveryEmail(email: String, redirectUrl: String? = supabaseClient.defaultRedirectUrl(), captchaToken: String? = null) + suspend fun sendRecoveryEmail(email: String, redirectUrl: String? = defaultRedirectUrl(), captchaToken: String? = null) /** * Sends a nonce to the user's email (preferred) or phone From 11c30e3bcce4df9961e73c962e2d3fc514719389 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 2 Dec 2023 23:08:53 +0100 Subject: [PATCH 05/12] Add android open url --- .../kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt | 2 +- .../kotlin/io/github/jan/supabase/gotrue/Utils.kt | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt diff --git a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt index ae5008e8..2b371da6 100644 --- a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt +++ b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/RedirectUrl.kt @@ -3,7 +3,7 @@ package io.github.jan.supabase.gotrue import io.github.jan.supabase.annotations.SupabaseInternal @SupabaseInternal -actual fun Auth.generateRedirectUrl(): String? = config.deepLinkOrNull +actual fun Auth.defaultRedirectUrl(): String? = config.deepLinkOrNull internal val AuthConfig.deepLink: String get() { diff --git a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt new file mode 100644 index 00000000..e8488b40 --- /dev/null +++ b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt @@ -0,0 +1,8 @@ +import android.net.Uri +import io.github.jan.supabase.SupabaseClient +import io.github.jan.supabase.gotrue.auth +import io.github.jan.supabase.gotrue.openUrl + +internal actual suspend fun SupabaseClient.openExternalUrl(url: String) { + openUrl(Uri.parse(url), auth.config.defaultExternalAuthAction) +} \ No newline at end of file From 278366b3782f4a6cec8dcaea998196aaa7b211b1 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 3 Dec 2023 11:25:35 +0100 Subject: [PATCH 06/12] Fix linking --- .../io/github/jan/supabase/gotrue/Android.kt | 18 +----- .../io/github/jan/supabase/gotrue/Utils.kt | 13 ++++- .../gotrue/providers/OAuthProvider.kt | 44 --------------- .../gotrue/providers/builtin/loginWithSSO.kt | 19 ------- .../io/github/jan/supabase/gotrue/Auth.kt | 5 ++ .../io/github/jan/supabase/gotrue/AuthImpl.kt | 21 ++++--- .../io/github/jan/supabase/gotrue/Utils.kt | 8 ++- .../gotrue/providers/OAuthProvider.kt | 23 +++++++- .../supabase/gotrue/providers/builtin/SSO.kt | 16 +++++- .../github/jan/supabase/gotrue/Utils.jvm.kt | 21 +++++++ .../gotrue/providers/OAuthProvider.kt | 55 ------------------- .../gotrue/providers/builtin/loginWithSSO.kt | 31 ----------- .../io/github/jan/supabase/gotrue/Utils.kt | 11 ++++ .../gotrue/providers/OAuthProvider.nonJvm.kt | 42 -------------- .../supabase/gotrue/providers/builtin/SSO.kt | 16 ------ 15 files changed, 105 insertions(+), 238 deletions(-) delete mode 100644 GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt delete mode 100644 GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt delete mode 100644 GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt delete mode 100644 GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt create mode 100644 GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt delete mode 100644 GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.nonJvm.kt delete mode 100644 GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/SSO.kt diff --git a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Android.kt b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Android.kt index 30dbb37f..1356f0d1 100644 --- a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Android.kt +++ b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Android.kt @@ -4,26 +4,12 @@ import android.content.Intent import android.net.Uri import androidx.browser.customtabs.CustomTabsIntent import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.annotations.SupabaseExperimental +import io.github.jan.supabase.annotations.SupabaseInternal import io.github.jan.supabase.gotrue.ExternalAuthAction.CUSTOM_TABS import io.github.jan.supabase.gotrue.ExternalAuthAction.EXTERNAL_BROWSER -import io.github.jan.supabase.gotrue.providers.ExternalAuthConfigDefaults -import io.github.jan.supabase.gotrue.providers.OAuthProvider import io.github.jan.supabase.gotrue.user.UserSession import kotlinx.coroutines.launch - -internal fun Auth.openOAuth(provider: OAuthProvider, redirectTo: String, config: ExternalAuthConfigDefaults) { - this as AuthImpl - openUrl( - uri = Uri.parse(oAuthUrl(provider, redirectTo) { - scopes.addAll(config.scopes) - queryParams.putAll(config.queryParams) - }), - action = this.config.defaultExternalAuthAction - ) -} - internal fun openUrl(uri: Uri, action: ExternalAuthAction) { when(action) { EXTERNAL_BROWSER -> { @@ -46,7 +32,7 @@ internal fun openUrl(uri: Uri, action: ExternalAuthAction) { * @param intent The intent from the activity * @param onSessionSuccess The callback when the session was successfully imported */ -@OptIn(SupabaseExperimental::class) +@OptIn(SupabaseInternal::class) fun SupabaseClient.handleDeeplinks(intent: Intent, onSessionSuccess: (UserSession) -> Unit = {}) { val data = intent.data ?: return val scheme = data.scheme ?: return diff --git a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt index e8488b40..da4691ef 100644 --- a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt +++ b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt @@ -1,8 +1,17 @@ +package io.github.jan.supabase.gotrue + import android.net.Uri import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.openUrl +import io.github.jan.supabase.gotrue.user.UserSession internal actual suspend fun SupabaseClient.openExternalUrl(url: String) { openUrl(Uri.parse(url), auth.config.defaultExternalAuthAction) +} + +internal actual suspend fun Auth.startExternalAuth( + redirectUrl: String?, + getUrl: suspend (redirectTo: String?) -> String, + onSessionSuccess: suspend (UserSession) -> Unit +) { + supabaseClient.openExternalUrl(getUrl(redirectUrl)) } \ No newline at end of file diff --git a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt deleted file mode 100644 index 7ac5caaa..00000000 --- a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt +++ /dev/null @@ -1,44 +0,0 @@ -package io.github.jan.supabase.gotrue.providers - -import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.AuthImpl -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.deepLink -import io.github.jan.supabase.gotrue.openOAuth -import io.github.jan.supabase.gotrue.user.UserSession - -/** - * Represents an OAuth provider. - */ -actual abstract class OAuthProvider : AuthProvider { - - /** - * The name of the provider. - */ - actual abstract val name: String - - actual override suspend fun login( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (ExternalAuthConfig.() -> Unit)? - ) { - val gotrue = supabaseClient.auth as AuthImpl - val redirectTo = redirectUrl ?: gotrue.config.deepLink - val externalConfig = ExternalAuthConfig().apply { config?.invoke(this) } - gotrue.openOAuth(this, redirectTo, externalConfig) - } - - actual override suspend fun signUp( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (ExternalAuthConfig.() -> Unit)? - ) { - login(supabaseClient, onSuccess, redirectUrl, config) - } - - actual companion object - - -} \ No newline at end of file diff --git a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt deleted file mode 100644 index 27db9808..00000000 --- a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt +++ /dev/null @@ -1,19 +0,0 @@ -package io.github.jan.supabase.gotrue.providers.builtin - -import android.net.Uri -import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.deepLink -import io.github.jan.supabase.gotrue.openUrl -import io.github.jan.supabase.gotrue.user.UserSession - -internal actual suspend fun SSO.loginWithSSO( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (SSO.Config.() -> Unit)? -) { - val gotrueConfig = supabaseClient.auth.config - val result = supabaseClient.auth.retrieveSSOUrl(redirectUrl ?: gotrueConfig.deepLink) { config?.invoke(this) } - openUrl(Uri.parse(result.url), gotrueConfig.defaultExternalAuthAction) -} \ No newline at end of file diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt index 48cd6716..5617cbd6 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt @@ -329,6 +329,11 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { */ fun currentUserOrNull() = currentSessionOrNull()?.user + /** + * Returns the connected identities to the current user or null + */ + fun currentIdentitiesOrNull() = currentUserOrNull()?.identities + companion object : SupabasePluginProvider { override val key = "auth" diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt index 074e459e..c95790f4 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt @@ -118,16 +118,23 @@ internal class AuthImpl( redirectUrl: String?, config: ExternalAuthConfigDefaults.() -> Unit ) { - val url = oAuthUrl(provider, redirectUrl, "user/identities/authorize", config) - val data = api.rawRequest(url) { - method = HttpMethod.Get - }.body() - val newUrl = data["url"]?.jsonPrimitive?.content ?: error("No url found in response") - supabaseClient.openExternalUrl(newUrl) //TODO: Add server callback on JVM and fix Android + startExternalAuth( + redirectUrl = redirectUrl, + getUrl = { + val url = oAuthUrl(provider, it, "user/identities/authorize", config) + val data = api.rawRequest(url) { + method = HttpMethod.Get + }.body() + data["url"]?.jsonPrimitive?.content ?: error("No url found in response") + }, + onSessionSuccess = { + importSession(it) + } + ) } override suspend fun unlinkIdentity(identityId: String) { - api.delete("user/identities/${identityId}") + api.delete("user/identities/$identityId") } override suspend fun retrieveSSOUrl( diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt index bc207b29..7b1036c0 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt @@ -27,4 +27,10 @@ fun HttpRequestBuilder.redirectTo(url: String) { internal fun invalidArg(message: String): Nothing = throw IllegalArgumentException(message) -internal expect suspend fun SupabaseClient.openExternalUrl(url: String) \ No newline at end of file +internal expect suspend fun SupabaseClient.openExternalUrl(url: String) + +internal expect suspend fun Auth.startExternalAuth( + redirectUrl: String?, + getUrl: suspend (redirectTo: String?) -> String, + onSessionSuccess: suspend (UserSession) -> Unit +) \ No newline at end of file diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt index cc25132c..3e30603d 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt @@ -1,12 +1,14 @@ package io.github.jan.supabase.gotrue.providers import io.github.jan.supabase.SupabaseClient +import io.github.jan.supabase.gotrue.auth +import io.github.jan.supabase.gotrue.startExternalAuth import io.github.jan.supabase.gotrue.user.UserSession /** * Represents an OAuth provider. */ -expect abstract class OAuthProvider() : AuthProvider { +abstract class OAuthProvider() : AuthProvider { /** * The name of the provider. @@ -18,14 +20,29 @@ expect abstract class OAuthProvider() : AuthProvider { onSuccess: suspend (UserSession) -> Unit, redirectUrl: String?, config: (ExternalAuthConfig.() -> Unit)? - ) + ) { + val authConfig = ExternalAuthConfig() + if (config != null) { + authConfig.config() + } + supabaseClient.auth.startExternalAuth( + redirectUrl = redirectUrl, + getUrl = { + supabaseClient.auth.oAuthUrl(this, it) { + scopes.addAll(authConfig.scopes) + queryParams.putAll(authConfig.queryParams) + } + }, + onSessionSuccess = onSuccess + ) + } override suspend fun signUp( supabaseClient: SupabaseClient, onSuccess: suspend (UserSession) -> Unit, redirectUrl: String?, config: (ExternalAuthConfig.() -> Unit)? - ) + ) = login(supabaseClient, onSuccess, redirectUrl, config) companion object diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/SSO.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/SSO.kt index 239dce12..f4c4361a 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/SSO.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/SSO.kt @@ -1,7 +1,9 @@ package io.github.jan.supabase.gotrue.providers.builtin import io.github.jan.supabase.SupabaseClient +import io.github.jan.supabase.gotrue.auth import io.github.jan.supabase.gotrue.providers.AuthProvider +import io.github.jan.supabase.gotrue.startExternalAuth import io.github.jan.supabase.gotrue.user.UserSession import kotlinx.serialization.Serializable @@ -58,9 +60,19 @@ data object SSO: AuthProvider { } -internal expect suspend fun SSO.loginWithSSO( +internal suspend fun loginWithSSO( supabaseClient: SupabaseClient, onSuccess: suspend (UserSession) -> Unit, redirectUrl: String?, config: (SSO.Config.() -> Unit)? -) \ No newline at end of file +) { + supabaseClient.auth.startExternalAuth( + redirectUrl = redirectUrl, + getUrl = { + supabaseClient.auth.retrieveSSOUrl(it) { + config?.invoke(this) + }.url + }, + onSessionSuccess = onSuccess + ) +} \ No newline at end of file diff --git a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.jvm.kt b/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.jvm.kt index 164b4895..9a225fa9 100644 --- a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.jvm.kt +++ b/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.jvm.kt @@ -1,7 +1,10 @@ package io.github.jan.supabase.gotrue import io.github.jan.supabase.SupabaseClient +import io.github.jan.supabase.gotrue.providers.createServer +import io.github.jan.supabase.gotrue.user.UserSession import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.awt.Desktop import java.net.URI @@ -11,4 +14,22 @@ internal actual suspend fun SupabaseClient.openExternalUrl(url: String) { Desktop.getDesktop() .browse(URI(url)) } +} + +internal actual suspend fun Auth.startExternalAuth( + redirectUrl: String?, + getUrl: suspend (redirectTo: String?) -> String, + onSessionSuccess: suspend (UserSession) -> Unit +) { + withContext(Dispatchers.IO) { + if(redirectUrl != null) { + supabaseClient.openExternalUrl(getUrl(redirectUrl)) + return@withContext + } + launch { + createServer({ + getUrl(it) + }, supabaseClient.auth, onSessionSuccess) + } + } } \ No newline at end of file diff --git a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt b/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt deleted file mode 100644 index d99cae61..00000000 --- a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt +++ /dev/null @@ -1,55 +0,0 @@ -package io.github.jan.supabase.gotrue.providers - -import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.openExternalUrl -import io.github.jan.supabase.gotrue.user.UserSession -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext - -/** - * Represents an OAuth provider. - */ -actual abstract class OAuthProvider actual constructor() : AuthProvider { - /** - * The name of the provider. - */ - actual abstract val name: String - - actual override suspend fun login( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (ExternalAuthConfig.() -> Unit)? - ) { - val externalConfig = ExternalAuthConfig().apply { config?.invoke(this) } - withContext(Dispatchers.IO) { - if(redirectUrl != null) { - supabaseClient.openExternalUrl(supabaseClient.auth.oAuthUrl(this@OAuthProvider, redirectUrl) { - scopes.addAll(externalConfig.scopes) - queryParams.putAll(externalConfig.queryParams) - }) - return@withContext - } - launch { - createServer({ - supabaseClient.auth.oAuthUrl(this@OAuthProvider, it) { - scopes.addAll(externalConfig.scopes) - queryParams.putAll(externalConfig.queryParams) - } - }, supabaseClient.auth, onSuccess) - } - } - } - - actual override suspend fun signUp( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (ExternalAuthConfig.() -> Unit)? - ) = login(supabaseClient, onSuccess, redirectUrl, config) - - actual companion object - -} \ No newline at end of file diff --git a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt b/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt deleted file mode 100644 index 0389c052..00000000 --- a/GoTrue/src/jvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/loginWithSSO.kt +++ /dev/null @@ -1,31 +0,0 @@ -package io.github.jan.supabase.gotrue.providers.builtin - -import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.openExternalUrl -import io.github.jan.supabase.gotrue.providers.createServer -import io.github.jan.supabase.gotrue.user.UserSession -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext - -internal actual suspend fun SSO.loginWithSSO( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (SSO.Config.() -> Unit)? -) { - withContext(Dispatchers.IO) { - if(redirectUrl == null) { - launch { - createServer({ - val result = supabaseClient.auth.retrieveSSOUrl(it) { config?.invoke(this) } - result.url - }, supabaseClient.auth, onSuccess) - } - } else { - val result = supabaseClient.auth.retrieveSSOUrl(redirectUrl) { config?.invoke(this) } - supabaseClient.openExternalUrl(result.url) - } - } -} \ No newline at end of file diff --git a/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt b/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt new file mode 100644 index 00000000..e8cad622 --- /dev/null +++ b/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt @@ -0,0 +1,11 @@ +package io.github.jan.supabase.gotrue + +import io.github.jan.supabase.gotrue.user.UserSession + +internal actual suspend fun Auth.startExternalAuth( + redirectUrl: String?, + getUrl: suspend (redirectTo: String?) -> String, + onSessionSuccess: suspend (UserSession) -> Unit +) { + supabaseClient.openExternalUrl(getUrl(redirectUrl)) +} \ No newline at end of file diff --git a/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.nonJvm.kt b/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.nonJvm.kt deleted file mode 100644 index ce4a0067..00000000 --- a/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.nonJvm.kt +++ /dev/null @@ -1,42 +0,0 @@ -package io.github.jan.supabase.gotrue.providers - -import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.openExternalUrl -import io.github.jan.supabase.gotrue.user.UserSession - -/** - * Represents an OAuth provider. - */ -actual abstract class OAuthProvider actual constructor() : AuthProvider { - /** - * The name of the provider. - */ - actual abstract val name: String - - actual override suspend fun login( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (ExternalAuthConfig.() -> Unit)? - ) { - val builtConfig = ExternalAuthConfig().apply { - config?.invoke(this) - } - val url = supabaseClient.auth.oAuthUrl(this, redirectUrl) { - scopes.addAll(builtConfig.scopes) - queryParams.putAll(builtConfig.queryParams) - } - supabaseClient.openExternalUrl(url) - } - - actual override suspend fun signUp( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (ExternalAuthConfig.() -> Unit)? - ) = login(supabaseClient, onSuccess, redirectUrl, config) - - actual companion object - -} \ No newline at end of file diff --git a/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/SSO.kt b/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/SSO.kt deleted file mode 100644 index 1fb9341d..00000000 --- a/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/providers/builtin/SSO.kt +++ /dev/null @@ -1,16 +0,0 @@ -package io.github.jan.supabase.gotrue.providers.builtin - -import io.github.jan.supabase.SupabaseClient -import io.github.jan.supabase.gotrue.auth -import io.github.jan.supabase.gotrue.openExternalUrl -import io.github.jan.supabase.gotrue.user.UserSession - -internal actual suspend fun SSO.loginWithSSO( - supabaseClient: SupabaseClient, - onSuccess: suspend (UserSession) -> Unit, - redirectUrl: String?, - config: (SSO.Config.() -> Unit)? -) { - val result = supabaseClient.auth.retrieveSSOUrl(redirectUrl) { config?.invoke(this) } - supabaseClient.openExternalUrl(result.url) -} \ No newline at end of file From e1972accb4bb785faaf3f4294ed1174c65fc3c48 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 3 Dec 2023 11:35:50 +0100 Subject: [PATCH 07/12] Add docs --- .../kotlin/io/github/jan/supabase/gotrue/Auth.kt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt index 5bd08061..cf81fd0f 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt @@ -125,18 +125,30 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { config: (C.() -> Unit)? = null ) + /** + * Links an OAuth Identity to an existing user. + * + * This methods works similar to signing in with OAuth providers. Refer to the [documentation](https://supabase.com/docs/reference/kotlin/initializing) to learn how to handle OAuth and OTP links. + * @param provider The OAuth provider + * @param redirectUrl The redirect url to use. If you don't specify this, the platform specific will be used, like deeplinks on android. + * @param config Extra configuration + */ suspend fun linkIdentity( provider: OAuthProvider, redirectUrl: String? = defaultRedirectUrl(), config: ExternalAuthConfigDefaults.() -> Unit = {} ) + /** + * Unlinks an OAuth Identity from an existing user. + * @param identityId The id of the OAuth identity + */ suspend fun unlinkIdentity( identityId: String ) /** - * Retrieves the sso url for the specified [type] + * Retrieves the sso url for the given [config] * @param redirectUrl The redirect url to use * @param config The configuration to use */ From 63c8cbeb1e10c49d510690ca01760c6aa2eb63e9 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 3 Dec 2023 11:36:26 +0100 Subject: [PATCH 08/12] Fix android error --- .../io/github/jan/supabase/gotrue/{Utils.kt => Utils.android.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/{Utils.kt => Utils.android.kt} (100%) diff --git a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.android.kt similarity index 100% rename from GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt rename to GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.android.kt From 753313547cd80a5a684b2c7a9f2be68c1142e614 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 3 Dec 2023 11:38:52 +0100 Subject: [PATCH 09/12] Remove empty constructor --- .../io/github/jan/supabase/gotrue/providers/OAuthProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt index 3e30603d..9dc25709 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/providers/OAuthProvider.kt @@ -8,7 +8,7 @@ import io.github.jan.supabase.gotrue.user.UserSession /** * Represents an OAuth provider. */ -abstract class OAuthProvider() : AuthProvider { +abstract class OAuthProvider : AuthProvider { /** * The name of the provider. From 968235e3c1a21dfbf78fd843ab3bb29d90df2be1 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 3 Dec 2023 11:43:06 +0100 Subject: [PATCH 10/12] Suppress detekt warning --- .../kotlin/io/github/jan/supabase/gotrue/Utils.android.kt | 1 + .../src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.android.kt b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.android.kt index da4691ef..0a1b89cd 100644 --- a/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.android.kt +++ b/GoTrue/src/androidMain/kotlin/io/github/jan/supabase/gotrue/Utils.android.kt @@ -1,3 +1,4 @@ +@file:Suppress("RedundantSuspendModifier") package io.github.jan.supabase.gotrue import android.net.Uri diff --git a/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt b/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt index e8cad622..7e68cf84 100644 --- a/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt +++ b/GoTrue/src/nonJvmMain/kotlin/io/github/jan/supabase/gotrue/Utils.kt @@ -1,3 +1,4 @@ +@file:Suppress("RedundantSuspendModifier") package io.github.jan.supabase.gotrue import io.github.jan.supabase.gotrue.user.UserSession From b88152b242d8e55f7ff210519894b120a77f2166 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 3 Dec 2023 11:46:05 +0100 Subject: [PATCH 11/12] Mark methods as experimental --- .../commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt | 3 +++ .../kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt | 2 ++ 2 files changed, 5 insertions(+) diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt index cf81fd0f..293e603f 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/Auth.kt @@ -2,6 +2,7 @@ package io.github.jan.supabase.gotrue import co.touchlab.kermit.Logger import io.github.jan.supabase.SupabaseClient +import io.github.jan.supabase.annotations.SupabaseExperimental import io.github.jan.supabase.exceptions.HttpRequestException import io.github.jan.supabase.exceptions.RestException import io.github.jan.supabase.gotrue.admin.AdminApi @@ -133,6 +134,7 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { * @param redirectUrl The redirect url to use. If you don't specify this, the platform specific will be used, like deeplinks on android. * @param config Extra configuration */ + @SupabaseExperimental suspend fun linkIdentity( provider: OAuthProvider, redirectUrl: String? = defaultRedirectUrl(), @@ -143,6 +145,7 @@ sealed interface Auth : MainPlugin, CustomSerializationPlugin { * Unlinks an OAuth Identity from an existing user. * @param identityId The id of the OAuth identity */ + @SupabaseExperimental suspend fun unlinkIdentity( identityId: String ) diff --git a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt index c719ddfe..41f9f6d4 100644 --- a/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt +++ b/GoTrue/src/commonMain/kotlin/io/github/jan/supabase/gotrue/AuthImpl.kt @@ -113,6 +113,7 @@ internal class AuthImpl( importSession(it) }, redirectUrl, config) + @SupabaseExperimental override suspend fun linkIdentity( provider: OAuthProvider, redirectUrl: String?, @@ -133,6 +134,7 @@ internal class AuthImpl( ) } + @SupabaseExperimental override suspend fun unlinkIdentity(identityId: String) { api.delete("user/identities/$identityId") } From 485665128f71753783742cd76c25d240065e30ca Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 3 Dec 2023 12:09:50 +0100 Subject: [PATCH 12/12] Fix apple error --- .../kotlin/io/github/jan/supabase/gotrue/Utils.apple.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/Utils.apple.kt b/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/Utils.apple.kt index fcf16f8e..af0b81ec 100644 --- a/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/Utils.apple.kt +++ b/GoTrue/src/appleMain/kotlin/io/github/jan/supabase/gotrue/Utils.apple.kt @@ -5,5 +5,5 @@ import io.github.jan.supabase.gotrue.providers.openUrl import platform.Foundation.NSURL internal actual suspend fun SupabaseClient.openExternalUrl(url: String) { - openUrl(NSURL(url)) + openUrl(NSURL(string = url)) } \ No newline at end of file