• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / supabase-swift / 17321717294

29 Aug 2025 10:44AM UTC coverage: 78.634% (+1.2%) from 77.386%
17321717294

Pull #781

github

web-flow
Merge 80b20054e into e4d8c3718
Pull Request #781: RFC: Migrate HTTP networking from URLSession to Alamofire

1027 of 1123 new or added lines in 27 files covered. (91.45%)

27 existing lines in 8 files now uncovered.

5156 of 6557 relevant lines covered (78.63%)

29.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.0
/Sources/Auth/AuthError.swift
1
import Foundation
2

3
#if canImport(FoundationNetworking)
4
  import FoundationNetworking
5
#endif
6

7
/// An error code thrown by the server.
8
public struct ErrorCode: Decodable, RawRepresentable, Sendable, Hashable {
9
  public var rawValue: String
10

11
  public init(rawValue: String) {
5✔
12
    self.rawValue = rawValue
5✔
13
  }
5✔
14

15
  public init(_ rawValue: String) {
5✔
16
    self.init(rawValue: rawValue)
5✔
17
  }
5✔
18
}
19

20
// Known error codes. Note that the server may also return other error codes
21
// not included in this list (if the client library is older than the version
22
// on the server).
23
extension ErrorCode {
24
  /// ErrorCodeUnknown should not be used directly, it only indicates a failure in the error handling system in such a way that an error code was not assigned properly.
25
  public static let unknown = ErrorCode("unknown")
26

27
  /// ErrorCodeUnexpectedFailure signals an unexpected failure such as a 500 Internal Server Error.
28
  public static let unexpectedFailure = ErrorCode("unexpected_failure")
29

30
  public static let validationFailed = ErrorCode("validation_failed")
31
  public static let badJSON = ErrorCode("bad_json")
32
  public static let emailExists = ErrorCode("email_exists")
33
  public static let phoneExists = ErrorCode("phone_exists")
34
  public static let badJWT = ErrorCode("bad_jwt")
35
  public static let notAdmin = ErrorCode("not_admin")
36
  public static let noAuthorization = ErrorCode("no_authorization")
37
  public static let userNotFound = ErrorCode("user_not_found")
38
  public static let sessionNotFound = ErrorCode("session_not_found")
39
  public static let sessionExpired = ErrorCode("session_expired")
40
  public static let refreshTokenNotFound = ErrorCode("refresh_token_not_found")
41
  public static let refreshTokenAlreadyUsed = ErrorCode("refresh_token_already_used")
42
  public static let flowStateNotFound = ErrorCode("flow_state_not_found")
43
  public static let flowStateExpired = ErrorCode("flow_state_expired")
44
  public static let signupDisabled = ErrorCode("signup_disabled")
45
  public static let userBanned = ErrorCode("user_banned")
46
  public static let providerEmailNeedsVerification = ErrorCode(
47
    "provider_email_needs_verification")
48
  public static let inviteNotFound = ErrorCode("invite_not_found")
49
  public static let badOAuthState = ErrorCode("bad_oauth_state")
50
  public static let badOAuthCallback = ErrorCode("bad_oauth_callback")
51
  public static let oauthProviderNotSupported = ErrorCode("oauth_provider_not_supported")
52
  public static let unexpectedAudience = ErrorCode("unexpected_audience")
53
  public static let singleIdentityNotDeletable = ErrorCode("single_identity_not_deletable")
54
  public static let emailConflictIdentityNotDeletable = ErrorCode(
55
    "email_conflict_identity_not_deletable")
56
  public static let identityAlreadyExists = ErrorCode("identity_already_exists")
57
  public static let emailProviderDisabled = ErrorCode("email_provider_disabled")
58
  public static let phoneProviderDisabled = ErrorCode("phone_provider_disabled")
59
  public static let tooManyEnrolledMFAFactors = ErrorCode("too_many_enrolled_mfa_factors")
60
  public static let mfaFactorNameConflict = ErrorCode("mfa_factor_name_conflict")
61
  public static let mfaFactorNotFound = ErrorCode("mfa_factor_not_found")
62
  public static let mfaIPAddressMismatch = ErrorCode("mfa_ip_address_mismatch")
63
  public static let mfaChallengeExpired = ErrorCode("mfa_challenge_expired")
64
  public static let mfaVerificationFailed = ErrorCode("mfa_verification_failed")
65
  public static let mfaVerificationRejected = ErrorCode("mfa_verification_rejected")
66
  public static let insufficientAAL = ErrorCode("insufficient_aal")
67
  public static let captchaFailed = ErrorCode("captcha_failed")
68
  public static let samlProviderDisabled = ErrorCode("saml_provider_disabled")
69
  public static let manualLinkingDisabled = ErrorCode("manual_linking_disabled")
70
  public static let smsSendFailed = ErrorCode("sms_send_failed")
71
  public static let emailNotConfirmed = ErrorCode("email_not_confirmed")
72
  public static let phoneNotConfirmed = ErrorCode("phone_not_confirmed")
73
  public static let samlRelayStateNotFound = ErrorCode("saml_relay_state_not_found")
74
  public static let samlRelayStateExpired = ErrorCode("saml_relay_state_expired")
75
  public static let samlIdPNotFound = ErrorCode("saml_idp_not_found")
76
  public static let samlAssertionNoUserID = ErrorCode("saml_assertion_no_user_id")
77
  public static let samlAssertionNoEmail = ErrorCode("saml_assertion_no_email")
78
  public static let userAlreadyExists = ErrorCode("user_already_exists")
79
  public static let ssoProviderNotFound = ErrorCode("sso_provider_not_found")
80
  public static let samlMetadataFetchFailed = ErrorCode("saml_metadata_fetch_failed")
81
  public static let samlIdPAlreadyExists = ErrorCode("saml_idp_already_exists")
82
  public static let ssoDomainAlreadyExists = ErrorCode("sso_domain_already_exists")
83
  public static let samlEntityIDMismatch = ErrorCode("saml_entity_id_mismatch")
84
  public static let conflict = ErrorCode("conflict")
85
  public static let providerDisabled = ErrorCode("provider_disabled")
86
  public static let userSSOManaged = ErrorCode("user_sso_managed")
87
  public static let reauthenticationNeeded = ErrorCode("reauthentication_needed")
88
  public static let samePassword = ErrorCode("same_password")
89
  public static let reauthenticationNotValid = ErrorCode("reauthentication_not_valid")
90
  public static let otpExpired = ErrorCode("otp_expired")
91
  public static let otpDisabled = ErrorCode("otp_disabled")
92
  public static let identityNotFound = ErrorCode("identity_not_found")
93
  public static let weakPassword = ErrorCode("weak_password")
94
  public static let overRequestRateLimit = ErrorCode("over_request_rate_limit")
95
  public static let overEmailSendRateLimit = ErrorCode("over_email_send_rate_limit")
96
  public static let overSMSSendRateLimit = ErrorCode("over_sms_send_rate_limit")
97
  public static let badCodeVerifier = ErrorCode("bad_code_verifier")
98
  public static let anonymousProviderDisabled = ErrorCode("anonymous_provider_disabled")
99
  public static let hookTimeout = ErrorCode("hook_timeout")
100
  public static let hookTimeoutAfterRetry = ErrorCode("hook_timeout_after_retry")
101
  public static let hookPayloadOverSizeLimit = ErrorCode("hook_payload_over_size_limit")
102
  public static let hookPayloadInvalidContentType = ErrorCode(
103
    "hook_payload_invalid_content_type")
104
  public static let requestTimeout = ErrorCode("request_timeout")
105
  public static let mfaPhoneEnrollDisabled = ErrorCode("mfa_phone_enroll_not_enabled")
106
  public static let mfaPhoneVerifyDisabled = ErrorCode("mfa_phone_verify_not_enabled")
107
  public static let mfaTOTPEnrollDisabled = ErrorCode("mfa_totp_enroll_not_enabled")
108
  public static let mfaTOTPVerifyDisabled = ErrorCode("mfa_totp_verify_not_enabled")
109
  public static let mfaWebAuthnEnrollDisabled = ErrorCode(
110
    "mfa_webauthn_enroll_not_enabled")
111
  public static let mfaWebAuthnVerifyDisabled = ErrorCode(
112
    "mfa_webauthn_verify_not_enabled")
113
  public static let mfaVerifiedFactorExists = ErrorCode("mfa_verified_factor_exists")
114
  //#nosec G101 -- Not a secret value.
115
  public static let invalidCredentials = ErrorCode("invalid_credentials")
116
  public static let emailAddressNotAuthorized = ErrorCode("email_address_not_authorized")
117
}
118

