@auth0/auth0-server-js 1.15.0 → 1.16.1

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.
package/dist/index.cjs CHANGED
@@ -20,43 +20,50 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ AbstractAnonymousStore: () => AbstractAnonymousStore,
23
24
  AbstractStateStore: () => AbstractStateStore,
24
25
  AbstractTransactionStore: () => AbstractTransactionStore,
26
+ AnonymousSessionError: () => import_auth0_auth_js7.AnonymousSessionError,
27
+ AnonymousSessionExpiredError: () => AnonymousSessionExpiredError,
25
28
  BackchannelLogoutError: () => BackchannelLogoutError,
26
- ChangePasswordError: () => import_auth0_auth_js5.ChangePasswordError,
29
+ ChangePasswordError: () => import_auth0_auth_js6.ChangePasswordError,
27
30
  CookieTransactionStore: () => CookieTransactionStore,
28
- EnterpriseConnectNotSupportedError: () => import_auth0_auth_js6.EnterpriseConnectNotSupportedError,
31
+ DEFAULT_ANONYMOUS_SESSION_LIFETIME: () => DEFAULT_ANONYMOUS_SESSION_LIFETIME,
32
+ EnterpriseConnectNotSupportedError: () => import_auth0_auth_js8.EnterpriseConnectNotSupportedError,
29
33
  InvalidConfigurationError: () => InvalidConfigurationError,
30
34
  IssuerValidationError: () => IssuerValidationError,
31
- MfaChallengeError: () => import_auth0_auth_js3.MfaChallengeError,
32
- MfaEnrollmentError: () => import_auth0_auth_js3.MfaEnrollmentError,
33
- MfaListAuthenticatorsError: () => import_auth0_auth_js3.MfaListAuthenticatorsError,
34
- MfaVerifyError: () => import_auth0_auth_js3.MfaVerifyError,
35
- MissingClientAuthError: () => import_auth0_auth_js6.MissingClientAuthError,
35
+ MfaChallengeError: () => import_auth0_auth_js4.MfaChallengeError,
36
+ MfaEnrollmentError: () => import_auth0_auth_js4.MfaEnrollmentError,
37
+ MfaListAuthenticatorsError: () => import_auth0_auth_js4.MfaListAuthenticatorsError,
38
+ MfaVerifyError: () => import_auth0_auth_js4.MfaVerifyError,
39
+ MissingAnonymousSessionError: () => MissingAnonymousSessionError,
40
+ MissingClientAuthError: () => import_auth0_auth_js8.MissingClientAuthError,
36
41
  MissingRequiredArgumentError: () => MissingRequiredArgumentError,
37
42
  MissingSessionError: () => MissingSessionError,
38
43
  MissingTransactionError: () => MissingTransactionError,
39
- OrganizationValidationError: () => import_auth0_auth_js6.OrganizationValidationError,
40
- PasskeyChallengeError: () => import_auth0_auth_js4.PasskeyChallengeError,
41
- PasskeyGetTokenError: () => import_auth0_auth_js4.PasskeyGetTokenError,
42
- PasskeyRegisterError: () => import_auth0_auth_js4.PasskeyRegisterError,
43
- PasswordlessStartError: () => import_auth0_auth_js6.PasswordlessStartError,
44
- PasswordlessVerifyError: () => import_auth0_auth_js6.PasswordlessVerifyError,
44
+ OrganizationValidationError: () => import_auth0_auth_js8.OrganizationValidationError,
45
+ PasskeyChallengeError: () => import_auth0_auth_js5.PasskeyChallengeError,
46
+ PasskeyGetTokenError: () => import_auth0_auth_js5.PasskeyGetTokenError,
47
+ PasskeyRegisterError: () => import_auth0_auth_js5.PasskeyRegisterError,
48
+ PasswordlessStartError: () => import_auth0_auth_js8.PasswordlessStartError,
49
+ PasswordlessVerifyError: () => import_auth0_auth_js8.PasswordlessVerifyError,
50
+ ServerAnonymousClient: () => ServerAnonymousClient,
45
51
  ServerClient: () => ServerClient,
46
52
  ServerDatabaseClient: () => ServerDatabaseClient,
47
53
  ServerMfaClient: () => ServerMfaClient,
48
54
  ServerPasskeyClient: () => ServerPasskeyClient,
49
55
  SessionExpiredError: () => SessionExpiredError,
50
- SignUpError: () => import_auth0_auth_js5.SignUpError,
56
+ SignUpError: () => import_auth0_auth_js6.SignUpError,
51
57
  StartLinkUserError: () => StartLinkUserError,
52
58
  StatefulStateStore: () => StatefulStateStore,
59
+ StatelessAnonymousStore: () => StatelessAnonymousStore,
53
60
  StatelessStateStore: () => StatelessStateStore,
54
- TokenExchangeError: () => import_auth0_auth_js6.TokenExchangeError,
61
+ TokenExchangeError: () => import_auth0_auth_js8.TokenExchangeError,
55
62
  TokenExchangeErrorCode: () => TokenExchangeErrorCode,
56
- TokenRevocationError: () => import_auth0_auth_js6.TokenRevocationError,
57
- UserInfoError: () => import_auth0_auth_js6.UserInfoError,
58
- isFederatedDomain: () => import_auth0_auth_js6.isFederatedDomain,
59
- isMfaRequiredError: () => import_auth0_auth_js6.isMfaRequiredError
63
+ TokenRevocationError: () => import_auth0_auth_js8.TokenRevocationError,
64
+ UserInfoError: () => import_auth0_auth_js8.UserInfoError,
65
+ isFederatedDomain: () => import_auth0_auth_js8.isFederatedDomain,
66
+ isMfaRequiredError: () => import_auth0_auth_js8.isMfaRequiredError
60
67
  });
61
68
  module.exports = __toCommonJS(index_exports);
62
69
 
@@ -115,6 +122,22 @@ var IssuerValidationError = class extends Error {
115
122
  this.name = "IssuerValidationError";
116
123
  }
117
124
  };
