File tree Expand file tree Collapse file tree 3 files changed +54
-2
lines changed Expand file tree Collapse file tree 3 files changed +54
-2
lines changed Original file line number Diff line number Diff line change @@ -712,8 +712,8 @@ public final class AuthClient: Sendable {
712
712
)
713
713
} catch {
714
714
// ignore 404s since user might not exist anymore
715
- // ignore 401s since an invalid or expired JWT should sign out the current session
716
- let ignoredCodes = Set ( [ 404 , 401 ] )
715
+ // ignore 401s, and 403s since an invalid or expired JWT should sign out the current session.
716
+ let ignoredCodes = Set ( [ 404 , 403 , 401 ] )
717
717
718
718
if case let AuthError . api( apiError) = error, let code = apiError. code,
719
719
!ignoredCodes. contains ( code)
Original file line number Diff line number Diff line change @@ -179,6 +179,37 @@ final class AuthClientTests: XCTestCase {
179
179
XCTAssertTrue ( sessionRemoved)
180
180
}
181
181
182
+ func testSignOutShouldRemoveSessionIf403Returned( ) async throws {
183
+ sut = makeSUT { _ in
184
+ throw AuthError . api ( AuthError . APIError ( code: 403 ) )
185
+ }
186
+
187
+ let validSession = Session . validSession
188
+ try storage. storeSession ( . init( session: validSession) )
189
+
190
+ let eventsTask = Task {
191
+ await sut. authStateChanges. prefix ( 2 ) . collect ( )
192
+ }
193
+
194
+ await Task . megaYield ( )
195
+
196
+ do {
197
+ try await sut. signOut ( )
198
+ } catch AuthError . api {
199
+ } catch {
200
+ XCTFail ( " Unexpected error: \( error) " )
201
+ }
202
+
203
+ let events = await eventsTask. value. map ( \. event)
204
+ let sessions = await eventsTask. value. map ( \. session)
205
+
206
+ XCTAssertNoDifference ( events, [ . initialSession, . signedOut] )
207
+ XCTAssertNoDifference ( sessions, [ validSession, nil ] )
208
+
209
+ let sessionRemoved = try storage. getSession ( ) == nil
210
+ XCTAssertTrue ( sessionRemoved)
211
+ }
212
+
182
213
func testSignInAnonymously( ) async throws {
183
214
let session = Session ( fromMockNamed: " anonymous-sign-in-response " )
184
215
Original file line number Diff line number Diff line change @@ -11,6 +11,10 @@ import CustomDump
11
11
import TestHelpers
12
12
import XCTest
13
13
14
+ #if canImport(FoundationNetworking)
15
+ import FoundationNetworking
16
+ #endif
17
+
14
18
final class AuthClientIntegrationTests : XCTestCase {
15
19
let authClient = AuthClient (
16
20
configuration: AuthClient . Configuration (
@@ -189,6 +193,23 @@ final class AuthClientIntegrationTests: XCTestCase {
189
193
}
190
194
}
191
195
196
+ func testDeleteAccountAndSignOut( ) async throws {
197
+ let response = try await signUpIfNeededOrSignIn ( email: mockEmail ( ) , password: mockPassword ( ) )
198
+
199
+ let session = try XCTUnwrap ( response. session)
200
+
201
+ var request = URLRequest ( url: URL ( string: " \( DotEnv . SUPABASE_URL) /rest/v1/rpc/delete_user " ) !)
202
+ request. httpMethod = " POST "
203
+ request. setValue ( DotEnv . SUPABASE_ANON_KEY, forHTTPHeaderField: " apikey " )
204
+ request. setValue ( " Bearer \( session. accessToken) " , forHTTPHeaderField: " Authorization " )
205
+
206
+ _ = try await URLSession . shared. data ( for: request)
207
+
208
+ try await XCTAssertAuthChangeEvents ( [ . initialSession, . signedOut] ) {
209
+ try await authClient. signOut ( )
210
+ }
211
+ }
212
+
192
213
@discardableResult
193
214
private func signUpIfNeededOrSignIn(
194
215
email: String ,
You can’t perform that action at this time.
0 commit comments