@auth0/auth0-server-js 1.7.0 → 1.9.0

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.d.cts CHANGED
@@ -26,6 +26,12 @@ interface ServerClientOptions<TStoreOptions = unknown> {
26
26
  clientAssertionSigningKey?: string | CryptoKey;
27
27
  clientAssertionSigningAlg?: string;
28
28
  authorizationParams?: AuthorizationParameters;
29
+ /**
30
+ * Default organization for all interactive login flows from this client.
31
+ * Can be an organization ID (e.g. `org_abc123`) or an organization name (e.g. `acme-corp`).
32
+ * A per-login value in {@link StartInteractiveLoginOptions} overrides this.
33
+ */
34
+ organization?: string;
29
35
  discoveryCache?: DiscoveryCacheOptions;
30
36
  transactionIdentifier?: string;
31
37
  stateIdentifier?: string;
@@ -57,12 +63,19 @@ interface UserClaims {
57
63
  email?: string;
58
64
  email_verified?: boolean;
59
65
  org_id?: string;
66
+ org_name?: string;
60
67
  [key: string]: unknown;
61
68
  }
62
69
  interface AuthorizationParameters {
63
70
  scope?: string;
64
71
  audience?: string;
65
72
  redirect_uri?: string;
73
+ /**
74
+ * The organization to log the user into. Prefer the first-class `organization`
75
+ * option on {@link StartInteractiveLoginOptions} / {@link ServerClientOptions};
76
+ * this is supported for backwards compatibility.
77
+ */
78
+ organization?: string;
66
79
  [key: string]: unknown;
67
80
  }
68
81
  interface TokenSet {
@@ -92,6 +105,15 @@ interface SessionData {
92
105
  tokenSets: TokenSet[];
93
106
  connectionTokenSets?: ConnectionTokenSet[];
94
107
  domain?: string;
108
+ /**
109
+ * IPSIE SL1 `session_expiry` ceiling for this session, as an absolute Unix timestamp in
110
+ * seconds. Present only when the user logged in through an enterprise connection configured
111
+ * with `id_token_session_expiry_supported: true`. When set, the SDK treats the session as
112
+ * expired once this time is reached (minus a small leeway) and forces re-authentication.
113
+ * Absent for database/social logins, connections without the option, and sessions created
114
+ * before this feature — those behave unchanged.
115
+ */
116
+ sessionExpiresAt?: number;
95
117
  [key: string]: unknown;
96
118
  }
97
119
  interface TransactionData {
@@ -103,6 +125,11 @@ interface TransactionData {
103
125
  */
104
126
  codeVerifier?: string;
105
127
  domain?: string;
128
+ /**
129
+ * The organization requested at login, carried across the redirect so the
130
+ * returned ID token's organization claim can be validated at callback.
131
+ */
132
+ organization?: string;
106
133
  [key: string]: unknown;
107
134
  }
108
135
  interface AbstractDataStore<TData, TStoreOptions = unknown> {
@@ -137,6 +164,18 @@ interface StartInteractiveLoginOptions<TAppState = unknown> {
137
164
  pushedAuthorizationRequests?: boolean;
138
165
  appState?: TAppState;
139
166
  authorizationParams?: AuthorizationParameters;
167
+ /**
168
+ * The organization to log the user into. Overrides the client-level
169
+ * `organization` default. Can be an organization ID (`org_abc123`) or name
170
+ * (`acme-corp`). Also passable via `authorizationParams.organization`.
171
+ */
172
+ organization?: string;
173
+ /**
174
+ * The organization invitation ticket, when handling an invitation-acceptance flow.
175
+ * Requires `organization` to be set (per-login, client-level default, or via
176
+ * `authorizationParams`); providing `invitation` without an organization throws.
177
+ */
178
+ invitation?: string;
140
179
  }
141
180
  interface LoginBackchannelOptions {
142
181
  bindingMessage: string;
@@ -603,9 +642,16 @@ declare class ServerClient<TStoreOptions = unknown> {
603
642
  constructor(options: ServerClientOptions<TStoreOptions>);
604
643
  /**
605
644
  * Starts the interactive login process, and returns a URL to redirect the user-agent to to request authorization at Auth0.
645
+ *
646
+ * When `organization` is provided (per-login option, client-level default, or via
647
+ * `authorizationParams.organization`), it is forwarded to `/authorize` and remembered so the
648
+ * returned ID token's organization claim can be validated in `completeInteractiveLogin`.
649
+ *
606
650
  * @param options Optional options used to configure the interactive login process.
607
651
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
608
652
  *
653
+ * @throws {OrganizationValidationError} If the resolved `organization` is blank.
654
+ * @throws {InvalidConfigurationError} If `invitation` is provided without an `organization`.
609
655
  * @throws {BuildAuthorizationUrlError} If there was an issue when building the Authorization URL.
610
656
  *
611
657
  * @returns A promise resolving to a URL object, representing the URL to redirect the user-agent to to request authorization at Auth0.
@@ -619,6 +665,8 @@ declare class ServerClient<TStoreOptions = unknown> {
619
665
  *
620
666
  * @throws {MissingTransactionError} When no transaction was found.
621
667
  * @throws {TokenByCodeError} If there was an issue requesting the access token.
668
+ * @throws {OrganizationValidationError} When an organization was requested at login and the returned ID token's organization claim is missing or does not match; nothing is persisted.
669
+ * @throws {SessionExpiredError} When the ID token's `session_expiry` is already in the past at login (the session is born expired); nothing is persisted.
622
670
  *
623
671
  * @returns A promise resolving to an object, containing the original appState (if present) and the authorizationDetails (when RAR was used).
624
672
  */
@@ -633,6 +681,7 @@ declare class ServerClient<TStoreOptions = unknown> {
633
681
  *
634
682
  * @throws {MissingSessionError} If there is no active session.
635
683
  * @throws {BuildLinkUserUrlError} If there was an issue when building the Authorization URL.
684
+ * @throws {SessionExpiredError} When the session's `session_expiry` ceiling has been reached; the session is cleared and re-authentication is required.
636
685
  *
637
686
  * @returns A promise resolving to a URL object, representing the URL to redirect the user-agent to to request authorization at Auth0.
638
687
  */
@@ -658,6 +707,7 @@ declare class ServerClient<TStoreOptions = unknown> {
658
707
  *
659
708
  * @throws {MissingSessionError} If there is no active session.
660
709
  * @throws {BuildUnlinkUserUrlError} If there was an issue when building the User Unlinking URL.
710
+ * @throws {SessionExpiredError} When the session's `session_expiry` ceiling has been reached; the session is cleared and re-authentication is required.
661
711
  *
662
712
  * @returns A promise resolving to a URL object, representing the URL to redirect the user-agent to to request authorization at Auth0.
663
713
  */
@@ -685,6 +735,7 @@ declare class ServerClient<TStoreOptions = unknown> {
685
735
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
686
736
  *
687
737
  * @throws {BackchannelAuthenticationError} If there was an issue when doing backchannel authentication.
738
+ * @throws {SessionExpiredError} When the ID token's `session_expiry` is already in the past at login (the session is born expired); nothing is persisted.
688
739
  *
689
740
  * @returns A promise resolving to an object, containing the authorizationDetails (when RAR was used).
690
741
  */
@@ -954,8 +1005,9 @@ declare abstract class AbstractSessionStore<TStoreOptions> extends AbstractState
954
1005
  constructor(options: SessionConfiguration & EncryptedStoreOptions);
955
1006
  /**
956
1007
  * calculateMaxAge calculates the max age of the session based on createdAt and the rolling and absolute durations.
1008
+ * When sessionExpiresAt is provided, caps the maxAge to not exceed the time until that ceiling.
957
1009
  */
958
- protected calculateMaxAge(createdAt: number): number;
1010
+ protected calculateMaxAge(createdAt: number, sessionExpiresAt?: number): number;
959
1011
  }
960
1012
 
961
1013
  interface StatefulStateStoreOptions<TStoreOptions> extends EncryptedStoreOptions {
@@ -1030,5 +1082,13 @@ declare class IssuerValidationError extends Error {
1030
1082
  code: string;
1031
1083
  constructor(message: string);
1032
1084
  }
1085
+ /**
1086
+ * Error thrown when the session has passed its upstream IdP-asserted
1087
+ * `session_expiry` ceiling (IPSIE SL1). The user must re-authenticate.
1088
+ */
1089
+ declare class SessionExpiredError extends Error {
1090
+ code: string;
1091
+ constructor(message?: string);
1092
+ }
1033
1093
 
1034
- export { type AbstractDataStore, AbstractStateStore, AbstractTransactionStore, type AccessTokenForConnectionOptions, type AuthorizationParameters, BackchannelLogoutError, type CompletePasswordlessEmailOptions, type CompletePasswordlessOptions, type CompletePasswordlessResult, type CompletePasswordlessSmsOptions, type ConnectionTokenSet, type CookieHandler, type CookieSerializeOptions, CookieTransactionStore, type CustomTokenExchangeOptions, type DomainResolver, type EncryptedStoreOptions, type GetAccessTokenOptions, type InternalStateData, InvalidConfigurationError, IssuerValidationError, type LoginBackchannelOptions, type LoginBackchannelResult, type LoginWithCustomTokenExchangeOptions, type LoginWithCustomTokenExchangeResult, type LogoutOptions, type LogoutTokenClaims, type MfaVerifyResponse, MissingRequiredArgumentError, MissingSessionError, MissingTransactionError, type PasskeyGetTokenResult, ServerClient, type ServerClientOptions, ServerMfaClient, ServerPasskeyClient, type SessionConfiguration, type SessionCookieOptions, type SessionData, type SessionStore, type StartInteractiveLoginOptions, StartLinkUserError, type StartLinkUserOptions, type StartPasswordlessEmailCodeOptions, type StartPasswordlessEmailLinkOptions, type StartPasswordlessOptions, type StartPasswordlessSmsOptions, type StartUnlinkUserOptions, type StateData, type StateStore, StatefulStateStore, type StatefulStateStoreOptions, StatelessStateStore, type TokenSet, type TransactionData, type TransactionStore, type UserClaims };
1094
+ export { type AbstractDataStore, AbstractStateStore, AbstractTransactionStore, type AccessTokenForConnectionOptions, type AuthorizationParameters, BackchannelLogoutError, type CompletePasswordlessEmailOptions, type CompletePasswordlessOptions, type CompletePasswordlessResult, type CompletePasswordlessSmsOptions, type ConnectionTokenSet, type CookieHandler, type CookieSerializeOptions, CookieTransactionStore, type CustomTokenExchangeOptions, type DomainResolver, type EncryptedStoreOptions, type GetAccessTokenOptions, type InternalStateData, InvalidConfigurationError, IssuerValidationError, type LoginBackchannelOptions, type LoginBackchannelResult, type LoginWithCustomTokenExchangeOptions, type LoginWithCustomTokenExchangeResult, type LogoutOptions, type LogoutTokenClaims, type MfaVerifyResponse, MissingRequiredArgumentError, MissingSessionError, MissingTransactionError, type PasskeyGetTokenResult, ServerClient, type ServerClientOptions, ServerMfaClient, ServerPasskeyClient, type SessionConfiguration, type SessionCookieOptions, type SessionData, SessionExpiredError, type SessionStore, type StartInteractiveLoginOptions, StartLinkUserError, type StartLinkUserOptions, type StartPasswordlessEmailCodeOptions, type StartPasswordlessEmailLinkOptions, type StartPasswordlessOptions, type StartPasswordlessSmsOptions, type StartUnlinkUserOptions, type StateData, type StateStore, StatefulStateStore, type StatefulStateStoreOptions, StatelessStateStore, type TokenSet, type TransactionData, type TransactionStore, type UserClaims };
package/dist/index.d.ts CHANGED
@@ -26,6 +26,12 @@ interface ServerClientOptions<TStoreOptions = unknown> {
26
26
  clientAssertionSigningKey?: string | CryptoKey;
27
27
  clientAssertionSigningAlg?: string;
28
28
  authorizationParams?: AuthorizationParameters;
29
+ /**
30
+ * Default organization for all interactive login flows from this client.
31
+ * Can be an organization ID (e.g. `org_abc123`) or an organization name (e.g. `acme-corp`).
32
+ * A per-login value in {@link StartInteractiveLoginOptions} overrides this.
33
+ */
34
+ organization?: string;
29
35
  discoveryCache?: DiscoveryCacheOptions;
30
36
  transactionIdentifier?: string;
31
37
  stateIdentifier?: string;
@@ -57,12 +63,19 @@ interface UserClaims {
57
63
  email?: string;
58
64
  email_verified?: boolean;
59
65
  org_id?: string;
66
+ org_name?: string;
60
67
  [key: string]: unknown;
61
68
  }
62
69
  interface AuthorizationParameters {
63
70
  scope?: string;
64
71
  audience?: string;
65
72
  redirect_uri?: string;
73
+ /**
74
+ * The organization to log the user into. Prefer the first-class `organization`
75
+ * option on {@link StartInteractiveLoginOptions} / {@link ServerClientOptions};
76
+ * this is supported for backwards compatibility.
77
+ */
78
+ organization?: string;
66
79
  [key: string]: unknown;
67
80
  }
68
81
  interface TokenSet {
@@ -92,6 +105,15 @@ interface SessionData {
92
105
  tokenSets: TokenSet[];
93
106
  connectionTokenSets?: ConnectionTokenSet[];
94
107
  domain?: string;
108
+ /**
109
+ * IPSIE SL1 `session_expiry` ceiling for this session, as an absolute Unix timestamp in
110
+ * seconds. Present only when the user logged in through an enterprise connection configured
111
+ * with `id_token_session_expiry_supported: true`. When set, the SDK treats the session as
112
+ * expired once this time is reached (minus a small leeway) and forces re-authentication.
113
+ * Absent for database/social logins, connections without the option, and sessions created
114
+ * before this feature — those behave unchanged.
115
+ */
116
+ sessionExpiresAt?: number;
95
117
  [key: string]: unknown;
96
118
  }
97
119
  interface TransactionData {
@@ -103,6 +125,11 @@ interface TransactionData {
103
125
  */
104
126
  codeVerifier?: string;
105
127
  domain?: string;
128
+ /**
129
+ * The organization requested at login, carried across the redirect so the
130
+ * returned ID token's organization claim can be validated at callback.
131
+ */
132
+ organization?: string;
106
133
  [key: string]: unknown;
107
134
  }
108
135
  interface AbstractDataStore<TData, TStoreOptions = unknown> {
@@ -137,6 +164,18 @@ interface StartInteractiveLoginOptions<TAppState = unknown> {
137
164
  pushedAuthorizationRequests?: boolean;
138
165
  appState?: TAppState;
139
166
  authorizationParams?: AuthorizationParameters;
167
+ /**
168
+ * The organization to log the user into. Overrides the client-level
169
+ * `organization` default. Can be an organization ID (`org_abc123`) or name
170
+ * (`acme-corp`). Also passable via `authorizationParams.organization`.
171
+ */
172
+ organization?: string;
173
+ /**
174
+ * The organization invitation ticket, when handling an invitation-acceptance flow.
175
+ * Requires `organization` to be set (per-login, client-level default, or via
176
+ * `authorizationParams`); providing `invitation` without an organization throws.
177
+ */
178
+ invitation?: string;
140
179
  }
141
180
  interface LoginBackchannelOptions {
142
181
  bindingMessage: string;
@@ -603,9 +642,16 @@ declare class ServerClient<TStoreOptions = unknown> {
603
642
  constructor(options: ServerClientOptions<TStoreOptions>);
604
643
  /**
605
644
  * Starts the interactive login process, and returns a URL to redirect the user-agent to to request authorization at Auth0.
645
+ *
646
+ * When `organization` is provided (per-login option, client-level default, or via
647
+ * `authorizationParams.organization`), it is forwarded to `/authorize` and remembered so the
648
+ * returned ID token's organization claim can be validated in `completeInteractiveLogin`.
649
+ *
606
650
  * @param options Optional options used to configure the interactive login process.
607
651
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
608
652
  *
653
+ * @throws {OrganizationValidationError} If the resolved `organization` is blank.
654
+ * @throws {InvalidConfigurationError} If `invitation` is provided without an `organization`.
609
655
  * @throws {BuildAuthorizationUrlError} If there was an issue when building the Authorization URL.
610
656
  *
611
657
  * @returns A promise resolving to a URL object, representing the URL to redirect the user-agent to to request authorization at Auth0.
@@ -619,6 +665,8 @@ declare class ServerClient<TStoreOptions = unknown> {
619
665
  *
620
666
  * @throws {MissingTransactionError} When no transaction was found.
621
667
  * @throws {TokenByCodeError} If there was an issue requesting the access token.
668
+ * @throws {OrganizationValidationError} When an organization was requested at login and the returned ID token's organization claim is missing or does not match; nothing is persisted.
669
+ * @throws {SessionExpiredError} When the ID token's `session_expiry` is already in the past at login (the session is born expired); nothing is persisted.
622
670
  *
623
671
  * @returns A promise resolving to an object, containing the original appState (if present) and the authorizationDetails (when RAR was used).
624
672
  */
@@ -633,6 +681,7 @@ declare class ServerClient<TStoreOptions = unknown> {
633
681
  *
634
682
  * @throws {MissingSessionError} If there is no active session.
635
683
  * @throws {BuildLinkUserUrlError} If there was an issue when building the Authorization URL.
684
+ * @throws {SessionExpiredError} When the session's `session_expiry` ceiling has been reached; the session is cleared and re-authentication is required.
636
685
  *
637
686
  * @returns A promise resolving to a URL object, representing the URL to redirect the user-agent to to request authorization at Auth0.
638
687
  */
@@ -658,6 +707,7 @@ declare class ServerClient<TStoreOptions = unknown> {
658
707
  *
659
708
  * @throws {MissingSessionError} If there is no active session.
660
709
  * @throws {BuildUnlinkUserUrlError} If there was an issue when building the User Unlinking URL.
710
+ * @throws {SessionExpiredError} When the session's `session_expiry` ceiling has been reached; the session is cleared and re-authentication is required.
661
711
  *
662
712
  * @returns A promise resolving to a URL object, representing the URL to redirect the user-agent to to request authorization at Auth0.
663
713
  */
@@ -685,6 +735,7 @@ declare class ServerClient<TStoreOptions = unknown> {
685
735
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
686
736
  *
687
737
  * @throws {BackchannelAuthenticationError} If there was an issue when doing backchannel authentication.
738
+ * @throws {SessionExpiredError} When the ID token's `session_expiry` is already in the past at login (the session is born expired); nothing is persisted.
688
739
  *
689
740
  * @returns A promise resolving to an object, containing the authorizationDetails (when RAR was used).
690
741
  */
@@ -954,8 +1005,9 @@ declare abstract class AbstractSessionStore<TStoreOptions> extends AbstractState
954
1005
  constructor(options: SessionConfiguration & EncryptedStoreOptions);
955
1006
  /**
956
1007
  * calculateMaxAge calculates the max age of the session based on createdAt and the rolling and absolute durations.
1008
+ * When sessionExpiresAt is provided, caps the maxAge to not exceed the time until that ceiling.
957
1009
  */
958
- protected calculateMaxAge(createdAt: number): number;
1010
+ protected calculateMaxAge(createdAt: number, sessionExpiresAt?: number): number;
959
1011
  }
960
1012
 
961
1013
  interface StatefulStateStoreOptions<TStoreOptions> extends EncryptedStoreOptions {
@@ -1030,5 +1082,13 @@ declare class IssuerValidationError extends Error {
1030
1082
  code: string;
1031
1083
  constructor(message: string);
1032
1084
  }
1085
+ /**
1086
+ * Error thrown when the session has passed its upstream IdP-asserted
1087
+ * `session_expiry` ceiling (IPSIE SL1). The user must re-authenticate.
1088
+ */
1089
+ declare class SessionExpiredError extends Error {
1090
+ code: string;
1091
+ constructor(message?: string);
1092
+ }
1033
1093
 
1034
- export { type AbstractDataStore, AbstractStateStore, AbstractTransactionStore, type AccessTokenForConnectionOptions, type AuthorizationParameters, BackchannelLogoutError, type CompletePasswordlessEmailOptions, type CompletePasswordlessOptions, type CompletePasswordlessResult, type CompletePasswordlessSmsOptions, type ConnectionTokenSet, type CookieHandler, type CookieSerializeOptions, CookieTransactionStore, type CustomTokenExchangeOptions, type DomainResolver, type EncryptedStoreOptions, type GetAccessTokenOptions, type InternalStateData, InvalidConfigurationError, IssuerValidationError, type LoginBackchannelOptions, type LoginBackchannelResult, type LoginWithCustomTokenExchangeOptions, type LoginWithCustomTokenExchangeResult, type LogoutOptions, type LogoutTokenClaims, type MfaVerifyResponse, MissingRequiredArgumentError, MissingSessionError, MissingTransactionError, type PasskeyGetTokenResult, ServerClient, type ServerClientOptions, ServerMfaClient, ServerPasskeyClient, type SessionConfiguration, type SessionCookieOptions, type SessionData, type SessionStore, type StartInteractiveLoginOptions, StartLinkUserError, type StartLinkUserOptions, type StartPasswordlessEmailCodeOptions, type StartPasswordlessEmailLinkOptions, type StartPasswordlessOptions, type StartPasswordlessSmsOptions, type StartUnlinkUserOptions, type StateData, type StateStore, StatefulStateStore, type StatefulStateStoreOptions, StatelessStateStore, type TokenSet, type TransactionData, type TransactionStore, type UserClaims };
1094
+ export { type AbstractDataStore, AbstractStateStore, AbstractTransactionStore, type AccessTokenForConnectionOptions, type AuthorizationParameters, BackchannelLogoutError, type CompletePasswordlessEmailOptions, type CompletePasswordlessOptions, type CompletePasswordlessResult, type CompletePasswordlessSmsOptions, type ConnectionTokenSet, type CookieHandler, type CookieSerializeOptions, CookieTransactionStore, type CustomTokenExchangeOptions, type DomainResolver, type EncryptedStoreOptions, type GetAccessTokenOptions, type InternalStateData, InvalidConfigurationError, IssuerValidationError, type LoginBackchannelOptions, type LoginBackchannelResult, type LoginWithCustomTokenExchangeOptions, type LoginWithCustomTokenExchangeResult, type LogoutOptions, type LogoutTokenClaims, type MfaVerifyResponse, MissingRequiredArgumentError, MissingSessionError, MissingTransactionError, type PasskeyGetTokenResult, ServerClient, type ServerClientOptions, ServerMfaClient, ServerPasskeyClient, type SessionConfiguration, type SessionCookieOptions, type SessionData, SessionExpiredError, type SessionStore, type StartInteractiveLoginOptions, StartLinkUserError, type StartLinkUserOptions, type StartPasswordlessEmailCodeOptions, type StartPasswordlessEmailLinkOptions, type StartPasswordlessOptions, type StartPasswordlessSmsOptions, type StartUnlinkUserOptions, type StateData, type StateStore, StatefulStateStore, type StatefulStateStoreOptions, StatelessStateStore, type TokenSet, type TransactionData, type TransactionStore, type UserClaims };
package/dist/index.js CHANGED
@@ -48,14 +48,55 @@ var IssuerValidationError = class extends Error {
48
48
  this.name = "IssuerValidationError";
49
49
  }
50
50
  };
51
+ var SessionExpiredError = class extends Error {
52
+ code = "session_expired";
53
+ constructor(message) {
54
+ super(
55
+ message ?? "The session has expired because the upstream identity provider session ceiling was reached. The user needs to re-authenticate."
56
+ );
57
+ this.name = "SessionExpiredError";
58
+ }
59
+ };
51
60
 
52
61
  // src/state/utils.ts
62
+ var SESSION_EXPIRY_LEEWAY = 30;
63
+ var MAX_PLAUSIBLE_UNIX_SECONDS = 1e10;
64
+ function isPlausibleUnixSeconds(value) {
65
+ return typeof value === "number" && Number.isInteger(value) && value > 0 && value < MAX_PLAUSIBLE_UNIX_SECONDS;
66
+ }
67
+ function extractSessionExpiry(claims) {
68
+ const value = claims?.session_expiry;
69
+ return isPlausibleUnixSeconds(value) ? value : void 0;
70
+ }
71
+ function isSessionExpiryReached(sessionExpiresAt, nowSeconds) {
72
+ if (sessionExpiresAt === void 0) {
73
+ return false;
74
+ }
75
+ const now = nowSeconds ?? Math.floor(Date.now() / 1e3);
76
+ return now >= sessionExpiresAt - SESSION_EXPIRY_LEEWAY;
77
+ }
53
78
  var createUpdatedTokenSet = (audience, response) => ({
54
79
  audience,
55
80
  accessToken: response.accessToken,
56
81
  scope: response.scope,
57
82
  expiresAt: response.expiresAt
58
83
  });
84
+ function isSessionExpiryInPast(sessionExpiresAt, issuedAt) {
85
+ if (sessionExpiresAt === void 0) {
86
+ return false;
87
+ }
88
+ const reference = isPlausibleUnixSeconds(issuedAt) ? issuedAt : Math.floor(Date.now() / 1e3);
89
+ return sessionExpiresAt <= reference + SESSION_EXPIRY_LEEWAY;
90
+ }
91
+ function applySessionExpiryAtLogin(stateData, claims) {
92
+ const sessionExpiresAt = extractSessionExpiry(claims);
93
+ if (isSessionExpiryInPast(sessionExpiresAt, claims?.iat)) {
94
+ throw new SessionExpiredError(
95
+ "The upstream identity provider session_expiry is at or before the issued-at time; refusing to create an already-expired session."
96
+ );
97
+ }
98
+ return { ...stateData, sessionExpiresAt };
99
+ }
59
100
  function updateStateData(audience, stateData, tokenEndpointResponse, context) {
60
101
  if (stateData && tokenEndpointResponse.claims) {
61
102
  const newSub = tokenEndpointResponse.claims.sub;
@@ -122,6 +163,7 @@ function updateStateDataForConnectionTokenSet(options, stateData, tokenEndpointR
122
163
  import {
123
164
  TokenForConnectionError,
124
165
  AuthClient,
166
+ OrganizationValidationError,
125
167
  PasswordlessStartError,
126
168
  PasswordlessVerifyError,
127
169
  TokenByRefreshTokenError
@@ -163,7 +205,7 @@ function getTelemetryConfig(config) {
163
205
  return {
164
206
  enabled: true,
165
207
  name: config?.name ?? "@auth0/auth0-server-js",
166
- version: config?.version ?? "1.7.0"
208
+ version: config?.version ?? "1.9.0"
167
209
  };
168
210
  }
169
211
 
@@ -225,9 +267,12 @@ var ServerMfaClient = class {
225
267
  this.#options.stateStoreIdentifier,
226
268
  storeOptions
227
269
  );
228
- const updatedStateData = updateStateData(audience, existingStateData, tokenResponse, {
229
- domain: this.#options.domain
230
- });
270
+ const updatedStateData = applySessionExpiryAtLogin(
271
+ updateStateData(audience, existingStateData, tokenResponse, {
272
+ domain: this.#options.domain
273
+ }),
274
+ tokenResponse.claims
275
+ );
231
276
  await this.#options.stateStore.set(
232
277
  this.#options.stateStoreIdentifier,
233
278
  updatedStateData,
@@ -511,9 +556,16 @@ var ServerClient = class {
511
556
  }
512
557
  /**
513
558
  * Starts the interactive login process, and returns a URL to redirect the user-agent to to request authorization at Auth0.
559
+ *
560
+ * When `organization` is provided (per-login option, client-level default, or via
561
+ * `authorizationParams.organization`), it is forwarded to `/authorize` and remembered so the
562
+ * returned ID token's organization claim can be validated in `completeInteractiveLogin`.
563
+ *
514
564
  * @param options Optional options used to configure the interactive login process.
515
565
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
516
566
  *
567
+ * @throws {OrganizationValidationError} If the resolved `organization` is blank.
568
+ * @throws {InvalidConfigurationError} If `invitation` is provided without an `organization`.
517
569
  * @throws {BuildAuthorizationUrlError} If there was an issue when building the Authorization URL.
518
570
  *
519
571
  * @returns A promise resolving to a URL object, representing the URL to redirect the user-agent to to request authorization at Auth0.
@@ -524,6 +576,16 @@ var ServerClient = class {
524
576
  throw new MissingRequiredArgumentError("authorizationParams.redirect_uri");
525
577
  }
526
578
  const scope = ensureOpenIdScope(options?.authorizationParams?.scope ?? this.#options.authorizationParams?.scope);
579
+ const perLoginAuthParamsOrganization = typeof options?.authorizationParams?.organization === "string" ? options.authorizationParams.organization : void 0;
580
+ const clientAuthParamsOrganization = typeof this.#options.authorizationParams?.organization === "string" ? this.#options.authorizationParams.organization : void 0;
581
+ const resolvedOrganization = options?.organization ?? perLoginAuthParamsOrganization ?? this.#options.organization ?? clientAuthParamsOrganization;
582
+ if (resolvedOrganization !== void 0 && !resolvedOrganization.trim()) {
583
+ throw new OrganizationValidationError("organization must not be blank");
584
+ }
585
+ const hasInvitation = !!(options?.invitation || options?.authorizationParams?.invitation);
586
+ if (hasInvitation && !resolvedOrganization) {
587
+ throw new InvalidConfigurationError("organization is required when invitation is provided.");
588
+ }
527
589
  const domain = await this.#resolveDomain(storeOptions);
528
590
  const authClient = this.#getAuthClient(domain);
529
591
  const { codeVerifier, authorizationUrl } = await authClient.buildAuthorizationUrl({
@@ -531,7 +593,9 @@ var ServerClient = class {
531
593
  authorizationParams: {
532
594
  ...options?.authorizationParams,
533
595
  redirect_uri: redirectUri,
534
- scope
596
+ scope,
597
+ ...resolvedOrganization ? { organization: resolvedOrganization } : {},
598
+ ...options?.invitation ? { invitation: options.invitation } : {}
535
599
  }
536
600
  });
537
601
  const transactionState = {
@@ -539,6 +603,9 @@ var ServerClient = class {
539
603
  codeVerifier,
540
604
  domain
541
605
  };
606
+ if (resolvedOrganization) {
607
+ transactionState.organization = resolvedOrganization;
608
+ }
542
609
  if (options?.appState) {
543
610
  transactionState.appState = options.appState;
544
611
  }
@@ -553,6 +620,8 @@ var ServerClient = class {
553
620
  *
554
621
  * @throws {MissingTransactionError} When no transaction was found.
555
622
  * @throws {TokenByCodeError} If there was an issue requesting the access token.
623
+ * @throws {OrganizationValidationError} When an organization was requested at login and the returned ID token's organization claim is missing or does not match; nothing is persisted.
624
+ * @throws {SessionExpiredError} When the ID token's `session_expiry` is already in the past at login (the session is born expired); nothing is persisted.
556
625
  *
557
626
  * @returns A promise resolving to an object, containing the original appState (if present) and the authorizationDetails (when RAR was used).
558
627
  */
@@ -565,14 +634,18 @@ var ServerClient = class {
565
634
  const authClient = this.#getAuthClient(domain);
566
635
  const tokenEndpointResponse = await authClient.getTokenByCode(url, {
567
636
  // TransactionData.codeVerifier is optional only to accommodate magic-link transactions.
568
- codeVerifier: transactionData.codeVerifier
637
+ codeVerifier: transactionData.codeVerifier,
638
+ organization: transactionData.organization
569
639
  });
640
+ await this.#transactionStore.delete(this.#transactionStoreIdentifier, storeOptions);
570
641
  const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
571
- const stateData = updateStateData(transactionData.audience ?? "default", existingStateData, tokenEndpointResponse, {
572
- domain
573
- });
642
+ const stateData = applySessionExpiryAtLogin(
643
+ updateStateData(transactionData.audience ?? "default", existingStateData, tokenEndpointResponse, {
644
+ domain
645
+ }),
646
+ tokenEndpointResponse.claims
647
+ );
574
648
  await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
575
- await this.#transactionStore.delete(this.#transactionStoreIdentifier, storeOptions);
576
649
  return { appState: transactionData.appState, authorizationDetails: tokenEndpointResponse.authorizationDetails };
577
650
  }
578
651
  /**
@@ -582,6 +655,7 @@ var ServerClient = class {
582
655
  *
583
656
  * @throws {MissingSessionError} If there is no active session.
584
657
  * @throws {BuildLinkUserUrlError} If there was an issue when building the Authorization URL.
658
+ * @throws {SessionExpiredError} When the session's `session_expiry` ceiling has been reached; the session is cleared and re-authentication is required.
585
659
  *
586
660
  * @returns A promise resolving to a URL object, representing the URL to redirect the user-agent to to request authorization at Auth0.
587
661
  */
@@ -598,6 +672,10 @@ var ServerClient = class {
598
672
  throw new MissingSessionError("Session domain does not match the current domain.");
599
673
  }
600
674
  }
675
+ if (isSessionExpiryReached(stateData.sessionExpiresAt)) {
676
+ await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
677
+ throw new SessionExpiredError();
678
+ }
601
679
  const domain = this.#getSessionDomain(stateData);
602
680
  const authClient = this.#getAuthClient(domain);
603
681
  const { linkUserUrl, codeVerifier } = await authClient.buildLinkUserUrl({
@@ -641,6 +719,7 @@ var ServerClient = class {
641
719
  *
642
720
  * @throws {MissingSessionError} If there is no active session.
643
721
  * @throws {BuildUnlinkUserUrlError} If there was an issue when building the User Unlinking URL.
722
+ * @throws {SessionExpiredError} When the session's `session_expiry` ceiling has been reached; the session is cleared and re-authentication is required.
644
723
  *
645
724
  * @returns A promise resolving to a URL object, representing the URL to redirect the user-agent to to request authorization at Auth0.
646
725
  */
@@ -657,6 +736,10 @@ var ServerClient = class {
657
736
  throw new MissingSessionError("Session domain does not match the current domain.");
658
737
  }
659
738
  }
739
+ if (isSessionExpiryReached(stateData.sessionExpiresAt)) {
740
+ await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
741
+ throw new SessionExpiredError();
742
+ }
660
743
  const domain = this.#getSessionDomain(stateData);
661
744
  const authClient = this.#getAuthClient(domain);
662
745
  const { unlinkUserUrl, codeVerifier } = await authClient.buildUnlinkUserUrl({
@@ -701,6 +784,7 @@ var ServerClient = class {
701
784
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
702
785
  *
703
786
  * @throws {BackchannelAuthenticationError} If there was an issue when doing backchannel authentication.
787
+ * @throws {SessionExpiredError} When the ID token's `session_expiry` is already in the past at login (the session is born expired); nothing is persisted.
704
788
  *
705
789
  * @returns A promise resolving to an object, containing the authorizationDetails (when RAR was used).
706
790
  */
@@ -717,11 +801,11 @@ var ServerClient = class {
717
801
  }
718
802
  });
719
803
  const existingStateData = await this.#stateStore.get(this.#stateStoreIdentifier, storeOptions);
720
- const stateData = updateStateData(
721
- this.#options.authorizationParams?.audience ?? "default",
722
- existingStateData,
723
- tokenEndpointResponse,
724
- { domain }
804
+ const stateData = applySessionExpiryAtLogin(
805
+ updateStateData(this.#options.authorizationParams?.audience ?? "default", existingStateData, tokenEndpointResponse, {
806
+ domain
807
+ }),
808
+ tokenEndpointResponse.claims
725
809
  );
726
810
  await this.#stateStore.set(this.#stateStoreIdentifier, stateData, true, storeOptions);
727
811
  return {
@@ -916,6 +1000,10 @@ var ServerClient = class {
916
1000
  return;
917
1001
  }
918
1002
  }
1003
+ if (isSessionExpiryReached(stateData.sessionExpiresAt)) {
1004
+ await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
1005
+ return;
1006
+ }
919
1007
  return stateData.user;
920
1008
  }
921
1009
  /**
@@ -932,6 +1020,10 @@ var ServerClient = class {
932
1020
  return;
933
1021
  }
934
1022
  }
1023
+ if (isSessionExpiryReached(stateData.sessionExpiresAt)) {
1024
+ await this.#stateStore.delete(this.#stateStoreIdentifier, storeOptions);
1025
+ return;
1026
+ }
935
1027
  const { internal, ...sessionData } = stateData;
936
1028
  return sessionData;
937
1029
  }
@@ -948,6 +1040,7 @@ var ServerClient = class {
948
1040
  * @param storeOptions Optional options used to pass to the Transaction and State Store.
949
1041
  *
950
1042
  * @throws {TokenByRefreshTokenError} If the refresh token was not found or there was an issue requesting the access token. When the cause is `mfa_required`, use `isMfaRequiredError(error)` to narrow the error and read `cause.mfa_token`.
1043
+ * @throws {SessionExpiredError} When the session's `session_expiry` ceiling has been reached; the session is cleared and no refresh is attempted — the user must re-authenticate.
951
1044
  *
952
1045
  * @returns The Token Set, containing the access token, as well as additional information.
953
1046
  */
@@ -975,6 +1068,10 @@ var ServerClient = class {
975
1068
  throw new MissingSessionError("Session domain does not match the current domain.");
976
1069
  }
977
1070
  }
1071
+ if (stateData && isSessionExpiryReached(stateData.sessionExpiresAt)) {
1072
+ await this.#stateStore.delete(this.#stateStoreIdentifier, resolvedStoreOptions);
1073
+ throw new SessionExpiredError();
1074
+ }
978
1075
  const tokenSet = stateData?.tokenSets.find(
979
1076
  (tokenSet2) => tokenSet2.audience === audience && (!scope || compareScopes(tokenSet2.scope, scope))
980
1077
  );
@@ -1309,7 +1406,7 @@ var AbstractTransactionStore = class extends AbstractStore {
1309
1406
  };
1310
1407
 
1311
1408
  // src/index.ts
1312
- import { TokenExchangeError, MissingClientAuthError } from "@auth0/auth0-auth-js";
1409
+ import { TokenExchangeError, MissingClientAuthError, OrganizationValidationError as OrganizationValidationError3 } from "@auth0/auth0-auth-js";
1313
1410
 
1314
1411
  // src/store/cookie-transaction-store.ts
1315
1412
  var CookieTransactionStore = class extends AbstractTransactionStore {
@@ -1349,14 +1446,14 @@ var AbstractSessionStore = class extends AbstractStateStore {
1349
1446
  }
1350
1447
  /**
1351
1448
  * calculateMaxAge calculates the max age of the session based on createdAt and the rolling and absolute durations.
1449
+ * When sessionExpiresAt is provided, caps the maxAge to not exceed the time until that ceiling.
1352
1450
  */
1353
- calculateMaxAge(createdAt) {
1354
- if (!this.#rolling) {
1355
- return this.#absoluteDuration;
1356
- }
1451
+ calculateMaxAge(createdAt, sessionExpiresAt) {
1357
1452
  const now = Date.now() / 1e3 | 0;
1358
- const expiresAt = Math.min(now + this.#inactivityDuration, createdAt + this.#absoluteDuration);
1359
- const maxAge = expiresAt - now;
1453
+ let maxAge = this.#rolling ? Math.min(now + this.#inactivityDuration, createdAt + this.#absoluteDuration) - now : this.#absoluteDuration;
1454
+ if (sessionExpiresAt !== void 0) {
1455
+ maxAge = Math.min(maxAge, sessionExpiresAt - now);
1456
+ }
1360
1457
  return maxAge > 0 ? maxAge : 0;
1361
1458
  }
1362
1459
  };
@@ -1384,7 +1481,7 @@ var StatefulStateStore = class extends AbstractSessionStore {
1384
1481
  sessionId = generateId();
1385
1482
  }
1386
1483
  sessionId ??= generateId();
1387
- const maxAge = this.calculateMaxAge(stateData.internal.createdAt);
1484
+ const maxAge = this.calculateMaxAge(stateData.internal.createdAt, stateData.sessionExpiresAt);
1388
1485
  const cookieOpts = this.#getCookieOptions({
1389
1486
  maxAge
1390
1487
  });
@@ -1449,7 +1546,7 @@ var StatelessStateStore = class extends AbstractSessionStore {
1449
1546
  this.#cookieHandler = cookieHandler;
1450
1547
  }
1451
1548
  async set(identifier, stateData, removeIfExists, options) {
1452
- const maxAge = this.calculateMaxAge(stateData.internal.createdAt);
1549
+ const maxAge = this.calculateMaxAge(stateData.internal.createdAt, stateData.sessionExpiresAt);
1453
1550
  const cookieOpts = this.#getCookieOptions({
1454
1551
  maxAge
1455
1552
  });
@@ -1519,7 +1616,7 @@ import {
1519
1616
  PasskeyRegisterError,
1520
1617
  PasskeyChallengeError,
1521
1618
  PasskeyGetTokenError,
1522
- OrganizationValidationError
1619
+ OrganizationValidationError as OrganizationValidationError2
1523
1620
  } from "@auth0/auth0-auth-js";
1524
1621
  export {
1525
1622
  AbstractStateStore,
@@ -1536,13 +1633,14 @@ export {
1536
1633
  MissingRequiredArgumentError,
1537
1634
  MissingSessionError,
1538
1635
  MissingTransactionError,
1539
- OrganizationValidationError,
1636
+ OrganizationValidationError3 as OrganizationValidationError,
1540
1637
  PasskeyChallengeError,
1541
1638
  PasskeyGetTokenError,
1542
1639
  PasskeyRegisterError,
1543
1640
  ServerClient,
1544
1641
  ServerMfaClient,
1545
1642
  ServerPasskeyClient,
1643
+ SessionExpiredError,
1546
1644
  StartLinkUserError,
1547
1645
  StatefulStateStore,
1548
1646
  StatelessStateStore,