@supabase/auth-js 3.0.0-next.4 → 3.0.0-next.6

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 (56) hide show
  1. package/dist/main/GoTrueAdminApi.d.ts +26 -2
  2. package/dist/main/GoTrueAdminApi.d.ts.map +1 -1
  3. package/dist/main/GoTrueAdminApi.js +48 -1
  4. package/dist/main/GoTrueAdminApi.js.map +1 -1
  5. package/dist/main/GoTrueClient.d.ts +63 -1
  6. package/dist/main/GoTrueClient.d.ts.map +1 -1
  7. package/dist/main/GoTrueClient.js +340 -3
  8. package/dist/main/GoTrueClient.js.map +1 -1
  9. package/dist/main/lib/fetch.d.ts +1 -1
  10. package/dist/main/lib/fetch.d.ts.map +1 -1
  11. package/dist/main/lib/helpers.d.ts +3 -0
  12. package/dist/main/lib/helpers.d.ts.map +1 -1
  13. package/dist/main/lib/helpers.js +6 -0
  14. package/dist/main/lib/helpers.js.map +1 -1
  15. package/dist/main/lib/types.d.ts +128 -1
  16. package/dist/main/lib/types.d.ts.map +1 -1
  17. package/dist/main/lib/types.js.map +1 -1
  18. package/dist/main/lib/version.d.ts +1 -1
  19. package/dist/main/lib/version.js +1 -1
  20. package/dist/main/lib/webauthn.d.ts +8 -0
  21. package/dist/main/lib/webauthn.d.ts.map +1 -1
  22. package/dist/main/lib/webauthn.js +1 -0
  23. package/dist/main/lib/webauthn.js.map +1 -1
  24. package/dist/module/GoTrueAdminApi.d.ts +26 -2
  25. package/dist/module/GoTrueAdminApi.d.ts.map +1 -1
  26. package/dist/module/GoTrueAdminApi.js +49 -2
  27. package/dist/module/GoTrueAdminApi.js.map +1 -1
  28. package/dist/module/GoTrueClient.d.ts +63 -1
  29. package/dist/module/GoTrueClient.d.ts.map +1 -1
  30. package/dist/module/GoTrueClient.js +342 -5
  31. package/dist/module/GoTrueClient.js.map +1 -1
  32. package/dist/module/lib/fetch.d.ts +1 -1
  33. package/dist/module/lib/fetch.d.ts.map +1 -1
  34. package/dist/module/lib/helpers.d.ts +3 -0
  35. package/dist/module/lib/helpers.d.ts.map +1 -1
  36. package/dist/module/lib/helpers.js +5 -0
  37. package/dist/module/lib/helpers.js.map +1 -1
  38. package/dist/module/lib/types.d.ts +128 -1
  39. package/dist/module/lib/types.d.ts.map +1 -1
  40. package/dist/module/lib/types.js.map +1 -1
  41. package/dist/module/lib/version.d.ts +1 -1
  42. package/dist/module/lib/version.js +1 -1
  43. package/dist/module/lib/webauthn.d.ts +8 -0
  44. package/dist/module/lib/webauthn.d.ts.map +1 -1
  45. package/dist/module/lib/webauthn.js +1 -1
  46. package/dist/module/lib/webauthn.js.map +1 -1
  47. package/dist/tsconfig.module.tsbuildinfo +1 -1
  48. package/dist/tsconfig.tsbuildinfo +1 -1
  49. package/package.json +1 -1
  50. package/src/GoTrueAdminApi.ts +80 -1
  51. package/src/GoTrueClient.ts +430 -0
  52. package/src/lib/fetch.ts +1 -1
  53. package/src/lib/helpers.ts +8 -0
  54. package/src/lib/types.ts +178 -0
  55. package/src/lib/version.ts +1 -1
  56. package/src/lib/webauthn.ts +1 -1
@@ -33,6 +33,7 @@ import {
33
33
  _userResponse,
34
34
  } from './lib/fetch'
