@tenxyte/core 0.9.3 → 0.9.4

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
@@ -146,7 +146,7 @@ declare function createAuthInterceptor(storage: TenxyteStorage, context: Tenxyte
146
146
  params?: Record<string, string | number | boolean>;
147
147
  url: string;
148
148
  }>;
149
- declare function createRefreshInterceptor(client: TenxyteHttpClient, storage: TenxyteStorage, onSessionExpired: () => void, onTokenRefreshed?: (accessToken: string, refreshToken?: string) => void): (response: Response, request: {
149
+ declare function createRefreshInterceptor(client: TenxyteHttpClient, storage: TenxyteStorage, onSessionExpired: () => void, onTokenRefreshed?: (accessToken: string, refreshToken?: string) => void, cookieMode?: boolean): (response: Response, request: {
150
150
  url: string;
151
151
  config: RequestConfig;
152
152
  }) => Promise<Response>;
@@ -289,6 +289,15 @@ interface TenxyteClientConfig {
289
289
  * with exponential backoff. Pass `{}` for sensible defaults.
290
290
  */
291
291
  retryConfig?: RetryConfig;
292
+ /**
293
+ * When true, the SDK assumes the backend is configured with
294
+ * `TENXYTE_REFRESH_TOKEN_COOKIE_ENABLED=True`. In this mode:
295
+ * - `refresh_token` is omitted from JSON response bodies (delivered via HttpOnly cookie).
296
+ * - `credentials: 'include'` is added to refresh/logout requests so the browser sends cookies.
297
+ * - The SDK does not require a stored refresh token to attempt a silent refresh.
298
+ * Defaults to false.
299
+ */
300
+ cookieMode?: boolean;
292
301
  }
293
302
  /**
294
303
  * Fully resolved configuration where every optional field has been
@@ -307,6 +316,7 @@ interface ResolvedTenxyteConfig {
307
316
  logLevel: LogLevel;
308
317
  deviceInfoOverride: CustomDeviceInfo | undefined;
309
318
  retryConfig: RetryConfig | undefined;
319
+ cookieMode: boolean;
310
320
  }
311
321
  /** Silent no-op logger used when the consumer does not provide one. */
312
322
  declare const NOOP_LOGGER: TenxyteLogger;
@@ -1233,7 +1243,7 @@ interface TenxyteUser {
1233
1243
  */
1234
1244
  interface TokenPair {
1235
1245
  access_token: string;
1236
- refresh_token: string;
1246
+ refresh_token?: string;
1237
1247
  token_type: 'Bearer';
1238
1248
  expires_in: number;
1239
1249
  device_summary: string | null;
@@ -1247,7 +1257,7 @@ interface TenxyteError {
1247
1257
  details?: Record<string, string[]> | string;
1248
1258
  retry_after?: number;
1249
1259
  }
1250
- type TenxyteErrorCode = 'LOGIN_FAILED' | 'INVALID_CREDENTIALS' | 'ACCOUNT_LOCKED' | 'ACCOUNT_BANNED' | '2FA_REQUIRED' | 'ADMIN_2FA_SETUP_REQUIRED' | 'TOKEN_EXPIRED' | 'TOKEN_BLACKLISTED' | 'REFRESH_FAILED' | 'PERMISSION_DENIED' | 'SESSION_LIMIT_EXCEEDED' | 'DEVICE_LIMIT_EXCEEDED' | 'RATE_LIMITED' | 'INVALID_OTP' | 'OTP_EXPIRED' | 'INVALID_PROVIDER' | 'SOCIAL_AUTH_FAILED' | 'VALIDATION_URL_REQUIRED' | 'INVALID_TOKEN' | 'CONFIRMATION_REQUIRED' | 'PASSWORD_REQUIRED' | 'INVALID_PASSWORD' | 'INVALID_DEVICE_INFO' | 'ORG_NOT_FOUND' | 'NOT_ORG_MEMBER' | 'NOT_OWNER' | 'ALREADY_MEMBER' | 'MEMBER_LIMIT_EXCEEDED' | 'HAS_CHILDREN' | 'CIRCULAR_HIERARCHY' | 'LAST_OWNER_REQUIRED' | 'INVITATION_EXISTS' | 'INVALID_ROLE' | 'AGENT_NOT_FOUND' | 'AGENT_SUSPENDED' | 'AGENT_REVOKED' | 'AGENT_EXPIRED' | 'BUDGET_EXCEEDED' | 'RATE_LIMIT_EXCEEDED' | 'HEARTBEAT_MISSING' | 'AIRS_DISABLED' | 'TIMEOUT' | 'NETWORK_ERROR';
1260
+ type TenxyteErrorCode = 'LOGIN_FAILED' | 'INVALID_CREDENTIALS' | 'ACCOUNT_LOCKED' | 'ACCOUNT_BANNED' | '2FA_REQUIRED' | 'ADMIN_2FA_SETUP_REQUIRED' | 'TOKEN_EXPIRED' | 'TOKEN_BLACKLISTED' | 'REFRESH_FAILED' | 'PERMISSION_DENIED' | 'SESSION_LIMIT_EXCEEDED' | 'DEVICE_LIMIT_EXCEEDED' | 'RATE_LIMITED' | 'INVALID_OTP' | 'OTP_EXPIRED' | 'MAX_ATTEMPTS_REACHED' | 'RESET_FAILED' | 'INVALID_PROVIDER' | 'SOCIAL_AUTH_FAILED' | 'VALIDATION_URL_REQUIRED' | 'INVALID_TOKEN' | 'MISSING_REFRESH_TOKEN' | 'APP_AUTH_REQUIRED' | 'REGISTRATION_FAILED' | 'INVALID_2FA_CODE' | 'REDIRECT_URI_REQUIRED' | 'REDIRECT_URI_NOT_ALLOWED' | 'INVALID_REDIRECT_URI' | 'MISSING_REDIRECT_URI' | 'MISSING_CREDENTIALS' | 'MISSING_CODE' | 'PROVIDER_NOT_SUPPORTED' | 'PROVIDER_AUTH_FAILED' | 'CODE_EXCHANGE_FAILED' | 'CALLBACK_ERROR' | 'CONFIRMATION_REQUIRED' | 'PASSWORD_REQUIRED' | 'INVALID_PASSWORD' | 'PASSWORD_BREACHED' | 'PASSWORD_REUSED' | 'INVALID_DEVICE_INFO' | 'ORG_NOT_FOUND' | 'NOT_ORG_MEMBER' | 'NOT_OWNER' | 'ALREADY_MEMBER' | 'MEMBER_LIMIT_EXCEEDED' | 'HAS_CHILDREN' | 'CIRCULAR_HIERARCHY' | 'LAST_OWNER_REQUIRED' | 'INVITATION_EXISTS' | 'INVALID_ROLE' | 'AGENT_NOT_FOUND' | 'AGENT_SUSPENDED' | 'AGENT_REVOKED' | 'AGENT_EXPIRED' | 'BUDGET_EXCEEDED' | 'RATE_LIMIT_EXCEEDED' | 'HEARTBEAT_MISSING' | 'AIRS_DISABLED' | 'TOKEN_REQUIRED' | 'MAGIC_LINK_INVALID' | 'LINK_EXPIRED' | 'LINK_ALREADY_USED' | '2FA_ALREADY_ENABLED' | 'INVALID_CODE' | 'CODE_REQUIRED' | 'WEBAUTHN_DISABLED' | 'WEBAUTHN_ERROR' | 'WEBAUTHN_AUTH_FAILED' | 'CREDENTIAL_EXISTS' | 'CREDENTIAL_NOT_FOUND' | 'REPLAY_ATTACK' | 'TIMEOUT' | 'NETWORK_ERROR';
1251
1261
  /**
1252
1262
  * Organization Structure defining a B2B tenant or hierarchical unit.
1253
1263
  */
@@ -1346,6 +1356,12 @@ interface SocialLoginRequest {
1346
1356
  access_token?: string;
1347
1357
  authorization_code?: string;
1348
1358
  id_token?: string;
1359
+ /** Authorization code for the code exchange flow. */
1360
+ code?: string;
1361
+ /** Redirect URI matching the one used in the authorization request. */
1362
+ redirect_uri?: string;
1363
+ /** PKCE code verifier (RFC 7636). Required if the authorization request included a code_challenge. */
1364
+ code_verifier?: string;
1349
1365
  }
1350
1366
  /** Response from the registration endpoint (may include tokens if `login: true`). */
1351
1367
  interface RegisterResponse {
@@ -1393,9 +1409,11 @@ declare class AuthModule {
1393
1409
  /**
1394
1410
  * Logout from the current session.
1395
1411
  * Informs the backend to immediately revoke the specified refresh token.
1396
- * @param refreshToken - The refresh token to revoke.
1412
+ * When cookie mode is enabled, the refresh token parameter is optional —
1413
+ * the server reads it from the HttpOnly cookie and clears it via Set-Cookie.
1414
+ * @param refreshToken - The refresh token to revoke (optional in cookie mode).
1397
1415
  */
1398
- logout(refreshToken: string): Promise<void>;
1416
+ logout(refreshToken?: string): Promise<void>;
1399
1417
  /**
1400
1418
  * Logout from all sessions across all devices.
1401
1419
  * Revokes all refresh tokens currently assigned to the user.
@@ -1404,10 +1422,12 @@ declare class AuthModule {
1404
1422
  /**
1405
1423
  * Manually refresh the access token using a valid refresh token.
1406
1424
  * The refresh token is automatically rotated for improved security.
1407
- * @param refreshToken - The current refresh token.
1425
+ * When cookie mode is enabled, the refresh token parameter is optional —
1426
+ * the server reads it from the HttpOnly cookie.
1427
+ * @param refreshToken - The current refresh token (optional in cookie mode).
1408
1428
  * @returns A new token pair (access + rotated refresh).
1409
1429
  */
1410
- refreshToken(refreshToken: string): Promise<TokenPair>;
1430
+ refreshToken(refreshToken?: string): Promise<TokenPair>;
1411
1431
  /**
1412
1432
  * Request a Magic Link for passwordless sign-in.
1413
1433
  * @param data - The email to send the logic link to.
@@ -1432,9 +1452,10 @@ declare class AuthModule {
1432
1452
  * @param provider - The OAuth provider ('google', 'github', etc.)
1433
1453
  * @param code - The authorization code retrieved from the query string parameters.
1434
1454
  * @param redirectUri - The original redirect URI that was requested.
1455
+ * @param codeVerifier - Optional PKCE code verifier (RFC 7636).
1435
1456
  * @returns An active session token pair after successful code exchange.
1436
1457
  */
1437
- handleSocialCallback(provider: 'google' | 'github' | 'microsoft' | 'facebook', code: string, redirectUri: string): Promise<TokenPair>;
1458
+ handleSocialCallback(provider: 'google' | 'github' | 'microsoft' | 'facebook', code: string, redirectUri: string, codeVerifier?: string): Promise<TokenPair>;
1438
1459
  }
1439
1460
 
1440
1461
  declare class SecurityModule {
package/dist/index.d.ts CHANGED
@@ -146,7 +146,7 @@ declare function createAuthInterceptor(storage: TenxyteStorage, context: Tenxyte
146
146
  params?: Record<string, string | number | boolean>;
147
147
  url: string;
148
148
  }>;
149
- declare function createRefreshInterceptor(client: TenxyteHttpClient, storage: TenxyteStorage, onSessionExpired: () => void, onTokenRefreshed?: (accessToken: string, refreshToken?: string) => void): (response: Response, request: {
149
+ declare function createRefreshInterceptor(client: TenxyteHttpClient, storage: TenxyteStorage, onSessionExpired: () => void, onTokenRefreshed?: (accessToken: string, refreshToken?: string) => void, cookieMode?: boolean): (response: Response, request: {
150
150
  url: string;
151
151
  config: RequestConfig;
152
152
  }) => Promise<Response>;
@@ -289,6 +289,15 @@ interface TenxyteClientConfig {
289
289
  * with exponential backoff. Pass `{}` for sensible defaults.
290
290
  */
291
291
  retryConfig?: RetryConfig;
292
+ /**
293
+ * When true, the SDK assumes the backend is configured with
294
+ * `TENXYTE_REFRESH_TOKEN_COOKIE_ENABLED=True`. In this mode:
295
+ * - `refresh_token` is omitted from JSON response bodies (delivered via HttpOnly cookie).
296
+ * - `credentials: 'include'` is added to refresh/logout requests so the browser sends cookies.
297
+ * - The SDK does not require a stored refresh token to attempt a silent refresh.
298
+ * Defaults to false.
299
+ */
300
+ cookieMode?: boolean;
292
301
  }
293
302
  /**
294
303
  * Fully resolved configuration where every optional field has been
@@ -307,6 +316,7 @@ interface ResolvedTenxyteConfig {
307
316
  logLevel: LogLevel;
308
317
  deviceInfoOverride: CustomDeviceInfo | undefined;
309
318
  retryConfig: RetryConfig | undefined;
319
+ cookieMode: boolean;
310
320
  }
311
321
  /** Silent no-op logger used when the consumer does not provide one. */
312
322
  declare const NOOP_LOGGER: TenxyteLogger;
@@ -1233,7 +1243,7 @@ interface TenxyteUser {
1233
1243
  */
1234
1244
  interface TokenPair {
1235
1245
  access_token: string;
1236
- refresh_token: string;
1246
+ refresh_token?: string;
1237
1247
  token_type: 'Bearer';
1238
1248
  expires_in: number;
1239
1249
  device_summary: string | null;
@@ -1247,7 +1257,7 @@ interface TenxyteError {
1247
1257
  details?: Record<string, string[]> | string;
1248
1258
  retry_after?: number;
1249
1259
  }
1250
- type TenxyteErrorCode = 'LOGIN_FAILED' | 'INVALID_CREDENTIALS' | 'ACCOUNT_LOCKED' | 'ACCOUNT_BANNED' | '2FA_REQUIRED' | 'ADMIN_2FA_SETUP_REQUIRED' | 'TOKEN_EXPIRED' | 'TOKEN_BLACKLISTED' | 'REFRESH_FAILED' | 'PERMISSION_DENIED' | 'SESSION_LIMIT_EXCEEDED' | 'DEVICE_LIMIT_EXCEEDED' | 'RATE_LIMITED' | 'INVALID_OTP' | 'OTP_EXPIRED' | 'INVALID_PROVIDER' | 'SOCIAL_AUTH_FAILED' | 'VALIDATION_URL_REQUIRED' | 'INVALID_TOKEN' | 'CONFIRMATION_REQUIRED' | 'PASSWORD_REQUIRED' | 'INVALID_PASSWORD' | 'INVALID_DEVICE_INFO' | 'ORG_NOT_FOUND' | 'NOT_ORG_MEMBER' | 'NOT_OWNER' | 'ALREADY_MEMBER' | 'MEMBER_LIMIT_EXCEEDED' | 'HAS_CHILDREN' | 'CIRCULAR_HIERARCHY' | 'LAST_OWNER_REQUIRED' | 'INVITATION_EXISTS' | 'INVALID_ROLE' | 'AGENT_NOT_FOUND' | 'AGENT_SUSPENDED' | 'AGENT_REVOKED' | 'AGENT_EXPIRED' | 'BUDGET_EXCEEDED' | 'RATE_LIMIT_EXCEEDED' | 'HEARTBEAT_MISSING' | 'AIRS_DISABLED' | 'TIMEOUT' | 'NETWORK_ERROR';
1260
+ type TenxyteErrorCode = 'LOGIN_FAILED' | 'INVALID_CREDENTIALS' | 'ACCOUNT_LOCKED' | 'ACCOUNT_BANNED' | '2FA_REQUIRED' | 'ADMIN_2FA_SETUP_REQUIRED' | 'TOKEN_EXPIRED' | 'TOKEN_BLACKLISTED' | 'REFRESH_FAILED' | 'PERMISSION_DENIED' | 'SESSION_LIMIT_EXCEEDED' | 'DEVICE_LIMIT_EXCEEDED' | 'RATE_LIMITED' | 'INVALID_OTP' | 'OTP_EXPIRED' | 'MAX_ATTEMPTS_REACHED' | 'RESET_FAILED' | 'INVALID_PROVIDER' | 'SOCIAL_AUTH_FAILED' | 'VALIDATION_URL_REQUIRED' | 'INVALID_TOKEN' | 'MISSING_REFRESH_TOKEN' | 'APP_AUTH_REQUIRED' | 'REGISTRATION_FAILED' | 'INVALID_2FA_CODE' | 'REDIRECT_URI_REQUIRED' | 'REDIRECT_URI_NOT_ALLOWED' | 'INVALID_REDIRECT_URI' | 'MISSING_REDIRECT_URI' | 'MISSING_CREDENTIALS' | 'MISSING_CODE' | 'PROVIDER_NOT_SUPPORTED' | 'PROVIDER_AUTH_FAILED' | 'CODE_EXCHANGE_FAILED' | 'CALLBACK_ERROR' | 'CONFIRMATION_REQUIRED' | 'PASSWORD_REQUIRED' | 'INVALID_PASSWORD' | 'PASSWORD_BREACHED' | 'PASSWORD_REUSED' | 'INVALID_DEVICE_INFO' | 'ORG_NOT_FOUND' | 'NOT_ORG_MEMBER' | 'NOT_OWNER' | 'ALREADY_MEMBER' | 'MEMBER_LIMIT_EXCEEDED' | 'HAS_CHILDREN' | 'CIRCULAR_HIERARCHY' | 'LAST_OWNER_REQUIRED' | 'INVITATION_EXISTS' | 'INVALID_ROLE' | 'AGENT_NOT_FOUND' | 'AGENT_SUSPENDED' | 'AGENT_REVOKED' | 'AGENT_EXPIRED' | 'BUDGET_EXCEEDED' | 'RATE_LIMIT_EXCEEDED' | 'HEARTBEAT_MISSING' | 'AIRS_DISABLED' | 'TOKEN_REQUIRED' | 'MAGIC_LINK_INVALID' | 'LINK_EXPIRED' | 'LINK_ALREADY_USED' | '2FA_ALREADY_ENABLED' | 'INVALID_CODE' | 'CODE_REQUIRED' | 'WEBAUTHN_DISABLED' | 'WEBAUTHN_ERROR' | 'WEBAUTHN_AUTH_FAILED' | 'CREDENTIAL_EXISTS' | 'CREDENTIAL_NOT_FOUND' | 'REPLAY_ATTACK' | 'TIMEOUT' | 'NETWORK_ERROR';
1251
1261
  /**
1252
1262
  * Organization Structure defining a B2B tenant or hierarchical unit.
1253
1263
  */
@@ -1346,6 +1356,12 @@ interface SocialLoginRequest {
1346
1356
  access_token?: string;
1347
1357
  authorization_code?: string;
1348
1358
  id_token?: string;
1359
+ /** Authorization code for the code exchange flow. */
1360
+ code?: string;
1361
+ /** Redirect URI matching the one used in the authorization request. */
1362
+ redirect_uri?: string;
1363
+ /** PKCE code verifier (RFC 7636). Required if the authorization request included a code_challenge. */
1364
+ code_verifier?: string;
1349
1365
  }
1350
1366
  /** Response from the registration endpoint (may include tokens if `login: true`). */
1351
1367
  interface RegisterResponse {
@@ -1393,9 +1409,11 @@ declare class AuthModule {
1393
1409
  /**
1394
1410
  * Logout from the current session.
1395
1411
  * Informs the backend to immediately revoke the specified refresh token.
1396
- * @param refreshToken - The refresh token to revoke.
1412
+ * When cookie mode is enabled, the refresh token parameter is optional —
1413
+ * the server reads it from the HttpOnly cookie and clears it via Set-Cookie.
1414
+ * @param refreshToken - The refresh token to revoke (optional in cookie mode).
1397
1415
  */
1398
- logout(refreshToken: string): Promise<void>;
1416
+ logout(refreshToken?: string): Promise<void>;
1399
1417
  /**
1400
1418
  * Logout from all sessions across all devices.
1401
1419
  * Revokes all refresh tokens currently assigned to the user.
@@ -1404,10 +1422,12 @@ declare class AuthModule {
1404
1422
  /**
1405
1423
  * Manually refresh the access token using a valid refresh token.
1406
1424
  * The refresh token is automatically rotated for improved security.
1407
- * @param refreshToken - The current refresh token.
1425
+ * When cookie mode is enabled, the refresh token parameter is optional —
1426
+ * the server reads it from the HttpOnly cookie.
1427
+ * @param refreshToken - The current refresh token (optional in cookie mode).
1408
1428
  * @returns A new token pair (access + rotated refresh).
1409
1429
  */
1410
- refreshToken(refreshToken: string): Promise<TokenPair>;
1430
+ refreshToken(refreshToken?: string): Promise<TokenPair>;
1411
1431
  /**
1412
1432
  * Request a Magic Link for passwordless sign-in.
1413
1433
  * @param data - The email to send the logic link to.
@@ -1432,9 +1452,10 @@ declare class AuthModule {
1432
1452
  * @param provider - The OAuth provider ('google', 'github', etc.)
1433
1453
  * @param code - The authorization code retrieved from the query string parameters.
1434
1454
  * @param redirectUri - The original redirect URI that was requested.
1455
+ * @param codeVerifier - Optional PKCE code verifier (RFC 7636).
1435
1456
  * @returns An active session token pair after successful code exchange.
1436
1457
  */
1437
- handleSocialCallback(provider: 'google' | 'github' | 'microsoft' | 'facebook', code: string, redirectUri: string): Promise<TokenPair>;
1458
+ handleSocialCallback(provider: 'google' | 'github' | 'microsoft' | 'facebook', code: string, redirectUri: string, codeVerifier?: string): Promise<TokenPair>;
1438
1459
  }
1439
1460
 
1440
1461
  declare class SecurityModule {
package/dist/index.js CHANGED
@@ -124,7 +124,8 @@ function resolveConfig(config) {
124
124
  logger: config.logger ?? NOOP_LOGGER,
125
125
  logLevel: config.logLevel ?? "silent",
126
126
  deviceInfoOverride: config.deviceInfoOverride,
127
- retryConfig: config.retryConfig
127
+ retryConfig: config.retryConfig,
128
+ cookieMode: config.cookieMode ?? false
128
129
  };
129
130
  }
130
131
 
@@ -346,7 +347,7 @@ function createAuthInterceptor(storage, context) {
346
347
  return { ...request, headers };
347
348
  };
348
349
  }
349
- function createRefreshInterceptor(client, storage, onSessionExpired, onTokenRefreshed) {
350
+ function createRefreshInterceptor(client, storage, onSessionExpired, onTokenRefreshed, cookieMode = false) {
350
351
  let isRefreshing = false;
351
352
  let refreshQueue = [];
352
353
  const processQueue = (error, token = null) => {
@@ -356,7 +357,7 @@ function createRefreshInterceptor(client, storage, onSessionExpired, onTokenRefr
356
357
  return async (response, request) => {
357
358
  if (response.status === 401 && !request.url.includes("/auth/refresh") && !request.url.includes("/auth/login")) {
358
359
  const refreshToken = await storage.getItem("tx_refresh");
359
- if (!refreshToken) {
360
+ if (!refreshToken && !cookieMode) {
360
361
  onSessionExpired();
361
362
  return response;
362
363
  }
@@ -374,10 +375,15 @@ function createRefreshInterceptor(client, storage, onSessionExpired, onTokenRefr
374
375
  }
375
376
  isRefreshing = true;
376
377
  try {
378
+ const refreshBody = {};
379
+ if (refreshToken) {
380
+ refreshBody.refresh_token = refreshToken;
381
+ }
377
382
  const refreshResponse = await fetch(`${client["baseUrl"]}/auth/refresh/`, {
378
383
  method: "POST",
379
384
  headers: { "Content-Type": "application/json" },
380
- body: JSON.stringify({ refresh_token: refreshToken })
385
+ body: JSON.stringify(refreshBody),
386
+ ...cookieMode ? { credentials: "include" } : {}
381
387
  });
382
388
  if (!refreshResponse.ok) {
383
389
  throw new Error("Refresh failed");
@@ -535,10 +541,16 @@ var AuthModule = class {
535
541
  /**
536
542
  * Logout from the current session.
537
543
  * Informs the backend to immediately revoke the specified refresh token.
538
- * @param refreshToken - The refresh token to revoke.
544
+ * When cookie mode is enabled, the refresh token parameter is optional —
545
+ * the server reads it from the HttpOnly cookie and clears it via Set-Cookie.
546
+ * @param refreshToken - The refresh token to revoke (optional in cookie mode).
539
547
  */
540
548
  async logout(refreshToken) {
541
- await this.client.post("/api/v1/auth/logout/", { refresh_token: refreshToken });
549
+ const body = {};
550
+ if (refreshToken) {
551
+ body.refresh_token = refreshToken;
552
+ }
553
+ await this.client.post("/api/v1/auth/logout/", body);
542
554
  await this.clearTokens();
543
555
  }
544
556
  /**
@@ -552,11 +564,17 @@ var AuthModule = class {
552
564
  /**
553
565
  * Manually refresh the access token using a valid refresh token.
554
566
  * The refresh token is automatically rotated for improved security.
555
- * @param refreshToken - The current refresh token.
567
+ * When cookie mode is enabled, the refresh token parameter is optional —
568
+ * the server reads it from the HttpOnly cookie.
569
+ * @param refreshToken - The current refresh token (optional in cookie mode).
556
570
  * @returns A new token pair (access + rotated refresh).
557
571
  */
558
572
  async refreshToken(refreshToken) {
559
- const tokens = await this.client.post("/api/v1/auth/refresh/", { refresh_token: refreshToken });
573
+ const body = {};
574
+ if (refreshToken) {
575
+ body.refresh_token = refreshToken;
576
+ }
577
+ const tokens = await this.client.post("/api/v1/auth/refresh/", body);
560
578
  return this.persistTokens(tokens);
561
579
  }
562
580
  /**
@@ -591,11 +609,16 @@ var AuthModule = class {
591
609
  * @param provider - The OAuth provider ('google', 'github', etc.)
592
610
  * @param code - The authorization code retrieved from the query string parameters.
593
611
  * @param redirectUri - The original redirect URI that was requested.
612
+ * @param codeVerifier - Optional PKCE code verifier (RFC 7636).
594
613
  * @returns An active session token pair after successful code exchange.
595
614
  */
596
- async handleSocialCallback(provider, code, redirectUri) {
615
+ async handleSocialCallback(provider, code, redirectUri, codeVerifier) {
616
+ const params = { code, redirect_uri: redirectUri };
617
+ if (codeVerifier) {
618
+ params.code_verifier = codeVerifier;
619
+ }
597
620
  const tokens = await this.client.get(`/api/v1/auth/social/${provider}/callback/`, {
598
- params: { code, redirect_uri: redirectUri }
621
+ params
599
622
  });
600
623
  return this.persistTokens(tokens);
601
624
  }
@@ -1698,7 +1721,8 @@ var TenxyteClient = class {
1698
1721
  this.rbac.setToken(accessToken);
1699
1722
  this.emit("token:refreshed", { accessToken });
1700
1723
  this.emit("token:stored", { accessToken, refreshToken });
1701
- }
1724
+ },
1725
+ this.config.cookieMode
1702
1726
  )
1703
1727
  );
1704
1728
  }