@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
@@ -27,6 +27,7 @@ const DEFAULT_OPTIONS = {
27
27
  throwOnError: false,
28
28
  lockAcquireTimeout: 5000, // 5 seconds
29
29
  skipAutoInitialize: false,
30
+ experimental: {},
30
31
  };
31
32
  async function lockNoOp(name, acquireTimeout, fn) {
32
33
  return await fn();
@@ -81,7 +82,7 @@ class GoTrueClient {
81
82
  * ```
82
83
  */
83
84
  constructor(options) {
84
- var _a, _b, _c;
85
+ var _a, _b, _c, _d;
85
86
  /**
86
87
  * @experimental
87
88
  */
@@ -126,10 +127,12 @@ class GoTrueClient {
126
127
  }
127
128
  this.persistSession = settings.persistSession;
128
129
  this.autoRefreshToken = settings.autoRefreshToken;
130
+ this.experimental = (_b = settings.experimental) !== null && _b !== void 0 ? _b : {};
129
131
  this.admin = new GoTrueAdminApi_1.default({
130
132
  url: settings.url,
131
133
  headers: settings.headers,
132
134
  fetch: settings.fetch,
135
+ experimental: this.experimental,
133
136
  });
134
137
  this.url = settings.url;
135
138
  this.headers = settings.headers;
@@ -143,7 +146,7 @@ class GoTrueClient {
143
146
  if (settings.lock) {
144
147
  this.lock = settings.lock;
145
148
  }
146
- else if (this.persistSession && (0, helpers_1.isBrowser)() && ((_b = globalThis === null || globalThis === void 0 ? void 0 : globalThis.navigator) === null || _b === void 0 ? void 0 : _b.locks)) {
149
+ else if (this.persistSession && (0, helpers_1.isBrowser)() && ((_c = globalThis === null || globalThis === void 0 ? void 0 : globalThis.navigator) === null || _c === void 0 ? void 0 : _c.locks)) {
147
150
  this.lock = locks_1.navigatorLock;
148
151
  }
149
152
  else {
@@ -170,6 +173,15 @@ class GoTrueClient {
170
173
  listGrants: this._listOAuthGrants.bind(this),
171
174
  revokeGrant: this._revokeOAuthGrant.bind(this),
172
175
  };
176
+ this.passkey = {
177
+ startRegistration: this._startPasskeyRegistration.bind(this),
178
+ verifyRegistration: this._verifyPasskeyRegistration.bind(this),
179
+ startAuthentication: this._startPasskeyAuthentication.bind(this),
180
+ verifyAuthentication: this._verifyPasskeyAuthentication.bind(this),
181
+ list: this._listPasskeys.bind(this),
182
+ update: this._updatePasskey.bind(this),
183
+ delete: this._deletePasskey.bind(this),
184
+ };
173
185
  if (this.persistSession) {
174
186
  if (settings.storage) {
175
187
  this.storage = settings.storage;
@@ -198,7 +210,7 @@ class GoTrueClient {
198
210
  catch (e) {
199
211
  console.error('Failed to create a new BroadcastChannel, multi-tab state changes will not be available', e);
200
212
  }
201
- (_c = this.broadcastChannel) === null || _c === void 0 ? void 0 : _c.addEventListener('message', async (event) => {
213
+ (_d = this.broadcastChannel) === null || _d === void 0 ? void 0 : _d.addEventListener('message', async (event) => {
202
214
  this._debug('received broadcast notification from other tab or client', event);
203
215
  try {
204
216
  await this._notifyAllSubscribers(event.data.event, event.data.session, false); // broadcast = false so we don't get an endless loop of messages
@@ -4859,6 +4871,331 @@ class GoTrueClient {
4859
4871
  throw error;
4860
4872
  }
4861
4873
  }
4874
+ // --- Passkey Methods ---
4875
+ /**
4876
+ * Sign in with a passkey. Handles the full WebAuthn ceremony:
4877
+ * 1. Fetches authentication challenge from server
4878
+ * 2. Prompts user via navigator.credentials.get()
4879
+ * 3. Verifies credential with server and creates session
4880
+ *
4881
+ * Requires `auth.experimental.passkey: true`.
4882
+ */
4883
+ async signInWithPasskey(credentials) {
4884
+ var _a, _b, _c;
4885
+ (0, helpers_1.assertPasskeyExperimentalEnabled)(this.experimental);
4886
+ try {
4887
+ if (!(0, webauthn_1.browserSupportsWebAuthn)()) {
4888
+ return this._returnResult({
4889
+ data: null,
4890
+ error: new errors_1.AuthUnknownError('Browser does not support WebAuthn', null),
4891
+ });
4892
+ }
4893
+ // 1. Get challenge options from server
4894
+ const { data: options, error: optionsError } = await this._startPasskeyAuthentication({
4895
+ options: { captchaToken: (_a = credentials === null || credentials === void 0 ? void 0 : credentials.options) === null || _a === void 0 ? void 0 : _a.captchaToken },
4896
+ });
4897
+ if (optionsError || !options) {
4898
+ return this._returnResult({ data: null, error: optionsError });
4899
+ }
4900
+ // 2. Deserialize and prompt user via browser WebAuthn API
4901
+ const publicKeyOptions = (0, webauthn_1.deserializeCredentialRequestOptions)(options.options);
4902
+ const signal = (_c = (_b = credentials === null || credentials === void 0 ? void 0 : credentials.options) === null || _b === void 0 ? void 0 : _b.signal) !== null && _c !== void 0 ? _c : webauthn_1.webAuthnAbortService.createNewAbortSignal();
4903
+ const { data: credential, error: credentialError } = await (0, webauthn_1.getCredential)({
4904
+ publicKey: publicKeyOptions,
4905
+ signal,
4906
+ });
4907
+ if (credentialError || !credential) {
4908
+ return this._returnResult({
4909
+ data: null,
4910
+ error: credentialError !== null && credentialError !== void 0 ? credentialError : new errors_1.AuthUnknownError('WebAuthn ceremony failed', null),
4911
+ });
4912
+ }
4913
+ // 3. Serialize and verify with server
4914
+ const serialized = (0, webauthn_1.serializeCredentialRequestResponse)(credential);
4915
+ return this._verifyPasskeyAuthentication({
4916
+ challengeId: options.challenge_id,
4917
+ credential: serialized,
4918
+ });
4919
+ }
4920
+ catch (error) {
4921
+ if ((0, errors_1.isAuthError)(error)) {
4922
+ return this._returnResult({ data: null, error });
4923
+ }
4924
+ throw error;
4925
+ }
4926
+ }
4927
+ /**
4928
+ * Register a passkey for the current authenticated user. Handles the full WebAuthn ceremony:
4929
+ * 1. Fetches registration challenge from server
4930
+ * 2. Prompts user via navigator.credentials.create()
4931
+ * 3. Verifies credential with server
4932
+ *
4933
+ * Requires an active session. Requires `auth.experimental.passkey: true`.
4934
+ */
4935
+ async registerPasskey(credentials) {
4936
+ var _a, _b;
4937
+ (0, helpers_1.assertPasskeyExperimentalEnabled)(this.experimental);
4938
+ try {
4939
+ if (!(0, webauthn_1.browserSupportsWebAuthn)()) {
4940
+ return this._returnResult({
4941
+ data: null,
4942
+ error: new errors_1.AuthUnknownError('Browser does not support WebAuthn', null),
4943
+ });
4944
+ }
4945
+ // 1. Get challenge options from server
4946
+ const { data: options, error: optionsError } = await this._startPasskeyRegistration();
4947
+ if (optionsError || !options) {
4948
+ return this._returnResult({ data: null, error: optionsError });
4949
+ }
4950
+ // 2. Deserialize and prompt user via browser WebAuthn API
4951
+ const publicKeyOptions = (0, webauthn_1.deserializeCredentialCreationOptions)(options.options);
4952
+ const signal = (_b = (_a = credentials === null || credentials === void 0 ? void 0 : credentials.options) === null || _a === void 0 ? void 0 : _a.signal) !== null && _b !== void 0 ? _b : webauthn_1.webAuthnAbortService.createNewAbortSignal();
4953
+ const { data: credential, error: credentialError } = await (0, webauthn_1.createCredential)({
4954
+ publicKey: publicKeyOptions,
4955
+ signal,
4956
+ });
4957
+ if (credentialError || !credential) {
4958
+ return this._returnResult({
4959
+ data: null,
4960
+ error: credentialError !== null && credentialError !== void 0 ? credentialError : new errors_1.AuthUnknownError('WebAuthn ceremony failed', null),
4961
+ });
4962
+ }
4963
+ // 3. Serialize and verify with server
4964
+ const serialized = (0, webauthn_1.serializeCredentialCreationResponse)(credential);
4965
+ return this._verifyPasskeyRegistration({
4966
+ challengeId: options.challenge_id,
4967
+ credential: serialized,
4968
+ });
4969
+ }
4970
+ catch (error) {
4971
+ if ((0, errors_1.isAuthError)(error)) {
4972
+ return this._returnResult({ data: null, error });
4973
+ }
4974
+ throw error;
4975
+ }
4976
+ }
4977
+ /**
4978
+ * Start passkey registration for the current authenticated user.
4979
+ * Returns WebAuthn credential creation options to pass to navigator.credentials.create().
4980
+ */
4981
+ async _startPasskeyRegistration() {
4982
+ (0, helpers_1.assertPasskeyExperimentalEnabled)(this.experimental);
4983
+ try {
4984
+ return await this._useSession(async (result) => {
4985
+ const { data: { session }, error: sessionError, } = result;
4986
+ if (sessionError) {
4987
+ return this._returnResult({ data: null, error: sessionError });
4988
+ }
4989
+ if (!session) {
4990
+ return this._returnResult({ data: null, error: new errors_1.AuthSessionMissingError() });
4991
+ }
4992
+ const { data, error } = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/passkeys/registration/options`, {
4993
+ headers: this.headers,
4994
+ jwt: session.access_token,
4995
+ body: {},
4996
+ });
4997
+ if (error) {
4998
+ return this._returnResult({ data: null, error });
4999
+ }
5000
+ return this._returnResult({ data, error: null });
5001
+ });
5002
+ }
5003
+ catch (error) {
5004
+ if ((0, errors_1.isAuthError)(error)) {
5005
+ return this._returnResult({ data: null, error });
5006
+ }
5007
+ throw error;
5008
+ }
5009
+ }
5010
+ /**
5011
+ * Verify passkey registration with the credential response.
5012
+ * The credentialResponse should be the serialized output of navigator.credentials.create().
5013
+ */
5014
+ async _verifyPasskeyRegistration(params) {
5015
+ (0, helpers_1.assertPasskeyExperimentalEnabled)(this.experimental);
5016
+ try {
5017
+ return await this._useSession(async (result) => {
5018
+ const { data: { session }, error: sessionError, } = result;
5019
+ if (sessionError) {
5020
+ return this._returnResult({ data: null, error: sessionError });
5021
+ }
5022
+ if (!session) {
5023
+ return this._returnResult({ data: null, error: new errors_1.AuthSessionMissingError() });
5024
+ }
5025
+ const { data, error } = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/passkeys/registration/verify`, {
5026
+ headers: this.headers,
5027
+ jwt: session.access_token,
5028
+ body: {
5029
+ challenge_id: params.challengeId,
5030
+ credential: params.credential,
5031
+ },
5032
+ });
5033
+ if (error) {
5034
+ return this._returnResult({ data: null, error });
5035
+ }
5036
+ return this._returnResult({ data, error: null });
5037
+ });
5038
+ }
5039
+ catch (error) {
5040
+ if ((0, errors_1.isAuthError)(error)) {
5041
+ return this._returnResult({ data: null, error });
5042
+ }
5043
+ throw error;
5044
+ }
5045
+ }
5046
+ /**
5047
+ * Start passkey authentication.
5048
+ * Returns WebAuthn credential request options to pass to navigator.credentials.get().
5049
+ */
5050
+ async _startPasskeyAuthentication(params) {
5051
+ var _a;
5052
+ (0, helpers_1.assertPasskeyExperimentalEnabled)(this.experimental);
5053
+ try {
5054
+ const { data, error } = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/passkeys/authentication/options`, {
5055
+ headers: this.headers,
5056
+ body: {
5057
+ gotrue_meta_security: { captcha_token: (_a = params === null || params === void 0 ? void 0 : params.options) === null || _a === void 0 ? void 0 : _a.captchaToken },
5058
+ },
5059
+ });
5060
+ if (error) {
5061
+ return this._returnResult({ data: null, error });
5062
+ }
5063
+ return this._returnResult({ data, error: null });
5064
+ }
5065
+ catch (error) {
5066
+ if ((0, errors_1.isAuthError)(error)) {
5067
+ return this._returnResult({ data: null, error });
5068
+ }
5069
+ throw error;
5070
+ }
5071
+ }
5072
+ /**
5073
+ * Verify passkey authentication and create a session.
5074
+ * The credential should be the serialized output of navigator.credentials.get().
5075
+ */
5076
+ async _verifyPasskeyAuthentication(params) {
5077
+ (0, helpers_1.assertPasskeyExperimentalEnabled)(this.experimental);
5078
+ try {
5079
+ const { data, error } = await (0, fetch_1._request)(this.fetch, 'POST', `${this.url}/passkeys/authentication/verify`, {
5080
+ headers: this.headers,
5081
+ body: {
5082
+ challenge_id: params.challengeId,
5083
+ credential: params.credential,
5084
+ },
5085
+ xform: fetch_1._sessionResponse,
5086
+ });
5087
+ if (error) {
5088
+ return this._returnResult({ data: null, error });
5089
+ }
5090
+ if (data.session) {
5091
+ await this._saveSession(data.session);
5092
+ await this._notifyAllSubscribers('SIGNED_IN', data.session);
5093
+ }
5094
+ return this._returnResult({ data, error: null });
5095
+ }
5096
+ catch (error) {
5097
+ if ((0, errors_1.isAuthError)(error)) {
5098
+ return this._returnResult({ data: null, error });
5099
+ }
5100
+ throw error;
5101
+ }
5102
+ }
5103
+ /**
5104
+ * List all passkeys for the current user.
5105
+ */
5106
+ async _listPasskeys() {
5107
+ (0, helpers_1.assertPasskeyExperimentalEnabled)(this.experimental);
5108
+ try {
5109
+ return await this._useSession(async (result) => {
5110
+ const { data: { session }, error: sessionError, } = result;
5111
+ if (sessionError) {
5112
+ return this._returnResult({ data: null, error: sessionError });
5113
+ }
5114
+ if (!session) {
5115
+ return this._returnResult({ data: null, error: new errors_1.AuthSessionMissingError() });
5116
+ }
5117
+ const { data, error } = await (0, fetch_1._request)(this.fetch, 'GET', `${this.url}/passkeys`, {
5118
+ headers: this.headers,
5119
+ jwt: session.access_token,
5120
+ xform: (data) => ({ data, error: null }),
5121
+ });
5122
+ if (error) {
5123
+ return this._returnResult({ data: null, error });
5124
+ }
5125
+ return this._returnResult({ data, error: null });
5126
+ });
5127
+ }
5128
+ catch (error) {
5129
+ if ((0, errors_1.isAuthError)(error)) {
5130
+ return this._returnResult({ data: null, error });
5131
+ }
5132
+ throw error;
5133
+ }
5134
+ }
5135
+ /**
5136
+ * Update a passkey.
5137
+ */
5138
+ async _updatePasskey(params) {
5139
+ (0, helpers_1.assertPasskeyExperimentalEnabled)(this.experimental);
5140
+ try {
5141
+ return await this._useSession(async (result) => {
5142
+ const { data: { session }, error: sessionError, } = result;
5143
+ if (sessionError) {
5144
+ return this._returnResult({ data: null, error: sessionError });
5145
+ }
5146
+ if (!session) {
5147
+ return this._returnResult({ data: null, error: new errors_1.AuthSessionMissingError() });
5148
+ }
5149
+ const { data, error } = await (0, fetch_1._request)(this.fetch, 'PATCH', `${this.url}/passkeys/${params.passkeyId}`, {
5150
+ headers: this.headers,
5151
+ jwt: session.access_token,
5152
+ body: { friendly_name: params.friendlyName },
5153
+ });
5154
+ if (error) {
5155
+ return this._returnResult({ data: null, error });
5156
+ }
5157
+ return this._returnResult({ data, error: null });
5158
+ });
5159
+ }
5160
+ catch (error) {
5161
+ if ((0, errors_1.isAuthError)(error)) {
5162
+ return this._returnResult({ data: null, error });
5163
+ }
5164
+ throw error;
5165
+ }
5166
+ }
5167
+ /**
5168
+ * Delete a passkey.
5169
+ */
5170
+ async _deletePasskey(params) {
5171
+ (0, helpers_1.assertPasskeyExperimentalEnabled)(this.experimental);
5172
+ try {
5173
+ return await this._useSession(async (result) => {
5174
+ const { data: { session }, error: sessionError, } = result;
5175
+ if (sessionError) {
5176
+ return this._returnResult({ data: null, error: sessionError });
5177
+ }
5178
+ if (!session) {
5179
+ return this._returnResult({ data: null, error: new errors_1.AuthSessionMissingError() });
5180
+ }
5181
+ const { error } = await (0, fetch_1._request)(this.fetch, 'DELETE', `${this.url}/passkeys/${params.passkeyId}`, {
5182
+ headers: this.headers,
5183
+ jwt: session.access_token,
5184
+ noResolveJson: true,
5185
+ });
5186
+ if (error) {
5187
+ return this._returnResult({ data: null, error });
5188
+ }
5189
+ return this._returnResult({ data: null, error: null });
5190
+ });
5191
+ }
5192
+ catch (error) {
5193
+ if ((0, errors_1.isAuthError)(error)) {
5194
+ return this._returnResult({ data: null, error });
5195
+ }
5196
+ throw error;
5197
+ }
5198
+ }
4862
5199
  }
4863
5200
  GoTrueClient.nextInstanceID = {};
4864
5201
  exports.default = GoTrueClient;