diff --git a/src/core/AuthKitCore.ts b/src/core/AuthKitCore.ts index 181798c..dfbbb11 100644 --- a/src/core/AuthKitCore.ts +++ b/src/core/AuthKitCore.ts @@ -152,12 +152,14 @@ export class AuthKitCore { * * @param refreshToken - The refresh token * @param organizationId - Optional organization ID to switch to + * @param context - Optional context for error reporting (userId, sessionId) * @returns New access token, refresh token, user, and impersonator * @throws TokenRefreshError if refresh fails */ async refreshTokens( refreshToken: string, organizationId?: string, + context?: { userId?: string; sessionId?: string }, ): Promise<{ accessToken: string; refreshToken: string; @@ -179,7 +181,7 @@ export class AuthKitCore { impersonator: result.impersonator, }; } catch (error) { - throw new TokenRefreshError('Failed to refresh tokens', error); + throw new TokenRefreshError('Failed to refresh tokens', error, context); } } @@ -226,9 +228,18 @@ export class AuthKitCore { } } + // Extract session ID for error context (works on expired tokens too) + let sessionId: string | undefined; + try { + sessionId = this.parseTokenClaims(accessToken).sid; + } catch { + // Token parsing failed - continue without session context + } + const newSession = await this.refreshTokens( session.refreshToken, organizationId, + { userId: session.user?.id, sessionId }, ); const newClaims = this.parseTokenClaims( newSession.accessToken, diff --git a/src/core/errors.spec.ts b/src/core/errors.spec.ts index 8561a0e..c75d959 100644 --- a/src/core/errors.spec.ts +++ b/src/core/errors.spec.ts @@ -93,6 +93,53 @@ describe('TokenRefreshError', () => { expect(error.cause).toBe(originalError); }); + + it('creates error with userId and sessionId', () => { + const error = new TokenRefreshError('Refresh failed', undefined, { + userId: 'user_123', + sessionId: 'session_456', + }); + + expect(error.userId).toBe('user_123'); + expect(error.sessionId).toBe('session_456'); + }); + + it('creates error with cause and context', () => { + const originalError = new Error('Network error'); + const error = new TokenRefreshError('Refresh failed', originalError, { + userId: 'user_123', + sessionId: 'session_456', + }); + + expect(error.cause).toBe(originalError); + expect(error.userId).toBe('user_123'); + expect(error.sessionId).toBe('session_456'); + }); + + it('creates error with partial context (userId only)', () => { + const error = new TokenRefreshError('Refresh failed', undefined, { + userId: 'user_123', + }); + + expect(error.userId).toBe('user_123'); + expect(error.sessionId).toBeUndefined(); + }); + + it('creates error with partial context (sessionId only)', () => { + const error = new TokenRefreshError('Refresh failed', undefined, { + sessionId: 'session_456', + }); + + expect(error.userId).toBeUndefined(); + expect(error.sessionId).toBe('session_456'); + }); + + it('has undefined properties when no context provided', () => { + const error = new TokenRefreshError('Refresh failed'); + + expect(error.userId).toBeUndefined(); + expect(error.sessionId).toBeUndefined(); + }); }); describe('error inheritance', () => { diff --git a/src/core/errors.ts b/src/core/errors.ts index cdb9bf3..313c62c 100644 --- a/src/core/errors.ts +++ b/src/core/errors.ts @@ -24,8 +24,17 @@ export class TokenValidationError extends AuthKitError { } export class TokenRefreshError extends AuthKitError { - constructor(message: string, cause?: unknown) { + readonly userId?: string; + readonly sessionId?: string; + + constructor( + message: string, + cause?: unknown, + context?: { userId?: string; sessionId?: string }, + ) { super(message, cause); this.name = 'TokenRefreshError'; + this.userId = context?.userId; + this.sessionId = context?.sessionId; } } diff --git a/src/index.ts b/src/index.ts index bded98d..511c63d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -58,6 +58,16 @@ export { ConfigurationProvider } from './core/config/ConfigurationProvider.js'; // ============================================ export { getWorkOS } from './core/client/workos.js'; +// ============================================ +// Errors +// ============================================ +export { + AuthKitError, + SessionEncryptionError, + TokenValidationError, + TokenRefreshError, +} from './core/errors.js'; + // ============================================ // Type Exports // ============================================