@hamak/auth 0.5.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.
Files changed (116) hide show
  1. package/README.md +366 -0
  2. package/dist/api/api/auth-service.d.ts +111 -0
  3. package/dist/api/api/auth-service.d.ts.map +1 -0
  4. package/dist/api/api/auth-service.js +5 -0
  5. package/dist/api/api/index.d.ts +2 -0
  6. package/dist/api/api/index.d.ts.map +1 -0
  7. package/dist/api/api/index.js +1 -0
  8. package/dist/api/index.d.ts +10 -0
  9. package/dist/api/index.d.ts.map +1 -0
  10. package/dist/api/index.js +12 -0
  11. package/dist/api/tokens/index.d.ts +2 -0
  12. package/dist/api/tokens/index.d.ts.map +1 -0
  13. package/dist/api/tokens/index.js +1 -0
  14. package/dist/api/tokens/service-tokens.d.ts +26 -0
  15. package/dist/api/tokens/service-tokens.d.ts.map +1 -0
  16. package/dist/api/tokens/service-tokens.js +25 -0
  17. package/dist/api/types/auth-result.d.ts +69 -0
  18. package/dist/api/types/auth-result.d.ts.map +1 -0
  19. package/dist/api/types/auth-result.js +5 -0
  20. package/dist/api/types/config.d.ts +130 -0
  21. package/dist/api/types/config.d.ts.map +1 -0
  22. package/dist/api/types/config.js +5 -0
  23. package/dist/api/types/credentials.d.ts +52 -0
  24. package/dist/api/types/credentials.d.ts.map +1 -0
  25. package/dist/api/types/credentials.js +5 -0
  26. package/dist/api/types/index.d.ts +5 -0
  27. package/dist/api/types/index.d.ts.map +1 -0
  28. package/dist/api/types/index.js +4 -0
  29. package/dist/api/types/user.d.ts +39 -0
  30. package/dist/api/types/user.d.ts.map +1 -0
  31. package/dist/api/types/user.js +5 -0
  32. package/dist/impl/index.d.ts +15 -0
  33. package/dist/impl/index.d.ts.map +1 -0
  34. package/dist/impl/index.js +21 -0
  35. package/dist/impl/plugin/auth-plugin-factory.d.ts +20 -0
  36. package/dist/impl/plugin/auth-plugin-factory.d.ts.map +1 -0
  37. package/dist/impl/plugin/auth-plugin-factory.js +226 -0
  38. package/dist/impl/plugin/index.d.ts +2 -0
  39. package/dist/impl/plugin/index.d.ts.map +1 -0
  40. package/dist/impl/plugin/index.js +1 -0
  41. package/dist/impl/services/AuthService.d.ts +44 -0
  42. package/dist/impl/services/AuthService.d.ts.map +1 -0
  43. package/dist/impl/services/AuthService.js +277 -0
  44. package/dist/impl/services/index.d.ts +2 -0
  45. package/dist/impl/services/index.d.ts.map +1 -0
  46. package/dist/impl/services/index.js +1 -0
  47. package/dist/impl/storage/LocalTokenStorage.d.ts +32 -0
  48. package/dist/impl/storage/LocalTokenStorage.d.ts.map +1 -0
  49. package/dist/impl/storage/LocalTokenStorage.js +148 -0
  50. package/dist/impl/storage/MemoryTokenStorage.d.ts +34 -0
  51. package/dist/impl/storage/MemoryTokenStorage.d.ts.map +1 -0
  52. package/dist/impl/storage/MemoryTokenStorage.js +91 -0
  53. package/dist/impl/storage/SessionTokenStorage.d.ts +33 -0
  54. package/dist/impl/storage/SessionTokenStorage.d.ts.map +1 -0
  55. package/dist/impl/storage/SessionTokenStorage.js +147 -0
  56. package/dist/impl/storage/index.d.ts +10 -0
  57. package/dist/impl/storage/index.d.ts.map +1 -0
  58. package/dist/impl/storage/index.js +26 -0
  59. package/dist/impl/store/auth-reducer.d.ts +135 -0
  60. package/dist/impl/store/auth-reducer.d.ts.map +1 -0
  61. package/dist/impl/store/auth-reducer.js +179 -0
  62. package/dist/impl/store/index.d.ts +2 -0
  63. package/dist/impl/store/index.d.ts.map +1 -0
  64. package/dist/impl/store/index.js +1 -0
  65. package/dist/impl/strategies/KeycloakStrategy.d.ts +42 -0
  66. package/dist/impl/strategies/KeycloakStrategy.d.ts.map +1 -0
  67. package/dist/impl/strategies/KeycloakStrategy.js +237 -0
  68. package/dist/impl/strategies/OAuth2Strategy.d.ts +30 -0
  69. package/dist/impl/strategies/OAuth2Strategy.d.ts.map +1 -0
  70. package/dist/impl/strategies/OAuth2Strategy.js +232 -0
  71. package/dist/impl/strategies/PasswordStrategy.d.ts +25 -0
  72. package/dist/impl/strategies/PasswordStrategy.d.ts.map +1 -0
  73. package/dist/impl/strategies/PasswordStrategy.js +159 -0
  74. package/dist/impl/strategies/StrategyRegistry.d.ts +24 -0
  75. package/dist/impl/strategies/StrategyRegistry.d.ts.map +1 -0
  76. package/dist/impl/strategies/StrategyRegistry.js +70 -0
  77. package/dist/impl/strategies/index.d.ts +5 -0
  78. package/dist/impl/strategies/index.d.ts.map +1 -0
  79. package/dist/impl/strategies/index.js +4 -0
  80. package/dist/impl/utils/index.d.ts +3 -0
  81. package/dist/impl/utils/index.d.ts.map +1 -0
  82. package/dist/impl/utils/index.js +2 -0
  83. package/dist/impl/utils/jwt.d.ts +81 -0
  84. package/dist/impl/utils/jwt.d.ts.map +1 -0
  85. package/dist/impl/utils/jwt.js +103 -0
  86. package/dist/impl/utils/pkce.d.ts +44 -0
  87. package/dist/impl/utils/pkce.d.ts.map +1 -0
  88. package/dist/impl/utils/pkce.js +93 -0
  89. package/dist/index.d.ts +12 -0
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +11 -0
  92. package/dist/spi/guards/AuthGuard.d.ts +108 -0
  93. package/dist/spi/guards/AuthGuard.d.ts.map +1 -0
  94. package/dist/spi/guards/AuthGuard.js +5 -0
  95. package/dist/spi/guards/index.d.ts +2 -0
  96. package/dist/spi/guards/index.d.ts.map +1 -0
  97. package/dist/spi/guards/index.js +1 -0
  98. package/dist/spi/index.d.ts +12 -0
  99. package/dist/spi/index.d.ts.map +1 -0
  100. package/dist/spi/index.js +15 -0
  101. package/dist/spi/storage/ITokenStorage.d.ts +107 -0
  102. package/dist/spi/storage/ITokenStorage.d.ts.map +1 -0
  103. package/dist/spi/storage/ITokenStorage.js +5 -0
  104. package/dist/spi/storage/index.d.ts +2 -0
  105. package/dist/spi/storage/index.d.ts.map +1 -0
  106. package/dist/spi/storage/index.js +1 -0
  107. package/dist/spi/strategies/IAuthStrategy.d.ts +114 -0
  108. package/dist/spi/strategies/IAuthStrategy.d.ts.map +1 -0
  109. package/dist/spi/strategies/IAuthStrategy.js +16 -0
  110. package/dist/spi/strategies/IStrategyRegistry.d.ts +64 -0
  111. package/dist/spi/strategies/IStrategyRegistry.d.ts.map +1 -0
  112. package/dist/spi/strategies/IStrategyRegistry.js +5 -0
  113. package/dist/spi/strategies/index.d.ts +3 -0
  114. package/dist/spi/strategies/index.d.ts.map +1 -0
  115. package/dist/spi/strategies/index.js +2 -0
  116. package/package.json +78 -0
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Auth Service Implementation
3
+ * Core authentication service that orchestrates strategies and storage
4
+ */
5
+ /**
6
+ * Auth service implementation
7
+ *
8
+ * Provides a unified authentication API that delegates to registered
9
+ * strategies and manages token storage and state.
10
+ */
11
+ export class AuthService {
12
+ constructor(strategyRegistry, tokenStorage) {
13
+ this.strategyRegistry = strategyRegistry;
14
+ this.tokenStorage = tokenStorage;
15
+ this.user = null;
16
+ this.listeners = new Set();
17
+ this.initialized = false;
18
+ }
19
+ // ============================================================
20
+ // Lifecycle
21
+ // ============================================================
22
+ async initialize() {
23
+ if (this.initialized) {
24
+ return;
25
+ }
26
+ // Restore user from storage
27
+ this.user = this.tokenStorage.getUser();
28
+ // Check if token is valid
29
+ if (this.tokenStorage.isTokenExpired()) {
30
+ // Try to refresh
31
+ const refreshToken = this.tokenStorage.getRefreshToken();
32
+ if (refreshToken) {
33
+ const result = await this.refreshToken();
34
+ if (!result.success) {
35
+ // Clear invalid session
36
+ this.tokenStorage.clearAll();
37
+ this.user = null;
38
+ }
39
+ }
40
+ else {
41
+ // No refresh token, clear session
42
+ this.tokenStorage.clearAll();
43
+ this.user = null;
44
+ }
45
+ }
46
+ this.initialized = true;
47
+ }
48
+ destroy() {
49
+ this.listeners.clear();
50
+ this.initialized = false;
51
+ }
52
+ // ============================================================
53
+ // State Queries
54
+ // ============================================================
55
+ isAuthenticated() {
56
+ return !!this.tokenStorage.getAccessToken() && !this.tokenStorage.isTokenExpired();
57
+ }
58
+ getCurrentUser() {
59
+ return this.user;
60
+ }
61
+ getAccessToken() {
62
+ return this.tokenStorage.getAccessToken();
63
+ }
64
+ getPermissions() {
65
+ return this.user?.permissions || [];
66
+ }
67
+ getRoles() {
68
+ return this.user?.roles || [];
69
+ }
70
+ hasPermission(permission) {
71
+ return this.getPermissions().includes(permission);
72
+ }
73
+ hasRole(role) {
74
+ return this.getRoles().includes(role);
75
+ }
76
+ hasAnyRole(roles) {
77
+ const userRoles = this.getRoles();
78
+ return roles.some((role) => userRoles.includes(role));
79
+ }
80
+ hasAllRoles(roles) {
81
+ const userRoles = this.getRoles();
82
+ return roles.every((role) => userRoles.includes(role));
83
+ }
84
+ // ============================================================
85
+ // Authentication Operations
86
+ // ============================================================
87
+ async login(credentials) {
88
+ const strategy = this.getStrategyForCredentials(credentials);
89
+ if (!strategy) {
90
+ return {
91
+ success: false,
92
+ error: {
93
+ code: 'server_error',
94
+ message: 'No suitable authentication strategy found'
95
+ }
96
+ };
97
+ }
98
+ const result = await strategy.authenticate(credentials);
99
+ if (result.success) {
100
+ this.handleAuthSuccess(result, 'login');
101
+ }
102
+ return result;
103
+ }
104
+ async logout() {
105
+ const accessToken = this.tokenStorage.getAccessToken();
106
+ const strategy = this.strategyRegistry.getDefault();
107
+ if (accessToken && strategy) {
108
+ try {
109
+ await strategy.logout(accessToken);
110
+ }
111
+ catch {
112
+ // Continue with local logout even if server logout fails
113
+ }
114
+ }
115
+ this.tokenStorage.clearAll();
116
+ this.user = null;
117
+ this.notifyListeners('logout');
118
+ }
119
+ async refreshToken() {
120
+ const refreshToken = this.tokenStorage.getRefreshToken();
121
+ if (!refreshToken) {
122
+ return {
123
+ success: false,
124
+ error: {
125
+ code: 'no_refresh_token',
126
+ message: 'No refresh token available'
127
+ }
128
+ };
129
+ }
130
+ const strategy = this.strategyRegistry.getDefault();
131
+ if (!strategy) {
132
+ return {
133
+ success: false,
134
+ error: {
135
+ code: 'server_error',
136
+ message: 'No authentication strategy configured'
137
+ }
138
+ };
139
+ }
140
+ const result = await strategy.refreshToken(refreshToken);
141
+ if (result.success) {
142
+ this.handleAuthSuccess(result, 'token_refresh');
143
+ }
144
+ else if (result.error?.code === 'invalid_token' || result.error?.code === 'token_expired') {
145
+ // Refresh token is invalid, clear session
146
+ this.tokenStorage.clearAll();
147
+ this.user = null;
148
+ this.notifyListeners('session_expired');
149
+ }
150
+ return result;
151
+ }
152
+ // ============================================================
153
+ // OAuth Operations
154
+ // ============================================================
155
+ initiateOAuth(provider) {
156
+ const strategy = this.getOAuthStrategy(provider);
157
+ if (!strategy) {
158
+ console.error('No OAuth strategy found');
159
+ return;
160
+ }
161
+ // getAuthorizationUrl returns a Promise, need to handle it
162
+ Promise.resolve(strategy.getAuthorizationUrl()).then((url) => {
163
+ window.location.href = url;
164
+ });
165
+ }
166
+ async handleOAuthCallback(params) {
167
+ // Find OAuth strategy that matches the stored state
168
+ const strategies = this.strategyRegistry.getAllOAuth();
169
+ for (const strategy of strategies) {
170
+ const storedState = strategy.getStoredState();
171
+ if (storedState === params.state) {
172
+ const result = await strategy.handleCallback(params);
173
+ if (result.success) {
174
+ this.handleAuthSuccess(result, 'login');
175
+ }
176
+ return result;
177
+ }
178
+ }
179
+ // No matching strategy found, try default
180
+ const defaultStrategy = this.getOAuthStrategy();
181
+ if (defaultStrategy) {
182
+ const result = await defaultStrategy.handleCallback(params);
183
+ if (result.success) {
184
+ this.handleAuthSuccess(result, 'login');
185
+ }
186
+ return result;
187
+ }
188
+ return {
189
+ success: false,
190
+ error: {
191
+ code: 'invalid_state',
192
+ message: 'No matching OAuth strategy found for this callback'
193
+ }
194
+ };
195
+ }
196
+ getAuthorizationUrl(provider) {
197
+ const strategy = this.getOAuthStrategy(provider);
198
+ if (!strategy) {
199
+ return null;
200
+ }
201
+ // Note: This is synchronous but the actual method might be async
202
+ // For full compatibility, use initiateOAuth instead
203
+ const url = strategy.getAuthorizationUrl();
204
+ // If it's a promise, return null - caller should use initiateOAuth instead
205
+ if (url && typeof url === 'object' && 'then' in url) {
206
+ return null;
207
+ }
208
+ return url;
209
+ }
210
+ // ============================================================
211
+ // Event Subscriptions
212
+ // ============================================================
213
+ onAuthStateChange(callback) {
214
+ this.listeners.add(callback);
215
+ return () => this.listeners.delete(callback);
216
+ }
217
+ // ============================================================
218
+ // Private Helpers
219
+ // ============================================================
220
+ handleAuthSuccess(result, changeType) {
221
+ if (result.accessToken) {
222
+ this.tokenStorage.setAccessToken(result.accessToken, result.expiresAt);
223
+ }
224
+ if (result.refreshToken) {
225
+ this.tokenStorage.setRefreshToken(result.refreshToken);
226
+ }
227
+ if (result.user) {
228
+ this.user = result.user;
229
+ this.tokenStorage.setUser(result.user);
230
+ }
231
+ this.notifyListeners(changeType);
232
+ }
233
+ notifyListeners(changeType) {
234
+ const isAuthenticated = this.isAuthenticated();
235
+ this.listeners.forEach((callback) => {
236
+ try {
237
+ callback(isAuthenticated, this.user, changeType);
238
+ }
239
+ catch (error) {
240
+ console.error('Auth state callback error:', error);
241
+ }
242
+ });
243
+ }
244
+ getStrategyForCredentials(credentials) {
245
+ // For OAuth credentials with a provider, use that specific strategy
246
+ if (credentials.type === 'oauth' && credentials.provider) {
247
+ return this.strategyRegistry.get(credentials.provider);
248
+ }
249
+ // For password credentials, look for a password strategy
250
+ if (credentials.type === 'password') {
251
+ const strategies = this.strategyRegistry.getAll();
252
+ const passwordStrategy = strategies.find((s) => s.type === 'password');
253
+ if (passwordStrategy) {
254
+ return passwordStrategy;
255
+ }
256
+ // Some OAuth strategies (like Keycloak) support direct password auth
257
+ return this.strategyRegistry.getDefault();
258
+ }
259
+ // Default to the default strategy
260
+ return this.strategyRegistry.getDefault();
261
+ }
262
+ getOAuthStrategy(provider) {
263
+ if (provider) {
264
+ return this.strategyRegistry.getOAuth(provider);
265
+ }
266
+ // Return first OAuth strategy or default if it's OAuth
267
+ const defaultStrategy = this.strategyRegistry.getDefault();
268
+ if (defaultStrategy && this.isOAuthStrategy(defaultStrategy)) {
269
+ return defaultStrategy;
270
+ }
271
+ const oauthStrategies = this.strategyRegistry.getAllOAuth();
272
+ return oauthStrategies[0];
273
+ }
274
+ isOAuthStrategy(strategy) {
275
+ return 'getAuthorizationUrl' in strategy && 'handleCallback' in strategy;
276
+ }
277
+ }
@@ -0,0 +1,2 @@
1
+ export * from './AuthService';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/impl/services/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC"}
@@ -0,0 +1 @@
1
+ export * from './AuthService';
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Local Storage Token Storage Implementation
3
+ * Persists tokens using browser localStorage
4
+ */
5
+ import type { User } from '../../api';
6
+ import type { ITokenStorage, StoredTokens, TokenStorageConfig } from '../../spi';
7
+ /**
8
+ * Token storage implementation using localStorage
9
+ */
10
+ export declare class LocalTokenStorage implements ITokenStorage {
11
+ private readonly keyPrefix;
12
+ constructor(config?: TokenStorageConfig);
13
+ private getKey;
14
+ private getItem;
15
+ private setItem;
16
+ private removeItem;
17
+ getAccessToken(): string | null;
18
+ setAccessToken(token: string, expiresAt?: number): void;
19
+ getRefreshToken(): string | null;
20
+ setRefreshToken(token: string): void;
21
+ getTokens(): StoredTokens | null;
22
+ setTokens(tokens: StoredTokens): void;
23
+ clearTokens(): void;
24
+ isTokenExpired(): boolean;
25
+ isTokenExpiringSoon(thresholdMs: number): boolean;
26
+ getTokenExpiry(): number | null;
27
+ getUser(): User | null;
28
+ setUser(user: User): void;
29
+ clearUser(): void;
30
+ clearAll(): void;
31
+ }
32
+ //# sourceMappingURL=LocalTokenStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocalTokenStorage.d.ts","sourceRoot":"","sources":["../../../src/impl/storage/LocalTokenStorage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAcjF;;GAEG;AACH,qBAAa,iBAAkB,YAAW,aAAa;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,MAAM,GAAE,kBAAuB;IAI3C,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,UAAU;IAQlB,cAAc,IAAI,MAAM,GAAG,IAAI;IAI/B,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAOvD,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpC,SAAS,IAAI,YAAY,GAAG,IAAI;IAkBhC,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAarC,WAAW,IAAI,IAAI;IAQnB,cAAc,IAAI,OAAO;IAezB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IASjD,cAAc,IAAI,MAAM,GAAG,IAAI;IAQ/B,OAAO,IAAI,IAAI,GAAG,IAAI;IAYtB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAIzB,SAAS,IAAI,IAAI;IAIjB,QAAQ,IAAI,IAAI;CAIjB"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Local Storage Token Storage Implementation
3
+ * Persists tokens using browser localStorage
4
+ */
5
+ /**
6
+ * Storage keys
7
+ */
8
+ const STORAGE_KEYS = {
9
+ ACCESS_TOKEN: 'accessToken',
10
+ REFRESH_TOKEN: 'refreshToken',
11
+ EXPIRES_AT: 'expiresAt',
12
+ TOKEN_TYPE: 'tokenType',
13
+ SCOPE: 'scope',
14
+ USER: 'user'
15
+ };
16
+ /**
17
+ * Token storage implementation using localStorage
18
+ */
19
+ export class LocalTokenStorage {
20
+ constructor(config = {}) {
21
+ this.keyPrefix = config.keyPrefix || '@hamak/auth';
22
+ }
23
+ getKey(key) {
24
+ return `${this.keyPrefix}:${key}`;
25
+ }
26
+ getItem(key) {
27
+ try {
28
+ return localStorage.getItem(this.getKey(key));
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ setItem(key, value) {
35
+ try {
36
+ localStorage.setItem(this.getKey(key), value);
37
+ }
38
+ catch {
39
+ // Storage might be full or disabled
40
+ console.warn('Failed to store item in localStorage:', key);
41
+ }
42
+ }
43
+ removeItem(key) {
44
+ try {
45
+ localStorage.removeItem(this.getKey(key));
46
+ }
47
+ catch {
48
+ // Ignore errors
49
+ }
50
+ }
51
+ getAccessToken() {
52
+ return this.getItem(STORAGE_KEYS.ACCESS_TOKEN);
53
+ }
54
+ setAccessToken(token, expiresAt) {
55
+ this.setItem(STORAGE_KEYS.ACCESS_TOKEN, token);
56
+ if (expiresAt !== undefined) {
57
+ this.setItem(STORAGE_KEYS.EXPIRES_AT, String(expiresAt));
58
+ }
59
+ }
60
+ getRefreshToken() {
61
+ return this.getItem(STORAGE_KEYS.REFRESH_TOKEN);
62
+ }
63
+ setRefreshToken(token) {
64
+ this.setItem(STORAGE_KEYS.REFRESH_TOKEN, token);
65
+ }
66
+ getTokens() {
67
+ const accessToken = this.getAccessToken();
68
+ if (!accessToken) {
69
+ return null;
70
+ }
71
+ const expiresAtStr = this.getItem(STORAGE_KEYS.EXPIRES_AT);
72
+ const scopeStr = this.getItem(STORAGE_KEYS.SCOPE);
73
+ return {
74
+ accessToken,
75
+ refreshToken: this.getRefreshToken() || undefined,
76
+ tokenType: this.getItem(STORAGE_KEYS.TOKEN_TYPE) || 'Bearer',
77
+ expiresAt: expiresAtStr ? parseInt(expiresAtStr, 10) : undefined,
78
+ scope: scopeStr ? JSON.parse(scopeStr) : undefined
79
+ };
80
+ }
81
+ setTokens(tokens) {
82
+ this.setAccessToken(tokens.accessToken, tokens.expiresAt);
83
+ if (tokens.refreshToken) {
84
+ this.setRefreshToken(tokens.refreshToken);
85
+ }
86
+ if (tokens.tokenType) {
87
+ this.setItem(STORAGE_KEYS.TOKEN_TYPE, tokens.tokenType);
88
+ }
89
+ if (tokens.scope) {
90
+ this.setItem(STORAGE_KEYS.SCOPE, JSON.stringify(tokens.scope));
91
+ }
92
+ }
93
+ clearTokens() {
94
+ this.removeItem(STORAGE_KEYS.ACCESS_TOKEN);
95
+ this.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
96
+ this.removeItem(STORAGE_KEYS.EXPIRES_AT);
97
+ this.removeItem(STORAGE_KEYS.TOKEN_TYPE);
98
+ this.removeItem(STORAGE_KEYS.SCOPE);
99
+ }
100
+ isTokenExpired() {
101
+ const accessToken = this.getAccessToken();
102
+ if (!accessToken) {
103
+ return true;
104
+ }
105
+ const expiresAt = this.getTokenExpiry();
106
+ if (!expiresAt) {
107
+ // No expiry info, assume valid
108
+ return false;
109
+ }
110
+ return Date.now() >= expiresAt;
111
+ }
112
+ isTokenExpiringSoon(thresholdMs) {
113
+ const expiresAt = this.getTokenExpiry();
114
+ if (!expiresAt) {
115
+ return false;
116
+ }
117
+ return Date.now() + thresholdMs >= expiresAt;
118
+ }
119
+ getTokenExpiry() {
120
+ const expiresAtStr = this.getItem(STORAGE_KEYS.EXPIRES_AT);
121
+ if (!expiresAtStr) {
122
+ return null;
123
+ }
124
+ return parseInt(expiresAtStr, 10);
125
+ }
126
+ getUser() {
127
+ const userStr = this.getItem(STORAGE_KEYS.USER);
128
+ if (!userStr) {
129
+ return null;
130
+ }
131
+ try {
132
+ return JSON.parse(userStr);
133
+ }
134
+ catch {
135
+ return null;
136
+ }
137
+ }
138
+ setUser(user) {
139
+ this.setItem(STORAGE_KEYS.USER, JSON.stringify(user));
140
+ }
141
+ clearUser() {
142
+ this.removeItem(STORAGE_KEYS.USER);
143
+ }
144
+ clearAll() {
145
+ this.clearTokens();
146
+ this.clearUser();
147
+ }
148
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Memory Token Storage Implementation
3
+ * Stores tokens in memory (cleared on page refresh)
4
+ */
5
+ import type { User } from '../../api';
6
+ import type { ITokenStorage, StoredTokens } from '../../spi';
7
+ /**
8
+ * Token storage implementation using in-memory storage
9
+ * Tokens are cleared when the page is refreshed
10
+ * Useful for high-security scenarios where persistence is not desired
11
+ */
12
+ export declare class MemoryTokenStorage implements ITokenStorage {
13
+ private accessToken;
14
+ private refreshToken;
15
+ private expiresAt;
16
+ private tokenType;
17
+ private scope;
18
+ private user;
19
+ getAccessToken(): string | null;
20
+ setAccessToken(token: string, expiresAt?: number): void;
21
+ getRefreshToken(): string | null;
22
+ setRefreshToken(token: string): void;
23
+ getTokens(): StoredTokens | null;
24
+ setTokens(tokens: StoredTokens): void;
25
+ clearTokens(): void;
26
+ isTokenExpired(): boolean;
27
+ isTokenExpiringSoon(thresholdMs: number): boolean;
28
+ getTokenExpiry(): number | null;
29
+ getUser(): User | null;
30
+ setUser(user: User): void;
31
+ clearUser(): void;
32
+ clearAll(): void;
33
+ }
34
+ //# sourceMappingURL=MemoryTokenStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoryTokenStorage.d.ts","sourceRoot":"","sources":["../../../src/impl/storage/MemoryTokenStorage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE7D;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,aAAa;IACtD,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,IAAI,CAAqB;IAEjC,cAAc,IAAI,MAAM,GAAG,IAAI;IAI/B,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAOvD,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpC,SAAS,IAAI,YAAY,GAAG,IAAI;IAchC,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAQrC,WAAW,IAAI,IAAI;IAQnB,cAAc,IAAI,OAAO;IAYzB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAQjD,cAAc,IAAI,MAAM,GAAG,IAAI;IAI/B,OAAO,IAAI,IAAI,GAAG,IAAI;IAItB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAIzB,SAAS,IAAI,IAAI;IAIjB,QAAQ,IAAI,IAAI;CAIjB"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Memory Token Storage Implementation
3
+ * Stores tokens in memory (cleared on page refresh)
4
+ */
5
+ /**
6
+ * Token storage implementation using in-memory storage
7
+ * Tokens are cleared when the page is refreshed
8
+ * Useful for high-security scenarios where persistence is not desired
9
+ */
10
+ export class MemoryTokenStorage {
11
+ constructor() {
12
+ this.accessToken = null;
13
+ this.refreshToken = null;
14
+ this.expiresAt = null;
15
+ this.tokenType = 'Bearer';
16
+ this.scope = null;
17
+ this.user = null;
18
+ }
19
+ getAccessToken() {
20
+ return this.accessToken;
21
+ }
22
+ setAccessToken(token, expiresAt) {
23
+ this.accessToken = token;
24
+ if (expiresAt !== undefined) {
25
+ this.expiresAt = expiresAt;
26
+ }
27
+ }
28
+ getRefreshToken() {
29
+ return this.refreshToken;
30
+ }
31
+ setRefreshToken(token) {
32
+ this.refreshToken = token;
33
+ }
34
+ getTokens() {
35
+ if (!this.accessToken) {
36
+ return null;
37
+ }
38
+ return {
39
+ accessToken: this.accessToken,
40
+ refreshToken: this.refreshToken || undefined,
41
+ tokenType: this.tokenType,
42
+ expiresAt: this.expiresAt || undefined,
43
+ scope: this.scope || undefined
44
+ };
45
+ }
46
+ setTokens(tokens) {
47
+ this.accessToken = tokens.accessToken;
48
+ this.refreshToken = tokens.refreshToken || null;
49
+ this.expiresAt = tokens.expiresAt || null;
50
+ this.tokenType = tokens.tokenType || 'Bearer';
51
+ this.scope = tokens.scope || null;
52
+ }
53
+ clearTokens() {
54
+ this.accessToken = null;
55
+ this.refreshToken = null;
56
+ this.expiresAt = null;
57
+ this.tokenType = 'Bearer';
58
+ this.scope = null;
59
+ }
60
+ isTokenExpired() {
61
+ if (!this.accessToken) {
62
+ return true;
63
+ }
64
+ if (!this.expiresAt) {
65
+ return false;
66
+ }
67
+ return Date.now() >= this.expiresAt;
68
+ }
69
+ isTokenExpiringSoon(thresholdMs) {
70
+ if (!this.expiresAt) {
71
+ return false;
72
+ }
73
+ return Date.now() + thresholdMs >= this.expiresAt;
74
+ }
75
+ getTokenExpiry() {
76
+ return this.expiresAt;
77
+ }
78
+ getUser() {
79
+ return this.user;
80
+ }
81
+ setUser(user) {
82
+ this.user = user;
83
+ }
84
+ clearUser() {
85
+ this.user = null;
86
+ }
87
+ clearAll() {
88
+ this.clearTokens();
89
+ this.clearUser();
90
+ }
91
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Session Storage Token Storage Implementation
3
+ * Persists tokens using browser sessionStorage (cleared when tab closes)
4
+ */
5
+ import type { User } from '../../api';
6
+ import type { ITokenStorage, StoredTokens, TokenStorageConfig } from '../../spi';
7
+ /**
8
+ * Token storage implementation using sessionStorage
9
+ * Tokens are cleared when the browser tab is closed
10
+ */
11
+ export declare class SessionTokenStorage implements ITokenStorage {
12
+ private readonly keyPrefix;
13
+ constructor(config?: TokenStorageConfig);
14
+ private getKey;
15
+ private getItem;
16
+ private setItem;
17
+ private removeItem;
18
+ getAccessToken(): string | null;
19
+ setAccessToken(token: string, expiresAt?: number): void;
20
+ getRefreshToken(): string | null;
21
+ setRefreshToken(token: string): void;
22
+ getTokens(): StoredTokens | null;
23
+ setTokens(tokens: StoredTokens): void;
24
+ clearTokens(): void;
25
+ isTokenExpired(): boolean;
26
+ isTokenExpiringSoon(thresholdMs: number): boolean;
27
+ getTokenExpiry(): number | null;
28
+ getUser(): User | null;
29
+ setUser(user: User): void;
30
+ clearUser(): void;
31
+ clearAll(): void;
32
+ }
33
+ //# sourceMappingURL=SessionTokenStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionTokenStorage.d.ts","sourceRoot":"","sources":["../../../src/impl/storage/SessionTokenStorage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAcjF;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,aAAa;IACvD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,MAAM,GAAE,kBAAuB;IAI3C,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,UAAU;IAQlB,cAAc,IAAI,MAAM,GAAG,IAAI;IAI/B,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAOvD,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpC,SAAS,IAAI,YAAY,GAAG,IAAI;IAkBhC,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAarC,WAAW,IAAI,IAAI;IAQnB,cAAc,IAAI,OAAO;IAczB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IASjD,cAAc,IAAI,MAAM,GAAG,IAAI;IAQ/B,OAAO,IAAI,IAAI,GAAG,IAAI;IAYtB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAIzB,SAAS,IAAI,IAAI;IAIjB,QAAQ,IAAI,IAAI;CAIjB"}