125
+ var MissingAnonymousSessionError = class extends Error {
126
+ code = "missing_anonymous_session_error";
127
+ constructor(message) {
128
+ super(message ?? "There is no anonymous session. Call `anonymous.createSession()` first.");
129
+ this.name = "MissingAnonymousSessionError";
130
+ }
131
+ };
132
+ var AnonymousSessionExpiredError = class extends Error {
133
+ code = "anonymous_session_expired";
134
+ constructor(message) {
135
+ super(
136
+ message ?? "The anonymous session has expired or is no longer valid. Call `anonymous.createSession()` to start a new one."
137
+ );
138
+ this.name = "AnonymousSessionExpiredError";
139
+ }
140
+ };
118
141
  var SessionExpiredError = class extends Error {
119
142
  code = "session_expired";
120
143
  constructor(message) {
@@ -227,7 +250,7 @@ function updateStateDataForConnectionTokenSet(options, stateData, tokenEndpointR
227
250
  }
228
251
 
229
252
  // src/server-client.ts
230
- var import_auth0_auth_js2 = require("@auth0/auth0-auth-js");
253
+ var import_auth0_auth_js3 = require("@auth0/auth0-auth-js");
231
254
 
232
255
  // src/utils.ts
233
256
  var DEFAULT_SCOPES = "openid profile email offline_access";
@@ -255,7 +278,7 @@ var compareScopes = (scopes, requiredScopes) => {
255
278
  };
256
279
 
257
280
  // src/server-client.ts
258
- var import_jose = require("jose");
281
+ var import_jose2 = require("jose");
259
282
 
260
283
  // src/telemetry.ts
261
284
  function getTelemetryConfig(config) {
@@ -265,7 +288,7 @@ function getTelemetryConfig(config) {
265
288
  return {
266
289
  enabled: true,
267
290
  name: config?.name ?? "@auth0/auth0-server-js",
268
- version: config?.version ?? "1.15.0"
291
+ version: config?.version ?? "1.16.1"
269
292
  };
270
293
  }
271
294
 
@@ -339,6 +362,7 @@ var ServerMfaClient = class {
339
362
  true,
340
363
  storeOptions
341
364
  );
365
+ await this.#options.onUserSessionEstablished?.(storeOptions);
342
366
  const result = {
343
367
  accessToken: tokenResponse.accessToken,
344
368
  tokenType: tokenResponse.tokenType ?? "bearer",
@@ -447,6 +471,7 @@ var ServerPasskeyClient = class {
447
471
  const existingStateData = await this.#options.stateStore.get(this.#options.stateStoreIdentifier, storeOptions);
448
472
  const stateData = updateStateData(audience ?? "default", existingStateData, tokenEndpointResponse, { domain });
449
473
  await this.#options.stateStore.set(this.#options.stateStoreIdentifier, stateData, true, storeOptions);
474
+ await this.#options.onUserSessionEstablished?.(storeOptions);
450
475
  return {
451
476
  authorizationDetails: tokenEndpointResponse.authorizationDetails
452
477
  };
@@ -541,6 +566,234 @@ function applyEnterpriseConnectRestrictions(instance) {
541
566
  }
542
567
  }
543
568
 
569
+ // src/anonymous/server-anonymous-client.ts
570
+ var import_jose = require("jose");
571
+ var import_auth0_auth_js2 = require("@auth0/auth0-auth-js");
572
+ var DEFAULT_AUDIENCE_CACHE_KEY = "default";
573
+ var readAnonymousSub = (accessToken) => {
574
+ try {
575
+ const { sub } = (0, import_jose.decodeJwt)(accessToken);
576
+ return typeof sub === "string" ? sub : void 0;
577
+ } catch {
578
+ return void 0;
579
+ }
580
+ };
581
+ var cacheKeyScope = (tokenSet) => tokenSet.requestedScope ?? tokenSet.scope;
582
+ var upsertTokenSet = (tokenSets, tokenSet) => {
583
+ const matches = (candidate) => candidate.audience === tokenSet.audience && cacheKeyScope(candidate) === cacheKeyScope(tokenSet);
584
+ return tokenSets.some(matches) ? tokenSets.map((candidate) => matches(candidate) ? tokenSet : candidate) : [...tokenSets, tokenSet];
585
+ };
586
+ var ServerAnonymousClient = class {
587
+ #options;
588
+ /**
589
+ * @internal
590
+ */
591
+ constructor(options) {
592
+ this.#options = options;
593
+ }
594
+ /**
595
+ * Creates an anonymous session and stores it, returning the first anonymous access token.
596
+ *
597
+ * Replaces any anonymous session already stored for this visitor. Metadata can only be
598
+ * attached here, because Auth0 rejects a request that carries both metadata and an
599
+ * existing session.
600
+ *
601
+ * The anonymous identity (`sub`) is read off the first access token and stored alongside
602
+ * the metadata, so {@link ServerAnonymousClient.getSession} can hand both back without the
603
+ * application decoding a token. It stays `undefined` for an audience with token encryption
604
+ * (`token_encryption`) enabled, whose access token is an encrypted JWE only the API can
605
+ * read.
606
+ *
607
+ * @param options Optional audience, scope and metadata for the new session.
608
+ * @param storeOptions Optional options used to pass to the anonymous store (and to resolve the domain in resolver mode).
609
+ *
610
+ * @throws {AnonymousSessionError} If Auth0 rejected the request. Common codes are
611
+ * `feature_not_enabled` (the tenant flag is off), `unauthorized_client` (the client is
612
+ * not enabled for anonymous sessions), `invalid_target` (the resource server does not
613
+ * allow anonymous access), `invalid_request` (metadata over 1024 bytes, or not all
614
+ * strings) and `access_denied`. `code` is `server_error` when Auth0 answers with a body
615
+ * that is not JSON.
616
+ *
617
+ * Only call this once you have established the visitor has no anonymous session (check
618
+ * {@link ServerAnonymousClient.getSession} first), rather than on every request.
619
+ *
620
+ * @returns The anonymous access token for the requested audience.
621
+ */
622
+ async createSession(options, storeOptions) {
623
+ const domain = await this.#options.resolveDomain(storeOptions);
624
+ const requestedAudience = options?.audience ?? this.#options.defaultAudience;
625
+ const audience = requestedAudience ?? DEFAULT_AUDIENCE_CACHE_KEY;
626
+ const scope = options?.scope;
627
+ const session = await this.#options.getAuthClient(domain).anonymous.createSession({
628
+ ...requestedAudience && { audience: requestedAudience },
629
+ ...scope && { scope },
630
+ ...options?.metadata && { metadata: options.metadata }
631
+ });
632
+ const tokenSet = {
633
+ audience,
634
+ accessToken: session.accessToken,
635
+ scope: session.scope,
636
+ ...scope && scope !== session.scope && { requestedScope: scope },
637
+ expiresAt: session.expiresAt
638
+ };
639
+ const stateData = {
640
+ sessionToken: session.sessionToken,
641
+ sessionTokenExpiresAt: session.sessionTokenExpiresAt,
642
+ sub: readAnonymousSub(session.accessToken),
643
+ ...options?.metadata && { metadata: options.metadata },
644
+ createdAt: Math.floor(Date.now() / 1e3),
645
+ tokenSets: [tokenSet],
646
+ domain
647
+ };
648
+ await this.#options.anonymousStore.set(
649
+ this.#options.anonymousStoreIdentifier,
650
+ stateData,
651
+ true,
652
+ storeOptions
653
+ );
654
+ return tokenSet;
655
+ }
656
+ /**
657
+ * Returns an anonymous access token for the stored anonymous session, fetching a fresh
658
+ * one from Auth0 when the cached one has expired.
659
+ *
660
+ * Tokens are cached per audience and scope, so requesting a second audience returns a
661
+ * second token for the same anonymous identity without replacing the first.
662
+ *
663
+ * Auth0 may grant fewer scopes than requested — a scope the anonymous identity is not
664
+ * entitled to is silently dropped and the response is still a success. Always check
665
+ * `tokenSet.scope` before calling your API; do not assume the token carries every scope
666
+ * you asked for.
667
+ *
668
+ * This never creates a session. If the anonymous session has expired, the stored session
669
+ * is deleted and `AnonymousSessionExpiredError` is thrown, so a visitor is never moved
670
+ * onto a fresh anonymous identity behind your back.
671
+ *
672
+ * @param options Optional audience and scope for the requested token.
673
+ * @param storeOptions Optional options used to pass to the anonymous store (and to resolve the domain in resolver mode).
674
+ *
675
+ * @throws {MissingAnonymousSessionError} When there is no anonymous session stored, or the stored one belongs to another Auth0 domain (resolver mode).
676
+ * @throws {AnonymousSessionExpiredError} When the anonymous session has expired or Auth0 rejected the session token. The stored session is deleted first.
677
+ *
678
+ * @returns The anonymous access token for the requested audience.
679
+ */
680
+ async getAccessToken(options, storeOptions) {
681
+ const stateData = await this.#options.anonymousStore.get(
682
+ this.#options.anonymousStoreIdentifier,
683
+ storeOptions
684
+ );
685
+ if (!stateData?.sessionToken) {
686
+ throw new MissingAnonymousSessionError();
687
+ }
688
+ const domain = await this.#options.resolveDomain(storeOptions);
689
+ if (this.#options.isResolverMode() && stateData.domain !== domain) {
690
+ throw new MissingAnonymousSessionError(
691
+ "The stored anonymous session was created for a different Auth0 domain."
692
+ );
693
+ }
694
+ const requestedAudience = options?.audience ?? this.#options.defaultAudience;
695
+ const audience = requestedAudience ?? DEFAULT_AUDIENCE_CACHE_KEY;
696
+ const scope = options?.scope;
697
+ const cachedTokenSet = stateData.tokenSets.find(
698
+ (tokenSet2) => tokenSet2.audience === audience && (!scope || cacheKeyScope(tokenSet2) === scope || compareScopes(tokenSet2.scope, scope))
699
+ );
700
+ if (cachedTokenSet && cachedTokenSet.expiresAt > Date.now() / 1e3) {
701
+ return cachedTokenSet;
702
+ }
703
+ let renewed;
704
+ try {
705
+ renewed = await this.#options.getAuthClient(domain).anonymous.getAccessToken({
706
+ sessionToken: stateData.sessionToken,
707
+ ...requestedAudience && { audience: requestedAudience },
708
+ ...scope && { scope }
709
+ });
710
+ } catch (e) {
711
+ if (e instanceof import_auth0_auth_js2.AnonymousSessionError && e.code === "session_expired") {
712
+ await this.#options.anonymousStore.delete(this.#options.anonymousStoreIdentifier, storeOptions);
713
+ throw new AnonymousSessionExpiredError();
714
+ }
715
+ if (e instanceof import_auth0_auth_js2.AnonymousSessionError && e.code === "invalid_session_token") {
716
+ await this.#options.anonymousStore.delete(this.#options.anonymousStoreIdentifier, storeOptions);
717
+ }
718
+ throw e;
719
+ }
720
+ const tokenSet = {
721
+ audience,
722
+ accessToken: renewed.accessToken,
723
+ scope: renewed.scope,
724
+ ...scope && scope !== renewed.scope && { requestedScope: scope },
725
+ expiresAt: renewed.expiresAt
726
+ };
727
+ const existingStateData = await this.#options.anonymousStore.get(
728
+ this.#options.anonymousStoreIdentifier,
729
+ storeOptions
730
+ );
731
+ if (existingStateData?.sessionToken === stateData.sessionToken) {
732
+ await this.#options.anonymousStore.set(
733
+ this.#options.anonymousStoreIdentifier,
734
+ {
735
+ ...existingStateData,
736
+ ...existingStateData.sub === void 0 && { sub: readAnonymousSub(renewed.accessToken) },
737
+ tokenSets: upsertTokenSet(existingStateData.tokenSets, tokenSet)
738
+ },
739
+ false,
740
+ storeOptions
741
+ );
742
+ }
743
+ return tokenSet;
744
+ }
745
+ /**
746
+ * Returns the stored anonymous session, or `undefined` when there is none.
747
+ *
748
+ * Two common uses:
749
+ * - **Gate `createSession`** — call this first; only create a session when the result is `undefined`.
750
+ * - **Read identity for a merge** — `sub` and `metadata` are available here without decoding a token.
751
+ *
752
+ * This is a local read of the store with no request to Auth0. It cannot tell you whether
753
+ * Auth0 still considers the session valid — only {@link ServerAnonymousClient.getAccessToken} can.
754
+ * The session token is never included in the result.
755
+ *
756
+ * @param storeOptions Optional options used to pass to the anonymous store (and to resolve the domain in resolver mode).
757
+ *
758
+ * @returns The anonymous session, or `undefined` when there is none for this visitor (or it belongs to another Auth0 domain in resolver mode).
759
+ */
760
+ async getSession(storeOptions) {
761
+ const stateData = await this.#options.anonymousStore.get(
762
+ this.#options.anonymousStoreIdentifier,
763
+ storeOptions
764
+ );
765
+ if (!stateData) {
766
+ return;
767
+ }
768
+ if (this.#options.isResolverMode()) {
769
+ const domain = await this.#options.resolveDomain(storeOptions);
770
+ if (stateData.domain !== domain) {
771
+ return;
772
+ }
773
+ }
774
+ const { sessionToken, ...sessionData } = stateData;
775
+ return sessionData;
776
+ }
777
+ /**
778
+ * Clears the anonymous session from the store.
779
+ *
780
+ * Does not call `POST /anonymous/logout` — that endpoint only clears the `auth0_anon`
781
+ * browser cookie, which your server never holds. Any access tokens already issued remain
782
+ * valid until they expire (~2 hours by default).
783
+ *
784
+ * You rarely need to call this directly: every method that establishes a user session
785
+ * clears the anonymous session automatically (unless `clearAnonymousSessionOnLogin: false`
786
+ * is set), and `serverClient.logout()` clears it too. Call this to explicitly reset a
787
+ * visitor's anonymous identity, or to clean up after your own post-login merge logic when
788
+ * automatic clearing is disabled.
789
+ *
790
+ * @param storeOptions Optional options used to pass to the anonymous store.
791
+ */
792
+ async logout(storeOptions) {
793
+ await this.#options.anonymousStore.delete(this.#options.anonymousStoreIdentifier, storeOptions);
794
+ }
795
+ };
796
+
544
797
  // src/server-client.ts
