Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -257,11 +257,13 @@ sealed interface GoTrue : MainPlugin<GoTrueConfig>, CustomSerializationPlugin {

/**
* Logs out the current user, which means [sessionStatus] will be [SessionStatus.NotAuthenticated] and the access token will be revoked
* @param scope The scope of the logout.
* @throws RestException or one of its subclasses if receiving an error response
* @throws HttpRequestTimeoutException if the request timed out
* @throws HttpRequestException on network related issues
* @see LogoutScope
*/
suspend fun logout()
suspend fun logout(scope: LogoutScope = LogoutScope.LOCAL)

/**
* Imports a user session and starts auto-refreshing if [autoRefresh] is true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import io.github.jan.supabase.putJsonObject
import io.github.jan.supabase.safeBody
import io.github.jan.supabase.supabaseJson
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.HttpStatusCode
Expand Down Expand Up @@ -237,11 +238,17 @@ internal class GoTrueImpl(
api.get("reauthenticate")
}

override suspend fun logout() {
sessionManager.deleteSession()
sessionJob?.cancel()
_sessionStatus.value = SessionStatus.NotAuthenticated
sessionJob = null
override suspend fun logout(scope: LogoutScope) {
api.post("logout") {
parameter("scope", scope.name.lowercase())
}
if(scope != LogoutScope.OTHERS) {
codeVerifierCache.deleteCodeVerifier()
sessionManager.deleteSession()
sessionJob?.cancel()
_sessionStatus.value = SessionStatus.NotAuthenticated
sessionJob = null
}
}

private suspend fun verify(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.github.jan.supabase.gotrue

/**
* Represents the scope of a logout action.
*
* The logout scope determines the scope of the logout action being performed.
*
* @property GLOBAL Logout action applies to all sessions across the entire system.
* @property LOCAL Logout action applies only to the current session.
* @property OTHERS Logout action applies to other sessions, excluding the current session.
*/
enum class LogoutScope {
GLOBAL, LOCAL, OTHERS
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package io.github.jan.supabase.gotrue.admin
import io.github.jan.supabase.annotations.SupabaseInternal
import io.github.jan.supabase.gotrue.GoTrue
import io.github.jan.supabase.gotrue.GoTrueImpl
import io.github.jan.supabase.gotrue.LogoutScope
import io.github.jan.supabase.gotrue.user.UserInfo
import io.github.jan.supabase.gotrue.user.UserMfaFactor
import io.github.jan.supabase.putJsonObject
import io.github.jan.supabase.safeBody
import io.github.jan.supabase.supabaseJson
import io.ktor.client.call.body
import io.ktor.client.request.parameter
import io.ktor.http.HttpHeaders
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
Expand Down Expand Up @@ -37,8 +39,10 @@ sealed interface AdminApi {

/**
* Removes a user session
* @param jwt the jwt of the session
* @param scope the scope of the logout action
*/
suspend fun logout(jwt: String)
suspend fun logout(jwt: String, scope: LogoutScope = LogoutScope.LOCAL)

/**
* Retrieves all users
Expand Down Expand Up @@ -92,8 +96,9 @@ internal class AdminApiImpl(val gotrue: GoTrue) : AdminApi {

val api = (gotrue as GoTrueImpl).api

override suspend fun logout(jwt: String) {
override suspend fun logout(jwt: String, scope: LogoutScope) {
api.post("logout") {
parameter("scope", scope.name.lowercase())
headers[HttpHeaders.Authorization] = "Bearer $jwt"
}
}
Expand Down
8 changes: 7 additions & 1 deletion GoTrue/src/commonTest/kotlin/GoTrueMock.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import io.ktor.http.HttpMethod
import io.ktor.http.HttpStatusCode
import io.ktor.http.headersOf
import kotlinx.datetime.Clock
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
Expand All @@ -40,10 +39,17 @@ class GoTrueMock {
urlWithoutQuery.endsWith("verify") -> handleVerify(request)
urlWithoutQuery.endsWith("otp") -> handleOtp(request)
urlWithoutQuery.endsWith("recover") -> handleRecovery(request)
urlWithoutQuery.endsWith("logout") -> handleLogout(request)
else -> null
}
}

private suspend fun MockRequestHandleScope.handleLogout(request: HttpRequestData): HttpResponseData {
if(request.method != HttpMethod.Post) return respondBadRequest("Invalid method")
if(!request.headers.contains("Authorization")) return respondBadRequest("access token missing")
return respondOk()
}

private suspend fun MockRequestHandleScope.handleRecovery(request: HttpRequestData): HttpResponseData {
if(request.method != HttpMethod.Post) respondBadRequest("Invalid method")
val body = try {
Expand Down