@trimble-oss/trimble-id-react 1.0.0 → 1.0.2-rc1

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 CHANGED
@@ -67,7 +67,7 @@ process related to the authentication for you. Configure the SDK by wrapping you
67
67
 
68
68
  Here TIDProvider can take two parameters :
69
69
  * **tidClient** : TID client instance. You can send an instance of the TID Client if you want to handle the initialization yourself
70
- * **onRedirectCallback** - When the redirect callback occur this function will be call once the user is login using the TIDClient. This could allow you to redirect the user into another page after the login happen.
70
+ * **onRedirectCallback** - When the redirect callback occur this function will be call once the user is login using the TIDClient. This function receives an `authState` parameter that contains a `returnTo` property with the user's original location before authentication, allowing you to redirect the user back to their intended destination after login.
71
71
 
72
72
 
73
73
  After wrapping your app with the TIDProvider, you have to configure the TID credentials registered in TrimbleCloud console. There are two ways of doing this:
@@ -102,6 +102,15 @@ After wrapping your app with the TIDProvider, you have to configure the TID cred
102
102
  </TIDProvider>
103
103
  ```
104
104
 
105
+ ```tsx
106
+ const handleRedirect = (authState: AuthState) => {
107
+ // Use returnTo for automatic redirection to original location
108
+ const redirectTo = authState.returnTo || '/dashboard'
109
+ // Navigate to the intended destination
110
+ navigate(redirectTo)
111
+ }
112
+ ```
113
+
105
114
  Below are the parameters of TIDClient.
106
115
  ### 1. TID Client configurations:
107
116
 
@@ -131,6 +140,21 @@ const {logout}= useAuth()
131
140
  await logout()
132
141
  ```
133
142
 
143
+ ### handleCallback
144
+
145
+ Handle OAuth callback to complete user authentication and returns the auth state with redirect path.
146
+
147
+ ```tsx
148
+ const { handleCallback } = useAuth()
149
+
150
+ // Handle callback and get redirect information
151
+ const authState = await handleCallback()
152
+
153
+ // Use returnTo for automatic redirection to original location
154
+ const redirectTo = authState.returnTo || '/dashboard'
155
+ navigate(redirectTo)
156
+ ```
157
+
134
158
  ### isAuthenticated
135
159
 
136
160
  True if the user is authenticated.