545
798
  var normalizeDomain = (value) => {
546
799
  const trimmed = value.trim();
@@ -549,7 +802,7 @@ var normalizeDomain = (value) => {
549
802
  };
550
803
  var decodeIssuer = (token) => {
551
804
  try {
552
- const { iss } = (0, import_jose.decodeJwt)(token);
805
+ const { iss } = (0, import_jose2.decodeJwt)(token);
553
806
  return typeof iss === "string" ? iss : void 0;
554
807
  } catch {
555
808
  return void 0;
@@ -558,13 +811,13 @@ var decodeIssuer = (token) => {
558
811
  var ID_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:id_token";
559
812
  var ID_TOKEN_EXPIRY_SKEW_SECONDS = 30;
560
813
  var actorUnavailableError = (message) => {
561
- const error = new import_auth0_auth_js2.TokenExchangeError(message);
814
+ const error = new import_auth0_auth_js3.TokenExchangeError(message);
562
815
  error.code = TokenExchangeErrorCode.ACTOR_UNAVAILABLE;
563
816
  return error;
564
817
  };
565
818
  var isTokenExpired = (token) => {
566
819
  try {
567
- const { exp } = (0, import_jose.decodeJwt)(token);
820
+ const { exp } = (0, import_jose2.decodeJwt)(token);
568
821
  if (typeof exp !== "number") {
569
822
  return true;
570
823
  }
@@ -586,6 +839,7 @@ var ServerClient = class {
586
839
  #mfaClient;
587
840
  #passkeyClient;
588
841
  #databaseClient;
842
+ #anonymousClient;
589
843
  /**
590
844
  * The underlying `authClient` instance that can be used to interact with the Auth0 Authentication API.
591
845
  * Generally, you should prefer to use the higher-level methods exposed on the `ServerClient` instance.
@@ -648,6 +902,42 @@ var ServerClient = class {
648
902
  get database() {
649
903
  return this.#databaseClient;
650
904
  }
905
+ /**
906
+ * The anonymous session client, for giving a visitor who has not logged in a stable
907
+ * identity and an access token for your API.
908
+ *
909
+ * Provides `createSession()` to establish the anonymous identity, `getAccessToken()` to
910
+ * obtain and renew anonymous access tokens, `getSession()` to check whether a visitor
911
+ * already has one, and `logout()` to discard it.
912
+ *
913
+ * Requires `anonymousStore` on the `ServerClient`, and a tenant and client configured for
914
+ * anonymous sessions. Anonymous sessions are kept in that store, never in the state
915
+ * store, so `getSession()` and `getUser()` still report no user while one is active.
916
+ *
917
+ * The anonymous session ends when the visitor logs in: every login method clears it once
918
+ * the user session is written, unless you set `clearAnonymousSessionOnLogin: false`.
919
+ * {@link ServerClient.logout} clears it too.
920
+ *
921
+ * For `/authorize` flows, `startInteractiveLogin()` links the anonymous session to
922
+ * the user automatically via a Session Transfer Ticket — no extra configuration needed.
923
+ * For logins that bypass `/authorize` (passkey, passwordless, backchannel, custom token
924
+ * exchange), the anonymous session is not linked. Read `anonymous.getSession()` before
925
+ * the login to get the anonymous `sub` for a manual merge, or set
926
+ * `clearAnonymousSessionOnLogin: false` and clear it yourself afterwards.
927
+ *
928
+ * Like `passkey` and `database`, this works in both static and resolver (multi-tenant)
929
+ * domain modes.
930
+ *
931
+ * @throws {InvalidConfigurationError} When no `anonymousStore` is configured.
932
+ */
933
+ get anonymous() {
934
+ if (!this.#anonymousClient) {
935
+ throw new InvalidConfigurationError(
936
+ "anonymous is only available when an `anonymousStore` is configured on the ServerClient."
937
+ );
938
+ }
939
+ return this.#anonymousClient;
940
+ }
651
941
  constructor(options) {
652
942
  this.#options = options;
653
943
  this.#enterpriseConnect = !!options.enterpriseConnect;
@@ -696,7 +986,7 @@ var ServerClient = class {
696
986
  if (typeof this.#options.domain === "string") {
697
987
  const domain = normalizeDomain(this.#options.domain);
698
988
  this.#staticDomain = domain;
699
- this.#authClient = new import_auth0_auth_js2.AuthClient({
989
+ this.#authClient = new import_auth0_auth_js3.AuthClient({
700
990
  domain,
701
991
  ...this.#authClientOptions,
702
992
  telemetry: getTelemetryConfig(this.#options.telemetry)
@@ -706,7 +996,8 @@ var ServerClient = class {
706
996
  domain,
707
997
  stateStore: this.#stateStore,
708
998
  stateStoreIdentifier: this.#stateStoreIdentifier,
709
- defaultAudience: this.#options.authorizationParams?.audience ?? "default"
999
+ defaultAudience: this.#options.authorizationParams?.audience ?? "default",
1000
+ onUserSessionEstablished: (storeOptions) => this.#clearAnonymousSessionAfterLogin(storeOptions)
710
1001
  });
711
1002
  }
712
1003
  this.#passkeyClient = new ServerPasskeyClient({
@@ -715,12 +1006,26 @@ var ServerClient = class {
715
1006
  stateStore: this.#stateStore,
716
1007
  stateStoreIdentifier: this.#stateStoreIdentifier,
717
1008
  defaultScope: this.#options.authorizationParams?.scope,
718
- defaultAudience: this.#options.authorizationParams?.audience
1009
+ defaultAudience: this.#options.authorizationParams?.audience,
1010
+ onUserSessionEstablished: (storeOptions) => this.#clearAnonymousSessionAfterLogin(storeOptions)
719
1011
  });
720
1012
  this.#databaseClient = new ServerDatabaseClient({
721
1013
  resolveDomain: (storeOptions) => this.#resolveDomain(storeOptions),
722
1014
  getAuthClient: (domain) => this.#getAuthClient(domain)
723
1015
  });
1016
+ if (this.#options.anonymousStore) {
1017
+ this.#anonymousClient = new ServerAnonymousClient({
1018
+ resolveDomain: (storeOptions) => this.#resolveDomain(storeOptions),
1019
+ getAuthClient: (domain) => this.#getAuthClient(domain),
1020
+ isResolverMode: () => this.#isResolverMode(),
1021
+ anonymousStore: this.#options.anonymousStore,
1022
+ anonymousStoreIdentifier: this.#options.anonymousSessionIdentifier || "__a0_anon",
1023
+ // Only the audience is inherited from the client-level authorizationParams. The
1024
+ // scope there is written for a user session (`openid profile email offline_access`)
1025
+ // and none of it applies to an anonymous identity.
1026
+ defaultAudience: this.#options.authorizationParams?.audience
1027
+ });
1028
+ }
724
1029
  }
725
1030
  async #resolveDomain(storeOptions) {
726
1031
  if (typeof this.#options.domain === "function") {
@@ -733,7 +1038,7 @@ var ServerClient = class {
733
1038
  return normalizeDomain(this.#options.domain);
734
1039
  }
735
1040
  #createAuthClient(domain) {
736
- return new import_auth0_auth_js2.AuthClient({
1041
+ return new import_auth0_auth_js3.AuthClient({
737
1042
  domain,
738
1043
  ...this.#authClientOptions,
739
1044
  telemetry: getTelemetryConfig(this.#options.telemetry)
@@ -784,7 +1089,7 @@ var ServerClient = class {
784
1089
  if (parts.length !== 2 || !parts[0] || !parts[1]) return null;
785
1090
  const emailDomain = parts[1].toLowerCase();
786
1091
  const domain = await this.#resolveDomain(storeOptions);
787
- const isFederated = await (0, import_auth0_auth_js2.isFederatedDomain)(domain, emailDomain, {
1092
+ const isFederated = await (0, import_auth0_auth_js3.isFederatedDomain)(domain, emailDomain, {
788
1093
  customFetch: this.#options.customFetch,
789
1094
  telemetry: getTelemetryConfig(this.#options.telemetry)
790
1095
  });
@@ -797,6 +1102,54 @@ var ServerClient = class {
797
1102
  storeOptions
798
1103
  );
799
1104
  }
1105
+ /**
1106
+ * Discards the anonymous session once a login has established a user session.
1107
+ *
1108
+ * Called by every method that writes a user session, always AFTER the state store has been
1109
+ * written. An anonymous session outliving the login would leave a 30-day bearer credential
1110
+ * in a cookie on every request, and `anonymous.getAccessToken()` would keep minting
1111
+ * anonymous tokens for a visitor who is no longer anonymous.
1112
+ *
1113
+ * Two deliberate properties:
1114
+ * - **Best-effort.** The user is authenticated and their session is already persisted by
1115
+ * this point, so a failing anonymous store must not turn a successful login into an
1116
+ * error. The visitor would be unable to log in at all because of leftover state they
1117
+ * cannot see or clear.
1118
+ * - **Unconditional across domains.** In resolver (multi-tenant) mode the anonymous session
1119
+ * is dropped even when it was created against a different Auth0 domain than the one just
1120
+ * logged into. The anonymous store holds a single session per visitor, and "no anonymous
1121
+ * session survives a login" is a rule that can be reasoned about; a domain-dependent one
1122
+ * cannot.
1123
+ *
1124
+ * Skipped entirely when no `anonymousStore` is configured, or when the application opted
1125
+ * out with `clearAnonymousSessionOnLogin: false`.
1126
+ */
1127
+ async #clearAnonymousSessionAfterLogin(storeOptions) {
1128
+ if (this.#options.clearAnonymousSessionOnLogin === false) {
1129
+ return;
1130
+ }
1131
+ await this.#discardAnonymousSession(storeOptions);
1132
+ }
1133
+ /**
1134
+ * Drops the anonymous session, swallowing store failures.
1135
+ *
1136
+ * Shared by the login sites and {@link ServerClient.logout}. Both run after the user
1137
+ * session has already been written or deleted, so the outcome the caller cares about is
1138
+ * settled: a failing anonymous store must not fail a login the user completed, nor block a
1139
+ * logout redirect and leave the visitor unable to log out. When the store is the
1140
+ * cookie-backed default this cannot fail, since deleting is a `Set-Cookie` on the response.
1141
+ *
1142
+ * No-op when no `anonymousStore` is configured.
1143
+ */
1144
+ async #discardAnonymousSession(storeOptions) {
1145
+ if (!this.#anonymousClient) {
1146
+ return;
1147
+ }
1148
+ try {
1149
+ await this.#anonymousClient.logout(storeOptions);
1150
+ } catch {
1151
+ }
1152
+ }
800
1153
  /**
801
1154
  * Starts the interactive login process, and returns a URL to redirect the user-agent to to request authorization at Auth0.
802
1155
  *
@@ -824,7 +1177,7 @@ var ServerClient = class {
824
1177
  const clientAuthParamsOrganization = typeof this.#options.authorizationParams?.organization === "string" ? this.#options.authorizationParams.organization : void 0;
825
1178
  const resolvedOrganization = options?.organization ?? perLoginAuthParamsOrganization ?? this.#options.organization ?? clientAuthParamsOrganization;
826
1179
  if (resolvedOrganization !== void 0 && !resolvedOrganization.trim()) {
827
- throw new import_auth0_auth_js2.OrganizationValidationError("organization must not be blank");
1180
+ throw new import_auth0_auth_js3.OrganizationValidationError("organization must not be blank");
828
1181
  }
829
1182
  const hasInvitation = !!(options?.invitation || options?.authorizationParams?.invitation);
830
1183
  if (hasInvitation && !resolvedOrganization) {
@@ -832,6 +1185,17 @@ var ServerClient = class {
832
1185
  }
833
1186
  const domain = await this.#resolveDomain(storeOptions);
834
1187
  const authClient = this.#getAuthClient(domain);
1188
+ let anonTransferToken;
1189
+ if (this.#options.anonymousStore) {
1190
+ try {
1191
+ const identifier = this.#options.anonymousSessionIdentifier || "__a0_anon";
1192
+ const stateData = await this.#options.anonymousStore.get(identifier, storeOptions);
1193
+ if (stateData?.sessionToken) {
1194
+ anonTransferToken = await authClient.anonymous.mintTransferToken(stateData.sessionToken) ?? void 0;
1195
+ }
1196
+ } catch {
1197
+ }
1198
+ }
835
1199
  const { codeVerifier, authorizationUrl } = await authClient.buildAuthorizationUrl({
836
1200
  pushedAuthorizationRequests: options?.pushedAuthorizationRequests,
837
1201
  authorizationParams: {
@@ -839,7 +1203,8 @@ var ServerClient = class {
839
1203
  redirect_uri: redirectUri,
840
1204
  scope,
841
1205
  ...resolvedOrganization ? { organization: resolvedOrganization } : {},
842
- ...options?.invitation ? { invitation: options.invitation } : {}
1206
+ ...options?.invitation ? { invitation: options.invitation } : {},
1207
+ ...anonTransferToken ? { anon_transfer_token: anonTransferToken } : {}
843
1208
  }
844
1209
  });
845
1210
  const transactionState = {
@@ -909,6 +1274,7 @@ var ServerClient = class {
909
1274
  tokenEndpointResponse.claims
910
1275
  );
911
1276
  await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
1277
+ await this.#clearAnonymousSessionAfterLogin(storeOptions);
912
1278
  return {
913
1279
  appState: transactionData.appState,
914
1280
  authorizationDetails: tokenEndpointResponse.authorizationDetails
@@ -1076,12 +1442,13 @@ var ServerClient = class {
1076
1442
  tokenEndpointResponse.claims
1077
1443
  );
1078
1444
  await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
1445
+ await this.#clearAnonymousSessionAfterLogin(storeOptions);
1079
1446
  const result = {
1080
1447
  authorizationDetails: tokenEndpointResponse.authorizationDetails
1081
1448
  };
1082
1449
  if (options.fullResponse) {
1083
1450
  if (!response) {
1084
- throw new import_auth0_auth_js2.MissingCapturedResponseError();
1451
+ throw new import_auth0_auth_js3.MissingCapturedResponseError();
1085
1452
  }
1086
1453
  return { data: result, response };
1087
1454
  }
@@ -1150,7 +1517,7 @@ var ServerClient = class {
1150
1517
  return;
1151
1518
  }
1152
1519
  if (!options.redirectUri || typeof options.redirectUri !== "string") {
1153
- throw new import_auth0_auth_js2.PasswordlessStartError("redirectUri is required to start a passwordless magic-link login.");
1520
+ throw new import_auth0_auth_js3.PasswordlessStartError("redirectUri is required to start a passwordless magic-link login.");
1154
1521
  }
1155
1522
  const state = crypto.randomUUID();
1156
1523
  const scope = ensureOpenIdScope(options.scope ?? this.#options.authorizationParams?.scope);
@@ -1222,12 +1589,13 @@ var ServerClient = class {
1222
1589
  { domain }
1223
1590
  );
1224
1591
  await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
1592
+ await this.#clearAnonymousSessionAfterLogin(storeOptions);
1225
1593
  const result = {
1226
1594
  authorizationDetails: tokenEndpointResponse.authorizationDetails
1227
1595
  };
1228
1596
  if (options.fullResponse) {
1229
1597
  if (!response) {
1230
- throw new import_auth0_auth_js2.MissingCapturedResponseError();
1598
+ throw new import_auth0_auth_js3.MissingCapturedResponseError();
1231
1599
  }
1232
1600
  return { data: result, response };
1233
1601
  }
@@ -1262,7 +1630,7 @@ var ServerClient = class {
1262
1630
  const expectedState = typeof transactionData.state === "string" ? transactionData.state : void 0;
1263
1631
  const returnedState = url.searchParams.get("state");
1264
1632
  if (!returnedState || !expectedState || returnedState !== expectedState) {
1265
- throw new import_auth0_auth_js2.PasswordlessVerifyError("State mismatch on magic-link callback");
1633
+ throw new import_auth0_auth_js3.PasswordlessVerifyError("State mismatch on magic-link callback");
1266
1634
  }
1267
1635
  const domain = transactionData.domain ?? await this.#resolveDomain(storeOptions);
1268
1636
  const authClient = this.#getAuthClient(domain);
@@ -1272,6 +1640,7 @@ var ServerClient = class {
1272
1640
  domain
1273
1641
  });
1274
1642
  await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
1643
+ await this.#clearAnonymousSessionAfterLogin(storeOptions);
1275
1644
  await this.#transactionStore.delete(this.#transactionStoreIdentifier, storeOptions);
1276
1645
  return {
1277
1646
  authorizationDetails: tokenEndpointResponse.authorizationDetails
@@ -1419,7 +1788,7 @@ var ServerClient = class {
1419
1788
  }
1420
1789
  }
1421
1790
  if (!stateData?.refreshToken) {
1422
- throw new import_auth0_auth_js2.TokenByRefreshTokenError(
1791
+ throw new import_auth0_auth_js3.TokenByRefreshTokenError(
1423
1792
  "The access token has expired and a refresh token was not provided. The user needs to re-authenticate."
1424
1793
  );
1425
1794
  }
@@ -1458,7 +1827,7 @@ var ServerClient = class {
1458
1827
  };
1459
1828
  if (resolvedOptions?.fullResponse) {
1460
1829
  if (!response) {
1461
- throw new import_auth0_auth_js2.MissingCapturedResponseError();
1830
+ throw new import_auth0_auth_js3.MissingCapturedResponseError();
1462
1831
  }
1463
1832
  return { data: returnTokenSet, response };
1464
1833
  }
@@ -1488,7 +1857,7 @@ var ServerClient = class {
1488
1857
  }
1489
1858
  }
1490
1859
  if (!stateData?.refreshToken) {
1491
- throw new import_auth0_auth_js2.TokenForConnectionError(
1860
+ throw new import_auth0_auth_js3.TokenForConnectionError(
1492
1861
  "A refresh token was not found but is required to be able to retrieve an access token for a connection."
1493
1862
  );
1494
1863
  }
@@ -1529,7 +1898,7 @@ var ServerClient = class {
1529
1898
  };
1530
1899
  if (options.fullResponse) {
1531
1900
  if (!response) {
1532
- throw new import_auth0_auth_js2.MissingCapturedResponseError();
1901
+ throw new import_auth0_auth_js3.MissingCapturedResponseError();
1533
1902
  }
1534
1903
  return { data: returnConnectionTokenSet, response };
1535
1904
  }
@@ -1579,6 +1948,29 @@ var ServerClient = class {
1579
1948
  }
1580
1949
  /**
1581
1950
  * Logs the user out and returns a URL to redirect the user-agent to after they log out.
1951
+ *
1952
+ * Clears the anonymous session as well, whenever an `anonymousStore` is configured. Logging
1953
+ * out means the visitor is done, so leaving a 30-day anonymous credential behind in a
1954
+ * cookie would be surprising, and `anonymous.getAccessToken()` would keep working right
1955
+ * after the user logged out. This happens even when there is no user session to clear: a
1956
+ * visitor who only ever had an anonymous session can log out. Unlike the automatic clearing
1957
+ * at login, it is not affected by `clearAnonymousSessionOnLogin`, which exists so an
1958
+ * application can finish its post-login work.
1959
+ *
1960
+ * In resolver (multi-tenant) mode the one exception is a stored user session belonging to a
1961
+ * different Auth0 domain than the request resolves to. Nothing local is cleared in that
1962
+ * case, anonymous session included, exactly as today: that state belongs to another tenant.
1963
+ *
1964
+ * The anonymous session is only ever cleared locally. The SDK does not call
1965
+ * `POST /anonymous/logout`: that endpoint exists to clear the `auth0_anon` cookie in a
1966
+ * browser, and it revokes nothing server-side. Your server never holds that cookie, so
1967
+ * calling it would achieve nothing. If the visitor's browser created an anonymous session
1968
+ * of its own (through `@auth0/auth0-spa-js`, for example), that cookie is not covered by
1969
+ * this SDK and has to be cleared from the browser.
1970
+ *
1971
+ * Anonymous access tokens already handed out stay valid until they expire; there is no
1972
+ * anonymous session to revoke them against.
1973
+ *
1582
1974
  * @param options Options used to configure the logout process.
1583
1975
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
1584
1976
  * @param requestOptions Optional per-request options (signal, headers, customFetch). Applied to the token revocation ONLY. Building the logout URL is local string work and issues no request, so nothing here can affect it.
@@ -1599,12 +1991,14 @@ var ServerClient = class {
1599
1991
  } catch {
1600
1992
  }
1601
1993
  await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
1994
+ await this.#discardAnonymousSession(storeOptions);
1602
1995
  return this.authClient.buildLogoutUrl(options);
1603
1996
  }
1604
1997
  const resolvedDomain = await this.#resolveDomain(storeOptions);
1605
1998
  const authClient = this.#getAuthClient(resolvedDomain);
1606
1999
  const stateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
1607
2000
  if (!stateData) {
2001
+ await this.#discardAnonymousSession(storeOptions);
1608
2002
  return authClient.buildLogoutUrl(options);
1609
2003
  }
1610
2004
  const sessionDomain = this.#getSessionDomain(stateData);
@@ -1615,6 +2009,7 @@ var ServerClient = class {
1615
2009
  } catch {
1616
2010
  }
1617
2011
  await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
2012
+ await this.#discardAnonymousSession(storeOptions);
1618
2013
  }
1619
2014
  return authClient.buildLogoutUrl(options);
1620
2015
  }
@@ -1646,12 +2041,13 @@ var ServerClient = class {
1646
2041
  { domain }
1647
2042
  );
1648
2043
  await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
2044
+ await this.#clearAnonymousSessionAfterLogin(storeOptions);
1649
2045
  const result = {
1650
2046
  authorizationDetails: tokenEndpointResponse.authorizationDetails
1651
2047
  };
1652
2048
  if (options.fullResponse) {
1653
2049
  if (!response) {
1654
- throw new import_auth0_auth_js2.MissingCapturedResponseError();
2050
+ throw new import_auth0_auth_js3.MissingCapturedResponseError();
1655
2051
  }
1656
2052
  return { data: result, response };
1657
2053
  }
@@ -1715,7 +2111,7 @@ var ServerClient = class {
1715
2111
  throw new MissingRequiredArgumentError("subjectTokenType");
1716
2112
  }
1717
2113
  if (options.organization !== void 0 && !options.organization.trim()) {
1718
- throw new import_auth0_auth_js2.OrganizationValidationError("organization must not be blank");
2114
+ throw new import_auth0_auth_js3.OrganizationValidationError("organization must not be blank");
1719
2115
  }
1720
2116
  const domain = await this.#resolveDomain(storeOptions);
1721
2117
  const actor = await this.#resolveSessionTransferActor(options.actor, domain, storeOptions);
@@ -1789,7 +2185,7 @@ var ServerClient = class {
1789
2185
  url.searchParams.set("session_transfer_token", result.sessionTransferToken);
1790
2186
  if (options?.organization !== void 0) {
1791
2187
  if (!options.organization.trim()) {
1792
- throw new import_auth0_auth_js2.OrganizationValidationError("organization must not be blank");
2188
+ throw new import_auth0_auth_js3.OrganizationValidationError("organization must not be blank");
1793
2189
  }
1794
2190
  url.searchParams.set("organization", options.organization);
1795
2191
  }
@@ -1893,7 +2289,7 @@ var ServerClient = class {
1893
2289
  };
1894
2290
 
1895
2291
  // src/encryption/index.ts
1896
- var import_jose2 = require("jose");
2292
+ var import_jose3 = require("jose");
1897
2293
  var ENC = "A256CBC-HS512";
1898
2294
  var ALG = "dir";
1899
2295
  var DIGEST = "SHA-256";
@@ -1901,7 +2297,7 @@ var BIT_LENGTH = 512;
1901
2297
  var HKDF_INFO = "derived cookie encryption secret";
1902
2298
  var encoder;
1903
2299
  function isDecryptionError(e) {
1904
- return e instanceof import_jose2.errors.JWEDecryptionFailed || e instanceof import_jose2.errors.JWEInvalid;
2300
+ return e instanceof import_jose3.errors.JWEDecryptionFailed || e instanceof import_jose3.errors.JWEInvalid;
1905
2301
  }
1906
2302
  async function deriveEncryptionSecret(secret, salt, kid) {
1907
2303
  encoder ||= new TextEncoder();
@@ -1922,7 +2318,7 @@ async function deriveEncryptionSecret(secret, salt, kid) {
1922
2318
  async function _encrypt(payload, secret, salt, expiration) {
1923
2319
  const kid = crypto.randomUUID();
1924
2320
  const encryptionSecret = await deriveEncryptionSecret(secret, salt, kid);
1925
- return await new import_jose2.EncryptJWT(payload).setProtectedHeader({ enc: ENC, alg: ALG, kid }).setExpirationTime(expiration).encrypt(encryptionSecret);
2321
+ return await new import_jose3.EncryptJWT(payload).setProtectedHeader({ enc: ENC, alg: ALG, kid }).setExpirationTime(expiration).encrypt(encryptionSecret);
1926
2322
  }
1927
2323
  async function encrypt(payload, secret, salt, expiration) {
1928
2324
  if (typeof secret === "string") {
@@ -1936,7 +2332,7 @@ async function encrypt(payload, secret, salt, expiration) {
1936
2332
  }
1937
2333
  }
1938
2334
  async function _decrypt(value, secret, salt) {
1939
- const res = await (0, import_jose2.jwtDecrypt)(
2335
+ const res = await (0, import_jose3.jwtDecrypt)(
1940
2336
  value,
1941
2337
  async (protectedHeader) => {
1942
2338
  if (!protectedHeader.kid) {
@@ -2014,7 +2410,7 @@ var AbstractTransactionStore = class extends AbstractStore {
2014
2410
  };
2015
2411
 
2016
2412
  // src/index.ts
2017
- var import_auth0_auth_js6 = require("@auth0/auth0-auth-js");
2413
+ var import_auth0_auth_js8 = require("@auth0/auth0-auth-js");
2018
2414
 
2019
2415
  // src/store/cookie-transaction-store.ts
2020
2416
  var CookieTransactionStore = class extends AbstractTransactionStore {
@@ -2210,21 +2606,110 @@ var StatelessStateStore = class extends AbstractSessionStore {
2210
2606
  }
2211
2607
  };
2212
2608
 
2609
+ // src/store/abstract-anonymous-store.ts
2610
+ var AbstractAnonymousStore = class extends AbstractStore {
2611
+ constructor(options) {
2612
+ super(options);
2613
+ }
2614
+ };
2615
+
2616
+ // src/store/stateless-anonymous-store.ts
2617
+ var DEFAULT_ANONYMOUS_SESSION_LIFETIME = 60 * 60 * 24 * 30;
2618
+ var CHUNK_SIZE = 3072;
2619
+ var StatelessAnonymousStore = class extends AbstractAnonymousStore {
2620
+ #cookieOptions;
2621
+ #cookieHandler;
2622
+ #sessionTokenLifetime;
2623
+ constructor(options, cookieHandler) {
2624
+ super(options);
2625
+ this.#cookieOptions = options.cookie;
2626
+ this.#cookieHandler = cookieHandler;
2627
+ this.#sessionTokenLifetime = options.sessionTokenLifetime ?? DEFAULT_ANONYMOUS_SESSION_LIFETIME;
2628
+ }
2629
+ async set(identifier, anonymousStateData, removeIfExists, options) {
2630
+ const expiration = this.#getExpiration(anonymousStateData);
2631
+ const maxAge = expiration - Math.floor(Date.now() / 1e3);
2632
+ if (maxAge <= 0) {
2633
+ await this.delete(identifier, options);
2634
+ return;
2635
+ }
2636
+ const cookieOpts = this.#getCookieOptions({ maxAge });
2637
+ const encryptedStateData = await this.encrypt(identifier, anonymousStateData, expiration);
2638
+ const chunkCount = Math.ceil(encryptedStateData.length / CHUNK_SIZE);
2639
+ const chunks = [...Array(chunkCount).keys()].map((i) => ({
2640
+ value: encryptedStateData.substring(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE),
2641
+ name: `${identifier}.${i}`
2642
+ }));
2643
+ chunks.forEach((chunk) => {
2644
+ this.#cookieHandler.setCookie(chunk.name, chunk.value, cookieOpts, options);
2645
+ });
2646
+ const existingCookieKeys = this.#getCookieKeys(identifier, options);
2647
+ existingCookieKeys.filter((key) => !chunks.some((chunk) => chunk.name === key)).forEach((key) => {
2648
+ this.#cookieHandler.deleteCookie(key, options, this.#getCookieOptions());
2649
+ });
2650
+ }
2651
+ async get(identifier, options) {
2652
+ const cookieKeys = this.#getCookieKeys(identifier, options);
2653
+ const encryptedStateData = cookieKeys.map((key) => ({
2654
+ index: parseInt(key.split(".")[1], 10),
2655
+ value: this.#cookieHandler.getCookie(key, options)
2656
+ })).sort((a, b) => a.index - b.index).map((item) => item.value).join("");
2657
+ if (encryptedStateData) {
2658
+ return await this.decrypt(identifier, encryptedStateData);
2659
+ }
2660
+ }
2661
+ async delete(identifier, options) {
2662
+ const cookieKeys = this.#getCookieKeys(identifier, options);
2663
+ for (const key of cookieKeys) {
2664
+ this.#cookieHandler.deleteCookie(key, options, this.#getCookieOptions());
2665
+ }
2666
+ }
2667
+ /**
2668
+ * Absolute expiry of the anonymous session, in Unix seconds.
2669
+ *
2670
+ * Prefers the value Auth0 reports. `sessionTokenExpiresAt` is not populated yet, because
2671
+ * `auth0-auth-js` does not surface `session_expires_in` from the token response; until it
2672
+ * does, this falls back to the configured lifetime measured from creation.
2673
+ */
2674
+ #getExpiration(anonymousStateData) {
2675
+ return anonymousStateData.sessionTokenExpiresAt ?? anonymousStateData.createdAt + this.#sessionTokenLifetime;
2676
+ }
2677
+ #getCookieKeys(identifier, options) {
2678
+ return Object.keys(this.#cookieHandler.getCookies(options)).filter((key) => key.startsWith(identifier));
2679
+ }
2680
+ #getCookieOptions(partial) {
2681
+ return {
2682
+ httpOnly: true,
2683
+ sameSite: this.#cookieOptions?.sameSite ?? "lax",
2684
+ path: this.#cookieOptions?.path ?? "/",
2685
+ secure: this.#cookieOptions?.secure ?? true,
2686
+ ...partial
2687
+ };
2688
+ }
2689
+ };
2690
+
2213
2691
  // src/mfa/index.ts
2214
- var import_auth0_auth_js3 = require("@auth0/auth0-auth-js");
2692
+ var import_auth0_auth_js4 = require("@auth0/auth0-auth-js");
2215
2693
 
2216
2694
  // src/passkey/index.ts
2217
- var import_auth0_auth_js4 = require("@auth0/auth0-auth-js");
2695
+ var import_auth0_auth_js5 = require("@auth0/auth0-auth-js");
2218
2696
 
2219
2697
  // src/database/index.ts
2220
- var import_auth0_auth_js5 = require("@auth0/auth0-auth-js");
2698
+ var import_auth0_auth_js6 = require("@auth0/auth0-auth-js");
2699
+
2700
+ // src/anonymous/index.ts
2701
+ var import_auth0_auth_js7 = require("@auth0/auth0-auth-js");
2221
2702
  // Annotate the CommonJS export names for ESM import in node:
2222
2703
  0 && (module.exports = {
2704
+ AbstractAnonymousStore,
2223
2705
  AbstractStateStore,
2224
2706
  AbstractTransactionStore,
2707
+ AnonymousSessionError,
2708
+ AnonymousSessionExpiredError,
2225
2709
  BackchannelLogoutError,
2226
2710
  ChangePasswordError,
2227
2711
  CookieTransactionStore,
2712
+ DEFAULT_ANONYMOUS_SESSION_LIFETIME,
2228
2713
  EnterpriseConnectNotSupportedError,
2229
2714
  InvalidConfigurationError,
2230
2715
  IssuerValidationError,
@@ -2232,6 +2717,7 @@ var import_auth0_auth_js5 = require("@auth0/auth0-auth-js");
2232
2717
  MfaEnrollmentError,
2233
2718
  MfaListAuthenticatorsError,
2234
2719
  MfaVerifyError,
2720
+ MissingAnonymousSessionError,
2235
2721
  MissingClientAuthError,
2236
2722
  MissingRequiredArgumentError,
2237
2723
  MissingSessionError,
@@ -2242,6 +2728,7 @@ var import_auth0_auth_js5 = require("@auth0/auth0-auth-js");
2242
2728
  PasskeyRegisterError,
2243
2729
  PasswordlessStartError,
2244
2730
  PasswordlessVerifyError,
2731
+ ServerAnonymousClient,
2245
2732
  ServerClient,
2246
2733
  ServerDatabaseClient,
2247
2734
  ServerMfaClient,
@@ -2250,6 +2737,7 @@ var import_auth0_auth_js5 = require("@auth0/auth0-auth-js");
2250
2737
  SignUpError,
2251
2738
  StartLinkUserError,
2252
2739
  StatefulStateStore,
2740
+ StatelessAnonymousStore,
2253
2741
  StatelessStateStore,
2254
2742
  TokenExchangeError,
2255
2743
  TokenExchangeErrorCode,