@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/README.md +47 -2
- package/dist/index.cjs +35 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -8
- package/dist/index.d.ts +29 -8
- package/dist/index.js +35 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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(
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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
|
}
|