@cemiar/auth-sdk 1.0.20 → 1.0.22

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.
@@ -5,12 +5,11 @@ export declare class CemiarAuthClient implements CemiarAuthClientInstance {
5
5
  private readonly tenantId;
6
6
  private readonly auds;
7
7
  private readonly redirectUrl?;
8
- private storage;
9
- private readonly onTokenChange?;
10
8
  private readonly onAuthFailure?;
11
- private readonly logoutRedirectUrl?;
9
+ private storage;
12
10
  private loginMethod;
13
- private refreshPromise;
11
+ private isRefreshing;
12
+ private failedQueue;
14
13
  constructor(config: CemiarAuthClientConfig);
15
14
  getAccessToken(): string | null;
16
15
  setAccessToken(token: string | null): void;
@@ -24,9 +23,8 @@ export declare class CemiarAuthClient implements CemiarAuthClientInstance {
24
23
  createApiClient(options: CreateApiClientOptions): AxiosInstance;
25
24
  attachInterceptors(instance: AxiosInstance): AxiosInstance;
26
25
  private addAuthHeader;
26
+ private processQueue;
27
27
  private handleResponseError;
28
- private queueTokenRefresh;
29
- private handleAuthFailure;
30
28
  private loadLoginMethodFromStorage;
31
29
  private persistLoginMethod;
32
30
  private getCurrentLoginMethod;
@@ -15,31 +15,27 @@ function extractAccessToken(data) {
15
15
  }
16
16
  export class CemiarAuthClient {
17
17
  constructor(config) {
18
- var _a, _b, _c;
18
+ var _a, _b;
19
19
  this.storage = createDefaultTokenStorage();
20
- this.refreshPromise = null;
20
+ this.isRefreshing = false;
21
+ this.failedQueue = [];
21
22
  this.baseUrl = normalizeBaseUrl(config.baseUrl || "http://localhost:3000") + "/auth";
22
23
  this.tenantId = config.tenantId;
23
24
  this.auds = parseAuds(config.auds);
24
25
  this.redirectUrl =
25
26
  (_a = config.redirectUrl) !== null && _a !== void 0 ? _a : (isBrowser ? `${window.location.origin}/auth/microsoft/callback` : undefined);
26
- this.onTokenChange = config.onTokenChange;
27
+ this.storage = (_b = config.storage) !== null && _b !== void 0 ? _b : createDefaultTokenStorage();
27
28
  this.onAuthFailure = config.onAuthFailure;
28
- this.logoutRedirectUrl =
29
- (_b = config.logoutRedirectUrl) !== null && _b !== void 0 ? _b : (isBrowser ? `${window.location.origin}/login` : undefined);
30
- this.storage = (_c = config.storage) !== null && _c !== void 0 ? _c : createDefaultTokenStorage();
31
29
  this.loginMethod = this.loadLoginMethodFromStorage();
32
30
  }
33
31
  getAccessToken() {
34
32
  return this.storage.getToken();
35
33
  }
36
34
  setAccessToken(token) {
37
- var _a;
38
35
  this.storage.setToken(token);
39
36
  if (token === null) {
40
37
  this.persistLoginMethod(null);
41
38
  }
42
- (_a = this.onTokenChange) === null || _a === void 0 ? void 0 : _a.call(this, token);
43
39
  }
44
40
  async authPost(path, body, withCredentials = true) {
45
41
  const url = `${this.baseUrl}${path}`;
@@ -133,40 +129,55 @@ export class CemiarAuthClient {
133
129
  }
134
130
  return config;
135
131
  }
132
+ processQueue(error, token = null) {
133
+ this.failedQueue.forEach(request => {
134
+ if (error) {
135
+ request.reject(error);
136
+ }
137
+ else if (token) {
138
+ request.resolve(token);
139
+ }
140
+ });
141
+ this.failedQueue = [];
142
+ }
136
143
  async handleResponseError(error, instance) {
137
- var _a;
144
+ var _a, _b;
138
145
  const status = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
139
146
  const originalRequest = error.config;
140
147
  if (status !== 401 || !originalRequest || originalRequest._retry) {
141
148
  return Promise.reject(error);
142
149
  }
150
+ // If already refreshing, queue this request to wait for the token
151
+ if (this.isRefreshing) {
152
+ return new Promise((resolve, reject) => {
153
+ this.failedQueue.push({ resolve, reject });
154
+ }).then(token => {
155
+ if (originalRequest.headers) {
156
+ originalRequest.headers.Authorization = `Bearer ${token}`;
157
+ }
158
+ return instance(originalRequest);
159
+ });
160
+ }
143
161
  originalRequest._retry = true;
162
+ this.isRefreshing = true;
144
163
  try {
145
- const newToken = await this.queueTokenRefresh();
164
+ const { accessToken: newToken } = await this.refreshToken();
165
+ this.processQueue(null, newToken);
146
166
  if (originalRequest.headers) {
147
167
  originalRequest.headers.Authorization = `Bearer ${newToken}`;
148
168
  }
149
- return instance(originalRequest);
169
+ const response = await instance(originalRequest);
170
+ return response;
150
171
  }
151
172
  catch (refreshError) {
152
- this.handleAuthFailure();
173
+ this.processQueue(refreshError, null);
174
+ this.setAccessToken(null);
175
+ (_b = this.onAuthFailure) === null || _b === void 0 ? void 0 : _b.call(this);
153
176
  return Promise.reject(refreshError);
154
177
  }
155
- }
156
- async queueTokenRefresh() {
157
- if (!this.refreshPromise) {
158
- this.refreshPromise = this.refreshToken()
159
- .then(tokens => tokens.accessToken)
160
- .finally(() => {
161
- this.refreshPromise = null;
162
- });
178
+ finally {
179
+ this.isRefreshing = false;
163
180
  }
164
- return this.refreshPromise;
165
- }
166
- handleAuthFailure() {
167
- var _a;
168
- this.setAccessToken(null);
169
- (_a = this.onAuthFailure) === null || _a === void 0 ? void 0 : _a.call(this);
170
181
  }
171
182
  loadLoginMethodFromStorage() {
172
183
  if (!isBrowser || !("localStorage" in globalThis)) {
@@ -17,7 +17,6 @@ export interface CemiarAuthClientConfig {
17
17
  storage?: TokenStorage;
18
18
  onTokenChange?: (token: string | null) => void;
19
19
  onAuthFailure?: () => void;
20
- logoutRedirectUrl?: string;
21
20
  }
22
21
  export interface AuthTokens {
23
22
  accessToken: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cemiar/auth-sdk",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "Cemiar Auth integration helpers for web apps and APIs.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",