@@ -198,7 +222,7 @@ See here for [Sample Code](https://github.com/trimble-oss/trimble-id-sdk-docs-fo
198
222
 
199
223
  ## Release notes
200
224
 
201
- See here for [releases](./CHANGELOG.md)
225
+ See here for [releases](https://github.com/trimble-oss/trimble-id-sdk-docs-for-react/blob/main/release-notes/CHANGELOG.md)
202
226
 
203
227
  ## Raise an issue
204
228
 
@@ -90,16 +90,15 @@ export declare class TIDClient {
90
90
  * @type {string}
91
91
  */
92
92
  private readonly redirectUrl;
93
- /**
94
- * AnalyticsHttpClient for sending events
95
- * @type {AnalyticsHttpClient}
96
- */
97
- private readonly analyticshttpclient;
98
93
  /**
99
94
  * Create a TID client to handle manage all user authentication functions and information
100
95
  * @param {CacheManagerOptions} props - TID client configuration
101
96
  */
102
97
  constructor(props: TIDClientOptions);
98
+ /**
99
+ * Clean up expired state payloads to prevent storage bloat
100
+ */
101
+ private cleanupExpiredState;
103
102
  /**
104
103
  * Redirect the user to TID using the browser
105
104
  * @param {LoginWithRedirectOptions} options - Custom configuration for the redirection
@@ -107,6 +106,7 @@ export declare class TIDClient {
107
106
  * @example No configuration
108
107
  * loginWithRedirect()
109
108
  * // Automatically redirects the user to TID with all necessary parameters
109
+ * // After authentication, user will be redirected back to the current page
110
110
  * @example Custom redirect
111
111
  * loginWithRedirect({onRedirect: (url) => router.navigate(url)})
112
112
  * // Redirect calls onRedirect with the log-out url for TID
@@ -116,8 +116,9 @@ export declare class TIDClient {
116
116
  /**
117
117
  * Authenticated the user using the url callback params
118
118
  * @param {string} url - Custom configuration for the redirection
119
- * @return {Promise<AuthState>} Object contain the state returned from TID
119
+ * @return {Promise<AuthState>} Object contain the state returned from TID and redirect path
120
120
  * @throws {CodeVerifierNotFoundException} Will throw an exception if the session doesn't contain the code verifier
121
+ * @throws {Error} Will throw an exception if state validation fails or replay attack is detected
121
122
  * @example No configuration
122
123
  * handleCallback()
123
124
  * // Will automatically take the url from the browser and try to log in the user
@@ -133,6 +134,23 @@ export declare class TIDClient {
133
134
  */
134
135
  private generateToken;
135
136
  private reloadCodeVerifier;
137
+ /**
138
+ * Create and encode state payload for replay attack protection
139
+ * @param {string} redirectTo - Path to redirect to after authentication
140
+ * @return {string} - Base64 encoded state payload
141
+ */
142
+ private createStatePayload;
143
+ /**
144
+ * Generate a random nonce for state validation
145
+ * @return {string} - Random nonce
146
+ */
147
+ private generateNonce;
148
+ /**
149
+ * Validate state payload to prevent replay attacks
150
+ * @param {string} receivedState - State received from OAuth callback
151
+ * @return {StateValidationResult} - Validation result with redirect path if valid
152
+ */
153
+ private validateStatePayload;
136
154
  /**
137
155
  * Return the user stored in cache
138
156
  * @return {Promise<TIDUser | undefined>} User in cache
@@ -8,3 +8,9 @@ export declare const CLOCK_SKEW_TIME: number;
8
8
  * @type {Array<string>}
9
9
  */
10
10
  export declare const LIST_PARAMS_REQUIRED: Array<string>;
11
+ /**
12
+ * Maximum time allowed for state parameter to be valid (10 minutes)
13
+ * Used to prevent replay attacks
14
+ * @type {number}
15
+ */
16
+ export declare const STATE_EXPIRATION_TIME: number;
@@ -6,3 +6,6 @@ export declare class TokenNotFoundException extends Error {
6
6
  }
7
7
  export declare class CodeVerifierNotFoundException extends Error {
8
8
  }
9
+ /** Class representing an OAuth state validation exception for CSRF protection */
10
+ export declare class StateValidationException extends Error {
11
+ }
@@ -51,6 +51,8 @@ export interface TIDUser {
51
51
  email?: string;
52
52
  /** True if the End-User's e-mail address has been verified; otherwise false. */
53
53
  email_verified?: boolean;
54
+ /** Account id of the user */
55
+ account_id?: string;
54
56
  }
55
57
  export interface TIDJWTUser {
56
58
  /**
@@ -172,7 +174,23 @@ export interface TIDJWTUser {
172
174
  * @type {string}
173
175
  */
174
176
  data_region: string;
177
+ /**
178
+ * Account id of the user
179
+ * @type {string}
180
+ */
181
+ account_id: string;
175
182
  }
176
183
  export interface AuthState {
177
184
  authState: any;
185
+ returnTo?: string;
186
+ }
187
+ export interface StatePayload {
188
+ redirectTo: string;
189
+ timestamp: number;
190
+ nonce: string;
191
+ }
192
+ export interface StateValidationResult {
193
+ isValid: boolean;
194
+ redirectTo?: string;
195
+ error?: string;
178
196
  }
@@ -12,6 +12,11 @@ interface CookieValue {
12
12
  * @type {string}
13
13
  */
14
14
  code_verifier: string;
15
+ /**
16
+ * State information used for replay attack protection
17
+ * @type {string}
18
+ */
19
+ state_payload?: string;
15
20
  }
16
21
  /** Class to manage cookies */
17
22
  export declare class CookiesManager {
@@ -32,9 +37,18 @@ export declare class CookiesManager {
32
37
  constructor(options: CookiesManagerOptions);
33
38
  /**
34
39
  * Store cookies in the browser
35
- * @param {CookieValue} value - information to store
40
+ * @param {Partial<CookieValue>} value - information to store
41
+ */
42
+ save(value: Partial<CookieValue>): void;
43
+ /**
44
+ * Retrieve state payload from cookies
45
+ * @return {string | undefined} - State payload from cookies
46
+ */
47
+ getStatePayload(): string | undefined;
48
+ /**
49
+ * Clear state payload from cookies
36
50
  */
37
- save(value: CookieValue): void;
51
+ clearStatePayload(): void;
38
52
  /**
39
53
  * Retrieve cookies in the browser
40
54
  * @return {CookieValue | undefined} - Cookies from the browser
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { TIDClient } from './TIDClient';
2
2
  export { TIDContext, useAuth, TIDProvider } from './TIDProvider';
3
3
  export { AuthenticationGuard } from './AuthenticationGuard/AuthenticationGuard';
4
- export type { TokenResponse } from './TIDClient';
4
+ export type { TokenResponse, AuthState } from './TIDClient';
@@ -1,75 +1,70 @@
1
- var F = Object.defineProperty;
2
- var B = (i, e, t) => e in i ? F(i, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : i[e] = t;
3
- var c = (i, e, t) => (B(i, typeof e != "symbol" ? e + "" : e, t), t);
4
- import { OpenIdEndpointProvider as $, AuthorizationCodeGrantTokenProvider as R, AnalyticsHttpClient as H, BearerTokenHttpClientProvider as Q } from "@trimble-oss/trimble-id";
5
- import * as w from "es-cookie";
1
+ import { OpenIdEndpointProvider as $, AuthorizationCodeGrantTokenProvider as R, AnalyticsHttpClient as h, BearerTokenHttpClientProvider as B } from "@trimble-oss/trimble-id";
2
+ import * as m from "es-cookie";
6
3
  import J from "jwt-decode";
7
- import { createContext as q, useContext as L, useState as z, useReducer as X, useRef as Y, useMemo as M, useEffect as D, useCallback as y } from "react";
8
- import { jsx as K, Fragment as Z } from "react/jsx-runtime";
9
- class j {
10
- constructor() {
11
- /**
12
- * This function generate a encapsulation function to store
13
- * the user and token information in a secure way disabled the
14
- * access from the outside
15
- * @see {https://medium.com/javascript-scene/encapsulation-in-javascript-26be60e325b4} Encapsulation
16
- * @return {CacheStorage} Key for the token
17
- */
18
- c(this, "generateCache", function() {
19
- const e = {
20
- token: void 0,
21
- user: void 0
22
- };
23
- return {
24
- /**
25
- * Get token store in cache
26
- * @return {Promise<TIDAuthToken | undefined>} Token store in memory
27
- */
28
- async getToken() {
29
- return e.token;
30
- },
31
- /**
32
- * Get user store in cache
33
- * @return {Promise<TIDUser | undefined>} User store in memory
34
- */
35
- async getUser() {
36
- return e.user;
37
- },
38
- /**
39
- * Store token in cache
40
- * @param {TIDAuthToken} token - Token that you want to store in cache
41
- * @return {Promise<void>} Empty promise
42
- */
43
- async storeToken(t) {
44
- e.token = t;
45
- },
46
- /**
47
- * Store user in cache
48
- * @param {TIDUser} user - User that you want to store in cache
49
- * @return {Promise<void>} Empty promise
50
- */
51
- async storeUser(t) {
52
- e.user = t;
53
- },
54
- /**
55
- * The clear the cache from the storage
56
- * @return {Promise<void>} Empty promise
57
- */
58
- clear() {
59
- return e.token = void 0, e.user = void 0, Promise.resolve(void 0);
60
- }
61
- };
62
- }());
63
- }
4
+ import { createContext as H, useContext as L, useState as Q, useReducer as X, useRef as q, useMemo as M, useEffect as N, useCallback as y } from "react";
5
+ import { jsx as V, Fragment as z } from "react/jsx-runtime";
6
+ class Y {
7
+ /**
8
+ * This function generate a encapsulation function to store
9
+ * the user and token information in a secure way disabled the
10
+ * access from the outside
11
+ * @see {https://medium.com/javascript-scene/encapsulation-in-javascript-26be60e325b4} Encapsulation
12
+ * @return {CacheStorage} Key for the token
13
+ */
14
+ generateCache = /* @__PURE__ */ (function() {
15
+ const e = {
16
+ token: void 0,
17
+ user: void 0
18
+ };
19
+ return {
20
+ /**
21
+ * Get token store in cache
22
+ * @return {Promise<TIDAuthToken | undefined>} Token store in memory
23
+ */
24
+ async getToken() {
25
+ return e.token;
26
+ },
27
+ /**
28
+ * Get user store in cache
29
+ * @return {Promise<TIDUser | undefined>} User store in memory
30
+ */
31
+ async getUser() {
32
+ return e.user;
33
+ },
34
+ /**
35
+ * Store token in cache
36
+ * @param {TIDAuthToken} token - Token that you want to store in cache
37
+ * @return {Promise<void>} Empty promise
38
+ */
39
+ async storeToken(t) {
40
+ e.token = t;
41
+ },
42
+ /**
43
+ * Store user in cache
44
+ * @param {TIDUser} user - User that you want to store in cache
45
+ * @return {Promise<void>} Empty promise
46
+ */
47
+ async storeUser(t) {
48
+ e.user = t;
49
+ },
50
+ /**
51
+ * The clear the cache from the storage
52
+ * @return {Promise<void>} Empty promise
53
+ */
54
+ clear() {
55
+ return e.token = void 0, e.user = void 0, Promise.resolve(void 0);
56
+ }
57
+ };
58
+ })();
64
59
  }
65
- class ee {
60
+ class Z {
61
+ /**
62
+ * Cache option selected
63
+ * @type {CacheStorage}
64
+ */
65
+ cacheStorage;
66
66
  constructor() {
67
- /**
68
- * Cache option selected
69
- * @type {CacheStorage}
70
- */
71
- c(this, "cacheStorage");
72
- this.cacheStorage = new j().generateCache;
67
+ this.cacheStorage = new Y().generateCache;
73
68
  }
74
69
  /**
75
70
  * Store token in cache
@@ -109,41 +104,42 @@ class ee {
109
104
  await this.cacheStorage.clear();
110
105
  }
111
106
  }
112
- const x = 5 * 6e4, te = ["code", "state"], A = (i) => i.split("?")[0], ie = (i) => i.split("?")[1], b = (i) => {
113
- let e = i;
114
- if (!i.startsWith("?"))
107
+ const x = 5 * 6e4, j = ["code", "state"], A = 600 * 1e3, U = (o) => o.split("?")[0], ee = (o) => o.split("?")[1], b = (o) => {
108
+ let e = o;
109
+ if (!o.startsWith("?"))
115
110
  try {
116
- e = new URL(i).search;
111
+ e = new URL(o).search;
117
112
  } catch {
118
113
  }
119
114
  return new URLSearchParams(e);
120
- }, ne = (i = window.location.href, e) => {
115
+ }, te = (o = window.location.href, e) => {
121
116
  if (e != null) {
122
- const n = A(e), r = A(i ?? "");
123
- if (n !== r)
117
+ const r = U(e), n = U(o ?? "");
118
+ if (r !== n)
124
119
  return !1;
125
120
  }
126
- const t = b(i);
127
- for (const n of te)
128
- if (!t.has(n))
121
+ const t = b(o);
122
+ for (const r of j)
123
+ if (!t.has(r))
129
124
  return !1;
130
125
  return !0;
131
- }, re = (i) => ({
132
- id: i.sub,
133
- name: `${i.given_name} ${i.family_name}`,
134
- given_name: i.given_name,
135
- family_name: i.family_name,
136
- picture: i.picture,
137
- email: i.email,
138
- email_verified: i.email_verified
139
- }), se = "@TID_COOKIE";
140
- class oe {
126
+ }, oe = (o) => ({
127
+ id: o.sub,
128
+ name: `${o.given_name} ${o.family_name}`,
129
+ given_name: o.given_name,
130
+ family_name: o.family_name,
131
+ picture: o.picture,
132
+ email: o.email,
133
+ email_verified: o.email_verified,
134
+ ...o.account_id && { account_id: o.account_id }
135
+ }), re = "@TID_COOKIE";
136
+ class ne {
141
137
  /**
142
138
  * Retrieve a cookie from the browser
143
139
  * @param {string} key - Key to retrieve the cookies
144
140
  */
145
141
  get(e) {
146
- const t = w.get(e);
142
+ const t = m.get(e);
147
143
  if (t == null)
148
144
  throw new Error("Cookie not found");
149
145
  return JSON.parse(t);
@@ -158,12 +154,12 @@ class oe {
158
154
  * @example Save cookies with a custom domain
159
155
  * cookiesStorage.set('key',{data:{...}},{domain:'https://example.com/subpath'})
160
156
  */
161
- set(e, t, n) {
162
- let r = {};
163
- window.location.protocol === "https:" && (r = {
157
+ set(e, t, r) {
158
+ let n = {};
159
+ window.location.protocol === "https:" && (n = {
164
160
  secure: !0,
165
161
  sameSite: "none"
166
- }), n != null && n.expires && (r.expires = n.expires), n != null && n.domain && (r.domain = n.domain), w.set(e, JSON.stringify(t), r);
162
+ }), r?.expires && (n.expires = r.expires), r?.domain && (n.domain = r.domain), m.set(e, JSON.stringify(t), n);
167
163
  }
168
164
  /**
169
165
  * Remove a cookie from the browser
@@ -175,37 +171,52 @@ class oe {
175
171
  * cookiesStorage.remove('key',{domain:'https://example.com/subpath'})
176
172
  */
177
173
  remove(e, t) {
178
- const n = {};
179
- t != null && t.domain && (n.domain = t.domain), w.remove(e, n);
174
+ const r = {};
175
+ t?.domain && (r.domain = t.domain), m.remove(e, r);
180
176
  }
181
177
  }
182
- class ae {
178
+ class ie {
179
+ /**
180
+ * Cookie full key to store and retrieve the information from cookies
181
+ * @type {string}
182
+ */
183
+ cookieKey;
184
+ /**
185
+ * Cookie storage. This object contain all functions necessary to retrieve and store tokens using cookies
186
+ * @type {CookiesStorage}
187
+ */
188
+ cookiesStorage;
183
189
  /**
184
190
  * Create a cookies manager to extract or save cookies in the browser
185
191
  * @param {CookiesManagerOptions} options - Configuration for the managing the cookies
186
192
  */
187
193
  constructor(e) {
188
- /**
189
- * Cookie full key to store and retrieve the information from cookies
190
- * @type {string}
191
- */
192
- c(this, "cookieKey");
193
- /**
194
- * Cookie storage. This object contain all functions necessary to retrieve and store tokens using cookies
195
- * @type {CookiesStorage}
196
- */
197
- c(this, "cookiesStorage");
198
- this.cookieKey = `${se}.${e.clientId}`, this.cookiesStorage = new oe();
194
+ this.cookieKey = `${re}.${e.clientId}`, this.cookiesStorage = new ne();
199
195
  }
200
196
  /**
201
197
  * Store cookies in the browser
202
- * @param {CookieValue} value - information to store
198
+ * @param {Partial<CookieValue>} value - information to store
203
199
  */
204
200
  save(e) {
205
- this.cookiesStorage.set(this.cookieKey, e, {
201
+ const r = { ...this.get() || {}, ...e };
202
+ this.cookiesStorage.set(this.cookieKey, r, {
206
203
  expires: 1
207
204
  });
208
205
  }
206
+ /**
207
+ * Retrieve state payload from cookies
208
+ * @return {string | undefined} - State payload from cookies
209
+ */
210
+ getStatePayload() {
211
+ return this.get()?.state_payload;
212
+ }
213
+ /**
214
+ * Clear state payload from cookies
215
+ */
216
+ clearStatePayload() {
217
+ const e = this.get();
218
+ e && (delete e.state_payload, this.cookiesStorage.set(this.cookieKey, e, { expires: 1 }));
219
+ }
209
220
  /**
210
221
  * Retrieve cookies in the browser
211
222
  * @return {CookieValue | undefined} - Cookies from the browser
@@ -224,70 +235,79 @@ class ae {
224
235
  this.cookiesStorage.remove(this.cookieKey);
225
236
  }
226
237
  }
227
- class U extends Error {
228
- }
229
238
  class O extends Error {
230
239
  }
231
- class ce extends Error {
240
+ class D extends Error {
232
241
  }
233
- const d = "@trimble-oss/trimble-id-react", h = "1.0.0", le = {
242
+ class ae extends Error {
243
+ }
244
+ const u = "@trimble-oss/trimble-id-react", g = "1.0.2-rc1", se = {
234
245
  configurationEndpoint: "",
235
246
  clientId: "",
236
247
  redirectUrl: "",
237
248
  logoutRedirectUrl: "",
238
249
  scopes: []
239
250
  };
240
- class de {
251
+ class ce {
252
+ /**
253
+ * Token provider SDK. This object handles all necessary communication with TID
254
+ * @type {AuthorizationCodeGrantTokenProvider}
255
+ */
256
+ tokenProvider;
257
+ /**
258
+ * This object manage all caching, and all configurations necessary
259
+ * @type {CacheManager}
260
+ */
261
+ cacheManager;
262
+ /**
263
+ * This object manage all cookies administration, and all configurations necessary
264
+ * @type {CookiesManager}
265
+ */
266
+ cookiesManager;
267
+ /**
268
+ * Client id of the application created in trimble developer console
269
+ * @type {string}
270
+ */
271
+ clientId;
272
+ /**
273
+ * Callback url to redirect the user after the authentication is successful
274
+ * @type {string}
275
+ */
276
+ redirectUrl;
241
277
  /**
242
278
  * Create a TID client to handle manage all user authentication functions and information
243
279
  * @param {CacheManagerOptions} props - TID client configuration
244
280
  */
245
281
  constructor(e) {
246
- /**
247
- * Token provider SDK. This object handles all necessary communication with TID
248
- * @type {AuthorizationCodeGrantTokenProvider}
249
- */
250
- c(this, "tokenProvider");
251
- /**
252
- * This object manage all caching, and all configurations necessary
253
- * @type {CacheManager}
254
- */
255
- c(this, "cacheManager");
256
- /**
257
- * This object manage all cookies administration, and all configurations necessary
258
- * @type {CookiesManager}
259
- */
260
- c(this, "cookiesManager");
261
- /**
262
- * Client id of the application created in trimble developer console
263
- * @type {string}
264
- */
265
- c(this, "clientId");
266
- /**
267
- * Callback url to redirect the user after the authentication is successful
268
- * @type {string}
269
- */
270
- c(this, "redirectUrl");
271
- /**
272
- * AnalyticsHttpClient for sending events
273
- * @type {AnalyticsHttpClient}
274
- */
275
- c(this, "analyticshttpclient");
276
- const { config: t = le } = e;
282
+ const { config: t = se } = e;
277
283
  if (this.redirectUrl = t.redirectUrl, t.configurationEndpoint == null || t.configurationEndpoint == "")
278
284
  throw new Error("Configuration endpoint not defined");
279
285
  if (t.clientId == null || t.clientId == "")
280
286
  throw new Error("Consumer key is not defined");
281
- this.cookiesManager = new ae({
287
+ this.cookiesManager = new ie({
282
288
  clientId: t.clientId
283
289
  });
284
- const n = this.cookiesManager.get(), r = new $(t.configurationEndpoint);
285
- let a = new R(
286
- r,
290
+ const r = this.cookiesManager.get(), n = new $(t.configurationEndpoint);
291
+ let i = new R(
292
+ n,
287
293
  t.clientId,
288
294
  t.redirectUrl
289
295
  ).WithScopes(t.scopes);
290
- t.logoutRedirectUrl && (a = a.WithLogoutRedirect(t.logoutRedirectUrl)), (n == null ? void 0 : n.code_verifier) != null && (a = a.WithProofKeyForCodeExchange(n.code_verifier)), this.tokenProvider = a, this.cacheManager = new ee(), this.clientId = t.clientId, this.analyticshttpclient = H, this.analyticshttpclient.sendInitEvent("TIDClient", this.clientId, d, h);
296
+ t.logoutRedirectUrl && (i = i.WithLogoutRedirect(t.logoutRedirectUrl)), r?.code_verifier != null && (i = i.WithProofKeyForCodeExchange(r.code_verifier)), this.tokenProvider = i, this.cacheManager = new Z(), this.clientId = t.clientId, h.sendInitEvent("TIDClient", this.clientId, u, g), this.cleanupExpiredState();
297
+ }
298
+ /**
299
+ * Clean up expired state payloads to prevent storage bloat
300
+ */
301
+ cleanupExpiredState() {
302
+ try {
303
+ const e = this.cookiesManager.getStatePayload();
304
+ if (e) {
305
+ const t = atob(e), r = JSON.parse(t);
306
+ Date.now() - r.timestamp > A && this.cookiesManager.clearStatePayload();
307
+ }
308
+ } catch {
309
+ this.cookiesManager.clearStatePayload();
310
+ }
291
311
  }
292
312
  /**
293
313
  * Redirect the user to TID using the browser
@@ -296,23 +316,27 @@ class de {
296
316
  * @example No configuration
297
317
  * loginWithRedirect()
298
318
  * // Automatically redirects the user to TID with all necessary parameters
319
+ * // After authentication, user will be redirected back to the current page
299
320
  * @example Custom redirect
300
321
  * loginWithRedirect({onRedirect: (url) => router.navigate(url)})
301
322
  * // Redirect calls onRedirect with the log-out url for TID
302
323
  * // So it can be handled by the developer
303
324
  */
304
325
  async loginWithRedirect(e) {
305
- this.analyticshttpclient.sendMethodEvent(this.loginWithRedirect.name, this.clientId, d, h);
306
- const { onRedirect: t } = e || {}, n = R.GenerateCodeVerifier();
307
- this.cookiesManager.save({ code_verifier: n }), this.tokenProvider = this.tokenProvider.WithProofKeyForCodeExchange(n);
308
- const r = await this.tokenProvider.GetOAuthRedirect("state");
309
- t != null ? t(r) : window.location.assign(r);
326
+ h.sendMethodEvent(this.loginWithRedirect.name, this.clientId, u, g);
327
+ const { onRedirect: t } = e || {}, r = window.location.pathname + window.location.search, n = this.createStatePayload(r);
328
+ this.cookiesManager.save({ state_payload: n });
329
+ const i = R.GenerateCodeVerifier();
330
+ this.cookiesManager.save({ code_verifier: i }), this.tokenProvider = this.tokenProvider.WithProofKeyForCodeExchange(i);
331
+ const c = await this.tokenProvider.GetOAuthRedirect(n);
332
+ t != null ? t(c) : window.location.assign(c);
310
333
  }
311
334
  /**
312
335
  * Authenticated the user using the url callback params
313
336
  * @param {string} url - Custom configuration for the redirection
314
- * @return {Promise<AuthState>} Object contain the state returned from TID
337
+ * @return {Promise<AuthState>} Object contain the state returned from TID and redirect path
315
338
  * @throws {CodeVerifierNotFoundException} Will throw an exception if the session doesn't contain the code verifier
339
+ * @throws {Error} Will throw an exception if state validation fails or replay attack is detected
316
340
  * @example No configuration
317
341
  * handleCallback()
318
342
  * // Will automatically take the url from the browser and try to log in the user
@@ -322,11 +346,14 @@ class de {
322
346
  */
323
347
  async handleCallback(e = window.location.href) {
324
348
  const t = this.cookiesManager.get();
325
- if (t == null || (t == null ? void 0 : t.code_verifier) == null)
326
- throw new ce("Code verifier not available");
327
- const n = ie(e), r = b(e), a = r.get("identity_provider") ?? "", g = r.get("state") ?? "";
328
- return await this.tokenProvider.ValidateQuery(n), await this.generateToken(a), {
329
- authState: g
349
+ if (t == null || t?.code_verifier == null)
350
+ throw new ae("Code verifier not available");
351
+ const r = ee(e), n = b(e), i = n.get("identity_provider") ?? "", c = n.get("state") ?? "", d = this.validateStatePayload(c);
352
+ if (!d.isValid)
353
+ throw new Error(`State validation failed: ${d.error}`);
354
+ return await this.tokenProvider.ValidateQuery(r), await this.generateToken(i), {
355
+ authState: c,
356
+ returnTo: d.redirectTo
330
357
  };
331
358
  }
332
359
  /**
@@ -335,32 +362,81 @@ class de {
335
362
  * @return {Promise<void>} Empty promise
336
363
  */
337
364
  async generateToken(e) {
338
- var s, f;
339
- const t = await this.tokenProvider.RetrieveToken(), n = await this.tokenProvider.RetrieveRefreshToken(), r = await this.tokenProvider.RetrieveIdToken(), a = await this.tokenProvider.RetrieveTokenExpiry(), k = new Date(a).getTime(), v = (f = (s = this.tokenProvider) == null ? void 0 : s._scopes) == null ? void 0 : f.join(" ");
365
+ const t = await this.tokenProvider.RetrieveToken(), r = await this.tokenProvider.RetrieveRefreshToken(), n = await this.tokenProvider.RetrieveIdToken(), i = await this.tokenProvider.RetrieveTokenExpiry(), d = new Date(i).getTime(), k = this.tokenProvider?._scopes?.join(" ");
340
366
  await this.cacheManager.setToken({
341
- scope: v,
367
+ scope: k,
342
368
  state: "",
343
369
  session_state: "",
344
370
  identity_provider: e,
345
371
  token_type: "bearer",
346
372
  access_token: t,
347
- refresh_token: n,
348
- id_token: r,
349
- expires_at: k
373
+ refresh_token: r,
374
+ id_token: n,
375
+ expires_at: d
350
376
  });
351
- const m = J(r), T = re(m);
352
- await this.cacheManager.setUser(T), await this.reloadCodeVerifier();
377
+ const v = J(n), p = oe(v);
378
+ await this.cacheManager.setUser(p), await this.reloadCodeVerifier();
353
379
  }
354
380
  async reloadCodeVerifier() {
355
381
  const e = await this.tokenProvider.RetrieveCodeVerifier();
356
382
  this.cookiesManager.save({ code_verifier: e }), this.tokenProvider = this.tokenProvider.WithProofKeyForCodeExchange(e);
357
383
  }
384
+ /**
385
+ * Create and encode state payload for replay attack protection
386
+ * @param {string} redirectTo - Path to redirect to after authentication
387
+ * @return {string} - Base64 encoded state payload
388
+ */
389
+ createStatePayload(e) {
390
+ const t = this.generateNonce(), r = Date.now();
391
+ return btoa(JSON.stringify({
392
+ redirectTo: e,
393
+ timestamp: r,
394
+ nonce: t
395
+ }));
396
+ }
397
+ /**
398
+ * Generate a random nonce for state validation
399
+ * @return {string} - Random nonce
400
+ */
401
+ generateNonce() {
402
+ const e = new Uint8Array(16);
403
+ return crypto.getRandomValues(e), Array.from(e, (t) => t.toString(16).padStart(2, "0")).join("");
404
+ }
405
+ /**
406
+ * Validate state payload to prevent replay attacks
407
+ * @param {string} receivedState - State received from OAuth callback
408
+ * @return {StateValidationResult} - Validation result with redirect path if valid
409
+ */
410
+ validateStatePayload(e) {
411
+ try {
412
+ if (!e || e.trim() === "")
413
+ return { isValid: !1, error: "Empty state parameter" };
414
+ const t = this.cookiesManager.getStatePayload();
415
+ if (!t)
416
+ return { isValid: !1, error: "No stored state found" };
417
+ const r = atob(e), n = JSON.parse(r), i = atob(t), c = JSON.parse(i);
418
+ if (!n.nonce || !n.timestamp || !n.redirectTo)
419
+ return { isValid: !1, error: "Invalid state payload structure" };
420
+ if (n.nonce !== c.nonce)
421
+ return { isValid: !1, error: "State nonce mismatch" };
422
+ const k = Date.now() - n.timestamp;
423
+ return k > A ? { isValid: !1, error: "State expired - possible replay attack" } : k < 0 ? {
424
+ isValid: !1,
425
+ error: "State timestamp is in the future - possible replay attack"
426
+ } : (this.cookiesManager.clearStatePayload(), {
427
+ isValid: !0,
428
+ redirectTo: n.redirectTo
429
+ });
430
+ } catch {
431
+ return { isValid: !1, error: "Invalid state format" };
432
+ }
433
+ }
358
434
  /**
359
435
  * Return the user stored in cache
360
436
  * @return {Promise<TIDUser | undefined>} User in cache
361
437
  */
362
438
  async getUser() {
363
- return this.analyticshttpclient.sendMethodEvent(this.getUser.name, this.clientId, d, h), await this.cacheManager.getUser();
439
+ return h.sendMethodEvent(this.getUser.name, this.clientId, u, g), await this.cacheManager.getUser();
364
440
  }
365
441
  /**
366
442
  * Gets the access token from cache. If the token already expired,
@@ -370,46 +446,75 @@ class de {
370
446
  * @throws {TokenExpiredException} Will throw an exception if the user token expired
371
447
  */
372
448
  async getAccessTokenSilently() {
373
- this.analyticshttpclient.sendMethodEvent(this.getAccessTokenSilently.name, this.clientId, d, h);
449
+ h.sendMethodEvent(
450
+ this.getAccessTokenSilently.name,
451
+ this.clientId,
452
+ u,
453
+ g
454
+ );
374
455
  let e = await this.cacheManager.getToken();
375
456
  if (e == null)
376
- throw this.analyticshttpclient.sendExceptionEvent(this.getAccessTokenSilently.name, "No token available", this.clientId, d, h), new O("No token available");
457
+ throw h.sendExceptionEvent(
458
+ this.getAccessTokenSilently.name,
459
+ "No token available",
460
+ this.clientId,
461
+ u,
462
+ g
463
+ ), new D("No token available");
377
464
  const t = new Date((/* @__PURE__ */ new Date()).getTime() + x);
378
- if ((e == null ? void 0 : e.expires_at) == null || (e == null ? void 0 : e.expires_at) < t.getTime()) {
465
+ if (e?.expires_at == null || e?.expires_at < t.getTime()) {
379
466
  try {
380
467
  await this.tokenProvider.RetrieveToken();
381
- } catch (n) {
382
- throw this.analyticshttpclient.sendExceptionEvent(this.getAccessTokenSilently.name, n.message, this.clientId, d, h), new U(n.message);
468
+ } catch (r) {
469
+ throw h.sendExceptionEvent(
470
+ this.getAccessTokenSilently.name,
471
+ r.message,
472
+ this.clientId,
473
+ u,
474
+ g
475
+ ), new O(r.message);
383
476
  }
384
- await this.generateToken((e == null ? void 0 : e.identity_provider) ?? ""), e = await this.cacheManager.getToken();
477
+ await this.generateToken(e?.identity_provider ?? ""), e = await this.cacheManager.getToken();
385
478
  }
386
- return (e == null ? void 0 : e.access_token) || "";
479
+ return e?.access_token || "";
387
480
  }
388
481
  /**
389
482
  * Retrieves token details from the cache, including the access token, ID token, and expiration time.
390
- * If the token already expired, will try to refresh it using the refresh token.
483
+ * If the token already expired, will try to refresh it using the refresh token.
391
484
  * @return {Promise<TokenResponse>} Token response
392
485
  * @throws {TokenNotFoundException} Will throw an exception if there are no tokens in cache
393
486
  * @throws {TokenExpiredException} Will throw an exception if the user token expired
394
487
  */
395
488
  async getTokens() {
396
- this.analyticshttpclient.sendMethodEvent(this.getTokens.name, this.clientId, d, h);
489
+ h.sendMethodEvent(this.getTokens.name, this.clientId, u, g);
397
490
  let e = await this.cacheManager.getToken();
398
491
  if (e == null)
399
- throw this.analyticshttpclient.sendExceptionEvent(this.getTokens.name, "No token available", this.clientId, d, h), new O("No token available");
492
+ throw h.sendExceptionEvent(
493
+ this.getTokens.name,
494
+ "No token available",
495
+ this.clientId,
496
+ u,
497
+ g
498
+ ), new D("No token available");
400
499
  const t = new Date((/* @__PURE__ */ new Date()).getTime() + x);
401
- if ((e == null ? void 0 : e.expires_at) == null || (e == null ? void 0 : e.expires_at) < t.getTime()) {
500
+ if (e?.expires_at == null || e?.expires_at < t.getTime()) {
402
501
  try {
403
502
  await this.tokenProvider.RetrieveToken();
404
- } catch (n) {
405
- throw this.analyticshttpclient.sendExceptionEvent(this.getTokens.name, n.message, this.clientId, d, h), new U(n.message);
503
+ } catch (r) {
504
+ throw h.sendExceptionEvent(
505
+ this.getTokens.name,
506
+ r.message,
507
+ this.clientId,
508
+ u,
509
+ g
510
+ ), new O(r.message);
406
511
  }
407
- await this.generateToken((e == null ? void 0 : e.identity_provider) ?? ""), e = await this.cacheManager.getToken();
512
+ await this.generateToken(e?.identity_provider ?? ""), e = await this.cacheManager.getToken();
408
513
  }
409
514
  return {
410
- access_token: (e == null ? void 0 : e.access_token) || "",
411
- expires_at: (e == null ? void 0 : e.expires_at) || 0,
412
- id_token: (e == null ? void 0 : e.id_token) || ""
515
+ access_token: e?.access_token || "",
516
+ expires_at: e?.expires_at || 0,
517
+ id_token: e?.id_token || ""
413
518
  };
414
519
  }
415
520
  /**
@@ -425,13 +530,13 @@ class de {
425
530
  * // So it can be handled by the developer
426
531
  */
427
532
  async logout(e) {
428
- this.analyticshttpclient.sendMethodEvent(this.logout.name, this.clientId, d, h);
429
- const { onRedirect: t, disabledAutoRedirect: n } = e || {};
533
+ h.sendMethodEvent(this.logout.name, this.clientId, u, g);
534
+ const { onRedirect: t, disabledAutoRedirect: r } = e || {};
430
535
  this.cacheManager && await this.cacheManager.clear(), this.cookiesManager && this.cookiesManager.clear();
431
- const r = await this.tokenProvider.GetOAuthLogoutRedirect("state");
536
+ const n = await this.tokenProvider.GetOAuthLogoutRedirect("state");
432
537
  if (t != null)
433
- return t(r);
434
- n || window.location.assign(r);
538
+ return t(n);
539
+ r || window.location.assign(n);
435
540
  }
436
541
  /**
437
542
  * Check if the user still has a valid session
@@ -460,15 +565,15 @@ class de {
460
565
  const e = await this.cacheManager.getToken();
461
566
  if (e == null)
462
567
  return;
463
- const t = e.access_token, n = e.refresh_token || "", r = e.id_token, a = e.expires_at;
464
- this.tokenProvider = this.tokenProvider.WithAccessToken(t, a).WithRefreshToken(n).WithIdToken(r);
568
+ const t = e.access_token, r = e.refresh_token || "", n = e.id_token, i = e.expires_at;
569
+ this.tokenProvider = this.tokenProvider.WithAccessToken(t, i).WithRefreshToken(r).WithIdToken(n);
465
570
  }
466
571
  /**
467
572
  * Get a http bearer token client to use it for another SDK (Ex: Processing framework)
468
573
  * @return {any} - BearerTokenHttpClientProvider
469
574
  */
470
575
  getBearerTokenHttpClient(e) {
471
- return new Q(this.tokenProvider, e);
576
+ return new B(this.tokenProvider, e);
472
577
  }
473
578
  /**
474
579
  * Get the redirect url to TID
@@ -478,11 +583,11 @@ class de {
478
583
  return this.redirectUrl;
479
584
  }
480
585
  }
481
- const E = q(null), W = () => L(E) ?? {}, he = (i, e) => {
586
+ const T = H(null), K = () => L(T) ?? {}, de = (o, e) => {
482
587
  switch (e.type) {
483
588
  case "INIT":
484
589
  return {
485
- ...i,
590
+ ...o,
486
591
  isLoading: !1,
487
592
  isAuthenticated: e.user != null,
488
593
  user: e.user,
@@ -492,7 +597,7 @@ const E = q(null), W = () => L(E) ?? {}, he = (i, e) => {
492
597
  case "HANDLE_CALLBACK_COMPLETE":
493
598
  case "GET_ACCESS_TOKEN_COMPLETE":
494
599
  return {
495
- ...i,
600
+ ...o,
496
601
  isLoading: !1,
497
602
  isAuthenticated: e.user != null,
498
603
  user: e.user,
@@ -500,136 +605,134 @@ const E = q(null), W = () => L(E) ?? {}, he = (i, e) => {
500
605
  };
501
606
  case "LOGOUT":
502
607
  return {
503
- ...i,
608
+ ...o,
504
609
  isAuthenticated: !1,
505
610
  user: void 0
506
611
  };
507
612
  case "ERROR":
508
613
  return {
509
- ...i,
614
+ ...o,
510
615
  isLoading: !1,
511
616
  error: e.error
512
617
  };
513
618
  }
514
- }, ue = {
619
+ }, le = {
515
620
  isLoading: !0,
516
621
  isAuthenticated: !1
517
- }, ge = (i) => {
518
- if (i == null || Object.keys(i).length <= 0)
622
+ }, he = (o) => {
623
+ if (o == null || Object.keys(o).length <= 0)
519
624
  return !0;
520
- const e = Object.keys(i);
625
+ const e = Object.keys(o);
521
626
  for (const t of e)
522
- if (i[t] != null && i[t] !== "")
627
+ if (o[t] != null && o[t] !== "")
523
628
  return !1;
524
629
  return !0;
525
- }, ke = (i) => !ge(i.config), fe = (i) => {
630
+ }, ue = (o) => !he(o.config), ge = (o) => {
526
631
  const {
527
632
  children: e,
528
633
  configurationEndpoint: t,
529
- clientId: n,
530
- redirectUrl: r,
531
- logoutRedirectUrl: a,
532
- scopes: g,
533
- onRedirectCallback: k,
534
- checkRedirectUrlMatch: v
535
- } = i;
536
- if (L(E) != null)
634
+ clientId: r,
635
+ redirectUrl: n,
636
+ logoutRedirectUrl: i,
637
+ scopes: c,
638
+ onRedirectCallback: d,
639
+ checkRedirectUrlMatch: k
640
+ } = o;
641
+ if (L(T) != null)
537
642
  throw new Error("TID Provider already defined");
538
- const T = {
643
+ const p = {
539
644
  config: {
540
645
  configurationEndpoint: t ?? "",
541
- clientId: n ?? "",
542
- redirectUrl: r ?? "",
543
- logoutRedirectUrl: a ?? "",
544
- scopes: g ?? [""]
646
+ clientId: r ?? "",
647
+ redirectUrl: n ?? "",
648
+ logoutRedirectUrl: i ?? "",
649
+ scopes: c ?? [""]
545
650
  }
546
- }, [s] = z(i.tidClient ?? new de(T)), [f, u] = X(he, ue), p = Y(!1), N = M(
547
- () => v ? s.getRedirectUrl() : void 0,
548
- [v, s]
651
+ }, [a] = Q(o.tidClient ?? new ce(p)), [w, f] = X(de, le), E = q(!1), W = M(
652
+ () => k ? a.getRedirectUrl() : void 0,
653
+ [k, a]
549
654
  );
550
- D(() => {
551
- p.current || (i.tidClient != null && ke({
655
+ N(() => {
656
+ E.current || (o.tidClient != null && ue({
552
657
  config: {
553
658
  configurationEndpoint: t,
554
- clientId: n,
555
- redirectUrl: r,
556
- logoutRedirectUrl: a,
557
- scopes: g
659
+ clientId: r,
660
+ redirectUrl: n,
661
+ logoutRedirectUrl: i,
662
+ scopes: c
558
663
  }
559
664
  }) && console.warn(
560
665
  "When TID client is pass as prop, any client configuration property sent directly to the TID Provider component will be ignored"
561
- ), p.current = !0, (async () => {
666
+ ), E.current = !0, (async () => {
562
667
  try {
563
- let o;
564
- if (ne(void 0, N)) {
565
- const { authState: l } = await s.handleCallback();
566
- o = await s.getUser(), k != null && k(l);
668
+ let s;
669
+ if (te(void 0, W)) {
670
+ const l = await a.handleCallback();
671
+ s = await a.getUser(), d?.(l);
567
672
  } else
568
- await s.loadUserSession(), o = await s.getUser();
569
- u({ type: "INIT", user: o });
570
- } catch (o) {
571
- let l = o;
572
- typeof o == "string" && (l = new Error(o)), u({ type: "ERROR", error: l });
673
+ await a.loadUserSession(), s = await a.getUser();
674
+ f({ type: "INIT", user: s });
675
+ } catch (s) {
676
+ let l = s;
677
+ typeof s == "string" && (l = new Error(s)), f({ type: "ERROR", error: l });
573
678
  }
574
679
  })());
575
- }, [s, k]);
576
- const _ = y(async () => {
577
- const o = await s.getAccessTokenSilently(), l = await s.getUser();
578
- return u({
680
+ }, [a, d]);
681
+ const S = y(async () => {
682
+ const s = await a.getAccessTokenSilently(), l = await a.getUser();
683
+ return f({
579
684
  type: "GET_ACCESS_TOKEN_COMPLETE",
580
685
  user: l
581
- }), o;
582
- }, [s]), C = y(async () => {
583
- const o = await s.getTokens(), l = await s.getUser();
584
- return u({
686
+ }), s;
687
+ }, [a]), _ = y(async () => {
688
+ const s = await a.getTokens(), l = await a.getUser();
689
+ return f({
585
690
  type: "GET_TOKENS_COMPLETE",
586
691
  user: l
587
- }), o;
588
- }, [s]), S = y(
589
- async (o) => {
590
- await s.loginWithRedirect(o);
692
+ }), s;
693
+ }, [a]), P = y(
694
+ async (s) => {
695
+ await a.loginWithRedirect(s);
591
696
  },
592
- [s]
593
- ), I = y(
594
- async (o) => {
595
- await s.logout(o), (o == null ? void 0 : o.disabledAutoRedirect) != null && o.disabledAutoRedirect && u({
697
+ [a]
698
+ ), C = y(
699
+ async (s) => {
700
+ await a.logout(s), s?.disabledAutoRedirect != null && s.disabledAutoRedirect && f({
596
701
  type: "LOGOUT"
597
702
  });
598
703
  },
599
- [s]
600
- ), P = y(
601
- async (o) => {
602
- const { authState: l } = await s.handleCallback(o), V = await s.getUser();
603
- return u({
704
+ [a]
705
+ ), I = y(
706
+ async (s) => {
707
+ const l = await a.handleCallback(s), F = await a.getUser();
708
+ return f({
604
709
  type: "HANDLE_CALLBACK_COMPLETE",
605
- user: V
606
- }), {
607
- authState: l
608
- };
710
+ user: F
711
+ }), l;
609
712
  },
610
- [s]
713
+ [a]
611
714
  ), G = M(
612
715
  () => ({
613
- ...f,
614
- getAccessTokenSilently: _,
615
- getTokens: C,
616
- loginWithRedirect: S,
617
- handleCallback: P,
618
- logout: I
716
+ ...w,
717
+ getAccessTokenSilently: S,
718
+ getTokens: _,
719
+ loginWithRedirect: P,
720
+ handleCallback: I,
721
+ logout: C
619
722
  }),
620
- [f, _, C, S, P, I]
723
+ [w, S, _, P, I, C]
621
724
  );
622
- return /* @__PURE__ */ K(E.Provider, { value: G, children: e });
623
- }, me = W, pe = fe, _e = ({ renderComponent: i, loader: e }) => {
624
- const { isAuthenticated: t, isLoading: n, loginWithRedirect: r } = W();
625
- return D(() => {
626
- !n && !t && (async () => await r())();
627
- }, [n, t, r]), t ? i : e || /* @__PURE__ */ K(Z, {});
725
+ return /* @__PURE__ */ V(T.Provider, { value: G, children: e });
726
+ }, me = K, Te = ge, ve = ({ renderComponent: o, loader: e }) => {
727
+ const { isAuthenticated: t, isLoading: r, loginWithRedirect: n } = K();
728
+ return N(() => {
729
+ !r && !t && (async () => await n())();
730
+ }, [r, t, n]), t ? o : e || /* @__PURE__ */ V(z, {});
628
731
  };
629
732
  export {
630
- _e as AuthenticationGuard,
631
- de as TIDClient,
632
- E as TIDContext,
633
- pe as TIDProvider,
733
+ ve as AuthenticationGuard,
734
+ ce as TIDClient,
735
+ T as TIDContext,
736
+ Te as TIDProvider,
634
737
  me as useAuth
635
738
  };
@@ -1 +1 @@
1
- (function(o,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("@trimble-oss/trimble-id"),require("es-cookie"),require("jwt-decode"),require("react"),require("react/jsx-runtime")):typeof define=="function"&&define.amd?define(["exports","@trimble-oss/trimble-id","es-cookie","jwt-decode","react","react/jsx-runtime"],c):(o=typeof globalThis<"u"?globalThis:o||self,c(o.ReactTID={},o.trimbleId,o.esCookie,o.jwt_decode,o.React,o.jsxRuntime))})(this,function(o,c,k,W,l,p){"use strict";var le=Object.defineProperty;var de=(o,c,k)=>c in o?le(o,c,{enumerable:!0,configurable:!0,writable:!0,value:k}):o[c]=k;var h=(o,c,k)=>(de(o,typeof c!="symbol"?c+"":c,k),k);function G(i){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(i){for(const t in i)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(i,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>i[t]})}}return e.default=i,Object.freeze(e)}const C=G(k);class V{constructor(){h(this,"generateCache",function(){const e={token:void 0,user:void 0};return{async getToken(){return e.token},async getUser(){return e.user},async storeToken(t){e.token=t},async storeUser(t){e.user=t},clear(){return e.token=void 0,e.user=void 0,Promise.resolve(void 0)}}}())}}class F{constructor(){h(this,"cacheStorage");this.cacheStorage=new V().generateCache}async setToken(e){await this.cacheStorage.storeToken(e)}async setUser(e){await this.cacheStorage.storeUser(e)}async getUser(){return this.cacheStorage.getUser()}async getToken(){return this.cacheStorage.getToken()}async clear(){await this.cacheStorage.clear()}}const S=5*6e4,j=["code","state"],P=i=>i.split("?")[0],q=i=>i.split("?")[1],I=i=>{let e=i;if(!i.startsWith("?"))try{e=new URL(i).search}catch{}return new URLSearchParams(e)},B=(i=window.location.href,e)=>{if(e!=null){const n=P(e),r=P(i??"");if(n!==r)return!1}const t=I(i);for(const n of j)if(!t.has(n))return!1;return!0},$=i=>({id:i.sub,name:`${i.given_name} ${i.family_name}`,given_name:i.given_name,family_name:i.family_name,picture:i.picture,email:i.email,email_verified:i.email_verified}),H="@TID_COOKIE";class z{get(e){const t=C.get(e);if(t==null)throw new Error("Cookie not found");return JSON.parse(t)}set(e,t,n){let r={};window.location.protocol==="https:"&&(r={secure:!0,sameSite:"none"}),n!=null&&n.expires&&(r.expires=n.expires),n!=null&&n.domain&&(r.domain=n.domain),C.set(e,JSON.stringify(t),r)}remove(e,t){const n={};t!=null&&t.domain&&(n.domain=t.domain),C.remove(e,n)}}class Q{constructor(e){h(this,"cookieKey");h(this,"cookiesStorage");this.cookieKey=`${H}.${e.clientId}`,this.cookiesStorage=new z}save(e){this.cookiesStorage.set(this.cookieKey,e,{expires:1})}get(){try{return this.cookiesStorage.get(this.cookieKey)}catch{return}}clear(){this.cookiesStorage.remove(this.cookieKey)}}class R extends Error{}class M extends Error{}class J extends Error{}const u="@trimble-oss/trimble-id-react",g="1.0.0",X={configurationEndpoint:"",clientId:"",redirectUrl:"",logoutRedirectUrl:"",scopes:[]};class x{constructor(e){h(this,"tokenProvider");h(this,"cacheManager");h(this,"cookiesManager");h(this,"clientId");h(this,"redirectUrl");h(this,"analyticshttpclient");const{config:t=X}=e;if(this.redirectUrl=t.redirectUrl,t.configurationEndpoint==null||t.configurationEndpoint=="")throw new Error("Configuration endpoint not defined");if(t.clientId==null||t.clientId=="")throw new Error("Consumer key is not defined");this.cookiesManager=new Q({clientId:t.clientId});const n=this.cookiesManager.get(),r=new c.OpenIdEndpointProvider(t.configurationEndpoint);let d=new c.AuthorizationCodeGrantTokenProvider(r,t.clientId,t.redirectUrl).WithScopes(t.scopes);t.logoutRedirectUrl&&(d=d.WithLogoutRedirect(t.logoutRedirectUrl)),(n==null?void 0:n.code_verifier)!=null&&(d=d.WithProofKeyForCodeExchange(n.code_verifier)),this.tokenProvider=d,this.cacheManager=new F,this.clientId=t.clientId,this.analyticshttpclient=c.AnalyticsHttpClient,this.analyticshttpclient.sendInitEvent("TIDClient",this.clientId,u,g)}async loginWithRedirect(e){this.analyticshttpclient.sendMethodEvent(this.loginWithRedirect.name,this.clientId,u,g);const{onRedirect:t}=e||{},n=c.AuthorizationCodeGrantTokenProvider.GenerateCodeVerifier();this.cookiesManager.save({code_verifier:n}),this.tokenProvider=this.tokenProvider.WithProofKeyForCodeExchange(n);const r=await this.tokenProvider.GetOAuthRedirect("state");t!=null?t(r):window.location.assign(r)}async handleCallback(e=window.location.href){const t=this.cookiesManager.get();if(t==null||(t==null?void 0:t.code_verifier)==null)throw new J("Code verifier not available");const n=q(e),r=I(e),d=r.get("identity_provider")??"",T=r.get("state")??"";return await this.tokenProvider.ValidateQuery(n),await this.generateToken(d),{authState:T}}async generateToken(e){var s,w;const t=await this.tokenProvider.RetrieveToken(),n=await this.tokenProvider.RetrieveRefreshToken(),r=await this.tokenProvider.RetrieveIdToken(),d=await this.tokenProvider.RetrieveTokenExpiry(),v=new Date(d).getTime(),m=(w=(s=this.tokenProvider)==null?void 0:s._scopes)==null?void 0:w.join(" ");await this.cacheManager.setToken({scope:m,state:"",session_state:"",identity_provider:e,token_type:"bearer",access_token:t,refresh_token:n,id_token:r,expires_at:v});const U=W(r),_=$(U);await this.cacheManager.setUser(_),await this.reloadCodeVerifier()}async reloadCodeVerifier(){const e=await this.tokenProvider.RetrieveCodeVerifier();this.cookiesManager.save({code_verifier:e}),this.tokenProvider=this.tokenProvider.WithProofKeyForCodeExchange(e)}async getUser(){return this.analyticshttpclient.sendMethodEvent(this.getUser.name,this.clientId,u,g),await this.cacheManager.getUser()}async getAccessTokenSilently(){this.analyticshttpclient.sendMethodEvent(this.getAccessTokenSilently.name,this.clientId,u,g);let e=await this.cacheManager.getToken();if(e==null)throw this.analyticshttpclient.sendExceptionEvent(this.getAccessTokenSilently.name,"No token available",this.clientId,u,g),new M("No token available");const t=new Date(new Date().getTime()+S);if((e==null?void 0:e.expires_at)==null||(e==null?void 0:e.expires_at)<t.getTime()){try{await this.tokenProvider.RetrieveToken()}catch(n){throw this.analyticshttpclient.sendExceptionEvent(this.getAccessTokenSilently.name,n.message,this.clientId,u,g),new R(n.message)}await this.generateToken((e==null?void 0:e.identity_provider)??""),e=await this.cacheManager.getToken()}return(e==null?void 0:e.access_token)||""}async getTokens(){this.analyticshttpclient.sendMethodEvent(this.getTokens.name,this.clientId,u,g);let e=await this.cacheManager.getToken();if(e==null)throw this.analyticshttpclient.sendExceptionEvent(this.getTokens.name,"No token available",this.clientId,u,g),new M("No token available");const t=new Date(new Date().getTime()+S);if((e==null?void 0:e.expires_at)==null||(e==null?void 0:e.expires_at)<t.getTime()){try{await this.tokenProvider.RetrieveToken()}catch(n){throw this.analyticshttpclient.sendExceptionEvent(this.getTokens.name,n.message,this.clientId,u,g),new R(n.message)}await this.generateToken((e==null?void 0:e.identity_provider)??""),e=await this.cacheManager.getToken()}return{access_token:(e==null?void 0:e.access_token)||"",expires_at:(e==null?void 0:e.expires_at)||0,id_token:(e==null?void 0:e.id_token)||""}}async logout(e){this.analyticshttpclient.sendMethodEvent(this.logout.name,this.clientId,u,g);const{onRedirect:t,disabledAutoRedirect:n}=e||{};this.cacheManager&&await this.cacheManager.clear(),this.cookiesManager&&this.cookiesManager.clear();const r=await this.tokenProvider.GetOAuthLogoutRedirect("state");if(t!=null)return t(r);n||window.location.assign(r)}async checkSession(){try{await this.getAccessTokenSilently()}catch{return!1}return!0}async loadUserSession(){await this.loadCacheSessionIntoSDK(),await this.checkSession()||await this.cacheManager.clear()}async loadCacheSessionIntoSDK(){const e=await this.cacheManager.getToken();if(e==null)return;const t=e.access_token,n=e.refresh_token||"",r=e.id_token,d=e.expires_at;this.tokenProvider=this.tokenProvider.WithAccessToken(t,d).WithRefreshToken(n).WithIdToken(r)}getBearerTokenHttpClient(e){return new c.BearerTokenHttpClientProvider(this.tokenProvider,e)}getRedirectUrl(){return this.redirectUrl}}const E=l.createContext(null),A=()=>l.useContext(E)??{},Y=(i,e)=>{switch(e.type){case"INIT":return{...i,isLoading:!1,isAuthenticated:e.user!=null,user:e.user,error:void 0};case"GET_TOKENS_COMPLETE":case"HANDLE_CALLBACK_COMPLETE":case"GET_ACCESS_TOKEN_COMPLETE":return{...i,isLoading:!1,isAuthenticated:e.user!=null,user:e.user,error:void 0};case"LOGOUT":return{...i,isAuthenticated:!1,user:void 0};case"ERROR":return{...i,isLoading:!1,error:e.error}}},Z={isLoading:!0,isAuthenticated:!1},ee=i=>{if(i==null||Object.keys(i).length<=0)return!0;const e=Object.keys(i);for(const t of e)if(i[t]!=null&&i[t]!=="")return!1;return!0},te=i=>!ee(i.config),ie=i=>{const{children:e,configurationEndpoint:t,clientId:n,redirectUrl:r,logoutRedirectUrl:d,scopes:T,onRedirectCallback:v,checkRedirectUrlMatch:m}=i;if(l.useContext(E)!=null)throw new Error("TID Provider already defined");const _={config:{configurationEndpoint:t??"",clientId:n??"",redirectUrl:r??"",logoutRedirectUrl:d??"",scopes:T??[""]}},[s]=l.useState(i.tidClient??new x(_)),[w,y]=l.useReducer(Y,Z),O=l.useRef(!1),oe=l.useMemo(()=>m?s.getRedirectUrl():void 0,[m,s]);l.useEffect(()=>{O.current||(i.tidClient!=null&&te({config:{configurationEndpoint:t,clientId:n,redirectUrl:r,logoutRedirectUrl:d,scopes:T}})&&console.warn("When TID client is pass as prop, any client configuration property sent directly to the TID Provider component will be ignored"),O.current=!0,(async()=>{try{let a;if(B(void 0,oe)){const{authState:f}=await s.handleCallback();a=await s.getUser(),v!=null&&v(f)}else await s.loadUserSession(),a=await s.getUser();y({type:"INIT",user:a})}catch(a){let f=a;typeof a=="string"&&(f=new Error(a)),y({type:"ERROR",error:f})}})())},[s,v]);const D=l.useCallback(async()=>{const a=await s.getAccessTokenSilently(),f=await s.getUser();return y({type:"GET_ACCESS_TOKEN_COMPLETE",user:f}),a},[s]),b=l.useCallback(async()=>{const a=await s.getTokens(),f=await s.getUser();return y({type:"GET_TOKENS_COMPLETE",user:f}),a},[s]),L=l.useCallback(async a=>{await s.loginWithRedirect(a)},[s]),K=l.useCallback(async a=>{await s.logout(a),(a==null?void 0:a.disabledAutoRedirect)!=null&&a.disabledAutoRedirect&&y({type:"LOGOUT"})},[s]),N=l.useCallback(async a=>{const{authState:f}=await s.handleCallback(a),ce=await s.getUser();return y({type:"HANDLE_CALLBACK_COMPLETE",user:ce}),{authState:f}},[s]),ae=l.useMemo(()=>({...w,getAccessTokenSilently:D,getTokens:b,loginWithRedirect:L,handleCallback:N,logout:K}),[w,D,b,L,N,K]);return p.jsx(E.Provider,{value:ae,children:e})},ne=A,re=ie,se=({renderComponent:i,loader:e})=>{const{isAuthenticated:t,isLoading:n,loginWithRedirect:r}=A();return l.useEffect(()=>{!n&&!t&&(async()=>await r())()},[n,t,r]),t?i:e||p.jsx(p.Fragment,{})};o.AuthenticationGuard=se,o.TIDClient=x,o.TIDContext=E,o.TIDProvider=re,o.useAuth=ne,Object.defineProperty(o,Symbol.toStringTag,{value:"Module"})});
1
+ (function(d,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("@trimble-oss/trimble-id"),require("es-cookie"),require("jwt-decode"),require("react"),require("react/jsx-runtime")):typeof define=="function"&&define.amd?define(["exports","@trimble-oss/trimble-id","es-cookie","jwt-decode","react","react/jsx-runtime"],c):(d=typeof globalThis<"u"?globalThis:d||self,c(d.ReactTID={},d.trimbleId,d.esCookie,d.jwt_decode,d.React,d.jsxRuntime))})(this,(function(d,c,b,K,l,m){"use strict";function W(n){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const t in n)if(t!=="default"){const i=Object.getOwnPropertyDescriptor(n,t);Object.defineProperty(e,t,i.get?i:{enumerable:!0,get:()=>n[t]})}}return e.default=n,Object.freeze(e)}const v=W(b);class G{generateCache=(function(){const e={token:void 0,user:void 0};return{async getToken(){return e.token},async getUser(){return e.user},async storeToken(t){e.token=t},async storeUser(t){e.user=t},clear(){return e.token=void 0,e.user=void 0,Promise.resolve(void 0)}}})()}class H{cacheStorage;constructor(){this.cacheStorage=new G().generateCache}async setToken(e){await this.cacheStorage.storeToken(e)}async setUser(e){await this.cacheStorage.storeUser(e)}async getUser(){return this.cacheStorage.getUser()}async getToken(){return this.cacheStorage.getToken()}async clear(){await this.cacheStorage.clear()}}const E=5*6e4,F=["code","state"],S=600*1e3,C=n=>n.split("?")[0],$=n=>n.split("?")[1],P=n=>{let e=n;if(!n.startsWith("?"))try{e=new URL(n).search}catch{}return new URLSearchParams(e)},q=(n=window.location.href,e)=>{if(e!=null){const i=C(e),o=C(n??"");if(i!==o)return!1}const t=P(n);for(const i of F)if(!t.has(i))return!1;return!0},B=n=>({id:n.sub,name:`${n.given_name} ${n.family_name}`,given_name:n.given_name,family_name:n.family_name,picture:n.picture,email:n.email,email_verified:n.email_verified,...n.account_id&&{account_id:n.account_id}}),J="@TID_COOKIE";class j{get(e){const t=v.get(e);if(t==null)throw new Error("Cookie not found");return JSON.parse(t)}set(e,t,i){let o={};window.location.protocol==="https:"&&(o={secure:!0,sameSite:"none"}),i?.expires&&(o.expires=i.expires),i?.domain&&(o.domain=i.domain),v.set(e,JSON.stringify(t),o)}remove(e,t){const i={};t?.domain&&(i.domain=t.domain),v.remove(e,i)}}class z{cookieKey;cookiesStorage;constructor(e){this.cookieKey=`${J}.${e.clientId}`,this.cookiesStorage=new j}save(e){const i={...this.get()||{},...e};this.cookiesStorage.set(this.cookieKey,i,{expires:1})}getStatePayload(){return this.get()?.state_payload}clearStatePayload(){const e=this.get();e&&(delete e.state_payload,this.cookiesStorage.set(this.cookieKey,e,{expires:1}))}get(){try{return this.cookiesStorage.get(this.cookieKey)}catch{return}}clear(){this.cookiesStorage.remove(this.cookieKey)}}class _ extends Error{}class A extends Error{}class Q extends Error{}const h="@trimble-oss/trimble-id-react",g="1.0.2-rc1",X={configurationEndpoint:"",clientId:"",redirectUrl:"",logoutRedirectUrl:"",scopes:[]};class M{tokenProvider;cacheManager;cookiesManager;clientId;redirectUrl;constructor(e){const{config:t=X}=e;if(this.redirectUrl=t.redirectUrl,t.configurationEndpoint==null||t.configurationEndpoint=="")throw new Error("Configuration endpoint not defined");if(t.clientId==null||t.clientId=="")throw new Error("Consumer key is not defined");this.cookiesManager=new z({clientId:t.clientId});const i=this.cookiesManager.get(),o=new c.OpenIdEndpointProvider(t.configurationEndpoint);let r=new c.AuthorizationCodeGrantTokenProvider(o,t.clientId,t.redirectUrl).WithScopes(t.scopes);t.logoutRedirectUrl&&(r=r.WithLogoutRedirect(t.logoutRedirectUrl)),i?.code_verifier!=null&&(r=r.WithProofKeyForCodeExchange(i.code_verifier)),this.tokenProvider=r,this.cacheManager=new H,this.clientId=t.clientId,c.AnalyticsHttpClient.sendInitEvent("TIDClient",this.clientId,h,g),this.cleanupExpiredState()}cleanupExpiredState(){try{const e=this.cookiesManager.getStatePayload();if(e){const t=atob(e),i=JSON.parse(t);Date.now()-i.timestamp>S&&this.cookiesManager.clearStatePayload()}}catch{this.cookiesManager.clearStatePayload()}}async loginWithRedirect(e){c.AnalyticsHttpClient.sendMethodEvent(this.loginWithRedirect.name,this.clientId,h,g);const{onRedirect:t}=e||{},i=window.location.pathname+window.location.search,o=this.createStatePayload(i);this.cookiesManager.save({state_payload:o});const r=c.AuthorizationCodeGrantTokenProvider.GenerateCodeVerifier();this.cookiesManager.save({code_verifier:r}),this.tokenProvider=this.tokenProvider.WithProofKeyForCodeExchange(r);const u=await this.tokenProvider.GetOAuthRedirect(o);t!=null?t(u):window.location.assign(u)}async handleCallback(e=window.location.href){const t=this.cookiesManager.get();if(t==null||t?.code_verifier==null)throw new Q("Code verifier not available");const i=$(e),o=P(e),r=o.get("identity_provider")??"",u=o.get("state")??"",f=this.validateStatePayload(u);if(!f.isValid)throw new Error(`State validation failed: ${f.error}`);return await this.tokenProvider.ValidateQuery(i),await this.generateToken(r),{authState:u,returnTo:f.redirectTo}}async generateToken(e){const t=await this.tokenProvider.RetrieveToken(),i=await this.tokenProvider.RetrieveRefreshToken(),o=await this.tokenProvider.RetrieveIdToken(),r=await this.tokenProvider.RetrieveTokenExpiry(),f=new Date(r).getTime(),y=this.tokenProvider?._scopes?.join(" ");await this.cacheManager.setToken({scope:y,state:"",session_state:"",identity_provider:e,token_type:"bearer",access_token:t,refresh_token:i,id_token:o,expires_at:f});const I=K(o),w=B(I);await this.cacheManager.setUser(w),await this.reloadCodeVerifier()}async reloadCodeVerifier(){const e=await this.tokenProvider.RetrieveCodeVerifier();this.cookiesManager.save({code_verifier:e}),this.tokenProvider=this.tokenProvider.WithProofKeyForCodeExchange(e)}createStatePayload(e){const t=this.generateNonce(),i=Date.now();return btoa(JSON.stringify({redirectTo:e,timestamp:i,nonce:t}))}generateNonce(){const e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}validateStatePayload(e){try{if(!e||e.trim()==="")return{isValid:!1,error:"Empty state parameter"};const t=this.cookiesManager.getStatePayload();if(!t)return{isValid:!1,error:"No stored state found"};const i=atob(e),o=JSON.parse(i),r=atob(t),u=JSON.parse(r);if(!o.nonce||!o.timestamp||!o.redirectTo)return{isValid:!1,error:"Invalid state payload structure"};if(o.nonce!==u.nonce)return{isValid:!1,error:"State nonce mismatch"};const y=Date.now()-o.timestamp;return y>S?{isValid:!1,error:"State expired - possible replay attack"}:y<0?{isValid:!1,error:"State timestamp is in the future - possible replay attack"}:(this.cookiesManager.clearStatePayload(),{isValid:!0,redirectTo:o.redirectTo})}catch{return{isValid:!1,error:"Invalid state format"}}}async getUser(){return c.AnalyticsHttpClient.sendMethodEvent(this.getUser.name,this.clientId,h,g),await this.cacheManager.getUser()}async getAccessTokenSilently(){c.AnalyticsHttpClient.sendMethodEvent(this.getAccessTokenSilently.name,this.clientId,h,g);let e=await this.cacheManager.getToken();if(e==null)throw c.AnalyticsHttpClient.sendExceptionEvent(this.getAccessTokenSilently.name,"No token available",this.clientId,h,g),new A("No token available");const t=new Date(new Date().getTime()+E);if(e?.expires_at==null||e?.expires_at<t.getTime()){try{await this.tokenProvider.RetrieveToken()}catch(i){throw c.AnalyticsHttpClient.sendExceptionEvent(this.getAccessTokenSilently.name,i.message,this.clientId,h,g),new _(i.message)}await this.generateToken(e?.identity_provider??""),e=await this.cacheManager.getToken()}return e?.access_token||""}async getTokens(){c.AnalyticsHttpClient.sendMethodEvent(this.getTokens.name,this.clientId,h,g);let e=await this.cacheManager.getToken();if(e==null)throw c.AnalyticsHttpClient.sendExceptionEvent(this.getTokens.name,"No token available",this.clientId,h,g),new A("No token available");const t=new Date(new Date().getTime()+E);if(e?.expires_at==null||e?.expires_at<t.getTime()){try{await this.tokenProvider.RetrieveToken()}catch(i){throw c.AnalyticsHttpClient.sendExceptionEvent(this.getTokens.name,i.message,this.clientId,h,g),new _(i.message)}await this.generateToken(e?.identity_provider??""),e=await this.cacheManager.getToken()}return{access_token:e?.access_token||"",expires_at:e?.expires_at||0,id_token:e?.id_token||""}}async logout(e){c.AnalyticsHttpClient.sendMethodEvent(this.logout.name,this.clientId,h,g);const{onRedirect:t,disabledAutoRedirect:i}=e||{};this.cacheManager&&await this.cacheManager.clear(),this.cookiesManager&&this.cookiesManager.clear();const o=await this.tokenProvider.GetOAuthLogoutRedirect("state");if(t!=null)return t(o);i||window.location.assign(o)}async checkSession(){try{await this.getAccessTokenSilently()}catch{return!1}return!0}async loadUserSession(){await this.loadCacheSessionIntoSDK(),await this.checkSession()||await this.cacheManager.clear()}async loadCacheSessionIntoSDK(){const e=await this.cacheManager.getToken();if(e==null)return;const t=e.access_token,i=e.refresh_token||"",o=e.id_token,r=e.expires_at;this.tokenProvider=this.tokenProvider.WithAccessToken(t,r).WithRefreshToken(i).WithIdToken(o)}getBearerTokenHttpClient(e){return new c.BearerTokenHttpClientProvider(this.tokenProvider,e)}getRedirectUrl(){return this.redirectUrl}}const T=l.createContext(null),R=()=>l.useContext(T)??{},Y=(n,e)=>{switch(e.type){case"INIT":return{...n,isLoading:!1,isAuthenticated:e.user!=null,user:e.user,error:void 0};case"GET_TOKENS_COMPLETE":case"HANDLE_CALLBACK_COMPLETE":case"GET_ACCESS_TOKEN_COMPLETE":return{...n,isLoading:!1,isAuthenticated:e.user!=null,user:e.user,error:void 0};case"LOGOUT":return{...n,isAuthenticated:!1,user:void 0};case"ERROR":return{...n,isLoading:!1,error:e.error}}},Z={isLoading:!0,isAuthenticated:!1},ee=n=>{if(n==null||Object.keys(n).length<=0)return!0;const e=Object.keys(n);for(const t of e)if(n[t]!=null&&n[t]!=="")return!1;return!0},te=n=>!ee(n.config),ne=n=>{const{children:e,configurationEndpoint:t,clientId:i,redirectUrl:o,logoutRedirectUrl:r,scopes:u,onRedirectCallback:f,checkRedirectUrlMatch:y}=n;if(l.useContext(T)!=null)throw new Error("TID Provider already defined");const w={config:{configurationEndpoint:t??"",clientId:i??"",redirectUrl:o??"",logoutRedirectUrl:r??"",scopes:u??[""]}},[a]=l.useState(n.tidClient??new M(w)),[x,p]=l.useReducer(Y,Z),O=l.useRef(!1),ae=l.useMemo(()=>y?a.getRedirectUrl():void 0,[y,a]);l.useEffect(()=>{O.current||(n.tidClient!=null&&te({config:{configurationEndpoint:t,clientId:i,redirectUrl:o,logoutRedirectUrl:r,scopes:u}})&&console.warn("When TID client is pass as prop, any client configuration property sent directly to the TID Provider component will be ignored"),O.current=!0,(async()=>{try{let s;if(q(void 0,ae)){const k=await a.handleCallback();s=await a.getUser(),f?.(k)}else await a.loadUserSession(),s=await a.getUser();p({type:"INIT",user:s})}catch(s){let k=s;typeof s=="string"&&(k=new Error(s)),p({type:"ERROR",error:k})}})())},[a,f]);const D=l.useCallback(async()=>{const s=await a.getAccessTokenSilently(),k=await a.getUser();return p({type:"GET_ACCESS_TOKEN_COMPLETE",user:k}),s},[a]),U=l.useCallback(async()=>{const s=await a.getTokens(),k=await a.getUser();return p({type:"GET_TOKENS_COMPLETE",user:k}),s},[a]),L=l.useCallback(async s=>{await a.loginWithRedirect(s)},[a]),N=l.useCallback(async s=>{await a.logout(s),s?.disabledAutoRedirect!=null&&s.disabledAutoRedirect&&p({type:"LOGOUT"})},[a]),V=l.useCallback(async s=>{const k=await a.handleCallback(s),ce=await a.getUser();return p({type:"HANDLE_CALLBACK_COMPLETE",user:ce}),k},[a]),se=l.useMemo(()=>({...x,getAccessTokenSilently:D,getTokens:U,loginWithRedirect:L,handleCallback:V,logout:N}),[x,D,U,L,V,N]);return m.jsx(T.Provider,{value:se,children:e})},ie=R,oe=ne,re=({renderComponent:n,loader:e})=>{const{isAuthenticated:t,isLoading:i,loginWithRedirect:o}=R();return l.useEffect(()=>{!i&&!t&&(async()=>await o())()},[i,t,o]),t?n:e||m.jsx(m.Fragment,{})};d.AuthenticationGuard=re,d.TIDClient=M,d.TIDContext=T,d.TIDProvider=oe,d.useAuth=ie,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@trimble-oss/trimble-id-react",
3
3
  "private": false,
4
- "version": "1.0.0",
4
+ "version": "1.0.2-rc1",
5
5
  "homepage": "https://github.com/trimble-oss/trimble-id-sdk-docs-for-react",
6
6
  "author": "Trimble developers <developers@trimble.com>",
7
7
  "license": "MIT",
@@ -14,8 +14,8 @@
14
14
  "build": "tsc && vite build",
15
15
  "test": "jest --coverage",
16
16
  "docs": "typedoc --out ./docs/documentation ./src/ --tsconfig ./tsconfig.json",
17
- "lint": "eslint --ext ts,tsx --report-unused-disable-directives",
18
- "lint:fix": "eslint --fix 'src/**/*.{jsx,ts,tsx}'",
17
+ "lint": "eslint src/",
18
+ "lint:fix": "eslint --fix src/",
19
19
  "format": "prettier --write src//**/*.{ts,tsx,css} --config ./.prettierrc",
20
20
  "prepare": "husky install"
21
21
  },
@@ -31,7 +31,7 @@
31
31
  "module": "./dist/trimble-id-react.es.js",
32
32
  "types": "./dist/index.d.ts",
33
33
  "dependencies": {
34
- "@trimble-oss/trimble-id": "^0.0.7",
34
+ "@trimble-oss/trimble-id": "^1.0.0",
35
35
  "es-cookie": "^1.4.0",
36
36
  "husky": "^8.0.3",
37
37
  "jwt-decode": "^3.1.2"
@@ -42,29 +42,30 @@
42
42
  },
43
43
  "devDependencies": {
44
44
  "@babel/preset-env": "^7.22.20",
45
+ "@eslint/js": "^9.37.0",
45
46
  "@testing-library/react": "^14.0.0",
46
47
  "@types/jest": "^29.5.3",
47
48
  "@types/react": "^18.2.15",
48
49
  "@types/react-dom": "^18.2.7",
49
- "@typescript-eslint/eslint-plugin": "^6.2.0",
50
- "@typescript-eslint/parser": "^6.2.0",
51
- "@vitejs/plugin-react": "^4.0.3",
50
+ "@vitejs/plugin-react": "^5.1.2",
52
51
  "babel-jest": "^29.7.0",
53
- "eslint": "^8.45.0",
54
- "eslint-config-prettier": "^8.9.0",
55
- "eslint-plugin-prettier": "^5.0.0",
56
- "eslint-plugin-react": "^7.33.0",
57
- "eslint-plugin-react-hooks": "^4.6.0",
58
- "eslint-plugin-react-refresh": "^0.4.3",
59
- "gts": "^5.0.0",
52
+ "eslint": "^9.37.0",
53
+ "eslint-config-prettier": "^10.1.8",
54
+ "eslint-plugin-prettier": "^5.5.4",
55
+ "eslint-plugin-react": "^7.37.5",
56
+ "eslint-plugin-react-hooks": "^5.2.0",
57
+ "eslint-plugin-react-refresh": "^0.4.26",
58
+ "globals": "^16.2.0",
59
+ "gts": "^7.0.0",
60
+ "typescript-eslint": "^8.46.0",
60
61
  "jest": "^29.6.2",
61
62
  "jest-environment-jsdom": "^29.6.2",
62
- "lint-staged": "^13.2.3",
63
+ "lint-staged": "^16.2.7",
63
64
  "prettier": "^3.0.0",
64
65
  "ts-jest": "^29.1.1",
65
66
  "typedoc": "^0.25.2",
66
67
  "typescript": "^5.0.2",
67
- "vite": "^4.4.5",
68
+ "vite": "^7.3.0",
68
69
  "vite-plugin-dts": "^1.4.1",
69
70
  "vite-plugin-linter": "^1.2.0",
70
71
  "vite-tsconfig-paths": "^3.5.0"