@fusionauth/angular-sdk 1.0.1 → 1.1.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 +5 -0
- package/esm2022/lib/SSRCookieAdapter.mjs +23 -0
- package/esm2022/lib/fusion-auth.module.mjs +4 -5
- package/esm2022/lib/fusion-auth.service.mjs +23 -3
- package/esm2022/lib/injectionToken.mjs +3 -0
- package/esm2022/lib/types.mjs +1 -1
- package/esm2022/sdkcore/CookieHelpers/CookieHelpers.mjs +34 -0
- package/esm2022/sdkcore/CookieHelpers/index.mjs +2 -0
- package/esm2022/sdkcore/RedirectHelper/RedirectHelper.mjs +47 -0
- package/esm2022/sdkcore/RedirectHelper/index.mjs +2 -0
- package/esm2022/sdkcore/SDKConfig/SDKConfig.mjs +2 -0
- package/esm2022/sdkcore/SDKConfig/index.mjs +2 -0
- package/esm2022/sdkcore/SDKContext/SDKContext.mjs +2 -0
- package/esm2022/sdkcore/SDKContext/index.mjs +2 -0
- package/esm2022/sdkcore/SDKCore/SDKCore.mjs +103 -0
- package/esm2022/sdkcore/SDKCore/index.mjs +2 -0
- package/esm2022/sdkcore/UrlHelper/UrlHelper.mjs +64 -0
- package/esm2022/sdkcore/UrlHelper/UrlHelperTypes.mjs +2 -0
- package/esm2022/sdkcore/UrlHelper/index.mjs +3 -0
- package/esm2022/sdkcore/index.mjs +5 -0
- package/esm2022/sdkcore/testUtils/index.mjs +3 -0
- package/esm2022/sdkcore/testUtils/mockLoggedIn.mjs +13 -0
- package/esm2022/sdkcore/testUtils/mockWindowLocation.mjs +10 -0
- package/fesm2022/fusionauth-angular-sdk.mjs +248 -183
- package/fesm2022/fusionauth-angular-sdk.mjs.map +1 -1
- package/lib/SSRCookieAdapter.d.ts +7 -0
- package/lib/fusion-auth.service.d.ts +6 -3
- package/lib/injectionToken.d.ts +3 -0
- package/lib/types.d.ts +8 -0
- package/package.json +3 -3
- package/sdkcore/CookieHelpers/CookieHelpers.d.ts +11 -0
- package/sdkcore/CookieHelpers/index.d.ts +1 -0
- package/sdkcore/RedirectHelper/RedirectHelper.d.ts +10 -0
- package/sdkcore/RedirectHelper/index.d.ts +1 -0
- package/sdkcore/SDKConfig/SDKConfig.d.ts +79 -0
- package/sdkcore/SDKConfig/index.d.ts +1 -0
- package/sdkcore/SDKContext/SDKContext.d.ts +65 -0
- package/sdkcore/SDKContext/index.d.ts +1 -0
- package/sdkcore/SDKCore/SDKCore.d.ts +23 -0
- package/sdkcore/SDKCore/index.d.ts +1 -0
- package/sdkcore/UrlHelper/UrlHelper.d.ts +22 -0
- package/sdkcore/UrlHelper/UrlHelperTypes.d.ts +11 -0
- package/sdkcore/UrlHelper/index.d.ts +2 -0
- package/sdkcore/index.d.ts +5 -0
- package/sdkcore/testUtils/index.d.ts +2 -0
- package/sdkcore/testUtils/mockLoggedIn.d.ts +5 -0
- package/sdkcore/testUtils/mockWindowLocation.d.ts +18 -0
- package/esm2022/lib/core.mjs +0 -241
- package/lib/core.d.ts +0 -57
|
@@ -1,57 +1,45 @@
|
|
|
1
|
-
import { BehaviorSubject, Observable, catchError } from 'rxjs';
|
|
2
1
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { Component, Input, NgModule } from '@angular/core';
|
|
2
|
+
import { InjectionToken, PLATFORM_ID, Injectable, Inject, Component, Input, NgModule } from '@angular/core';
|
|
3
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
4
|
+
import { BehaviorSubject, Observable, catchError } from 'rxjs';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
i(this, 'loginPath');
|
|
19
|
-
i(this, 'registerPath');
|
|
20
|
-
i(this, 'logoutPath');
|
|
21
|
-
i(this, 'tokenRefreshPath');
|
|
22
|
-
(this.serverUrl = e.serverUrl),
|
|
23
|
-
(this.clientId = e.clientId),
|
|
24
|
-
(this.redirectUri = e.redirectUri),
|
|
25
|
-
(this.scope = e.scope),
|
|
26
|
-
(this.mePath = e.mePath ?? '/app/me'),
|
|
27
|
-
(this.loginPath = e.loginPath ?? '/app/login'),
|
|
28
|
-
(this.registerPath = e.registerPath ?? '/app/register'),
|
|
29
|
-
(this.logoutPath = e.logoutPath ?? '/app/logout'),
|
|
30
|
-
(this.tokenRefreshPath = e.tokenRefreshPath ?? '/app/refresh');
|
|
6
|
+
/** A class responsible for generating URLs that FusionAuth SDKs interact with. */
|
|
7
|
+
class UrlHelper {
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.serverUrl = config.serverUrl;
|
|
10
|
+
this.clientId = config.clientId;
|
|
11
|
+
this.redirectUri = config.redirectUri;
|
|
12
|
+
this.scope = config.scope;
|
|
13
|
+
this.postLogoutRedirectUri = config.postLogoutRedirectUri;
|
|
14
|
+
this.mePath = config.mePath ?? '/app/me';
|
|
15
|
+
this.loginPath = config.loginPath ?? '/app/login';
|
|
16
|
+
this.registerPath = config.registerPath ?? '/app/register';
|
|
17
|
+
this.logoutPath = config.logoutPath ?? '/app/logout';
|
|
18
|
+
this.tokenRefreshPath = config.tokenRefreshPath ?? '/app/refresh';
|
|
31
19
|
}
|
|
32
20
|
getMeUrl() {
|
|
33
21
|
return this.generateUrl(this.mePath);
|
|
34
22
|
}
|
|
35
|
-
getLoginUrl(
|
|
23
|
+
getLoginUrl(state) {
|
|
36
24
|
return this.generateUrl(this.loginPath, {
|
|
37
25
|
client_id: this.clientId,
|
|
38
26
|
redirect_uri: this.redirectUri,
|
|
39
27
|
scope: this.scope,
|
|
40
|
-
state
|
|
28
|
+
state,
|
|
41
29
|
});
|
|
42
30
|
}
|
|
43
|
-
getRegisterUrl(
|
|
31
|
+
getRegisterUrl(state) {
|
|
44
32
|
return this.generateUrl(this.registerPath, {
|
|
45
33
|
client_id: this.clientId,
|
|
46
34
|
redirect_uri: this.redirectUri,
|
|
47
35
|
scope: this.scope,
|
|
48
|
-
state
|
|
36
|
+
state,
|
|
49
37
|
});
|
|
50
38
|
}
|
|
51
39
|
getLogoutUrl() {
|
|
52
40
|
return this.generateUrl(this.logoutPath, {
|
|
53
41
|
client_id: this.clientId,
|
|
54
|
-
post_logout_redirect_uri: this.redirectUri,
|
|
42
|
+
post_logout_redirect_uri: this.postLogoutRedirectUri || this.redirectUri,
|
|
55
43
|
});
|
|
56
44
|
}
|
|
57
45
|
getTokenRefreshUrl() {
|
|
@@ -59,199 +47,264 @@ class g {
|
|
|
59
47
|
client_id: this.clientId,
|
|
60
48
|
});
|
|
61
49
|
}
|
|
62
|
-
generateUrl(
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
50
|
+
generateUrl(path, params) {
|
|
51
|
+
const url = new URL(this.serverUrl);
|
|
52
|
+
url.pathname = path;
|
|
53
|
+
if (params) {
|
|
54
|
+
const urlSearchParams = this.generateURLSearchParams(params);
|
|
55
|
+
url.search = urlSearchParams.toString();
|
|
67
56
|
}
|
|
68
|
-
return
|
|
69
|
-
}
|
|
70
|
-
generateURLSearchParams(e) {
|
|
71
|
-
const t = new URLSearchParams();
|
|
72
|
-
return (Object.entries(e).forEach(([s, n]) => {
|
|
73
|
-
n && t.append(s, n);
|
|
74
|
-
}),
|
|
75
|
-
t);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
class o {
|
|
79
|
-
/**
|
|
80
|
-
* Parses document.cookie for the access token expiration cookie value.
|
|
81
|
-
* @returns {(number | null)} The moment of expiration in milliseconds since epoch.
|
|
82
|
-
*/
|
|
83
|
-
static getAccessTokenExpirationMoment(e = 'app.at_exp') {
|
|
84
|
-
const t = document.cookie
|
|
85
|
-
.split('; ')
|
|
86
|
-
.map(n => n.split('='))
|
|
87
|
-
.find(([n]) => n === e), s = t == null ? void 0 : t[1];
|
|
88
|
-
return s ? parseInt(s) * 1e3 : null;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
class p {
|
|
92
|
-
constructor(e) {
|
|
93
|
-
i(this, 'url');
|
|
94
|
-
this.url = e;
|
|
57
|
+
return url;
|
|
95
58
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
headers: {
|
|
102
|
-
'Content-Type': 'text/plain',
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
if (!(e.status >= 200 && e.status < 300))
|
|
106
|
-
throw new Error('error refreshing access token in fusionauth');
|
|
107
|
-
}
|
|
108
|
-
/** Initializes continuous automatic token refresh. */
|
|
109
|
-
initAutoRefresh(e = 10, t) {
|
|
110
|
-
const s = o.getAccessTokenExpirationMoment(t);
|
|
111
|
-
if (!s)
|
|
112
|
-
return;
|
|
113
|
-
const n = e * 1e3, a = /* @__PURE__ */ new Date().getTime(), h = s - n, c = Math.max(h - a, 0);
|
|
114
|
-
return setTimeout(async () => {
|
|
115
|
-
try {
|
|
116
|
-
await this.refreshToken(), this.initAutoRefresh(e);
|
|
117
|
-
}
|
|
118
|
-
catch (l) {
|
|
119
|
-
console.error(l);
|
|
59
|
+
generateURLSearchParams(params) {
|
|
60
|
+
const urlSearchParams = new URLSearchParams();
|
|
61
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
62
|
+
if (value) {
|
|
63
|
+
urlSearchParams.append(key, value);
|
|
120
64
|
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
class m {
|
|
125
|
-
/**
|
|
126
|
-
* Schedules a callback to be invoked at the given moment.
|
|
127
|
-
* @param expirationMoment - the access token expiration moment in milliseconds since the epoch.
|
|
128
|
-
* @param onExpiration - the callback to be invoked at the `expirationMoment`.
|
|
129
|
-
*/
|
|
130
|
-
static scheduleTokenExpirationCallback(e, t) {
|
|
131
|
-
const s = /* @__PURE__ */ new Date().getTime(), n = e - s;
|
|
132
|
-
n > 0 && setTimeout(t, n);
|
|
65
|
+
});
|
|
66
|
+
return urlSearchParams;
|
|
133
67
|
}
|
|
134
68
|
}
|
|
135
|
-
|
|
69
|
+
|
|
70
|
+
/** A class responsible for storing a redirect value in localStorage and cleanup afterward. */
|
|
71
|
+
class RedirectHelper {
|
|
136
72
|
constructor() {
|
|
137
|
-
|
|
73
|
+
this.REDIRECT_VALUE = 'fa-sdk-redirect-value';
|
|
138
74
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
75
|
+
get storage() {
|
|
76
|
+
try {
|
|
77
|
+
return localStorage;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// fallback for non-browser environments where localStorage is not defined.
|
|
81
|
+
return {
|
|
82
|
+
/* eslint-disable */
|
|
83
|
+
setItem(_key, _value) { },
|
|
84
|
+
getItem(_key) { },
|
|
85
|
+
removeItem(_key) { },
|
|
86
|
+
/* eslint-enable */
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
handlePreRedirect(state) {
|
|
91
|
+
const valueForStorage = `${this.generateRandomString()}:${state ?? ''}`;
|
|
92
|
+
this.storage.setItem(this.REDIRECT_VALUE, valueForStorage);
|
|
142
93
|
}
|
|
143
|
-
handlePostRedirect(
|
|
144
|
-
const
|
|
145
|
-
|
|
94
|
+
handlePostRedirect(callback) {
|
|
95
|
+
const stateValue = this.stateValue ?? undefined;
|
|
96
|
+
callback?.(stateValue);
|
|
97
|
+
this.storage.removeItem(this.REDIRECT_VALUE);
|
|
146
98
|
}
|
|
147
99
|
get didRedirect() {
|
|
148
|
-
return
|
|
100
|
+
return Boolean(this.storage.getItem(this.REDIRECT_VALUE));
|
|
149
101
|
}
|
|
150
102
|
get stateValue() {
|
|
151
|
-
const
|
|
152
|
-
if (!
|
|
103
|
+
const redirectValue = this.storage.getItem(this.REDIRECT_VALUE);
|
|
104
|
+
if (!redirectValue) {
|
|
153
105
|
return null;
|
|
154
|
-
|
|
155
|
-
|
|
106
|
+
}
|
|
107
|
+
const [, ...stateValue] = redirectValue.split(':');
|
|
108
|
+
return stateValue.join(':');
|
|
156
109
|
}
|
|
157
110
|
generateRandomString() {
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
111
|
+
const array = new Uint32Array(56 / 2);
|
|
112
|
+
window.crypto.getRandomValues(array);
|
|
113
|
+
return Array.from(array, (n) => ('0' + n.toString(16)).substring(-2)).join('');
|
|
161
114
|
}
|
|
162
115
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Gets the `app.at_exp` cookie and converts it to milliseconds since epoch.
|
|
119
|
+
* Returns -1 if the cookie is not present.
|
|
120
|
+
* @param cookieName - defaults to `app.at_exp`.
|
|
121
|
+
* @param adapter - SSR frameworks like Nuxt, Next, and angular/ssr will pass in an adapter.
|
|
122
|
+
*/
|
|
123
|
+
function getAccessTokenExpirationMoment(cookieName = 'app.at_exp', adapter) {
|
|
124
|
+
if (adapter) {
|
|
125
|
+
return toMilliseconds(adapter.at_exp(cookieName));
|
|
126
|
+
}
|
|
127
|
+
let cookie;
|
|
128
|
+
try {
|
|
129
|
+
// `document` throws a ReferenceError if this runs in a
|
|
130
|
+
// non-browser environment such as an SSR framework like Nuxt or Next.
|
|
131
|
+
cookie = document.cookie;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
console.error('Error accessing cookies in fusionauth. If you are using SSR you must configure the SDK with a cookie adapter');
|
|
135
|
+
return -1;
|
|
136
|
+
}
|
|
137
|
+
const expCookie = cookie
|
|
138
|
+
.split('; ')
|
|
139
|
+
.map(c => c.split('='))
|
|
140
|
+
.find(([name]) => name === cookieName);
|
|
141
|
+
const cookieValue = expCookie?.[1];
|
|
142
|
+
return toMilliseconds(cookieValue);
|
|
143
|
+
}
|
|
144
|
+
function toMilliseconds(seconds) {
|
|
145
|
+
if (!seconds)
|
|
146
|
+
return -1;
|
|
147
|
+
else
|
|
148
|
+
return Number(seconds) * 1000;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** A class containing framework-agnostic SDK methods */
|
|
152
|
+
class SDKCore {
|
|
153
|
+
constructor(config) {
|
|
154
|
+
this.redirectHelper = new RedirectHelper();
|
|
155
|
+
this.config = config;
|
|
156
|
+
this.urlHelper = new UrlHelper({
|
|
157
|
+
serverUrl: config.serverUrl,
|
|
158
|
+
clientId: config.clientId,
|
|
159
|
+
redirectUri: config.redirectUri,
|
|
160
|
+
scope: config.scope,
|
|
161
|
+
mePath: config.mePath,
|
|
162
|
+
loginPath: config.loginPath,
|
|
163
|
+
registerPath: config.registerPath,
|
|
164
|
+
logoutPath: config.logoutPath,
|
|
165
|
+
tokenRefreshPath: config.tokenRefreshPath,
|
|
166
|
+
postLogoutRedirectUri: config.postLogoutRedirectUri,
|
|
167
|
+
});
|
|
168
|
+
this.scheduleTokenExpiration();
|
|
169
|
+
}
|
|
170
|
+
startLogin(state) {
|
|
171
|
+
this.redirectHelper.handlePreRedirect(state);
|
|
172
|
+
window.location.assign(this.urlHelper.getLoginUrl(state));
|
|
173
|
+
}
|
|
174
|
+
startRegister(state) {
|
|
175
|
+
this.redirectHelper.handlePreRedirect(state);
|
|
176
|
+
window.location.assign(this.urlHelper.getRegisterUrl(state));
|
|
191
177
|
}
|
|
192
178
|
startLogout() {
|
|
193
179
|
window.location.assign(this.urlHelper.getLogoutUrl());
|
|
194
180
|
}
|
|
195
181
|
async fetchUserInfo() {
|
|
196
|
-
const
|
|
182
|
+
const userInfoResponse = await fetch(this.urlHelper.getMeUrl(), {
|
|
197
183
|
credentials: 'include',
|
|
198
184
|
});
|
|
199
|
-
if (!
|
|
200
|
-
throw new Error(`Unable to fetch userInfo in fusionauth. Request failed with status code ${
|
|
201
|
-
|
|
185
|
+
if (!userInfoResponse.ok) {
|
|
186
|
+
throw new Error(`Unable to fetch userInfo in fusionauth. Request failed with status code ${userInfoResponse?.status}`);
|
|
187
|
+
}
|
|
188
|
+
const userInfo = await userInfoResponse.json();
|
|
189
|
+
return userInfo;
|
|
202
190
|
}
|
|
203
191
|
async refreshToken() {
|
|
204
|
-
|
|
192
|
+
const response = await fetch(this.urlHelper.getTokenRefreshUrl(), {
|
|
193
|
+
method: 'POST',
|
|
194
|
+
credentials: 'include',
|
|
195
|
+
headers: {
|
|
196
|
+
'Content-Type': 'text/plain',
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
if (!(response.status >= 200 && response.status < 300)) {
|
|
200
|
+
const message = (await response?.text()) ||
|
|
201
|
+
'Error refreshing access token in fusionauth';
|
|
202
|
+
throw new Error(message);
|
|
203
|
+
}
|
|
204
|
+
// a successful request means that app_exp was bumped into the future.
|
|
205
|
+
// reschedule the access token expiration event.
|
|
206
|
+
this.scheduleTokenExpiration();
|
|
207
|
+
return response;
|
|
205
208
|
}
|
|
206
209
|
initAutoRefresh() {
|
|
207
|
-
|
|
210
|
+
if (!this.isLoggedIn) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const secondsBeforeRefresh = this.config.autoRefreshSecondsBeforeExpiry ?? 10;
|
|
214
|
+
const millisecondsBeforeRefresh = secondsBeforeRefresh * 1000;
|
|
215
|
+
const now = new Date().getTime();
|
|
216
|
+
const refreshTime = this.at_exp - millisecondsBeforeRefresh;
|
|
217
|
+
const timeTillRefresh = Math.max(refreshTime - now, 0);
|
|
218
|
+
return setTimeout(async () => {
|
|
219
|
+
try {
|
|
220
|
+
await this.refreshToken();
|
|
221
|
+
this.initAutoRefresh();
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
this.config.onAutoRefreshFailure?.(error);
|
|
225
|
+
}
|
|
226
|
+
}, timeTillRefresh);
|
|
208
227
|
}
|
|
209
|
-
handlePostRedirect(
|
|
210
|
-
this.isLoggedIn &&
|
|
211
|
-
this.redirectHelper.
|
|
212
|
-
|
|
228
|
+
handlePostRedirect(callback) {
|
|
229
|
+
if (this.isLoggedIn && this.redirectHelper.didRedirect) {
|
|
230
|
+
this.redirectHelper.handlePostRedirect(callback);
|
|
231
|
+
}
|
|
213
232
|
}
|
|
214
233
|
get isLoggedIn() {
|
|
215
|
-
return this.
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
this.
|
|
224
|
-
|
|
225
|
-
|
|
234
|
+
return this.at_exp > new Date().getTime();
|
|
235
|
+
}
|
|
236
|
+
/** The moment of access token expiration in milliseconds since epoch. */
|
|
237
|
+
get at_exp() {
|
|
238
|
+
return getAccessTokenExpirationMoment(this.config.accessTokenExpireCookieName, this.config.cookieAdapter);
|
|
239
|
+
}
|
|
240
|
+
/** Schedules `onTokenExpiration` at moment of access token expiration. */
|
|
241
|
+
scheduleTokenExpiration() {
|
|
242
|
+
clearTimeout(this.tokenExpirationTimeout);
|
|
243
|
+
const now = new Date().getTime();
|
|
244
|
+
const millisecondsTillExpiration = this.at_exp - now;
|
|
245
|
+
if (millisecondsTillExpiration > 0) {
|
|
246
|
+
this.tokenExpirationTimeout = setTimeout(this.config.onTokenExpiration, millisecondsTillExpiration);
|
|
247
|
+
}
|
|
226
248
|
}
|
|
227
249
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
250
|
+
|
|
251
|
+
/** Sets `app.at_exp` moment cookie so the user will be logged in for 1 hour. */
|
|
252
|
+
function mockIsLoggedIn() {
|
|
253
|
+
const expirationMoment = new Date();
|
|
254
|
+
expirationMoment.setHours(expirationMoment.getHours() + 1);
|
|
255
|
+
const oneHourInTheFutureInMilliseconds = expirationMoment.getTime() / 1000;
|
|
256
|
+
document.cookie = `app.at_exp=${oneHourInTheFutureInMilliseconds}`;
|
|
233
257
|
}
|
|
234
|
-
|
|
235
|
-
|
|
258
|
+
/** Removes the `app.at_exp` cookie. */
|
|
259
|
+
function removeAt_expCookie() {
|
|
260
|
+
document.cookie = 'app.at_exp' + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT';
|
|
236
261
|
}
|
|
237
|
-
|
|
238
|
-
|
|
262
|
+
|
|
263
|
+
function mockWindowLocation(vi) {
|
|
264
|
+
const mockedLocation = {
|
|
239
265
|
...window.location,
|
|
240
|
-
assign:
|
|
266
|
+
assign: vi.fn(),
|
|
241
267
|
};
|
|
242
|
-
|
|
268
|
+
vi.spyOn(window, 'location', 'get').mockReturnValue(mockedLocation);
|
|
269
|
+
return mockedLocation;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** An adapter class that supports accessing cookies with SSR */
|
|
273
|
+
class SSRCookieAdapter {
|
|
274
|
+
constructor(isBrowser) {
|
|
275
|
+
this.isBrowser = isBrowser;
|
|
276
|
+
}
|
|
277
|
+
at_exp(cookieName = 'app.at_exp') {
|
|
278
|
+
if (!this.isBrowser) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
const expCookie = document.cookie
|
|
283
|
+
.split('; ')
|
|
284
|
+
.map(c => c.split('='))
|
|
285
|
+
.find(([name]) => name === cookieName);
|
|
286
|
+
return expCookie?.[1];
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
console.error('Error within the SSRCookieAdapter: ', error);
|
|
290
|
+
return -1;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
243
293
|
}
|
|
244
294
|
|
|
295
|
+
const FUSIONAUTH_SERVICE_CONFIG = new InjectionToken('FUSIONAUTH_SERVICE_CONFIG');
|
|
296
|
+
|
|
245
297
|
/**
|
|
246
298
|
* Service class to use with FusionAuth backend endpoints.
|
|
247
299
|
*/
|
|
248
300
|
class FusionAuthService {
|
|
249
|
-
constructor(config) {
|
|
250
|
-
this.core = new
|
|
301
|
+
constructor(config, platformId) {
|
|
302
|
+
this.core = new SDKCore({
|
|
251
303
|
...config,
|
|
252
304
|
onTokenExpiration: () => {
|
|
253
305
|
this.isLoggedInSubject.next(false);
|
|
254
306
|
},
|
|
307
|
+
cookieAdapter: new SSRCookieAdapter(isPlatformBrowser(platformId)),
|
|
255
308
|
});
|
|
256
309
|
this.isLoggedInSubject = new BehaviorSubject(this.core.isLoggedIn);
|
|
257
310
|
this.isLoggedIn$ = this.isLoggedInSubject.asObservable();
|
|
@@ -329,7 +382,21 @@ class FusionAuthService {
|
|
|
329
382
|
logout() {
|
|
330
383
|
this.core.startLogout();
|
|
331
384
|
}
|
|
385
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.1", ngImport: i0, type: FusionAuthService, deps: [{ token: FUSIONAUTH_SERVICE_CONFIG }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
386
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.1", ngImport: i0, type: FusionAuthService, providedIn: 'root' }); }
|
|
332
387
|
}
|
|
388
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.1", ngImport: i0, type: FusionAuthService, decorators: [{
|
|
389
|
+
type: Injectable,
|
|
390
|
+
args: [{
|
|
391
|
+
providedIn: 'root',
|
|
392
|
+
}]
|
|
393
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
394
|
+
type: Inject,
|
|
395
|
+
args: [FUSIONAUTH_SERVICE_CONFIG]
|
|
396
|
+
}] }, { type: Object, decorators: [{
|
|
397
|
+
type: Inject,
|
|
398
|
+
args: [PLATFORM_ID]
|
|
399
|
+
}] }] });
|
|
333
400
|
|
|
334
401
|
class FusionAuthLoginButtonComponent {
|
|
335
402
|
constructor(fusionAuth) {
|
|
@@ -385,10 +452,8 @@ class FusionAuthModule {
|
|
|
385
452
|
return {
|
|
386
453
|
ngModule: FusionAuthModule,
|
|
387
454
|
providers: [
|
|
388
|
-
{
|
|
389
|
-
|
|
390
|
-
useValue: new FusionAuthService(fusionAuthConfig),
|
|
391
|
-
},
|
|
455
|
+
{ provide: FUSIONAUTH_SERVICE_CONFIG, useValue: fusionAuthConfig },
|
|
456
|
+
FusionAuthService,
|
|
392
457
|
],
|
|
393
458
|
};
|
|
394
459
|
}
|