From 90faf5df8830f82cb1d7db849f196f049f49638c Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Wed, 29 Oct 2025 17:37:30 -0300 Subject: [PATCH] feat(auth): remove deprecated code --- Sources/Auth/AuthError.swift | 130 --------------- Sources/Auth/Deprecated.swift | 149 ------------------ Sources/Auth/Types.swift | 36 +---- Tests/AuthTests/AuthClientTests.swift | 8 +- Tests/AuthTests/RequestsTests.swift | 3 +- .../RequestsTests/testUpdateUser.1.txt | 2 +- 6 files changed, 12 insertions(+), 316 deletions(-) delete mode 100644 Sources/Auth/Deprecated.swift diff --git a/Sources/Auth/AuthError.swift b/Sources/Auth/AuthError.swift index 991100bf5..9e2da3e19 100644 --- a/Sources/Auth/AuthError.swift +++ b/Sources/Auth/AuthError.swift @@ -118,129 +118,6 @@ extension ErrorCode { } public enum AuthError: LocalizedError, Equatable { - @available( - *, - deprecated, - message: - "Error used to be thrown when no exp claim was found in JWT during setSession(accessToken:refreshToken:) method." - ) - case missingExpClaim - - @available( - *, - deprecated, - message: - "Error used to be thrown when provided JWT wasn't valid during setSession(accessToken:refreshToken:) method." - ) - case malformedJWT - - @available(*, deprecated, renamed: "sessionMissing") - public static var sessionNotFound: AuthError { .sessionMissing } - - /// Error thrown during PKCE flow. - @available( - *, - deprecated, - renamed: "pkceGrantCodeExchange", - message: "Error was grouped in `pkceGrantCodeExchange`, please use it instead of `pkce`." - ) - public static func pkce(_ reason: PKCEFailureReason) -> AuthError { - switch reason { - case .codeVerifierNotFound: - .pkceGrantCodeExchange(message: "A code verifier wasn't found in PKCE flow.") - case .invalidPKCEFlowURL: - .pkceGrantCodeExchange(message: "Not a valid PKCE flow url.") - } - } - - @available(*, deprecated, message: "Use `pkceGrantCodeExchange` instead.") - public enum PKCEFailureReason: Sendable { - /// Code verifier not found in the URL. - case codeVerifierNotFound - - /// Not a valid PKCE flow URL. - case invalidPKCEFlowURL - } - - @available(*, deprecated, renamed: "implicitGrantRedirect") - public static var invalidImplicitGrantFlowURL: AuthError { - .implicitGrantRedirect(message: "Not a valid implicit grant flow url.") - } - - @available( - *, - deprecated, - message: - "This error is never thrown, if you depend on it, you can remove the logic as it never happens." - ) - case missingURL - - @available( - *, - deprecated, - message: - "Error used to be thrown on methods which required a valid redirect scheme, such as signInWithOAuth. This is now considered a programming error an a assertion is triggered in case redirect scheme isn't provided." - ) - case invalidRedirectScheme - - @available( - *, - deprecated, - renamed: "api(message:errorCode:underlyingData:underlyingResponse:)" - ) - public static func api(_ error: APIError) -> AuthError { - let message = error.msg ?? error.error ?? error.errorDescription ?? "Unexpected API error." - if let weakPassword = error.weakPassword { - return .weakPassword(message: message, reasons: weakPassword.reasons) - } - - return .api( - message: message, - errorCode: .unknown, - underlyingData: (try? AuthClient.Configuration.jsonEncoder.encode(error)) ?? Data(), - underlyingResponse: HTTPURLResponse( - url: defaultAuthURL, - statusCode: error.code ?? 500, - httpVersion: nil, - headerFields: nil - )! - ) - } - - /// An error returned by the API. - @available( - *, - deprecated, - renamed: "api(message:errorCode:underlyingData:underlyingResponse:)" - ) - public struct APIError: Error, Codable, Sendable, Equatable { - /// A basic message describing the problem with the request. Usually missing if - /// ``AuthError/APIError/error`` is present. - public var msg: String? - - /// The HTTP status code. Usually missing if ``AuthError/APIError/error`` is present. - public var code: Int? - - /// Certain responses will contain this property with the provided values. - /// - /// Usually one of these: - /// - `invalid_request` - /// - `unauthorized_client` - /// - `access_denied` - /// - `server_error` - /// - `temporarily_unavailable` - /// - `unsupported_otp_type` - public var error: String? - - /// Certain responses that have an ``AuthError/APIError/error`` property may have this property - /// which describes the error. - public var errorDescription: String? - - /// Only returned when signing up if the password used is too weak. Inspect the - /// ``WeakPassword/reasons`` and ``AuthError/APIError/msg`` property to identify the causes. - public var weakPassword: WeakPassword? - } - /// Error thrown when a session is required to proceed, but none was found, either thrown by the client, or returned by the server. case sessionMissing @@ -274,11 +151,6 @@ public enum AuthError: LocalizedError, Equatable { let .implicitGrantRedirect(message), let .jwtVerificationFailed(message): message - // Deprecated cases - case .missingExpClaim: "Missing expiration claim in the access token." - case .malformedJWT: "A malformed JWT received." - case .invalidRedirectScheme: "Invalid redirect scheme." - case .missingURL: "Missing URL." } } @@ -289,8 +161,6 @@ public enum AuthError: LocalizedError, Equatable { case let .api(_, errorCode, _, _): errorCode case .pkceGrantCodeExchange, .implicitGrantRedirect: .unknown case .jwtVerificationFailed: .invalidJWT - // Deprecated cases - case .missingExpClaim, .malformedJWT, .invalidRedirectScheme, .missingURL: .unknown } } diff --git a/Sources/Auth/Deprecated.swift b/Sources/Auth/Deprecated.swift deleted file mode 100644 index 9b0ca5f24..000000000 --- a/Sources/Auth/Deprecated.swift +++ /dev/null @@ -1,149 +0,0 @@ -// -// Deprecated.swift -// -// -// Created by Guilherme Souza on 14/12/23. -// - -import Foundation - -#if canImport(FoundationNetworking) - import FoundationNetworking -#endif - -@available(*, deprecated, renamed: "AuthClient") -public typealias GoTrueClient = AuthClient - -@available(*, deprecated, renamed: "AuthMFA") -public typealias GoTrueMFA = AuthMFA - -@available(*, deprecated, renamed: "AuthLocalStorage") -public typealias GoTrueLocalStorage = AuthLocalStorage - -@available(*, deprecated, renamed: "AuthMetaSecurity") -public typealias GoTrueMetaSecurity = AuthMetaSecurity - -@available(*, deprecated, renamed: "AuthError") -public typealias GoTrueError = AuthError - -extension JSONEncoder { - @available( - *, - deprecated, - renamed: "AuthClient.Configuration.jsonEncoder", - message: - "Access to the default JSONEncoder instance moved to AuthClient.Configuration.jsonEncoder" - ) - public static var goTrue: JSONEncoder { - AuthClient.Configuration.jsonEncoder - } -} - -extension JSONDecoder { - @available( - *, - deprecated, - renamed: "AuthClient.Configuration.jsonDecoder", - message: - "Access to the default JSONDecoder instance moved to AuthClient.Configuration.jsonDecoder" - ) - public static var goTrue: JSONDecoder { - AuthClient.Configuration.jsonDecoder - } -} - -extension AuthClient.Configuration { - /// Initializes a AuthClient Configuration with optional parameters. - /// - /// - Parameters: - /// - url: The base URL of the Auth server. - /// - headers: Custom headers to be included in requests. - /// - flowType: The authentication flow type. - /// - localStorage: The storage mechanism for local data. - /// - encoder: The JSON encoder to use for encoding requests. - /// - decoder: The JSON decoder to use for decoding responses. - /// - fetch: The asynchronous fetch handler for network requests. - @available( - *, - deprecated, - message: - "Replace usages of this initializer with new init(url:headers:flowType:localStorage:logger:encoder:decoder:fetch)" - ) - public init( - url: URL, - headers: [String: String] = [:], - flowType: AuthFlowType = Self.defaultFlowType, - localStorage: any AuthLocalStorage, - encoder: JSONEncoder = AuthClient.Configuration.jsonEncoder, - decoder: JSONDecoder = AuthClient.Configuration.jsonDecoder, - fetch: @escaping AuthClient.FetchHandler = { try await URLSession.shared.data(for: $0) } - ) { - self.init( - url: url, - headers: headers, - flowType: flowType, - localStorage: localStorage, - logger: nil, - encoder: encoder, - decoder: decoder, - fetch: fetch - ) - } -} - -extension AuthClient { - /// Initializes a AuthClient Configuration with optional parameters. - /// - /// - Parameters: - /// - url: The base URL of the Auth server. - /// - headers: Custom headers to be included in requests. - /// - flowType: The authentication flow type. - /// - localStorage: The storage mechanism for local data. - /// - encoder: The JSON encoder to use for encoding requests. - /// - decoder: The JSON decoder to use for decoding responses. - /// - fetch: The asynchronous fetch handler for network requests. - @available( - *, - deprecated, - message: - "Replace usages of this initializer with new init(url:headers:flowType:localStorage:logger:encoder:decoder:fetch)" - ) - public init( - url: URL, - headers: [String: String] = [:], - flowType: AuthFlowType = Configuration.defaultFlowType, - localStorage: any AuthLocalStorage, - encoder: JSONEncoder = AuthClient.Configuration.jsonEncoder, - decoder: JSONDecoder = AuthClient.Configuration.jsonDecoder, - fetch: @escaping AuthClient.FetchHandler = { try await URLSession.shared.data(for: $0) } - ) { - self.init( - url: url, - headers: headers, - flowType: flowType, - localStorage: localStorage, - logger: nil, - encoder: encoder, - decoder: decoder, - fetch: fetch - ) - } -} - -@available(*, deprecated, message: "Use MFATotpEnrollParams or MFAPhoneEnrollParams instead.") -public typealias MFAEnrollParams = MFATotpEnrollParams - -extension AuthAdmin { - @available( - *, - deprecated, - message: "Use deleteUser with UUID instead of string." - ) - public func deleteUser(id: String, shouldSoftDelete: Bool = false) async throws { - guard let id = UUID(uuidString: id) else { - fatalError("id should be a valid UUID") - } - - try await self.deleteUser(id: id, shouldSoftDelete: shouldSoftDelete) - } -} diff --git a/Sources/Auth/Types.swift b/Sources/Auth/Types.swift index f0400d4e8..1248d0e0c 100644 --- a/Sources/Auth/Types.swift +++ b/Sources/Auth/Types.swift @@ -11,31 +11,12 @@ public enum AuthChangeEvent: String, Sendable { case mfaChallengeVerified = "MFA_CHALLENGE_VERIFIED" } -@available( - *, - deprecated, - message: "Access to UserCredentials will be removed on the next major release." -) -public struct UserCredentials: Codable, Hashable, Sendable { - public var email: String? - public var password: String? - public var phone: String? - public var refreshToken: String? - public var gotrueMetaSecurity: AuthMetaSecurity? - - public init( - email: String? = nil, - password: String? = nil, - phone: String? = nil, - refreshToken: String? = nil, - gotrueMetaSecurity: AuthMetaSecurity? = nil - ) { - self.email = email - self.password = password - self.phone = phone - self.refreshToken = refreshToken - self.gotrueMetaSecurity = gotrueMetaSecurity - } +struct UserCredentials: Codable, Hashable, Sendable { + var email: String? + var password: String? + var phone: String? + var refreshToken: String? + var gotrueMetaSecurity: AuthMetaSecurity? } struct SignUpRequest: Codable, Hashable, Sendable { @@ -479,9 +460,6 @@ public struct UserAttributes: Codable, Hashable, Sendable { /// Note: Call ``AuthClient/reauthenticate()`` to obtain the nonce first. public var nonce: String? - /// An email change token. - @available(*, deprecated, message: "This is an old field, stop relying on it.") - public var emailChangeToken: String? /// A custom data object to store the user's metadata. This maps to the `auth.users.user_metadata` /// column. The `data` should be a JSON object that includes user-specific info, such as their /// first and last name. @@ -495,14 +473,12 @@ public struct UserAttributes: Codable, Hashable, Sendable { phone: String? = nil, password: String? = nil, nonce: String? = nil, - emailChangeToken: String? = nil, data: [String: AnyJSON]? = nil ) { self.email = email self.phone = phone self.password = password self.nonce = nonce - self.emailChangeToken = emailChangeToken self.data = data } } diff --git a/Tests/AuthTests/AuthClientTests.swift b/Tests/AuthTests/AuthClientTests.swift index 48e7a5d84..9711569f7 100644 --- a/Tests/AuthTests/AuthClientTests.swift +++ b/Tests/AuthTests/AuthClientTests.swift @@ -1246,12 +1246,12 @@ final class AuthClientTests: XCTestCase { curl \ --request PUT \ --header "Authorization: Bearer accesstoken" \ - --header "Content-Length: 258" \ + --header "Content-Length: 228" \ --header "Content-Type: application/json" \ --header "X-Client-Info: auth-swift/0.0.0" \ --header "X-Supabase-Api-Version: 2024-01-01" \ --header "apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0" \ - --data "{\"code_challenge\":\"hgJeigklONUI1pKSS98MIAbtJGaNu0zJU1iSiFOn2lY\",\"code_challenge_method\":\"s256\",\"data\":{\"custom_key\":\"custom_value\"},\"email\":\"example@mail.com\",\"email_change_token\":\"123456\",\"nonce\":\"abcdef\",\"password\":\"another.pass\",\"phone\":\"+1 202-918-2132\"}" \ + --data "{\"code_challenge\":\"hgJeigklONUI1pKSS98MIAbtJGaNu0zJU1iSiFOn2lY\",\"code_challenge_method\":\"s256\",\"data\":{\"custom_key\":\"custom_value\"},\"email\":\"example@mail.com\",\"nonce\":\"abcdef\",\"password\":\"another.pass\",\"phone\":\"+1 202-918-2132\"}" \ "http://localhost:54321/auth/v1/user" """# } @@ -1267,7 +1267,6 @@ final class AuthClientTests: XCTestCase { phone: "+1 202-918-2132", password: "another.pass", nonce: "abcdef", - emailChangeToken: "123456", data: ["custom_key": .string("custom_value")] ) ) @@ -1560,7 +1559,7 @@ final class AuthClientTests: XCTestCase { Dependencies[sut.clientID].sessionStorage.store(.validSession) let response = try await sut.mfa.enroll( - params: MFAEnrollParams( + params: .totp( issuer: "supabase.com", friendlyName: "test" ) @@ -2660,6 +2659,7 @@ final class AuthClientTests: XCTestCase { /// - action: The async action to perform that should trigger events /// - expectedEvents: Array of expected AuthChangeEvent values /// - expectedSessions: Array of expected Session values (optional) + @discardableResult private func assertAuthStateChanges( sut: AuthClient, action: () async throws -> T, diff --git a/Tests/AuthTests/RequestsTests.swift b/Tests/AuthTests/RequestsTests.swift index a8dcde072..eaae7e42b 100644 --- a/Tests/AuthTests/RequestsTests.swift +++ b/Tests/AuthTests/RequestsTests.swift @@ -291,7 +291,6 @@ final class RequestsTests: XCTestCase { phone: "+1 202-918-2132", password: "another.pass", nonce: "abcdef", - emailChangeToken: "123456", data: ["custom_key": .string("custom_value")] ) ) @@ -431,7 +430,7 @@ final class RequestsTests: XCTestCase { await assert { _ = try await sut.mfa.enroll( - params: MFAEnrollParams(issuer: "supabase.com", friendlyName: "test")) + params: .totp(issuer: "supabase.com", friendlyName: "test")) } } diff --git a/Tests/AuthTests/__Snapshots__/RequestsTests/testUpdateUser.1.txt b/Tests/AuthTests/__Snapshots__/RequestsTests/testUpdateUser.1.txt index 45eaa5f0f..7efb07af0 100644 --- a/Tests/AuthTests/__Snapshots__/RequestsTests/testUpdateUser.1.txt +++ b/Tests/AuthTests/__Snapshots__/RequestsTests/testUpdateUser.1.txt @@ -5,5 +5,5 @@ curl \ --header "Content-Type: application/json" \ --header "X-Client-Info: gotrue-swift/x.y.z" \ --header "X-Supabase-Api-Version: 2024-01-01" \ - --data "{\"data\":{\"custom_key\":\"custom_value\"},\"email\":\"example@mail.com\",\"email_change_token\":\"123456\",\"nonce\":\"abcdef\",\"password\":\"another.pass\",\"phone\":\"+1 202-918-2132\"}" \ + --data "{\"data\":{\"custom_key\":\"custom_value\"},\"email\":\"example@mail.com\",\"nonce\":\"abcdef\",\"password\":\"another.pass\",\"phone\":\"+1 202-918-2132\"}" \ "http://localhost:54321/auth/v1/user" \ No newline at end of file