35
35
  import {
36
+ assertPasskeyExperimentalEnabled,
36
37
  decodeJWT,
37
38
  deepClone,
38
39
  Deferred,
@@ -136,6 +137,22 @@ import type {
136
137
  UserResponse,
137
138
  VerifyOtpParams,
138
139
  Web3Credentials,
140
+ AuthPasskeyApi,
141
+ ExperimentalFeatureFlags,
142
+ SignInWithPasskeyCredentials,
143
+ RegisterPasskeyCredentials,
144
+ VerifyPasskeyRegistrationParams,
145
+ StartPasskeyAuthenticationParams,
146
+ VerifyPasskeyAuthenticationParams,
147
+ PasskeyUpdateParams,
148
+ PasskeyDeleteParams,
149
+ AuthPasskeyRegistrationOptionsResponse,
150
+ AuthPasskeyRegistrationVerifyResponse,
151
+ AuthPasskeyAuthenticationOptionsResponse,
152
+ AuthPasskeyAuthenticationVerifyResponse,
153
+ AuthPasskeyListResponse,
154
+ AuthPasskeyUpdateResponse,
155
+ AuthPasskeyDeleteResponse,
139
156
  } from './lib/types'
140
157
  import {
141
158
  createSiweMessage,
@@ -146,10 +163,14 @@ import {
146
163
  toHex,
147
164
  } from './lib/web3/ethereum'
148
165
  import {
166
+ createCredential,
149
167
  deserializeCredentialCreationOptions,
150
168
  deserializeCredentialRequestOptions,
169
+ getCredential,
151
170
  serializeCredentialCreationResponse,
152
171
  serializeCredentialRequestResponse,
172
+ browserSupportsWebAuthn,
173
+ webAuthnAbortService,
153
174
  WebAuthnApi,
154
175
  } from './lib/webauthn'
155
176
  import {
@@ -176,6 +197,7 @@ const DEFAULT_OPTIONS: Omit<
176
197
  throwOnError: false,
177
198
  lockAcquireTimeout: 5000, // 5 seconds
178
199
  skipAutoInitialize: false,
200
+ experimental: {},
179
201
  }
180
202
 
181
203
  async function lockNoOp<R>(name: string, acquireTimeout: number, fn: () => Promise<R>): Promise<R> {
@@ -212,6 +234,13 @@ export default class GoTrueClient {
212
234
  * Used to implement the authorization code flow on the consent page.
213
235
  */
214
236
  oauth: AuthOAuthServerApi
237
+ /**
238
+ * Namespace for passkey methods.
239
+ * Includes lower-level two-step registration/authentication and passkey management.
240
+ *
241
+ * Requires `auth.experimental.passkey: true`; otherwise all methods throw.
242
+ */
243
+ passkey: AuthPasskeyApi
215
244
  /**
216
245
  * The storage key used to identify the values saved in localStorage
217
246
  */
@@ -273,6 +302,11 @@ export default class GoTrueClient {
273
302
  protected pendingInLock: Promise<any>[] = []
274
303
  protected throwOnError: boolean
275
304
  protected lockAcquireTimeout: number
305
+ /**
306
+ * Opt-in flags for experimental features. Defaults to an empty object.
307
+ * See `GoTrueClientOptions.experimental`.
308
+ */
309
+ protected experimental: ExperimentalFeatureFlags
276
310
 
277
311
  /**
278
312
  * Used to broadcast state change events to other tabs listening.
@@ -326,10 +360,12 @@ export default class GoTrueClient {
326
360
 
327
361
  this.persistSession = settings.persistSession
328
362
  this.autoRefreshToken = settings.autoRefreshToken
363
+ this.experimental = settings.experimental ?? {}
329
364
  this.admin = new GoTrueAdminApi({
330
365
  url: settings.url,
331
366
  headers: settings.headers,
332
367
  fetch: settings.fetch,
368
+ experimental: this.experimental,
333
369
  })
334
370
 
335
371
  this.url = settings.url
@@ -374,6 +410,16 @@ export default class GoTrueClient {
374
410
  revokeGrant: this._revokeOAuthGrant.bind(this),
375
411
  }
376
412
 
413
+ this.passkey = {
414
+ startRegistration: this._startPasskeyRegistration.bind(this),
415
+ verifyRegistration: this._verifyPasskeyRegistration.bind(this),
416
+ startAuthentication: this._startPasskeyAuthentication.bind(this),
417
+ verifyAuthentication: this._verifyPasskeyAuthentication.bind(this),
418
+ list: this._listPasskeys.bind(this),
419
+ update: this._updatePasskey.bind(this),
420
+ delete: this._deletePasskey.bind(this),
421
+ }
422
+
377
423
  if (this.persistSession) {
378
424
  if (settings.storage) {
379
425
  this.storage = settings.storage
@@ -5912,4 +5958,388 @@ export default class GoTrueClient {
5912
5958
  throw error
5913
5959
  }
5914
5960
  }
5961
+
5962
+ // --- Passkey Methods ---
5963
+
5964
+ /**
5965
+ * Sign in with a passkey. Handles the full WebAuthn ceremony:
5966
+ * 1. Fetches authentication challenge from server
5967
+ * 2. Prompts user via navigator.credentials.get()
5968
+ * 3. Verifies credential with server and creates session
5969
+ *
5970
+ * Requires `auth.experimental.passkey: true`.
5971
+ */
5972
+ async signInWithPasskey(
5973
+ credentials?: SignInWithPasskeyCredentials
5974
+ ): Promise<AuthPasskeyAuthenticationVerifyResponse> {
5975
+ assertPasskeyExperimentalEnabled(this.experimental)
5976
+ try {
5977
+ if (!browserSupportsWebAuthn()) {
5978
+ return this._returnResult({
5979
+ data: null,
5980
+ error: new AuthUnknownError('Browser does not support WebAuthn', null),
5981
+ })
5982
+ }
5983
+
5984
+ // 1. Get challenge options from server
5985
+ const { data: options, error: optionsError } = await this._startPasskeyAuthentication({
5986
+ options: { captchaToken: credentials?.options?.captchaToken },
5987
+ })
5988
+ if (optionsError || !options) {
5989
+ return this._returnResult({ data: null, error: optionsError })
5990
+ }
5991
+
5992
+ // 2. Deserialize and prompt user via browser WebAuthn API
5993
+ const publicKeyOptions = deserializeCredentialRequestOptions(options.options)
5994
+ const signal = credentials?.options?.signal ?? webAuthnAbortService.createNewAbortSignal()
5995
+ const { data: credential, error: credentialError } = await getCredential({
5996
+ publicKey: publicKeyOptions,
5997
+ signal,
5998
+ })
5999
+ if (credentialError || !credential) {
6000
+ return this._returnResult({
6001
+ data: null,
6002
+ error: credentialError ?? new AuthUnknownError('WebAuthn ceremony failed', null),
6003
+ })
6004
+ }
6005
+
6006
+ // 3. Serialize and verify with server
6007
+ const serialized = serializeCredentialRequestResponse(credential)
6008
+ return this._verifyPasskeyAuthentication({
6009
+ challengeId: options.challenge_id,
6010
+ credential: serialized,
6011
+ })
6012
+ } catch (error) {
6013
+ if (isAuthError(error)) {
6014
+ return this._returnResult({ data: null, error })
6015
+ }
6016
+ throw error
6017
+ }
6018
+ }
6019
+
6020
+ /**
6021
+ * Register a passkey for the current authenticated user. Handles the full WebAuthn ceremony:
6022
+ * 1. Fetches registration challenge from server
6023
+ * 2. Prompts user via navigator.credentials.create()
6024
+ * 3. Verifies credential with server
6025
+ *
6026
+ * Requires an active session. Requires `auth.experimental.passkey: true`.
6027
+ */
6028
+ async registerPasskey(
6029
+ credentials?: RegisterPasskeyCredentials
6030
+ ): Promise<AuthPasskeyRegistrationVerifyResponse> {
6031
+ assertPasskeyExperimentalEnabled(this.experimental)
6032
+ try {
6033
+ if (!browserSupportsWebAuthn()) {
6034
+ return this._returnResult({
6035
+ data: null,
6036
+ error: new AuthUnknownError('Browser does not support WebAuthn', null),
6037
+ })
6038
+ }
6039
+
6040
+ // 1. Get challenge options from server
6041
+ const { data: options, error: optionsError } = await this._startPasskeyRegistration()
6042
+ if (optionsError || !options) {
6043
+ return this._returnResult({ data: null, error: optionsError })
6044
+ }
6045
+
6046
+ // 2. Deserialize and prompt user via browser WebAuthn API
6047
+ const publicKeyOptions = deserializeCredentialCreationOptions(options.options)
6048
+ const signal = credentials?.options?.signal ?? webAuthnAbortService.createNewAbortSignal()
6049
+ const { data: credential, error: credentialError } = await createCredential({
6050
+ publicKey: publicKeyOptions,
6051
+ signal,
6052
+ })
6053
+ if (credentialError || !credential) {
6054
+ return this._returnResult({
6055
+ data: null,
6056
+ error: credentialError ?? new AuthUnknownError('WebAuthn ceremony failed', null),
6057
+ })
6058
+ }
6059
+
6060
+ // 3. Serialize and verify with server
6061
+ const serialized = serializeCredentialCreationResponse(credential)
6062
+ return this._verifyPasskeyRegistration({
6063
+ challengeId: options.challenge_id,
6064
+ credential: serialized,
6065
+ })
6066
+ } catch (error) {
6067
+ if (isAuthError(error)) {
6068
+ return this._returnResult({ data: null, error })
6069
+ }
6070
+ throw error
6071
+ }
6072
+ }
6073
+
6074
+ /**
6075
+ * Start passkey registration for the current authenticated user.
6076
+ * Returns WebAuthn credential creation options to pass to navigator.credentials.create().
6077
+ */
6078
+ private async _startPasskeyRegistration(): Promise<AuthPasskeyRegistrationOptionsResponse> {
6079
+ assertPasskeyExperimentalEnabled(this.experimental)
6080
+ try {
6081
+ return await this._useSession(async (result) => {
6082
+ const {
6083
+ data: { session },
6084
+ error: sessionError,
6085
+ } = result
6086
+ if (sessionError) {
6087
+ return this._returnResult({ data: null, error: sessionError })
6088
+ }
6089
+ if (!session) {
6090
+ return this._returnResult({ data: null, error: new AuthSessionMissingError() })
6091
+ }
6092
+ const { data, error } = await _request(
6093
+ this.fetch,
6094
+ 'POST',
6095
+ `${this.url}/passkeys/registration/options`,
6096
+ {
6097
+ headers: this.headers,
6098
+ jwt: session.access_token,
6099
+ body: {},
6100
+ }
6101
+ )
6102
+ if (error) {
6103
+ return this._returnResult({ data: null, error })
6104
+ }
6105
+ return this._returnResult({ data, error: null })
6106
+ })
6107
+ } catch (error) {
6108
+ if (isAuthError(error)) {
6109
+ return this._returnResult({ data: null, error })
6110
+ }
6111
+ throw error
6112
+ }
6113
+ }
6114
+
6115
+ /**
6116
+ * Verify passkey registration with the credential response.
6117
+ * The credentialResponse should be the serialized output of navigator.credentials.create().
6118
+ */
6119
+ private async _verifyPasskeyRegistration(
6120
+ params: VerifyPasskeyRegistrationParams
6121
+ ): Promise<AuthPasskeyRegistrationVerifyResponse> {
6122
+ assertPasskeyExperimentalEnabled(this.experimental)
6123
+ try {
6124
+ return await this._useSession(async (result) => {
6125
+ const {
6126
+ data: { session },
6127
+ error: sessionError,
6128
+ } = result
6129
+ if (sessionError) {
6130
+ return this._returnResult({ data: null, error: sessionError })
6131
+ }
6132
+ if (!session) {
6133
+ return this._returnResult({ data: null, error: new AuthSessionMissingError() })
6134
+ }
6135
+ const { data, error } = await _request(
6136
+ this.fetch,
6137
+ 'POST',
6138
+ `${this.url}/passkeys/registration/verify`,
6139
+ {
6140
+ headers: this.headers,
6141
+ jwt: session.access_token,
6142
+ body: {
6143
+ challenge_id: params.challengeId,
6144
+ credential: params.credential,
6145
+ },
6146
+ }
6147
+ )
6148
+ if (error) {
6149
+ return this._returnResult({ data: null, error })
6150
+ }
6151
+ return this._returnResult({ data, error: null })
6152
+ })
6153
+ } catch (error) {
6154
+ if (isAuthError(error)) {
6155
+ return this._returnResult({ data: null, error })
6156
+ }
6157
+ throw error
6158
+ }
6159
+ }
6160
+
6161
+ /**
6162
+ * Start passkey authentication.
6163
+ * Returns WebAuthn credential request options to pass to navigator.credentials.get().
6164
+ */
6165
+ private async _startPasskeyAuthentication(
6166
+ params?: StartPasskeyAuthenticationParams
6167
+ ): Promise<AuthPasskeyAuthenticationOptionsResponse> {
6168
+ assertPasskeyExperimentalEnabled(this.experimental)
6169
+ try {
6170
+ const { data, error } = await _request(
6171
+ this.fetch,
6172
+ 'POST',
6173
+ `${this.url}/passkeys/authentication/options`,
6174
+ {
6175
+ headers: this.headers,
6176
+ body: {
6177
+ gotrue_meta_security: { captcha_token: params?.options?.captchaToken },
6178
+ },
6179
+ }
6180
+ )
6181
+ if (error) {
6182
+ return this._returnResult({ data: null, error })
6183
+ }
6184
+ return this._returnResult({ data, error: null })
6185
+ } catch (error) {
6186
+ if (isAuthError(error)) {
6187
+ return this._returnResult({ data: null, error })
6188
+ }
6189
+ throw error
6190
+ }
6191
+ }
6192
+
6193
+ /**
6194
+ * Verify passkey authentication and create a session.
6195
+ * The credential should be the serialized output of navigator.credentials.get().
6196
+ */
6197
+ private async _verifyPasskeyAuthentication(
6198
+ params: VerifyPasskeyAuthenticationParams
6199
+ ): Promise<AuthPasskeyAuthenticationVerifyResponse> {
6200
+ assertPasskeyExperimentalEnabled(this.experimental)
6201
+ try {
6202
+ const { data, error } = await _request(
6203
+ this.fetch,
6204
+ 'POST',
6205
+ `${this.url}/passkeys/authentication/verify`,
6206
+ {
6207
+ headers: this.headers,
6208
+ body: {
6209
+ challenge_id: params.challengeId,
6210
+ credential: params.credential,
6211
+ },
6212
+ xform: _sessionResponse,
6213
+ }
6214
+ )
6215
+ if (error) {
6216
+ return this._returnResult({ data: null, error })
6217
+ }
6218
+ if (data.session) {
6219
+ await this._saveSession(data.session)
6220
+ await this._notifyAllSubscribers('SIGNED_IN', data.session)
6221
+ }
6222
+ return this._returnResult({ data, error: null })
6223
+ } catch (error) {
6224
+ if (isAuthError(error)) {
6225
+ return this._returnResult({ data: null, error })
6226
+ }
6227
+ throw error
6228
+ }
6229
+ }
6230
+
6231
+ /**
6232
+ * List all passkeys for the current user.
6233
+ */
6234
+ private async _listPasskeys(): Promise<AuthPasskeyListResponse> {
6235
+ assertPasskeyExperimentalEnabled(this.experimental)
6236
+ try {
6237
+ return await this._useSession(async (result) => {
6238
+ const {
6239
+ data: { session },
6240
+ error: sessionError,
6241
+ } = result
6242
+ if (sessionError) {
6243
+ return this._returnResult({ data: null, error: sessionError })
6244
+ }
6245
+ if (!session) {
6246
+ return this._returnResult({ data: null, error: new AuthSessionMissingError() })
6247
+ }
6248
+ const { data, error } = await _request(this.fetch, 'GET', `${this.url}/passkeys`, {
6249
+ headers: this.headers,
6250
+ jwt: session.access_token,
6251
+ xform: (data: any) => ({ data, error: null }),
6252
+ })
6253
+ if (error) {
6254
+ return this._returnResult({ data: null, error })
6255
+ }
6256
+ return this._returnResult({ data, error: null })
6257
+ })
6258
+ } catch (error) {
6259
+ if (isAuthError(error)) {
6260
+ return this._returnResult({ data: null, error })
6261
+ }
6262
+ throw error
6263
+ }
6264
+ }
6265
+
6266
+ /**
6267
+ * Update a passkey.
6268
+ */
6269
+ private async _updatePasskey(params: PasskeyUpdateParams): Promise<AuthPasskeyUpdateResponse> {
6270
+ assertPasskeyExperimentalEnabled(this.experimental)
6271
+ try {
6272
+ return await this._useSession(async (result) => {
6273
+ const {
6274
+ data: { session },
6275
+ error: sessionError,
6276
+ } = result
6277
+ if (sessionError) {
6278
+ return this._returnResult({ data: null, error: sessionError })
6279
+ }
6280
+ if (!session) {
6281
+ return this._returnResult({ data: null, error: new AuthSessionMissingError() })
6282
+ }
6283
+ const { data, error } = await _request(
6284
+ this.fetch,
6285
+ 'PATCH',
6286
+ `${this.url}/passkeys/${params.passkeyId}`,
6287
+ {
6288
+ headers: this.headers,
6289
+ jwt: session.access_token,
6290
+ body: { friendly_name: params.friendlyName },
6291
+ }
6292
+ )
6293
+ if (error) {
6294
+ return this._returnResult({ data: null, error })
6295
+ }
6296
+ return this._returnResult({ data, error: null })
6297
+ })
6298
+ } catch (error) {
6299
+ if (isAuthError(error)) {
6300
+ return this._returnResult({ data: null, error })
6301
+ }
6302
+ throw error
6303
+ }
6304
+ }
6305
+
6306
+ /**
6307
+ * Delete a passkey.
6308
+ */
6309
+ private async _deletePasskey(params: PasskeyDeleteParams): Promise<AuthPasskeyDeleteResponse> {
6310
+ assertPasskeyExperimentalEnabled(this.experimental)
6311
+ try {
6312
+ return await this._useSession(async (result) => {
6313
+ const {
6314
+ data: { session },
6315
+ error: sessionError,
6316
+ } = result
6317
+ if (sessionError) {
6318
+ return this._returnResult({ data: null, error: sessionError })
6319
+ }
6320
+ if (!session) {
6321
+ return this._returnResult({ data: null, error: new AuthSessionMissingError() })
6322
+ }
6323
+ const { error } = await _request(
6324
+ this.fetch,
6325
+ 'DELETE',
6326
+ `${this.url}/passkeys/${params.passkeyId}`,
6327
+ {
6328
+ headers: this.headers,
6329
+ jwt: session.access_token,
6330
+ noResolveJson: true,
6331
+ }
6332
+ )
6333
+ if (error) {
6334
+ return this._returnResult({ data: null, error })
6335
+ }
6336
+ return this._returnResult({ data: null, error: null })
6337
+ })
6338
+ } catch (error) {
6339
+ if (isAuthError(error)) {
6340
+ return this._returnResult({ data: null, error })
6341
+ }
6342
+ throw error
6343
+ }
6344
+ }
5915
6345
  }
package/src/lib/fetch.ts CHANGED
@@ -30,7 +30,7 @@ export interface FetchParameters {
30
30
  signal?: AbortSignal
31
31
  }
32
32
 
33
- export type RequestMethodType = 'GET' | 'POST' | 'PUT' | 'DELETE'
33
+ export type RequestMethodType = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
34
34
 
35
35
  const _getErrorMessage = (err: any): string =>
36
36
  err.msg || err.message || err.error_description || err.error || JSON.stringify(err)
@@ -372,6 +372,14 @@ export function validateUUID(str: string) {
372
372
  }
373
373
  }
374
374
 
375
+ export function assertPasskeyExperimentalEnabled(experimental: { passkey?: boolean }): void {
376
+ if (!experimental.passkey) {
377
+ throw new Error(
378
+ '@supabase/auth-js: the passkey API is experimental and disabled by default. Enable it by passing `auth: { experimental: { passkey: true } }` to createClient (or to the GoTrueClient constructor).'
379
+ )
380
+ }
381
+ }
382
+
375
383
  export function userNotAvailableProxy(): User {
376
384
  const proxyTarget = {} as User
377
385
 
package/src/lib/types.ts CHANGED
@@ -6,6 +6,12 @@ import {
6
6
  ServerCredentialCreationOptions,
7
7
  ServerCredentialRequestOptions,
8
8
  WebAuthnApi,
9
+ WebAuthnError,
10
+ } from './webauthn'
11
+ import type {
12
+ RegistrationResponseJSON,
13
+ AuthenticationResponseJSON,
14
+ ServerCredentialResponse,
9
15
  } from './webauthn'
10
16
  import {
11
17
  AuthenticationCredential,
@@ -174,6 +180,27 @@ export type GoTrueClientOptions = {
174
180
  * @default false
175
181
  */
176
182
  skipAutoInitialize?: boolean
183
+
184
+ /**
185
+ * Opt-in flags for experimental features. These APIs may change without
186
+ * notice and are disabled by default.
187
+ *
188
+ * @experimental
189
+ */
190
+ experimental?: ExperimentalFeatureFlags
191
+ }
192
+
193
+ export type ExperimentalFeatureFlags = {
194
+ /**
195
+ * Enables passkey support:
196
+ * - `auth.signInWithPasskey()`, `auth.registerPasskey()`
197
+ * - `auth.passkey.*`
198
+ * - `auth.admin.passkey.*`
199
+ *
200
+ * Defaults to `false`. Calling any passkey method while this flag is
201
+ * disabled throws a descriptive error at call time.
202
+ */
203
+ passkey?: boolean
177
204
  }
178
205
 
179
206
  const WeakPasswordReasons = ['length', 'characters', 'pwned'] as const
@@ -2624,3 +2651,154 @@ export interface AuthOAuthServerApi {
2624
2651
  */
2625
2652
  revokeGrant(options: { clientId: string }): Promise<AuthOAuthRevokeGrantResponse>
2626
2653
  }
2654
+
2655
+ // --- Passkey Types ---
2656
+
2657
+ /** Response from POST /passkeys/registration/options */
2658
+ export type PasskeyRegistrationOptionsResponse = {
2659
+ challenge_id: string
2660
+ options: ServerCredentialCreationOptions
2661
+ expires_at: number
2662
+ }
2663
+
2664
+ /** Request body for POST /passkeys/registration/verify */
2665
+ export type PasskeyRegistrationVerifyParams = {
2666
+ challenge_id: string
2667
+ credential: RegistrationResponseJSON
2668
+ }
2669
+
2670
+ /** Response from POST /passkeys/registration/verify */
2671
+ export type PasskeyMetadata = {
2672
+ id: string
2673
+ friendly_name?: string
2674
+ created_at: string
2675
+ }
2676
+
2677
+ /** Response from POST /passkeys/authentication/options */
2678
+ export type PasskeyAuthenticationOptionsResponse = {
2679
+ challenge_id: string
2680
+ options: ServerCredentialRequestOptions
2681
+ expires_at: number
2682
+ }
2683
+
2684
+ /** Request body for POST /passkeys/authentication/verify */
2685
+ export type PasskeyAuthenticationVerifyParams = {
2686
+ challenge_id: string
2687
+ credential: AuthenticationResponseJSON
2688
+ }
2689
+
2690
+ /** Item in the passkeys list (GET /passkeys/ and admin list) */
2691
+ export type PasskeyListItem = {
2692
+ id: string
2693
+ friendly_name?: string
2694
+ created_at: string
2695
+ last_used_at?: string
2696
+ }
2697
+
2698
+ // --- Passkey SDK Method Parameter/Response Types ---
2699
+
2700
+ export type SignInWithPasskeyCredentials = {
2701
+ options?: {
2702
+ captchaToken?: string
2703
+ signal?: AbortSignal
2704
+ }
2705
+ }
2706
+
2707
+ export type RegisterPasskeyCredentials = {
2708
+ options?: {
2709
+ signal?: AbortSignal
2710
+ }
2711
+ }
2712
+
2713
+ export type VerifyPasskeyRegistrationParams = {
2714
+ /** Challenge ID from startRegistration */
2715
+ challengeId: string
2716
+ /** Serialized credential from navigator.credentials.create() */
2717
+ credential: ServerCredentialResponse
2718
+ }
2719
+
2720
+ export type StartPasskeyAuthenticationParams = {
2721
+ options?: {
2722
+ captchaToken?: string
2723
+ }
2724
+ }
2725
+
2726
+ export type VerifyPasskeyAuthenticationParams = {
2727
+ /** Challenge ID from startAuthentication */
2728
+ challengeId: string
2729
+ /** Serialized credential from navigator.credentials.get() */
2730
+ credential: ServerCredentialResponse
2731
+ }
2732
+
2733
+ export type PasskeyUpdateParams = {
2734
+ /** UUID of the passkey to update */
2735
+ passkeyId: string
2736
+ /** New friendly name (max 120 chars) */
2737
+ friendlyName: string
2738
+ }
2739
+
2740
+ export type PasskeyDeleteParams = {
2741
+ /** UUID of the passkey to delete */
2742
+ passkeyId: string
2743
+ }
2744
+
2745
+ // --- Passkey Response Types ---
2746
+
2747
+ export type AuthPasskeyRegistrationOptionsResponse =
2748
+ RequestResult<PasskeyRegistrationOptionsResponse>
2749
+ export type AuthPasskeyRegistrationVerifyResponse = RequestResult<
2750
+ PasskeyMetadata,
2751
+ WebAuthnError | AuthError
2752
+ >
2753
+ export type AuthPasskeyAuthenticationOptionsResponse =
2754
+ RequestResult<PasskeyAuthenticationOptionsResponse>
2755
+ export type AuthPasskeyAuthenticationVerifyResponse = RequestResult<
2756
+ { session: Session | null; user: User | null },
2757
+ WebAuthnError | AuthError
2758
+ >
2759
+ export type AuthPasskeyListResponse = RequestResult<PasskeyListItem[]>
2760
+ export type AuthPasskeyUpdateResponse = RequestResult<PasskeyListItem>
2761
+ export type AuthPasskeyDeleteResponse = RequestResult<null>
2762
+
2763
+ // --- Passkey Admin Types ---
2764
+
2765
+ export type AuthPasskeyAdminListParams = {
2766
+ userId: string
2767
+ }
2768
+
2769
+ export type AuthPasskeyAdminDeleteParams = {
2770
+ userId: string
2771
+ passkeyId: string
2772
+ }
2773
+
2774
+ // --- Passkey Namespace Interfaces ---
2775
+
2776
+ /**
2777
+ * Lower-level two-step API and management methods for passkeys.
2778
+ * Access via `supabase.auth.passkey`.
2779
+ */
2780
+ export interface AuthPasskeyApi {
2781
+ // Two-step registration
2782
+ startRegistration(): Promise<AuthPasskeyRegistrationOptionsResponse>
2783
+ verifyRegistration(
2784
+ params: VerifyPasskeyRegistrationParams
2785
+ ): Promise<AuthPasskeyRegistrationVerifyResponse>
2786
+
2787
+ // Two-step authentication
2788
+ startAuthentication(
2789
+ params?: StartPasskeyAuthenticationParams
2790
+ ): Promise<AuthPasskeyAuthenticationOptionsResponse>
2791
+ verifyAuthentication(
2792
+ params: VerifyPasskeyAuthenticationParams
2793
+ ): Promise<AuthPasskeyAuthenticationVerifyResponse>
2794
+
2795
+ // Management
2796
+ list(): Promise<AuthPasskeyListResponse>
2797
+ update(params: PasskeyUpdateParams): Promise<AuthPasskeyUpdateResponse>
2798
+ delete(params: PasskeyDeleteParams): Promise<AuthPasskeyDeleteResponse>
2799
+ }
2800
+
2801
+ export interface GoTrueAdminPasskeyApi {
2802
+ listPasskeys(params: AuthPasskeyAdminListParams): Promise<AuthPasskeyListResponse>
2803
+ deletePasskey(params: AuthPasskeyAdminDeleteParams): Promise<AuthPasskeyDeleteResponse>
2804
+ }