@gandalan/weblibs 1.2.0 → 1.3.0
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 +20 -30
- package/api/fluentApi.js +72 -257
- package/api/fluentAuthManager.js +291 -0
- package/api/fluentAuthUtils.js +15 -0
- package/api/fluentEnvUtils.js +40 -0
- package/index.js +5 -3
- package/package.json +2 -2
- package/api/fluentAuthBuilder.js +0 -203
package/README.md
CHANGED
|
@@ -1,42 +1,32 @@
|
|
|
1
1
|
# WebLibs for Gandalan JS/TS/Svelte projects
|
|
2
2
|
|
|
3
|
-
## IDAS API
|
|
4
|
-
|
|
3
|
+
## Initialize Fluent IDAS API + local API
|
|
4
|
+
Example:
|
|
5
5
|
```js
|
|
6
|
-
import {
|
|
7
|
-
let idas = IDASFactory.create();
|
|
8
|
-
```
|
|
6
|
+
import { fetchEnvConfig, fluentApi, fluentIdasAuthManager } from '@gandalan/weblibs';
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
async function initializeAuthAndApi() {
|
|
9
|
+
const appToken = 'your-app-token';
|
|
10
|
+
const envConfig = await fetchEnvConfig('dev'); // Replace 'dev' with your desired environment
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
const authManager = await fluentIdasAuthManager(appToken, envConfig.idas).init();
|
|
13
|
+
if (!authManager) {
|
|
14
|
+
return; // init() has redirected to login.
|
|
15
|
+
}
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
globalThis.idas = fluentApi(envConfig.idas, authManager); // IDAS-API instance
|
|
18
|
+
globalThis.api = fluentApi("/api/", authManager); // Local API instance
|
|
19
|
+
}
|
|
16
20
|
```
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
## Usage samples
|
|
19
23
|
|
|
20
24
|
```js
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
.then(d => mandanten = d.sort((a,b) => a.Name.localeCompare(b.Name)))
|
|
25
|
-
.catch(e => error = e),
|
|
26
|
-
idas
|
|
27
|
-
.then(i => i.rollen.getAll())
|
|
28
|
-
.then(d => rollen = d.sort((a,b) => a.Name.localeCompare(b.Name)))
|
|
29
|
-
.catch(e => error = e)
|
|
30
|
-
])
|
|
31
|
-
.then(_ => setMandant(mandantGuid));
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
der hier eingeführte `loader` kann mit dem `{#await}`-Svelte-Konstrukt verwendet werden:
|
|
25
|
+
// Example IDAS API usage
|
|
26
|
+
const responseIdas = await globalThis.idas.get('mandanten');
|
|
27
|
+
console.log(responseIdas[0].Name);
|
|
35
28
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
{:then}
|
|
40
|
-
...
|
|
41
|
-
{/await}
|
|
29
|
+
// Example local API usage
|
|
30
|
+
const responseApi = await globalThis.api.get('some-endpoint');
|
|
31
|
+
console.log(responseApi);
|
|
42
32
|
```
|
package/api/fluentApi.js
CHANGED
|
@@ -1,157 +1,29 @@
|
|
|
1
|
-
import { jwtDecode } from "jwt-decode";
|
|
2
1
|
import { restClient } from "./fluentRestClient";
|
|
3
|
-
import { authBuilder } from "./fluentAuthBuilder";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @typedef {Object} EnvironmentConfig
|
|
7
|
-
* @property {string} name - The environment name.
|
|
8
|
-
* @property {string} version - The version number.
|
|
9
|
-
* @property {string} cms - The CMS URL.
|
|
10
|
-
* @property {string} idas - The IDAS API URL.
|
|
11
|
-
* @property {string} store - The store API URL.
|
|
12
|
-
* @property {string} docs - The documentation URL.
|
|
13
|
-
* @property {string} notify - The notification service URL.
|
|
14
|
-
* @property {string} feedback - The feedback service URL.
|
|
15
|
-
* @property {string} helpcenter - The help center URL.
|
|
16
|
-
* @property {string} reports - The reports service URL.
|
|
17
|
-
* @property {string} webhookService - The webhook service URL.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* buffer for environment data
|
|
22
|
-
* @private
|
|
23
|
-
* @type {Object.<string, EnvironmentConfig>}
|
|
24
|
-
*/
|
|
25
|
-
const envs = {};
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* configure the time before token expiry to renew
|
|
29
|
-
* @type {number}
|
|
30
|
-
*/
|
|
31
|
-
const JWT_SAFE_RENEWAL = 30; // seconds before token expiry to renew
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* fetches the environment data from the hub
|
|
35
|
-
* @export
|
|
36
|
-
* @async
|
|
37
|
-
* @param {string} [env="", env="dev", env="staging", env="produktiv"]
|
|
38
|
-
* @returns {Promise<EnvironmentConfig>}
|
|
39
|
-
*/
|
|
40
|
-
export async function fetchEnv(env = "") {
|
|
41
|
-
if (!(env in envs)) {
|
|
42
|
-
const hubUrl = `https://connect.idas-cloudservices.net/api/Endpoints?env=${env}`;
|
|
43
|
-
console.log("fetching env", hubUrl);
|
|
44
|
-
const r = await fetch(hubUrl);
|
|
45
|
-
const data = await r.json();
|
|
46
|
-
envs[env] = data;
|
|
47
|
-
}
|
|
48
|
-
return envs[env];
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* @typedef {Object} JwtTokenExt
|
|
53
|
-
* @property {string} id
|
|
54
|
-
* @property {string} refreshToken
|
|
55
|
-
*/
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* decode the JWT token and return the refresh token
|
|
59
|
-
* @export
|
|
60
|
-
* @param {string} token
|
|
61
|
-
* @returns {string}
|
|
62
|
-
*/
|
|
63
|
-
export function getRefreshToken(token) {
|
|
64
|
-
const decoded = /** @type {JwtTokenExt} */(jwtDecode(token));
|
|
65
|
-
return decoded.refreshToken;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* check if the token is still valid
|
|
70
|
-
* - checks the expiry date and the JWT_SAFE_RENEWAL buffer
|
|
71
|
-
*
|
|
72
|
-
* @export
|
|
73
|
-
* @param {string} token
|
|
74
|
-
* @returns {boolean}
|
|
75
|
-
*/
|
|
76
|
-
export function isTokenValid(token)
|
|
77
|
-
{
|
|
78
|
-
try
|
|
79
|
-
{
|
|
80
|
-
const decoded = jwtDecode(token);
|
|
81
|
-
if (!decoded || !decoded.exp)
|
|
82
|
-
throw new Error("Invalid token");
|
|
83
|
-
return (decoded.exp - JWT_SAFE_RENEWAL > Date.now() / 1000);
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
2
|
|
|
90
3
|
/**
|
|
91
4
|
* @typedef {Object} FluentApi
|
|
92
5
|
* @property {string} baseUrl - The base URL for API requests.
|
|
93
|
-
* @property {
|
|
94
|
-
* @property {string} env - The environment setting.
|
|
95
|
-
* @property {string} appToken - The application token.
|
|
96
|
-
* @property {string} storageEntry - The storage entry.
|
|
97
|
-
* @property {string} token - The JWT token for authorization.
|
|
98
|
-
* @property {string} refreshToken - The refresh token.
|
|
99
|
-
* @property {function(EnvironmentConfig) : FluentApi} useEnvironment - Sets the environment and returns the FluentApi object.
|
|
100
|
-
* @property {function(string) : FluentApi} useAppToken - Sets the application token and returns the FluentApi object.
|
|
6
|
+
* @property {FluentAuthManager} authManager - The authentication manager.
|
|
101
7
|
* @property {function(string) : FluentApi} useBaseUrl - Sets the base URL for API requests and returns the FluentApi object.
|
|
102
|
-
* @property {function(
|
|
103
|
-
* @property {function(string) : FluentApi} useToken - Sets the JWT token for authorization and returns the FluentApi object.
|
|
104
|
-
* @property {function(string) : FluentApi} useRefreshToken - Sets the refresh token and returns the FluentApi object.
|
|
105
|
-
* @property {function() : FluentApi} useGlobalAuth - Uses global authentication tokens and returns the FluentApi object.
|
|
8
|
+
* @property {function(FluentAuthManager) : FluentApi} useAuthManager - Sets the auth manager and returns the FluentApi object.
|
|
106
9
|
* @property {function(string) : object|Array<any>} get - Async function to perform GET requests.
|
|
107
10
|
* @property {function(string, object|null) : object|Array<any>} put - Async function to perform PUT requests with a payload.
|
|
108
11
|
* @property {function(string, object|null) : object|Array<any>} post - Async function to perform POST requests with a payload.
|
|
109
12
|
* @property {function(string) : object|Array<any>} delete - Async function to perform DELETE requests.
|
|
110
|
-
* @property {Function} ensureAuthenticated - Ensures the user is authenticated before making a request.
|
|
111
|
-
* @property {Function} ensureBaseUrlIsSet - Ensures the base URL is set before making a request.
|
|
112
|
-
* @property {Function} redirectToLogin - Redirects to the login page.
|
|
113
13
|
*/
|
|
114
14
|
|
|
115
15
|
/**
|
|
116
|
-
* Builds a client to communicate with the IDAS
|
|
117
|
-
*
|
|
118
|
-
* @return {FluentApi}
|
|
16
|
+
* Builds a client to communicate with the IDAS or local API using fluent syntax.
|
|
17
|
+
*
|
|
18
|
+
* @return {FluentApi} A configured API client instance.
|
|
119
19
|
*/
|
|
120
20
|
export function createApi() {
|
|
121
21
|
return {
|
|
22
|
+
authManager: {},
|
|
122
23
|
baseUrl: "",
|
|
123
|
-
authUrl: "",
|
|
124
|
-
env: "",
|
|
125
|
-
appToken: "",
|
|
126
|
-
storageEntry: "",
|
|
127
|
-
token: "",
|
|
128
|
-
refreshToken: "",
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* set the environment to use
|
|
132
|
-
*
|
|
133
|
-
* @param {EnvironmentConfig} env
|
|
134
|
-
* @return {FluentApi}
|
|
135
|
-
*/
|
|
136
|
-
useEnvironment(env = {}) {
|
|
137
|
-
this.env = env;
|
|
138
|
-
this.baseUrl = env.idas;
|
|
139
|
-
this.authUrl = env.idas;
|
|
140
|
-
return this;
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* set the app token to use
|
|
145
|
-
*
|
|
146
|
-
* @param {string} [newApptoken=""]
|
|
147
|
-
* @return {FluentApi}
|
|
148
|
-
*/
|
|
149
|
-
useAppToken(newApptoken = "") {
|
|
150
|
-
this.appToken = newApptoken; return this;
|
|
151
|
-
},
|
|
152
24
|
|
|
153
25
|
/**
|
|
154
|
-
*
|
|
26
|
+
* Sets the base URL for API requests.
|
|
155
27
|
*
|
|
156
28
|
* @param {string} [url=""]
|
|
157
29
|
* @return {FluentApi}
|
|
@@ -162,96 +34,59 @@ export function createApi() {
|
|
|
162
34
|
},
|
|
163
35
|
|
|
164
36
|
/**
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
* @param {string} [url=""]
|
|
168
|
-
* @return {FluentApi}
|
|
169
|
-
*/
|
|
170
|
-
useAuthUrl(url = "") {
|
|
171
|
-
this.authUrl = url; return this;
|
|
172
|
-
},
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* set the JWT token for authorization
|
|
176
|
-
*
|
|
177
|
-
* @param {string} [jwtToken=""]
|
|
178
|
-
* @return {FluentApi}
|
|
179
|
-
*/
|
|
180
|
-
useToken(jwtToken = "") {
|
|
181
|
-
this.token = jwtToken; return this;
|
|
182
|
-
},
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* set the refresh token
|
|
186
|
-
*
|
|
187
|
-
* @param {string} [storedRefreshToken=""]
|
|
188
|
-
* @return {FluentApi}
|
|
189
|
-
*/
|
|
190
|
-
useRefreshToken(storedRefreshToken = "") {
|
|
191
|
-
this.refreshToken = storedRefreshToken; return this;
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* tell the client to use the global authentication tokens
|
|
37
|
+
* Sets the authentication manager.
|
|
196
38
|
*
|
|
39
|
+
* @param {FluentAuthManager} authManager
|
|
197
40
|
* @return {FluentApi}
|
|
198
41
|
*/
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
this.token = globalThis.idasTokens.token;
|
|
202
|
-
// eslint-disable-next-line no-undef
|
|
203
|
-
this.refreshToken = globalThis.idasTokens.refreshToken;
|
|
204
|
-
// eslint-disable-next-line no-undef
|
|
205
|
-
this.appToken = globalThis.idasTokens.appToken;
|
|
42
|
+
useAuthManager(authManager) {
|
|
43
|
+
this.authManager = authManager;
|
|
206
44
|
return this;
|
|
207
45
|
},
|
|
208
|
-
|
|
46
|
+
|
|
209
47
|
/**
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
48
|
+
* Sends a GET request, ensuring authentication if needed.
|
|
49
|
+
*
|
|
50
|
+
* @async
|
|
51
|
+
* @param {string} [url=""]
|
|
52
|
+
* @param {boolean} [auth=true]
|
|
53
|
+
* @returns {Promise<Object>}
|
|
54
|
+
*/
|
|
217
55
|
async get(url = "", auth = true) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
return restClient().useBaseUrl(this.baseUrl).useToken(this.token).get(url);
|
|
56
|
+
await this.preCheck(auth);
|
|
57
|
+
return await this.createRestClient().get(url);
|
|
221
58
|
},
|
|
222
59
|
|
|
223
60
|
/**
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
61
|
+
* Sends a PUT request with a payload, ensuring authentication if needed.
|
|
62
|
+
*
|
|
63
|
+
* @async
|
|
64
|
+
* @param {string} [url=""]
|
|
65
|
+
* @param {Object} [payload={}]
|
|
66
|
+
* @param {boolean} [auth=true]
|
|
67
|
+
* @returns {Promise<Object>}
|
|
68
|
+
*/
|
|
232
69
|
async put(url = "", payload = {}, auth = true) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
return restClient().useBaseUrl(this.baseUrl).useToken(this.token).put(url, payload);
|
|
70
|
+
await this.preCheck(auth);
|
|
71
|
+
return await this.createRestClient().put(url, payload);
|
|
236
72
|
},
|
|
237
73
|
|
|
238
74
|
/**
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
75
|
+
* Sends a POST request with a payload, ensuring authentication if needed.
|
|
76
|
+
*
|
|
77
|
+
* @async
|
|
78
|
+
* @param {string} [url=""]
|
|
79
|
+
* @param {Object} [payload={}]
|
|
80
|
+
* @param {boolean} [auth=true]
|
|
81
|
+
* @returns {Promise<Object>}
|
|
82
|
+
*/
|
|
247
83
|
async post(url = "", payload = {}, auth = true) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
return restClient().useBaseUrl(this.baseUrl).useToken(this.token).post(url, payload);
|
|
84
|
+
await this.preCheck(auth);
|
|
85
|
+
return await this.createRestClient().post(url, payload);
|
|
251
86
|
},
|
|
252
|
-
|
|
87
|
+
|
|
253
88
|
/**
|
|
254
|
-
* DELETE request,
|
|
89
|
+
* Sends a DELETE request, ensuring authentication if needed.
|
|
255
90
|
*
|
|
256
91
|
* @async
|
|
257
92
|
* @param {string} [url=""]
|
|
@@ -259,71 +94,51 @@ export function createApi() {
|
|
|
259
94
|
* @returns {Promise<Object>}
|
|
260
95
|
*/
|
|
261
96
|
async delete(url = "", auth = true) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
return restClient().useBaseUrl(this.baseUrl).useToken(this.token).delete(url);
|
|
97
|
+
await this.preCheck(auth);
|
|
98
|
+
return await this.createRestClient().delete(url);
|
|
265
99
|
},
|
|
266
100
|
|
|
267
101
|
/**
|
|
268
|
-
*
|
|
102
|
+
* Creates the REST client instance with the current configuration.
|
|
269
103
|
*
|
|
270
|
-
* @async
|
|
271
104
|
* @private
|
|
105
|
+
* @returns {FluentRestClient}
|
|
272
106
|
*/
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
try {
|
|
278
|
-
const temptoken = await authBuilder()
|
|
279
|
-
.useAppToken(this.appToken)
|
|
280
|
-
.useBaseUrl(this.authUrl || this.env.idas)
|
|
281
|
-
.useToken(this.token)
|
|
282
|
-
.useRefreshToken(this.refreshToken)
|
|
283
|
-
.authenticate() || "";
|
|
284
|
-
|
|
285
|
-
if (!temptoken) {
|
|
286
|
-
throw new Error("not authenticated");
|
|
287
|
-
}
|
|
107
|
+
createRestClient() {
|
|
108
|
+
return restClient().useBaseUrl(this.baseUrl).useToken(this.authManager?.token);
|
|
109
|
+
},
|
|
288
110
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
console.error("not authenticated", e);
|
|
111
|
+
/**
|
|
112
|
+
* Ensures the user is authenticated before making a request.
|
|
113
|
+
*
|
|
114
|
+
* @private
|
|
115
|
+
* @async
|
|
116
|
+
* @param {boolean} [auth=true]
|
|
117
|
+
* @returns {void}
|
|
118
|
+
*/
|
|
119
|
+
async preCheck(auth = true) {
|
|
120
|
+
if (auth && this.authManager) {
|
|
121
|
+
await this.authManager.ensureAuthenticated();
|
|
301
122
|
}
|
|
302
123
|
}
|
|
303
124
|
};
|
|
304
125
|
}
|
|
305
126
|
|
|
306
127
|
/**
|
|
307
|
-
*
|
|
128
|
+
* Sets up a client for API requests.
|
|
308
129
|
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
|
|
313
|
-
export function idasApi(appToken = "") {
|
|
314
|
-
return createApi()
|
|
315
|
-
.useGlobalAuth()
|
|
316
|
-
.useAppToken(appToken);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Default setup for local API
|
|
130
|
+
* - Requests will be sent to the url provided.
|
|
131
|
+
* - Example usage:
|
|
132
|
+
* const api = fluentApi("https://jsonplaceholder.typicode.com/todos/", null);
|
|
133
|
+
* api.get("1"); // Sends a GET request to https://jsonplaceholder.typicode.com/todos/1.
|
|
321
134
|
*
|
|
322
135
|
* @export
|
|
323
|
-
* @
|
|
136
|
+
* @param {string} url - The base URL for API requests.
|
|
137
|
+
* @param {FluentAuthManager} authManager - The authentication manager instance.
|
|
138
|
+
* @return {FluentApi} Configured API instance for local use.
|
|
324
139
|
*/
|
|
325
|
-
export function
|
|
140
|
+
export function fluentApi(url, authManager) {
|
|
326
141
|
return createApi()
|
|
327
|
-
.
|
|
328
|
-
.useBaseUrl(
|
|
142
|
+
.useAuthManager(authManager)
|
|
143
|
+
.useBaseUrl(url);
|
|
329
144
|
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { jwtDecode } from "jwt-decode";
|
|
2
|
+
import validator from "validator";
|
|
3
|
+
import { popRefreshTokenFromUrl } from "./fluentAuthUtils";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {Object} FluentAuthManager
|
|
7
|
+
* @property {string} appToken - The application token.
|
|
8
|
+
* @property {string} authUrl - The authentication URL.
|
|
9
|
+
* @property {string} token - The JWT token for authorization.
|
|
10
|
+
* @property {string} refreshToken - The refresh token.
|
|
11
|
+
* @property {object} userInfo - The user information.
|
|
12
|
+
* @property {function(string) : FluentAuthManager} useAppToken - Sets the application token and returns the FluentApi object.
|
|
13
|
+
* @property {function(string) : FluentAuthManager} useBaseUrl - Sets the base URL for authentication and returns the FluentApi object.
|
|
14
|
+
* @property {function(string|null) : FluentAuthManager} useToken - Sets the JWT token and returns the FluentApi object. Only intended for usage with Service Tokens.
|
|
15
|
+
* @property {function(string|null) : FluentAuthManager} useRefreshToken - Sets the refresh token and returns the FluentApi object.
|
|
16
|
+
* @property {function} ensureAuthenticated - Ensures the user is authenticated before making a request.
|
|
17
|
+
* @property {function() : string} authenticate - Authenticates the user with username and password, or refreshes the token.
|
|
18
|
+
* @property {function():Promise<FluentAuthManager|null>} init - Returns promise for authManager. Returns null if not authenticated.
|
|
19
|
+
* @property {function(string,string) : string} login - Logs in with the provided credentials.
|
|
20
|
+
* @property {function} tryRefreshToken - Attempts to refresh the authentication token using the refresh token.
|
|
21
|
+
* @property {function} updateUserSession - Updates the user session with the new token.
|
|
22
|
+
* @property {function} redirectToLogin - Redirects to the login page.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Creates a new FluentAuthManager
|
|
27
|
+
*
|
|
28
|
+
* @export
|
|
29
|
+
* @returns {FluentAuthManager}
|
|
30
|
+
*/
|
|
31
|
+
export function createAuthManager() {
|
|
32
|
+
return {
|
|
33
|
+
appToken: "",
|
|
34
|
+
authUrl: "",
|
|
35
|
+
token: "",
|
|
36
|
+
refreshToken: "",
|
|
37
|
+
userInfo: {},
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* app token to use for authentication
|
|
41
|
+
*
|
|
42
|
+
* @param {string} [appToken=""]
|
|
43
|
+
* @returns {FluentAuthManager}
|
|
44
|
+
*/
|
|
45
|
+
useAppToken(appToken = "") {
|
|
46
|
+
if (!validator.isUUID(appToken)) {
|
|
47
|
+
console.error("AppToken is not valid GUID");
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
this.appToken = appToken;
|
|
51
|
+
return this;
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* set the authentication URL
|
|
56
|
+
*
|
|
57
|
+
* @param {string} [url=""]
|
|
58
|
+
* @return {FluentAuthManager}
|
|
59
|
+
*/
|
|
60
|
+
useBaseUrl(url = "") {
|
|
61
|
+
this.authUrl = url;
|
|
62
|
+
return this;
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* set the JWT token for authorization
|
|
67
|
+
*
|
|
68
|
+
* @param {string} [jwtToken=""]
|
|
69
|
+
* @return {FluentAuthManager}
|
|
70
|
+
*/
|
|
71
|
+
useToken(jwtToken = "") {
|
|
72
|
+
this.token = jwtToken;
|
|
73
|
+
return this;
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* set the refresh token
|
|
78
|
+
*
|
|
79
|
+
* @param {string} [storedRefreshToken=""]
|
|
80
|
+
* @return {FluentAuthManager}
|
|
81
|
+
*/
|
|
82
|
+
useRefreshToken(storedRefreshToken = "") {
|
|
83
|
+
this.refreshToken = storedRefreshToken;
|
|
84
|
+
return this;
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Ensure the user is authenticated before making a request
|
|
89
|
+
*
|
|
90
|
+
* @async
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
async ensureAuthenticated() {
|
|
94
|
+
if (this.token && isTokenValid(this.token))
|
|
95
|
+
return;
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
await this.authenticate();
|
|
99
|
+
} catch (e) {
|
|
100
|
+
// no redirect to login, because we're in a request
|
|
101
|
+
console.error("not authenticated", e);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Authenticates the user with the JWT token or refreshes the token with
|
|
107
|
+
* the refreshToken set before.
|
|
108
|
+
*
|
|
109
|
+
* @throws {Error} if JWT token and refreshToken are not set or both are invalid
|
|
110
|
+
* @return {string} the JWT token
|
|
111
|
+
*/
|
|
112
|
+
async authenticate() { // benutzt bei existierendem JWT oder RefreshToken, wenn keins vorhanden ERROR
|
|
113
|
+
console.log("authenticating:", this.token ? `token set, exp: ${jwtDecode(this.token).exp - (Date.now() / 1000)}` : "no token,", this.refreshToken, this.appToken);
|
|
114
|
+
|
|
115
|
+
if (this.token && isTokenValid(this.token))
|
|
116
|
+
return;
|
|
117
|
+
|
|
118
|
+
if (this.token && !this.refreshToken)
|
|
119
|
+
this.refreshToken = getRefreshToken(this.token);
|
|
120
|
+
|
|
121
|
+
if (!this.refreshToken) {
|
|
122
|
+
throw new Error("not authenticated");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
const temptoken = await this.tryRefreshToken(this.refreshToken);
|
|
127
|
+
this.updateUserSession(temptoken);
|
|
128
|
+
} catch {
|
|
129
|
+
// if refresh failed
|
|
130
|
+
// - current token should still be valid for a while
|
|
131
|
+
// - or user has invalid (refresh) token and needs to login/refresh manually
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Initializes the authentication object. Before calling, set the token and refresh token if available.
|
|
137
|
+
* If the token is not set, the refresh token will be used to try to refresh the token.
|
|
138
|
+
* If the token is not valid, the user will be redirected to the login page.
|
|
139
|
+
* If tokens are valid, they will be stored in this instance of the FluentAuthManager.
|
|
140
|
+
*
|
|
141
|
+
* Side effect if refreshToken is not set: tries to get the refreshToken from the URL or localStorage.
|
|
142
|
+
*
|
|
143
|
+
* @async
|
|
144
|
+
* @return {Promise<FluentAuthManager> | null} the FluentAuthManager or null if not authenticated
|
|
145
|
+
*/
|
|
146
|
+
async init() {
|
|
147
|
+
if (!this.refreshToken) {
|
|
148
|
+
this.refreshToken = popRefreshTokenFromUrl() || localStorage.getItem("idas-refresh-token");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!this.token && this.refreshToken) {
|
|
152
|
+
this.token = await this.tryRefreshToken(this.refreshToken);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (this.token && isTokenValid(this.token)) {
|
|
156
|
+
this.updateUserSession(this.token);
|
|
157
|
+
return this;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!isTokenValid(this.token)) {
|
|
161
|
+
this.redirectToLogin();
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
return this;
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Login with credentials and return the JWT token
|
|
169
|
+
* @param {string} username
|
|
170
|
+
* @param {string} password
|
|
171
|
+
* @return {string} the JWT token
|
|
172
|
+
*/
|
|
173
|
+
async login(username = "", password = "") {
|
|
174
|
+
if (username && password) {
|
|
175
|
+
const payload = { "Email": username, "Password": password, "AppToken": this.appToken };
|
|
176
|
+
const res = await fetch(`${this.authUrl}/LoginJwt`,
|
|
177
|
+
{ method: "POST", body: JSON.stringify(payload), headers: { "Content-Type": "application/json" } });
|
|
178
|
+
this.updateUserSession((await res.json()));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
throw new Error("not authenticated");
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* try to refresh the JWT token by using the refreshToken
|
|
186
|
+
* @async
|
|
187
|
+
* @private
|
|
188
|
+
* @param {string} [refreshToken=""]
|
|
189
|
+
* @returns {unknown}
|
|
190
|
+
*/
|
|
191
|
+
async tryRefreshToken(refreshToken = "") {
|
|
192
|
+
const payload = { "Token": refreshToken };
|
|
193
|
+
const res = await fetch(`${this.authUrl}LoginJwt/Refresh`,
|
|
194
|
+
{
|
|
195
|
+
method: "PUT",
|
|
196
|
+
body: JSON.stringify(payload),
|
|
197
|
+
headers: { "Content-Type": "application/json" },
|
|
198
|
+
});
|
|
199
|
+
return res.ok ? await res.json() : null;
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* update the user session with the new token
|
|
204
|
+
* @private
|
|
205
|
+
* @param {string} token
|
|
206
|
+
* @returns {void}
|
|
207
|
+
*/
|
|
208
|
+
updateUserSession(token) {
|
|
209
|
+
if (token) {
|
|
210
|
+
this.token = token;
|
|
211
|
+
this.refreshToken = getRefreshToken(token);
|
|
212
|
+
this.userInfo = jwtDecode(this.token);
|
|
213
|
+
localStorage.setItem("idas-refresh-token", this.refreshToken);
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Redirect to the login page
|
|
219
|
+
* @private
|
|
220
|
+
*/
|
|
221
|
+
redirectToLogin() {
|
|
222
|
+
if (!window) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const redirectAfterAuth = new URL(window.location.href).origin;
|
|
227
|
+
let redirectUrl = `${redirectAfterAuth}?t=%token%`;
|
|
228
|
+
const url = new URL(this.authUrl);
|
|
229
|
+
url.pathname = "/Session";
|
|
230
|
+
url.search = `?a=${this.appToken}&r=${encodeURIComponent(redirectUrl)}`;
|
|
231
|
+
let loginUrl = url.toString();
|
|
232
|
+
window.location.href = loginUrl;
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* configure the time before token expiry to renew
|
|
239
|
+
* @type {number}
|
|
240
|
+
*/
|
|
241
|
+
const JWT_SAFE_RENEWAL = 30; // seconds before token expiry to renew
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* @typedef {Object} JwtTokenExt
|
|
245
|
+
* @property {string} id
|
|
246
|
+
* @property {string} refreshToken
|
|
247
|
+
*/
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* decode the JWT token and return the refresh token
|
|
251
|
+
* @export
|
|
252
|
+
* @param {string} token
|
|
253
|
+
* @returns {string}
|
|
254
|
+
*/
|
|
255
|
+
export function getRefreshToken(token) {
|
|
256
|
+
const decoded = /** @type {JwtTokenExt} */(jwtDecode(token));
|
|
257
|
+
return decoded.refreshToken;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* check if the token is still valid
|
|
262
|
+
* - checks the expiry date and the JWT_SAFE_RENEWAL buffer
|
|
263
|
+
*
|
|
264
|
+
* @export
|
|
265
|
+
* @param {string} token
|
|
266
|
+
* @returns {boolean}
|
|
267
|
+
*/
|
|
268
|
+
export function isTokenValid(token) {
|
|
269
|
+
try {
|
|
270
|
+
const decoded = jwtDecode(token);
|
|
271
|
+
if (!decoded || !decoded.exp)
|
|
272
|
+
throw new Error("Invalid token");
|
|
273
|
+
return (decoded.exp - JWT_SAFE_RENEWAL > Date.now() / 1000);
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* create a new FluentAuthManager with the provided tokens
|
|
282
|
+
* @export
|
|
283
|
+
* @param {string} appToken
|
|
284
|
+
* @param {string} authBaseUrl
|
|
285
|
+
* @returns {FluentAuthManager}
|
|
286
|
+
*/
|
|
287
|
+
export function fluentIdasAuthManager(appToken, authBaseUrl) {
|
|
288
|
+
return createAuthManager()
|
|
289
|
+
.useAppToken(appToken)
|
|
290
|
+
.useBaseUrl(authBaseUrl)
|
|
291
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gets idas refresh token from the URL if it exists and removes it from the URL.
|
|
3
|
+
*
|
|
4
|
+
* @returns {string|null} The refresh token or null if it does not exist.
|
|
5
|
+
*/
|
|
6
|
+
export function popRefreshTokenFromUrl() {
|
|
7
|
+
const url = new URL(window.location.href);
|
|
8
|
+
const refreshToken = url.searchParams.get("t");
|
|
9
|
+
if (refreshToken) {
|
|
10
|
+
url.searchParams.delete("t");
|
|
11
|
+
window.history.replaceState({}, document.title, url);
|
|
12
|
+
return refreshToken;
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} EnvironmentConfig
|
|
3
|
+
* @property {string} name - The environment name.
|
|
4
|
+
* @property {string} version - The version number.
|
|
5
|
+
* @property {string} cms - The CMS URL.
|
|
6
|
+
* @property {string} idas - The IDAS API URL.
|
|
7
|
+
* @property {string} store - The store API URL.
|
|
8
|
+
* @property {string} docs - The documentation URL.
|
|
9
|
+
* @property {string} notify - The notification service URL.
|
|
10
|
+
* @property {string} feedback - The feedback service URL.
|
|
11
|
+
* @property {string} helpcenter - The help center URL.
|
|
12
|
+
* @property {string} reports - The reports service URL.
|
|
13
|
+
* @property {string} webhookService - The webhook service URL.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* buffer for environment data
|
|
18
|
+
* @private
|
|
19
|
+
* @type {Object.<string, EnvironmentConfig>}
|
|
20
|
+
*/
|
|
21
|
+
const envConfigs = {};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Fetches the environment data from the hub.
|
|
25
|
+
*
|
|
26
|
+
* @export
|
|
27
|
+
* @async
|
|
28
|
+
* @param {string} [envConfig=""] - The environment name (e.g., "dev", "staging", "produktiv").
|
|
29
|
+
* @returns {Promise<EnvironmentConfig>}
|
|
30
|
+
*/
|
|
31
|
+
export async function fetchEnvConfig(envConfig = "") {
|
|
32
|
+
if (!(envConfig in envConfigs)) {
|
|
33
|
+
const hubUrl = `https://connect.idas-cloudservices.net/api/Endpoints?env=${envConfig}`;
|
|
34
|
+
console.log("fetching env", hubUrl);
|
|
35
|
+
const r = await fetch(hubUrl);
|
|
36
|
+
const data = await r.json();
|
|
37
|
+
envConfigs[envConfig] = data;
|
|
38
|
+
}
|
|
39
|
+
return envConfigs[envConfig];
|
|
40
|
+
}
|
package/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { IDASFactory } from "./api/IDAS";
|
|
2
2
|
import { RESTClient } from "./api/RESTClient";
|
|
3
3
|
import { initIDAS } from "./api/authUtils";
|
|
4
|
-
export { IDASFactory,
|
|
4
|
+
export { IDASFactory, initIDAS, RESTClient };
|
|
5
5
|
|
|
6
|
-
export { createApi
|
|
7
|
-
export {
|
|
6
|
+
export { createApi, fluentApi } from "./api/fluentApi";
|
|
7
|
+
export { createAuthManager, fluentIdasAuthManager } from "./api/fluentAuthManager";
|
|
8
|
+
export { fetchEnvConfig } from "./api/fluentEnvUtils";
|
|
8
9
|
export { restClient } from "./api/fluentRestClient";
|
|
10
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gandalan/weblibs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "WebLibs for Gandalan JS/TS/Svelte projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gandalan"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@mdi/js": "^7.4.47",
|
|
25
|
-
"axios": "^1.7.
|
|
25
|
+
"axios": "^1.7.8",
|
|
26
26
|
"jwt-decode": "^4.0.0",
|
|
27
27
|
"validator": "^13.12.0"
|
|
28
28
|
},
|
package/api/fluentAuthBuilder.js
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { jwtDecode } from "jwt-decode";
|
|
2
|
-
import { isTokenValid, getRefreshToken } from "./fluentApi";
|
|
3
|
-
import validator from "validator";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @typedef {Object} FluentAuth
|
|
7
|
-
* @property {string} authUrl - The authentication URL.
|
|
8
|
-
* @property {string} appToken - The application token.
|
|
9
|
-
* @property {string} token - The JWT token.
|
|
10
|
-
* @property {string} refreshToken - The refresh token.
|
|
11
|
-
* @property {function(string) : FluentAuth} useAppToken - Sets the application token and returns the FluentApi object.
|
|
12
|
-
* @property {function(string) : FluentAuth} useBaseUrl - Sets the base URL for authentication and returns the FluentApi object.
|
|
13
|
-
* @property {function(string|null) : FluentAuth} useToken - Sets the JWT token and returns the FluentApi object.
|
|
14
|
-
* @property {function(string|null) : FluentAuth} useRefreshToken - Sets the refresh token and returns the FluentApi object.
|
|
15
|
-
* @property {function() : string} authenticate - Authenticates the user with username and password, or refreshes the token.
|
|
16
|
-
* @property {Function} tryRefreshToken - Attempts to refresh the authentication token using the refresh token.
|
|
17
|
-
* @property {Function} redirectToLogin - Redirects to the login page.
|
|
18
|
-
* @property {Function} init - Initializes the authentication object.
|
|
19
|
-
* @property {function(string,string) : string} login - Logs in with the provided credentials.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Builds an authentication object
|
|
24
|
-
*
|
|
25
|
-
* @export
|
|
26
|
-
* @returns {FluentAuth}
|
|
27
|
-
*/
|
|
28
|
-
export function authBuilder() {
|
|
29
|
-
return {
|
|
30
|
-
authUrl: "",
|
|
31
|
-
appToken: "",
|
|
32
|
-
token: "",
|
|
33
|
-
refreshToken: "",
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* app token to use for authentication
|
|
37
|
-
*
|
|
38
|
-
* @param {string} [appToken=""]
|
|
39
|
-
* @returns {FluentAuth}
|
|
40
|
-
*/
|
|
41
|
-
useAppToken(appToken = "") {
|
|
42
|
-
if (!validator.isUUID(appToken)) {
|
|
43
|
-
console.error("AppToken is not valid GUID");
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
this.appToken = appToken; return this;
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* base URL for authentication
|
|
52
|
-
*
|
|
53
|
-
* @param {string} [authUrl=""]
|
|
54
|
-
* @returns {FluentAuth}
|
|
55
|
-
*/
|
|
56
|
-
useBaseUrl(authUrl = "") {
|
|
57
|
-
this.authUrl = authUrl; return this;
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* token to use for authentication
|
|
62
|
-
*
|
|
63
|
-
* @param {string} [jwtToken=""]
|
|
64
|
-
* @returns {FluentAuth}
|
|
65
|
-
*/
|
|
66
|
-
useToken(jwtToken = "") {
|
|
67
|
-
this.token = jwtToken; return this;
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* sets the refresh token to use
|
|
72
|
-
* @param {string} a refresh token (UUID v4 format)
|
|
73
|
-
* @returns {FluentAuth}
|
|
74
|
-
*/
|
|
75
|
-
useRefreshToken(storedRefreshToken = "") {
|
|
76
|
-
this.refreshToken = storedRefreshToken; return this;
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Authenticates the user with the JWT token or refreshes the token with
|
|
81
|
-
* the refreshToken set before
|
|
82
|
-
* @return {string} the JWT token
|
|
83
|
-
*/
|
|
84
|
-
async authenticate() {
|
|
85
|
-
console.log("authenticating:", this.token ? `token set, exp: ${jwtDecode(this.token).exp - (Date.now() / 1000)}` : "no token,", this.refreshToken, this.appToken);
|
|
86
|
-
|
|
87
|
-
if (this.token && isTokenValid(this.token))
|
|
88
|
-
return this.token;
|
|
89
|
-
|
|
90
|
-
if (this.token && !this.refreshToken)
|
|
91
|
-
this.refreshToken = getRefreshToken(this.token);
|
|
92
|
-
|
|
93
|
-
if (this.refreshToken) {
|
|
94
|
-
try {
|
|
95
|
-
const temptoken = await this.tryRefreshToken(this.refreshToken);
|
|
96
|
-
if (temptoken) {
|
|
97
|
-
this.token = temptoken;
|
|
98
|
-
this.refreshToken = getRefreshToken(temptoken);
|
|
99
|
-
}
|
|
100
|
-
} catch {
|
|
101
|
-
// if refresh failed, we'll return the current token
|
|
102
|
-
// - should still be valid for a while
|
|
103
|
-
}
|
|
104
|
-
return this.token;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
throw new Error("not authenticated");
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Login with credentials and return the JWT token
|
|
112
|
-
* @param {string} username
|
|
113
|
-
* @param {string} password
|
|
114
|
-
* @return {string} the JWT token
|
|
115
|
-
*/
|
|
116
|
-
async login(username = "", password = "")
|
|
117
|
-
{
|
|
118
|
-
if (username && password) {
|
|
119
|
-
const payload = { "Email": username, "Password": password, "AppToken": this.appToken };
|
|
120
|
-
const res = await fetch(`${this.authUrl}/LoginJwt`,
|
|
121
|
-
{ method: "POST", body: JSON.stringify(payload), headers: { "Content-Type": "application/json" } });
|
|
122
|
-
const temptoken = await res.json();
|
|
123
|
-
if (temptoken) {
|
|
124
|
-
this.token = temptoken;
|
|
125
|
-
this.refreshToken = getRefreshToken(temptoken);
|
|
126
|
-
return this.token;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
throw new Error("not authenticated");
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* try to refresh the JWT token by using the refreshToken
|
|
134
|
-
* @async
|
|
135
|
-
* @private
|
|
136
|
-
* @param {string} [refreshToken=""]
|
|
137
|
-
* @returns {unknown}
|
|
138
|
-
*/
|
|
139
|
-
async tryRefreshToken(refreshToken = "") {
|
|
140
|
-
const payload = { "Token": refreshToken };
|
|
141
|
-
const res = await fetch(`${this.authUrl}LoginJwt/Refresh`,
|
|
142
|
-
{
|
|
143
|
-
method: "PUT",
|
|
144
|
-
body: JSON.stringify(payload),
|
|
145
|
-
headers: { "Content-Type": "application/json" },
|
|
146
|
-
});
|
|
147
|
-
return res.ok ? await res.json() : null;
|
|
148
|
-
},
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Initializes the authentication object. Before calling, set the token and refresh token if available.
|
|
152
|
-
* If the token is not set, the refresh token will be used to try to refresh the token.
|
|
153
|
-
* If the token is not valid, the user will be redirected to the login page.
|
|
154
|
-
* If tokens are valid, they will be stored in the global variable idasTokens.
|
|
155
|
-
*/
|
|
156
|
-
async init()
|
|
157
|
-
{
|
|
158
|
-
if (!this.token && this.refreshToken)
|
|
159
|
-
{
|
|
160
|
-
this.token = await this.tryRefreshToken(this.refreshToken);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (this.token && isTokenValid(this.token))
|
|
164
|
-
{
|
|
165
|
-
this.refreshToken = getRefreshToken(this.token);
|
|
166
|
-
localStorage.setItem("idas-refresh-token", this.refreshToken);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (!isTokenValid(this.token))
|
|
170
|
-
{
|
|
171
|
-
this.redirectToLogin();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
let userInfo = {};
|
|
175
|
-
if (this.token)
|
|
176
|
-
{
|
|
177
|
-
userInfo = jwtDecode(this.token);
|
|
178
|
-
}
|
|
179
|
-
// eslint-disable-next-line no-undef
|
|
180
|
-
globalThis.idasTokens = { token: this.token, refreshToken: this.refreshToken, appToken: this.appToken, userInfo };
|
|
181
|
-
},
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Redirect to the login page
|
|
185
|
-
* @private
|
|
186
|
-
*/
|
|
187
|
-
redirectToLogin() {
|
|
188
|
-
if (!window) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const redirectAfterAuth = new URL(window.location.href).origin;
|
|
193
|
-
//let redirectUrl = `${redirectAfterAuth}?r=%target%&j=%jwt%&m=%mandant%`;
|
|
194
|
-
//redirectUrl = redirectUrl.replace("%target%", encodeURIComponent(window.location.href));
|
|
195
|
-
let redirectUrl = `${redirectAfterAuth}?t=%token%`;
|
|
196
|
-
const url = new URL(this.authUrl);
|
|
197
|
-
url.pathname = "/Session";
|
|
198
|
-
url.search = `?a=${this.appToken}&r=${encodeURIComponent(redirectUrl)}`;
|
|
199
|
-
let loginUrl = url.toString();
|
|
200
|
-
window.location.href = loginUrl;
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
}
|