119
public enum AuthError: LocalizedError {
120
  @available(
121
    *,
122
    deprecated,
123
    message:
124
      "Error used to be thrown when no exp claim was found in JWT during setSession(accessToken:refreshToken:) method."
125
  )
126
  case missingExpClaim
127

128
  @available(
129
    *,
130
    deprecated,
131
    message:
132
      "Error used to be thrown when provided JWT wasn't valid during setSession(accessToken:refreshToken:) method."
133
  )
134
  case malformedJWT
135

136
  @available(*, deprecated, renamed: "sessionMissing")
137
  public static var sessionNotFound: AuthError { .sessionMissing }
×
138

139
  /// Error thrown during PKCE flow.
140
  @available(
141
    *,
142
    deprecated,
143
    renamed: "pkceGrantCodeExchange",
144
    message: "Error was grouped in `pkceGrantCodeExchange`, please use it instead of `pkce`."
145
  )
146
  public static func pkce(_ reason: PKCEFailureReason) -> AuthError {
×
147
    switch reason {
×
148
    case .codeVerifierNotFound:
×
149
      .pkceGrantCodeExchange(message: "A code verifier wasn't found in PKCE flow.")
×
150
    case .invalidPKCEFlowURL:
×
151
      .pkceGrantCodeExchange(message: "Not a valid PKCE flow url.")
×
152
    }
×
153
  }
×
154

155
  @available(*, deprecated, message: "Use `pkceGrantCodeExchange` instead.")
156
  public enum PKCEFailureReason: Sendable {
157
    /// Code verifier not found in the URL.
158
    case codeVerifierNotFound
159

160
    /// Not a valid PKCE flow URL.
161
    case invalidPKCEFlowURL
162
  }
163

164
  @available(*, deprecated, renamed: "implicitGrantRedirect")
165
  public static var invalidImplicitGrantFlowURL: AuthError {
×
166
    .implicitGrantRedirect(message: "Not a valid implicit grant flow url.")
×
167
  }
×
168

169
  @available(
170
    *,
171
    deprecated,
172
    message:
173
      "This error is never thrown, if you depend on it, you can remove the logic as it never happens."
174
  )
175
  case missingURL
176

177
  @available(
178
    *,
179
    deprecated,
180
    message:
181
      "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."
182
  )
183
  case invalidRedirectScheme
184

185
  @available(
186
    *,
187
    deprecated,
188
    renamed: "api(message:errorCode:underlyingData:underlyingResponse:)"
189
  )
190
  public static func api(_ error: APIError) -> AuthError {
×
191
    let message = error.msg ?? error.error ?? error.errorDescription ?? "Unexpected API error."
×
192
    if let weakPassword = error.weakPassword {
×
193
      return .weakPassword(message: message, reasons: weakPassword.reasons)
×
194
    }
×
195

×
196
    return .api(
×
197
      message: message,
×
198
      errorCode: .unknown,
×
199
      underlyingData: (try? AuthClient.Configuration.jsonEncoder.encode(error)) ?? Data(),
×
200
      underlyingResponse: HTTPURLResponse(
×
201
        url: defaultAuthURL,
×
202
        statusCode: error.code ?? 500,
×
203
        httpVersion: nil,
×
204
        headerFields: nil
×
205
      )!
×
206
    )
×
207
  }
×
208

209
  /// An error returned by the API.
210
  @available(
211
    *,
212
    deprecated,
213
    renamed: "api(message:errorCode:underlyingData:underlyingResponse:)"
214
  )
215
  public struct APIError: Error, Codable, Sendable, Equatable {
216
    /// A basic message describing the problem with the request. Usually missing if
217
    /// ``AuthError/APIError/error`` is present.
218
    public var msg: String?
219

220
    /// The HTTP status code. Usually missing if ``AuthError/APIError/error`` is present.
221
    public var code: Int?
222

223
    /// Certain responses will contain this property with the provided values.
224
    ///
225
    /// Usually one of these:
226
    ///   - `invalid_request`
227
    ///   - `unauthorized_client`
228
    ///   - `access_denied`
229
    ///   - `server_error`
230
    ///   - `temporarily_unavailable`
231
    ///   - `unsupported_otp_type`
232
    public var error: String?
233

234
    /// Certain responses that have an ``AuthError/APIError/error`` property may have this property
235
    /// which describes the error.
236
    public var errorDescription: String?
237

238
    /// Only returned when signing up if the password used is too weak. Inspect the
239
    /// ``WeakPassword/reasons`` and ``AuthError/APIError/msg`` property to identify the causes.
240
    public var weakPassword: WeakPassword?
241
  }
242

243
  /// Error thrown when a session is required to proceed, but none was found, either thrown by the client, or returned by the server.
244
  case sessionMissing
245

246
  /// Error thrown when password is deemed weak, check associated reasons to know why.
247
  case weakPassword(message: String, reasons: [String])
248

249
  /// Error thrown by API when an error occurs, check `errorCode` to know more,
250
  /// or use `underlyingData` or `underlyingResponse` for access to the response which originated this error.
251
  case api(
252
    message: String,
253
    errorCode: ErrorCode,
254
    underlyingData: Data,
255
    underlyingResponse: HTTPURLResponse
256
  )
257

258
  /// Error thrown when an error happens during PKCE grant flow.
259
  case pkceGrantCodeExchange(message: String, error: String? = nil, code: String? = nil)
260

261
  /// Error thrown when an error happens during implicit grant flow.
262
  case implicitGrantRedirect(message: String)
263

264
  case unknown(any Error)
265

266
  /// The message of the error.
267
  public var message: String {
5✔
268
    switch self {
5✔
269
    case .sessionMissing: "Auth session missing."
5✔
270
    case let .weakPassword(message, _),
5✔
271
      let .api(message, _, _, _),
4✔
272
      let .pkceGrantCodeExchange(message, _, _),
4✔
273
      let .implicitGrantRedirect(message):
4✔
274
      message
4✔
275
    // Deprecated cases
5✔
276
    case .missingExpClaim: "Missing expiration claim in the access token."
5✔
277
    case .malformedJWT: "A malformed JWT received."
5✔
278
    case .invalidRedirectScheme: "Invalid redirect scheme."
5✔
279
    case .missingURL: "Missing URL."
5✔
280
    case .unknown(let error): "Unkown error: \(error.localizedDescription)"
5✔
281
    }
5✔
282
  }
5✔
283

284
  /// The error code of the error.
285
  public var errorCode: ErrorCode {
5✔
286
    switch self {
5✔
287
    case .sessionMissing: .sessionNotFound
5✔
288
    case .weakPassword: .weakPassword
5✔
289
    case let .api(_, errorCode, _, _): errorCode
5✔
290
    case .pkceGrantCodeExchange, .implicitGrantRedirect: .unknown
5✔
291
    // Deprecated cases
5✔
292
    case .missingExpClaim, .malformedJWT, .invalidRedirectScheme, .missingURL, .unknown: .unknown
5✔
293
    }
5✔
294
  }
5✔
295

296
  /// The description of the error.
297
  public var errorDescription: String? {
×
298
    message
×
299
  }
×
300

301
  /// The underlying error if the error is an ``AuthError/unknown(any Error)`` error.
NEW
302
  public var underlyingError: (any Error)? {
×
NEW
303
    switch self {
×
NEW
304
    case .unknown(let error): error
×
NEW
305
    default: nil
×
NEW
306
    }
×
NEW
307
  }
×
308
}
309

310
/// Maps an error to an ``AuthError``.
311
func mapToAuthError(_ error: any Error) -> AuthError {
9✔
312
  if let error = error as? AuthError {
9✔
313
    return error
6✔
314
  }
6✔
315
  if let error = error.asAFError {
3✔
316
    if let underlyingError = error.underlyingError as? AuthError {
3✔
317
      return underlyingError
3✔
318
    }
3✔
UNCOV
319
  }
×
NEW
320
  return AuthError.unknown(error)
×
321
}
9✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc