@supabase/gotrue-js 2.108.2 → 2.112.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +6 -2
  2. package/dist/main/GoTrueAdminApi.d.ts +1 -4
  3. package/dist/main/GoTrueAdminApi.d.ts.map +1 -1
  4. package/dist/main/GoTrueAdminApi.js +1 -4
  5. package/dist/main/GoTrueAdminApi.js.map +1 -1
  6. package/dist/main/GoTrueClient.d.ts +67 -21
  7. package/dist/main/GoTrueClient.d.ts.map +1 -1
  8. package/dist/main/GoTrueClient.js +217 -68
  9. package/dist/main/GoTrueClient.js.map +1 -1
  10. package/dist/main/lib/constants.d.ts +13 -0
  11. package/dist/main/lib/constants.d.ts.map +1 -1
  12. package/dist/main/lib/constants.js +14 -1
  13. package/dist/main/lib/constants.js.map +1 -1
  14. package/dist/main/lib/errors.d.ts +1 -1
  15. package/dist/main/lib/fetch.d.ts.map +1 -1
  16. package/dist/main/lib/fetch.js +12 -6
  17. package/dist/main/lib/fetch.js.map +1 -1
  18. package/dist/main/lib/helpers.d.ts +50 -1
  19. package/dist/main/lib/helpers.d.ts.map +1 -1
  20. package/dist/main/lib/helpers.js +161 -5
  21. package/dist/main/lib/helpers.js.map +1 -1
  22. package/dist/main/lib/locks.d.ts +1 -1
  23. package/dist/main/lib/locks.js +1 -1
  24. package/dist/main/lib/types.d.ts +71 -9
  25. package/dist/main/lib/types.d.ts.map +1 -1
  26. package/dist/main/lib/types.js.map +1 -1
  27. package/dist/main/lib/version.d.ts +1 -1
  28. package/dist/main/lib/version.js +1 -1
  29. package/dist/module/GoTrueAdminApi.d.ts +1 -4
  30. package/dist/module/GoTrueAdminApi.d.ts.map +1 -1
  31. package/dist/module/GoTrueAdminApi.js +1 -4
  32. package/dist/module/GoTrueAdminApi.js.map +1 -1
  33. package/dist/module/GoTrueClient.d.ts +67 -21
  34. package/dist/module/GoTrueClient.d.ts.map +1 -1
  35. package/dist/module/GoTrueClient.js +219 -70
  36. package/dist/module/GoTrueClient.js.map +1 -1
  37. package/dist/module/lib/constants.d.ts +13 -0
  38. package/dist/module/lib/constants.d.ts.map +1 -1
  39. package/dist/module/lib/constants.js +13 -0
  40. package/dist/module/lib/constants.js.map +1 -1
  41. package/dist/module/lib/errors.d.ts +1 -1
  42. package/dist/module/lib/fetch.d.ts.map +1 -1
  43. package/dist/module/lib/fetch.js +12 -6
  44. package/dist/module/lib/fetch.js.map +1 -1
  45. package/dist/module/lib/helpers.d.ts +50 -1
  46. package/dist/module/lib/helpers.d.ts.map +1 -1
  47. package/dist/module/lib/helpers.js +153 -5
  48. package/dist/module/lib/helpers.js.map +1 -1
  49. package/dist/module/lib/locks.d.ts +1 -1
  50. package/dist/module/lib/locks.js +1 -1
  51. package/dist/module/lib/types.d.ts +71 -9
  52. package/dist/module/lib/types.d.ts.map +1 -1
  53. package/dist/module/lib/types.js.map +1 -1
  54. package/dist/module/lib/version.d.ts +1 -1
  55. package/dist/module/lib/version.js +1 -1
  56. package/dist/tsconfig.module.tsbuildinfo +1 -1
  57. package/dist/tsconfig.tsbuildinfo +1 -1
  58. package/package.json +4 -4
  59. package/src/GoTrueAdminApi.ts +1 -4
  60. package/src/GoTrueClient.ts +268 -91
  61. package/src/lib/constants.ts +15 -0
  62. package/src/lib/errors.ts +1 -1
  63. package/src/lib/fetch.ts +13 -8
  64. package/src/lib/helpers.ts +198 -6
  65. package/src/lib/locks.ts +1 -1
  66. package/src/lib/types.ts +71 -9
  67. package/src/lib/version.ts +1 -1
@@ -40,4 +40,19 @@ export const API_VERSIONS = {
40
40
 
41
41
  export const BASE64URL_REGEX = /^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}$|[a-z0-9_-]{2}$)$/i
42
42
 
43
+ /**
44
+ * Reserved query parameter appended to `redirectTo` URLs (behind
45
+ * `experimental.appendPkceFlowIdToRedirects`) that correlates a PKCE callback
46
+ * with the code verifier stored when its flow started. It round-trips through
47
+ * the auth server untouched and identifies a verifier slot in storage — the
48
+ * verifier itself never appears in a URL.
49
+ */
50
+ export const PKCE_FLOW_ID_PARAM = 'sb_flow_id'
51
+
52
+ /**
53
+ * Maximum number of PKCE code verifiers kept in storage at once. Starting a
54
+ * new flow beyond this evicts the oldest pending verifier.
55
+ */
56
+ export const PKCE_MAX_CONCURRENT_FLOWS = 5
57
+
43
58
  export const JWKS_TTL = 10 * 60 * 1000 // 10 minutes
package/src/lib/errors.ts CHANGED
@@ -16,7 +16,7 @@ export class AuthError extends Error {
16
16
  * Error code associated with the error. Most errors coming from
17
17
  * HTTP responses will have a code, though some errors that occur
18
18
  * before a response is received will not have one present. In that
19
- * case {@link #status} will also be undefined.
19
+ * case {@link AuthError.status} will also be undefined.
20
20
  */
21
21
  code: ErrorCode | (string & {}) | undefined
22
22
 
package/src/lib/fetch.ts CHANGED
@@ -81,18 +81,22 @@ export async function handleError(error: unknown) {
81
81
  throw new AuthRetryableFetchError(_getErrorMessage(error), 0)
82
82
  }
83
83
 
84
- if (NETWORK_ERROR_CODES.includes(error.status)) {
85
- // status in 500...599 range - server had an error, request might be retryed.
86
- throw new AuthRetryableFetchError(_getErrorMessage(error), error.status)
87
- }
88
-
89
84
  let data: any
90
85
  try {
91
86
  data = await error.json()
92
87
  } catch (e) {
88
+ if (NETWORK_ERROR_CODES.includes(error.status)) {
89
+ // statusText can be empty — HTTP/2 has no reason phrase
90
+ throw new AuthRetryableFetchError(error.statusText || `HTTP ${error.status}`, error.status)
91
+ }
93
92
  throw new AuthUnknownError(_getErrorMessage(e), e)
94
93
  }
95
94
 
95
+ if (NETWORK_ERROR_CODES.includes(error.status)) {
96
+ // status in 500...599 range - server had an error, request might be retryed.
97
+ throw new AuthRetryableFetchError(_getErrorMessage(data), error.status)
98
+ }
99
+
96
100
  let errorCode: string | undefined = undefined
97
101
 
98
102
  const responseAPIVersion = parseResponseAPIVersion(error)
@@ -224,9 +228,10 @@ async function _handleRequest(
224
228
  ...requestParams,
225
229
  })
226
230
  } catch (e) {
227
- console.error(e)
228
-
229
- // fetch failed, likely due to a network or CORS error
231
+ // fetch failed (network / CORS / aborted request) — surfaced to the
232
+ // caller as a retryable error below. Deliberately not logged here: an
233
+ // aborted in-flight request (e.g. a superseded page navigation) is a
234
+ // transient condition, and logging the raw error pollutes the console.
230
235
  throw new AuthRetryableFetchError(_getErrorMessage(e), 0)
231
236
  }
232
237
 
@@ -1,4 +1,9 @@
1
- import { API_VERSION_HEADER_NAME, BASE64URL_REGEX } from './constants'
1
+ import {
2
+ API_VERSION_HEADER_NAME,
3
+ BASE64URL_REGEX,
4
+ PKCE_FLOW_ID_PARAM,
5
+ PKCE_MAX_CONCURRENT_FLOWS,
6
+ } from './constants'
2
7
  import { AuthInvalidJwtError } from './errors'
3
8
  import { base64UrlToUint8Array, stringFromBase64URL } from './base64url'
4
9
  import { JwtHeader, JwtPayload, SupportedStorage, User } from './types'
@@ -301,20 +306,207 @@ export async function generatePKCEChallenge(verifier: string) {
301
306
  return btoa(hashed).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
302
307
  }
303
308
 
309
+ const PKCE_FLOW_ID_PATTERN = /^[a-zA-Z0-9_-]{8,64}$/
310
+
311
+ /**
312
+ * Returns the flow id if it is a plausible flow id, `null` otherwise. Flow
313
+ * ids can arrive via URL parameters, so anything outside the expected shape
314
+ * is discarded before it is used to build a storage key.
315
+ */
316
+ export function validatePKCEFlowId(flowId: unknown): string | null {
317
+ return typeof flowId === 'string' && PKCE_FLOW_ID_PATTERN.test(flowId) ? flowId : null
318
+ }
319
+
320
+ export function generatePKCEFlowId(): string {
321
+ if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {
322
+ const bytes = new Uint8Array(16)
323
+ crypto.getRandomValues(bytes)
324
+ return Array.from(bytes, dec2hex).join('')
325
+ }
326
+ let flowId = ''
327
+ for (let i = 0; i < 32; i++) {
328
+ flowId += Math.floor(Math.random() * 16).toString(16)
329
+ }
330
+ return flowId
331
+ }
332
+
333
+ // Slot keys deliberately end in `-code-verifier`: @supabase/ssr's server
334
+ // cookie adapter only persists writes immediately for keys with that suffix
335
+ // (no auth event fires when a verifier is stored). They also contain no dot,
336
+ // because @supabase/ssr chunks oversized cookies as `<key>.<number>` and a
337
+ // dot-delimited key could be mistaken for a chunk of the fixed
338
+ // `-code-verifier` cookie and clobbered by its chunk management.
339
+ export const pkceVerifierSlotKey = (storageKey: string, flowId: string) =>
340
+ `${storageKey}-flow-${flowId}-code-verifier`
341
+
342
+ const pkceFlowIndexKey = (storageKey: string) => `${storageKey}-flows-code-verifier`
343
+
344
+ /**
345
+ * Storage adapters cannot enumerate keys, so the ids of pending verifier
346
+ * slots are tracked in an index entry, oldest first. Index entries pass
347
+ * through the same validation as URL-provided flow ids: with cookie-based
348
+ * storage the index contents are no more trustworthy than a URL parameter.
349
+ */
350
+ async function getPKCEFlowIndex(storage: SupportedStorage, storageKey: string): Promise<string[]> {
351
+ const index = await getItemAsync(storage, pkceFlowIndexKey(storageKey))
352
+ return Array.isArray(index)
353
+ ? index.filter((id): id is string => validatePKCEFlowId(id) !== null)
354
+ : []
355
+ }
356
+
357
+ /**
358
+ * The index is read-modify-write without a lock: two concurrent starts (e.g.
359
+ * two tabs) can lose one index update. The losing flow still works — its slot
360
+ * is addressed directly by key — but its entry is missing from the index, so
361
+ * it escapes both ring eviction and removeAllPKCEVerifiers: the orphaned slot
362
+ * persists for the storage medium's lifetime (up to the cookie max age in
363
+ * cookie storage) and repeated races accumulate one orphan each. Accepted
364
+ * trade-off: locking every flow start is far more intrusive than the leak.
365
+ */
366
+ export async function storePKCEVerifier(
367
+ storage: SupportedStorage,
368
+ storageKey: string,
369
+ flowId: string,
370
+ verifier: string,
371
+ onEvictFlow?: (evictedFlowId: string) => void
372
+ ): Promise<void> {
373
+ await setItemAsync(storage, pkceVerifierSlotKey(storageKey, flowId), verifier)
374
+
375
+ const index = (await getPKCEFlowIndex(storage, storageKey)).filter((id) => id !== flowId)
376
+ index.push(flowId)
377
+ while (index.length > PKCE_MAX_CONCURRENT_FLOWS) {
378
+ const evicted = index.shift()!
379
+ await removeItemAsync(storage, pkceVerifierSlotKey(storageKey, evicted))
380
+ onEvictFlow?.(evicted)
381
+ }
382
+ await setItemAsync(storage, pkceFlowIndexKey(storageKey), index)
383
+
384
+ // Deprecation-window dual write: exchanges that cannot identify their flow
385
+ // (older SDK versions, redirects without the flow id parameter) read the
386
+ // fixed key, which mirrors the most recently started flow.
387
+ await setItemAsync(storage, `${storageKey}-code-verifier`, verifier)
388
+ }
389
+
390
+ /**
391
+ * Looks up the verifier for `flowId`. When a flow id is given, only that slot
392
+ * is consulted — deliberately no fallback to the fixed legacy key: submitting
393
+ * another flow's verifier would burn the single-use auth code, and the
394
+ * subsequent cleanup would delete a pending flow's only fallback. The legacy
395
+ * key is read only when no flow id is available at all.
396
+ */
397
+ export async function retrievePKCEVerifier(
398
+ storage: SupportedStorage,
399
+ storageKey: string,
400
+ flowId: string | null
401
+ ): Promise<{ verifier: string | null; flowId: string | null }> {
402
+ if (flowId) {
403
+ const verifier = await getItemAsync(storage, pkceVerifierSlotKey(storageKey, flowId))
404
+ return { verifier: typeof verifier === 'string' ? verifier : null, flowId }
405
+ }
406
+ const verifier = await getItemAsync(storage, `${storageKey}-code-verifier`)
407
+ return { verifier: typeof verifier === 'string' ? verifier : null, flowId: null }
408
+ }
409
+
410
+ /**
411
+ * Removes a single flow's verifier. Never clears other flows' slots: with a
412
+ * `flowId` only that slot is deleted (plus the legacy fixed key when it holds
413
+ * the same verifier); without one, only the legacy fixed key is deleted.
414
+ */
415
+ export async function removePKCEVerifier(
416
+ storage: SupportedStorage,
417
+ storageKey: string,
418
+ flowId: string | null
419
+ ): Promise<void> {
420
+ const legacyKey = `${storageKey}-code-verifier`
421
+ if (!flowId) {
422
+ await removeItemAsync(storage, legacyKey)
423
+ return
424
+ }
425
+
426
+ const slotKey = pkceVerifierSlotKey(storageKey, flowId)
427
+ const slotValue = await getItemAsync(storage, slotKey)
428
+ await removeItemAsync(storage, slotKey)
429
+
430
+ // Skip the index rewrite when the flow was never indexed (e.g. a failed
431
+ // exchange for an absent slot): on cookie storage every write is a full
432
+ // Set-Cookie cycle.
433
+ const index = await getPKCEFlowIndex(storage, storageKey)
434
+ const remaining = index.filter((id) => id !== flowId)
435
+ if (remaining.length !== index.length) {
436
+ if (remaining.length > 0) {
437
+ await setItemAsync(storage, pkceFlowIndexKey(storageKey), remaining)
438
+ } else {
439
+ await removeItemAsync(storage, pkceFlowIndexKey(storageKey))
440
+ }
441
+ }
442
+
443
+ if (slotValue != null && slotValue === (await getItemAsync(storage, legacyKey))) {
444
+ await removeItemAsync(storage, legacyKey)
445
+ }
446
+ }
447
+
448
+ /**
449
+ * Removes every pending verifier: all slots in the index, the index itself
450
+ * and the fixed legacy key. Used on session teardown (sign-out, invalid
451
+ * session) — matches the pre-slot behavior where tearing down the session
452
+ * deleted the only verifier, and prevents long-lived stale verifier cookies.
453
+ */
454
+ export async function removeAllPKCEVerifiers(
455
+ storage: SupportedStorage,
456
+ storageKey: string
457
+ ): Promise<void> {
458
+ const index = await getPKCEFlowIndex(storage, storageKey)
459
+ for (const flowId of index) {
460
+ await removeItemAsync(storage, pkceVerifierSlotKey(storageKey, flowId))
461
+ }
462
+ await removeItemAsync(storage, pkceFlowIndexKey(storageKey))
463
+ await removeItemAsync(storage, `${storageKey}-code-verifier`)
464
+ }
465
+
466
+ /**
467
+ * Appends the reserved flow id parameter to a `redirectTo` URL, replacing any
468
+ * existing occurrence. String-based (no URL round-trip) so custom schemes
469
+ * (native deep links) and the exact encoding of the app's own parameters
470
+ * survive untouched; an existing fragment stays at the end of the URL.
471
+ */
472
+ export function appendFlowIdToRedirectTo(redirectTo: string, flowId: string): string {
473
+ const hashIndex = redirectTo.indexOf('#')
474
+ let base = hashIndex === -1 ? redirectTo : redirectTo.slice(0, hashIndex)
475
+ const fragment = hashIndex === -1 ? '' : redirectTo.slice(hashIndex)
476
+
477
+ const queryIndex = base.indexOf('?')
478
+ if (queryIndex !== -1) {
479
+ const path = base.slice(0, queryIndex)
480
+ const remaining = base
481
+ .slice(queryIndex + 1)
482
+ .split('&')
483
+ .filter(
484
+ (pair) =>
485
+ pair !== '' && pair !== PKCE_FLOW_ID_PARAM && !pair.startsWith(`${PKCE_FLOW_ID_PARAM}=`)
486
+ )
487
+ base = remaining.length > 0 ? `${path}?${remaining.join('&')}` : path
488
+ }
489
+
490
+ const separator = base.includes('?') ? '&' : '?'
491
+ return `${base}${separator}${PKCE_FLOW_ID_PARAM}=${encodeURIComponent(flowId)}${fragment}`
492
+ }
493
+
304
494
  export async function getCodeChallengeAndMethod(
305
495
  storage: SupportedStorage,
306
496
  storageKey: string,
307
- isPasswordRecovery = false
308
- ) {
497
+ isPasswordRecovery = false,
498
+ onEvictFlow?: (evictedFlowId: string) => void
499
+ ): Promise<[string, string, string]> {
309
500
  const codeVerifier = generatePKCEVerifier()
310
501
  let storedCodeVerifier = codeVerifier
311
502
  if (isPasswordRecovery) {
312
503
  storedCodeVerifier += '/recovery'
313
504
  }
314
- await setItemAsync(storage, `${storageKey}-code-verifier`, storedCodeVerifier)
505
+ const flowId = generatePKCEFlowId()
506
+ await storePKCEVerifier(storage, storageKey, flowId, storedCodeVerifier, onEvictFlow)
315
507
  const codeChallenge = await generatePKCEChallenge(codeVerifier)
316
508
  const codeChallengeMethod = codeVerifier === codeChallenge ? 'plain' : 's256'
317
- return [codeChallenge, codeChallengeMethod]
509
+ return [codeChallenge, codeChallengeMethod, flowId]
318
510
  }
319
511
 
320
512
  /** Parses the API version which is 2YYY-MM-DD. */
@@ -369,7 +561,7 @@ export function getAlgorithm(
369
561
  }
370
562
  }
371
563
 
372
- const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
564
+ const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
373
565
 
374
566
  export function validateUUID(str: string) {
375
567
  if (!UUID_REGEX.test(str)) {
package/src/lib/locks.ts CHANGED
@@ -302,7 +302,7 @@ const PROCESS_LOCKS: { [name: string]: Promise<any> } = {}
302
302
  * Useful for environments like React Native or other non-browser
303
303
  * single-process (i.e. no concept of "tabs") environments.
304
304
  *
305
- * Use {@link #navigatorLock} in browser environments.
305
+ * Use {@link navigatorLock} in browser environments.
306
306
  *
307
307
  * @param name Name of the lock to be acquired.
308
308
  * @param acquireTimeout If negative, no timeout. If 0 an error is thrown if
package/src/lib/types.ts CHANGED
@@ -190,6 +190,30 @@ export type ExperimentalFeatureFlags = {
190
190
  * disabled throws a descriptive error at call time.
191
191
  */
192
192
  passkey?: boolean
193
+ /**
194
+ * Appends a reserved `sb_flow_id` query parameter to `redirectTo` URLs on
195
+ * PKCE flows. The parameter round-trips through the auth server back to
196
+ * your callback URL, where the client uses it to select the code verifier
197
+ * created by that specific flow — so multiple sign-in flows (e.g. two OAuth
198
+ * providers started in different tabs) can be in flight at the same time
199
+ * without overwriting each other.
200
+ *
201
+ * Before enabling, make sure your [redirect URL allow
202
+ * list](https://supabase.com/docs/guides/auth/redirect-urls) tolerates the
203
+ * extra query parameter: allow-list entries are matched against the full
204
+ * URL including the query string, so an exact entry (no wildcard) stops
205
+ * matching once the parameter is appended and the redirect falls back to
206
+ * your Site URL. Redirects to the Site URL's own origin always pass.
207
+ *
208
+ * Defaults to `false`. Without it, concurrent flows still keep separate
209
+ * verifiers in storage, but no flow id travels through the redirect: to
210
+ * match a callback to its verifier you must carry the `flowId` returned by
211
+ * `signInWithOAuth` (or `linkIdentity`) through your own channel and pass
212
+ * it to `exchangeCodeForSession`. Flows that offer no way to obtain the
213
+ * flow id (email OTP, password recovery, sign-up confirmation) can only be
214
+ * correlated via this flag.
215
+ */
216
+ appendPkceFlowIdToRedirects?: boolean
193
217
  }
194
218
 
195
219
  const WeakPasswordReasons = ['length', 'characters', 'pwned'] as const
@@ -228,7 +252,7 @@ export type RequestResult<T, ErrorType extends Error = AuthError> =
228
252
 
229
253
  /**
230
254
  * similar to RequestResult except it allows you to destructure the possible shape of the success response
231
- * {@see RequestResult}
255
+ * {@link RequestResult}
232
256
  */
233
257
  export type RequestResultSafeDestructure<T> =
234
258
  | { data: T; error: null }
@@ -251,7 +275,7 @@ export type AuthResponsePassword = RequestResultSafeDestructure<{
251
275
  /**
252
276
  * AuthOtpResponse is returned when OTP is used.
253
277
  *
254
- * {@see AuthResponse}
278
+ * {@link AuthResponse}
255
279
  */
256
280
  export type AuthOtpResponse = RequestResultSafeDestructure<{
257
281
  user: null
@@ -275,6 +299,19 @@ export type OAuthResponse =
275
299
  data: {
276
300
  provider: Provider
277
301
  url: string
302
+ /**
303
+ * Identifier of the PKCE flow started by this call, usable as the
304
+ * `flowId` option of {@link GoTrueClient#exchangeCodeForSession} to
305
+ * select this flow's code verifier when several flows are in flight.
306
+ * `null` on the implicit flow. The id is a selector for a verifier
307
+ * kept in storage — it is not a secret and never contains the
308
+ * verifier itself.
309
+ *
310
+ * Always set at runtime; optional in the type so existing code that
311
+ * constructs `OAuthResponse` values (e.g. test mocks) keeps
312
+ * compiling.
313
+ */
314
+ flowId?: string | null
278
315
  }
279
316
  error: null
280
317
  }
@@ -282,6 +319,7 @@ export type OAuthResponse =
282
319
  data: {
283
320
  provider: Provider
284
321
  url: null
322
+ flowId?: string | null
285
323
  }
286
324
  error: AuthError
287
325
  }
@@ -407,7 +445,7 @@ type FactorVerificationStatus = (typeof FactorVerificationStatuses)[number]
407
445
  *
408
446
  * @see {@link GoTrueMFAApi#enroll}
409
447
  * @see {@link GoTrueMFAApi#listFactors}
410
- * @see {@link GoTrueMFAAdminApi#listFactors}
448
+ * @see {@link GoTrueAdminMFAApi#listFactors}
411
449
  */
412
450
  export type Factor<
413
451
  Type extends FactorType = FactorType,
@@ -1691,14 +1729,14 @@ export interface GoTrueMFAApi {
1691
1729
  }
1692
1730
 
1693
1731
  /**
1694
- * @expermental
1732
+ * @experimental
1695
1733
  */
1696
1734
  export type AuthMFAAdminDeleteFactorResponse = RequestResult<{
1697
1735
  /** ID of the factor that was successfully deleted. */
1698
1736
  id: string
1699
1737
  }>
1700
1738
  /**
1701
- * @expermental
1739
+ * @experimental
1702
1740
  */
1703
1741
  export type AuthMFAAdminDeleteFactorParams = {
1704
1742
  /** ID of the MFA factor to delete. */
@@ -1709,7 +1747,7 @@ export type AuthMFAAdminDeleteFactorParams = {
1709
1747
  }
1710
1748
 
1711
1749
  /**
1712
- * @expermental
1750
+ * @experimental
1713
1751
  */
1714
1752
  export type AuthMFAAdminListFactorsResponse = RequestResult<{
1715
1753
  /** All factors attached to the user. */
@@ -1717,7 +1755,7 @@ export type AuthMFAAdminListFactorsResponse = RequestResult<{
1717
1755
  }>
1718
1756
 
1719
1757
  /**
1720
- * @expermental
1758
+ * @experimental
1721
1759
  */
1722
1760
  export type AuthMFAAdminListFactorsParams = {
1723
1761
  /** ID of the user. */
@@ -1727,7 +1765,7 @@ export type AuthMFAAdminListFactorsParams = {
1727
1765
  /**
1728
1766
  * Contains the full multi-factor authentication administration API.
1729
1767
  *
1730
- * @expermental
1768
+ * @experimental
1731
1769
  */
1732
1770
  export interface GoTrueAdminMFAApi {
1733
1771
  /**
@@ -1769,7 +1807,7 @@ export interface GoTrueAdminMFAApi {
1769
1807
  *
1770
1808
  * @see {@link GoTrueMFAApi#unenroll}
1771
1809
  *
1772
- * @expermental
1810
+ * @experimental
1773
1811
  *
1774
1812
  * @category Auth
1775
1813
  * @subcategory Auth Admin
@@ -2250,6 +2288,14 @@ export type CustomOAuthProvider = {
2250
2288
  acceptable_client_ids?: string[]
2251
2289
  /** OAuth scopes requested during authorization */
2252
2290
  scopes?: string[]
2291
+ /**
2292
+ * Allowlist of raw identity provider claim keys to copy verbatim into the
2293
+ * user's `custom_claims` field (within `identity_data` and
2294
+ * `raw_user_meta_data`), e.g. `["groups", "org_id", "mail"]`. This is an
2295
+ * opt-in allowlist that defaults to empty (no claims captured) and operates
2296
+ * independently from `attribute_mapping`.
2297
+ */
2298
+ custom_claims_allowlist?: string[]
2253
2299
  /** Whether PKCE is enabled */
2254
2300
  pkce_enabled?: boolean
2255
2301
  /** Mapping of provider attributes to Supabase user attributes */
@@ -2300,6 +2346,14 @@ export type CreateCustomProviderParams = {
2300
2346
  acceptable_client_ids?: string[]
2301
2347
  /** OAuth scopes requested during authorization */
2302
2348
  scopes?: string[]
2349
+ /**
2350
+ * Allowlist of raw identity provider claim keys to copy verbatim into the
2351
+ * user's `custom_claims` field (within `identity_data` and
2352
+ * `raw_user_meta_data`), e.g. `["groups", "org_id", "mail"]`. This is an
2353
+ * opt-in allowlist that defaults to empty (no claims captured) and operates
2354
+ * independently from `attribute_mapping`.
2355
+ */
2356
+ custom_claims_allowlist?: string[]
2303
2357
  /** Whether PKCE is enabled */
2304
2358
  pkce_enabled?: boolean
2305
2359
  /** Mapping of provider attributes to Supabase user attributes */
@@ -2342,6 +2396,14 @@ export type UpdateCustomProviderParams = {
2342
2396
  acceptable_client_ids?: string[]
2343
2397
  /** OAuth scopes requested during authorization */
2344
2398
  scopes?: string[]
2399
+ /**
2400
+ * Allowlist of raw identity provider claim keys to copy verbatim into the
2401
+ * user's `custom_claims` field (within `identity_data` and
2402
+ * `raw_user_meta_data`), e.g. `["groups", "org_id", "mail"]`. This is an
2403
+ * opt-in allowlist that defaults to empty (no claims captured) and operates
2404
+ * independently from `attribute_mapping`.
2405
+ */
2406
+ custom_claims_allowlist?: string[]
2345
2407
  /** Whether PKCE is enabled */
2346
2408
  pkce_enabled?: boolean
2347
2409
  /** Mapping of provider attributes to Supabase user attributes */
@@ -4,4 +4,4 @@
4
4
  // - Debugging and support (identifying which version is running)
5
5
  // - Telemetry and logging (version reporting in errors/analytics)
6
6
  // - Ensuring build artifacts match the published package version
7
- export const version = '2.108.2'
7
+ export const version = '2.112.3'