authscape 1.0.755 → 1.0.760
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/index.js +98 -21
- package/package.json +2 -2
- package/readme.md +103 -103
- package/src/components/AuthScapeApp.js +81 -3
package/index.js
CHANGED
|
@@ -76,6 +76,7 @@ function AuthScapeApp(_ref) {
|
|
|
76
76
|
var Component = _ref.Component,
|
|
77
77
|
layout = _ref.layout,
|
|
78
78
|
loadingLayout = _ref.loadingLayout,
|
|
79
|
+
signInLoadingComponent = _ref.signInLoadingComponent,
|
|
79
80
|
pageProps = _ref.pageProps,
|
|
80
81
|
_ref$muiTheme = _ref.muiTheme,
|
|
81
82
|
muiTheme = _ref$muiTheme === void 0 ? {} : _ref$muiTheme,
|
|
@@ -97,6 +98,10 @@ function AuthScapeApp(_ref) {
|
|
|
97
98
|
_useState6 = _slicedToArray(_useState5, 2),
|
|
98
99
|
signedInUserState = _useState6[0],
|
|
99
100
|
setSignedInUserState = _useState6[1];
|
|
101
|
+
var _useState7 = (0, _react.useState)(false),
|
|
102
|
+
_useState8 = _slicedToArray(_useState7, 2),
|
|
103
|
+
isSigningIn = _useState8[0],
|
|
104
|
+
setIsSigningIn = _useState8[1];
|
|
100
105
|
var loadingAuth = (0, _react.useRef)(false);
|
|
101
106
|
var signedInUser = (0, _react.useRef)(null);
|
|
102
107
|
var queryCodeUsed = (0, _react.useRef)(null);
|
|
@@ -105,10 +110,13 @@ function AuthScapeApp(_ref) {
|
|
|
105
110
|
var queryCode = searchParams.get("code");
|
|
106
111
|
var pathname = (0, _navigation.usePathname)();
|
|
107
112
|
|
|
113
|
+
// Check if we're on the signin-oidc page
|
|
114
|
+
var isOnSignInPage = pathname === "/signin-oidc";
|
|
115
|
+
|
|
108
116
|
// ----- PKCE Sign-in (browser-only) -----
|
|
109
117
|
var signInValidator = /*#__PURE__*/function () {
|
|
110
118
|
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee(codeFromQuery) {
|
|
111
|
-
var codeVerifier, headers, body, response, domainHost, redirectUri;
|
|
119
|
+
var codeVerifier, headers, body, response, domainHost, redirectUri, usr;
|
|
112
120
|
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
113
121
|
while (1) switch (_context.prev = _context.next) {
|
|
114
122
|
case 0:
|
|
@@ -125,13 +133,17 @@ function AuthScapeApp(_ref) {
|
|
|
125
133
|
}
|
|
126
134
|
return _context.abrupt("return");
|
|
127
135
|
case 5:
|
|
136
|
+
setIsSigningIn(true);
|
|
128
137
|
codeVerifier = window.localStorage.getItem("verifier");
|
|
129
138
|
if (!(!codeFromQuery || !codeVerifier)) {
|
|
130
|
-
_context.next =
|
|
139
|
+
_context.next = 11;
|
|
131
140
|
break;
|
|
132
141
|
}
|
|
142
|
+
// No code or verifier - redirect to login
|
|
143
|
+
window.localStorage.clear();
|
|
144
|
+
module.exports.authService().login();
|
|
133
145
|
return _context.abrupt("return");
|
|
134
|
-
case
|
|
146
|
+
case 11:
|
|
135
147
|
headers = {
|
|
136
148
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
137
149
|
};
|
|
@@ -143,55 +155,83 @@ function AuthScapeApp(_ref) {
|
|
|
143
155
|
client_secret: process.env.client_secret,
|
|
144
156
|
code_verifier: codeVerifier
|
|
145
157
|
});
|
|
146
|
-
_context.prev =
|
|
147
|
-
_context.next =
|
|
158
|
+
_context.prev = 13;
|
|
159
|
+
_context.next = 16;
|
|
148
160
|
return _axios["default"].post(process.env.authorityUri + "/connect/token", body, {
|
|
149
161
|
headers: headers
|
|
150
162
|
});
|
|
151
|
-
case
|
|
163
|
+
case 16:
|
|
152
164
|
response = _context.sent;
|
|
153
165
|
domainHost = window.location.hostname.split(".").slice(-2).join(".");
|
|
154
166
|
window.localStorage.removeItem("verifier");
|
|
155
167
|
|
|
156
168
|
// NOTE: replace setCookie below with your implementation if different
|
|
157
|
-
_context.next =
|
|
169
|
+
_context.next = 21;
|
|
158
170
|
return setCookie("access_token", response.data.access_token, {
|
|
159
171
|
maxAge: 60 * 60 * 24 * 365,
|
|
160
172
|
path: "/",
|
|
161
173
|
domain: domainHost,
|
|
162
174
|
secure: true
|
|
163
175
|
});
|
|
164
|
-
case
|
|
165
|
-
_context.next =
|
|
176
|
+
case 21:
|
|
177
|
+
_context.next = 23;
|
|
166
178
|
return setCookie("expires_in", response.data.expires_in, {
|
|
167
179
|
maxAge: 60 * 60 * 24 * 365,
|
|
168
180
|
path: "/",
|
|
169
181
|
domain: domainHost,
|
|
170
182
|
secure: true
|
|
171
183
|
});
|
|
172
|
-
case
|
|
173
|
-
_context.next =
|
|
184
|
+
case 23:
|
|
185
|
+
_context.next = 25;
|
|
174
186
|
return setCookie("refresh_token", response.data.refresh_token, {
|
|
175
187
|
maxAge: 60 * 60 * 24 * 365,
|
|
176
188
|
path: "/",
|
|
177
189
|
domain: domainHost,
|
|
178
190
|
secure: true
|
|
179
191
|
});
|
|
180
|
-
case
|
|
181
|
-
redirectUri = window.localStorage.getItem("redirectUri");
|
|
192
|
+
case 25:
|
|
193
|
+
redirectUri = window.localStorage.getItem("redirectUri") || "/";
|
|
182
194
|
window.localStorage.clear();
|
|
183
|
-
|
|
184
|
-
|
|
195
|
+
|
|
196
|
+
// Use history.replaceState to change URL without a page reload, then fetch user
|
|
197
|
+
window.history.replaceState({}, "", redirectUri);
|
|
198
|
+
|
|
199
|
+
// Now load the current user and update state
|
|
200
|
+
_context.prev = 28;
|
|
201
|
+
_context.next = 31;
|
|
202
|
+
return module.exports.apiService().GetCurrentUser();
|
|
203
|
+
case 31:
|
|
204
|
+
usr = _context.sent;
|
|
205
|
+
signedInUser.current = ensureUserHelpers(usr);
|
|
206
|
+
setSignedInUserState(signedInUser.current);
|
|
207
|
+
setFrontEndLoadedState(true);
|
|
208
|
+
|
|
209
|
+
// Trigger a soft navigation using Next.js router
|
|
210
|
+
_router["default"].replace(redirectUri, undefined, {
|
|
211
|
+
shallow: false
|
|
212
|
+
});
|
|
213
|
+
_context.next = 41;
|
|
185
214
|
break;
|
|
186
|
-
case
|
|
187
|
-
_context.prev =
|
|
188
|
-
_context.t0 = _context["catch"](
|
|
189
|
-
|
|
190
|
-
|
|
215
|
+
case 38:
|
|
216
|
+
_context.prev = 38;
|
|
217
|
+
_context.t0 = _context["catch"](28);
|
|
218
|
+
// If we can't get user, still navigate
|
|
219
|
+
_router["default"].replace(redirectUri);
|
|
220
|
+
case 41:
|
|
221
|
+
_context.next = 48;
|
|
222
|
+
break;
|
|
223
|
+
case 43:
|
|
224
|
+
_context.prev = 43;
|
|
225
|
+
_context.t1 = _context["catch"](13);
|
|
226
|
+
console.error("PKCE sign-in failed", _context.t1);
|
|
227
|
+
// Invalid code - clear storage and redirect to login
|
|
228
|
+
window.localStorage.clear();
|
|
229
|
+
module.exports.authService().login();
|
|
230
|
+
case 48:
|
|
191
231
|
case "end":
|
|
192
232
|
return _context.stop();
|
|
193
233
|
}
|
|
194
|
-
}, _callee, null, [[
|
|
234
|
+
}, _callee, null, [[13, 43], [28, 38]]);
|
|
195
235
|
}));
|
|
196
236
|
return function signInValidator(_x) {
|
|
197
237
|
return _ref2.apply(this, arguments);
|
|
@@ -321,6 +361,43 @@ function AuthScapeApp(_ref) {
|
|
|
321
361
|
});
|
|
322
362
|
|
|
323
363
|
// ----- Render (SSR-safe; always output page so <title> is visible) -----
|
|
364
|
+
|
|
365
|
+
// Default sign-in loading component if none provided
|
|
366
|
+
var defaultSignInLoading = /*#__PURE__*/_react["default"].createElement("div", {
|
|
367
|
+
style: {
|
|
368
|
+
display: 'flex',
|
|
369
|
+
flexDirection: 'column',
|
|
370
|
+
alignItems: 'center',
|
|
371
|
+
justifyContent: 'center',
|
|
372
|
+
height: '100vh',
|
|
373
|
+
width: '100%',
|
|
374
|
+
backgroundColor: '#f5f5f5'
|
|
375
|
+
}
|
|
376
|
+
}, /*#__PURE__*/_react["default"].createElement("div", {
|
|
377
|
+
style: {
|
|
378
|
+
width: '40px',
|
|
379
|
+
height: '40px',
|
|
380
|
+
border: '4px solid #e0e0e0',
|
|
381
|
+
borderTop: '4px solid #3498db',
|
|
382
|
+
borderRadius: '50%',
|
|
383
|
+
animation: 'spin 1s linear infinite'
|
|
384
|
+
}
|
|
385
|
+
}), /*#__PURE__*/_react["default"].createElement("p", {
|
|
386
|
+
style: {
|
|
387
|
+
marginTop: '16px',
|
|
388
|
+
color: '#666'
|
|
389
|
+
}
|
|
390
|
+
}, "Signing in..."), /*#__PURE__*/_react["default"].createElement("style", null, "\n @keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n "));
|
|
391
|
+
|
|
392
|
+
// Show loading screen when on signin-oidc page
|
|
393
|
+
if (isOnSignInPage || isSigningIn) {
|
|
394
|
+
return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement(_head["default"], null, /*#__PURE__*/_react["default"].createElement("meta", {
|
|
395
|
+
name: "viewport",
|
|
396
|
+
content: "width=device-width, initial-scale=0.86, maximum-scale=5.0, minimum-scale=0.86"
|
|
397
|
+
})), /*#__PURE__*/_react["default"].createElement(_styles.ThemeProvider, {
|
|
398
|
+
theme: muiTheme
|
|
399
|
+
}, signInLoadingComponent || defaultSignInLoading));
|
|
400
|
+
}
|
|
324
401
|
var pageContent = layout ? layout({
|
|
325
402
|
children: /*#__PURE__*/_react["default"].createElement(Component, _extends({}, pageProps, {
|
|
326
403
|
currentUser: currentUser,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "authscape",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.760",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"html2canvas": "^1.4.1",
|
|
49
49
|
"js-cookie": "^3.0.5",
|
|
50
50
|
"js-file-download": "^0.4.12",
|
|
51
|
-
"jspdf": "^
|
|
51
|
+
"jspdf": "^4.0.0",
|
|
52
52
|
"query-string": "^7.1.1",
|
|
53
53
|
"react": "^18.2.0",
|
|
54
54
|
"react-color": "^2.19.3",
|
package/readme.md
CHANGED
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
# AuthScape NPM Package
|
|
2
|
-
|
|
3
|
-
Complete authentication and user management solution for Next.js applications.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install authscape
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Quick Start
|
|
12
|
-
|
|
13
|
-
See the main [AuthScape Documentation](https://authscape.com/docs) for complete setup instructions.
|
|
14
|
-
|
|
15
|
-
## Features
|
|
16
|
-
|
|
17
|
-
### Core Features
|
|
18
|
-
- OAuth2/PKCE Authentication
|
|
19
|
-
- Multi-tenant support
|
|
20
|
-
- User management
|
|
21
|
-
- Role-based permissions
|
|
22
|
-
- Analytics integration (GA4, Microsoft Clarity)
|
|
23
|
-
- Material-UI components
|
|
24
|
-
|
|
25
|
-
### Components
|
|
26
|
-
- Document Manager
|
|
27
|
-
- File Uploader
|
|
28
|
-
- Rich Text Editor
|
|
29
|
-
- Data Tables
|
|
30
|
-
- Stripe Payment Integration
|
|
31
|
-
- Google Maps Integration
|
|
32
|
-
- And more...
|
|
33
|
-
|
|
34
|
-
## Additional Features
|
|
35
|
-
|
|
36
|
-
### Sitemap Generation (NEW!)
|
|
37
|
-
|
|
38
|
-
Automatically generate SEO-friendly sitemaps for your Next.js application.
|
|
39
|
-
|
|
40
|
-
**Automatic setup on install:**
|
|
41
|
-
|
|
42
|
-
When you run `npm install authscape`, a sitemap is automatically configured at `/sitemap.xml` that syncs with your AuthScape content.
|
|
43
|
-
|
|
44
|
-
- Supports both Pages Router and App Router
|
|
45
|
-
- Automatically detects your Next.js project structure
|
|
46
|
-
- Works with both `pages/` and `src/pages/` layouts
|
|
47
|
-
- Works with both `app/` and `src/app/` layouts
|
|
48
|
-
|
|
49
|
-
**To disable:** Simply delete the auto-generated file:
|
|
50
|
-
- Pages Router: `pages/sitemap.xml.js`
|
|
51
|
-
- App Router: `app/sitemap.xml/route.js`
|
|
52
|
-
|
|
53
|
-
## Environment Variables
|
|
54
|
-
|
|
55
|
-
Required environment variables in your `.env.local`:
|
|
56
|
-
|
|
57
|
-
```env
|
|
58
|
-
apiUri=https://your-authscape-api.com
|
|
59
|
-
authorityUri=https://your-auth-server.com
|
|
60
|
-
client_id=your-client-id
|
|
61
|
-
client_secret=your-client-secret
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Optional analytics:
|
|
65
|
-
|
|
66
|
-
```env
|
|
67
|
-
googleAnalytics4=G-XXXXXXXXXX
|
|
68
|
-
microsoftClarityTrackingCode=xxxxxxxxxx
|
|
69
|
-
enableDatabaseAnalytics=true
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Usage Example
|
|
73
|
-
|
|
74
|
-
```javascript
|
|
75
|
-
// pages/_app.js
|
|
76
|
-
import { AuthScapeApp } from 'authscape';
|
|
77
|
-
import 'react-toastify/dist/ReactToastify.css';
|
|
78
|
-
|
|
79
|
-
function MyApp({ Component, pageProps }) {
|
|
80
|
-
return (
|
|
81
|
-
<AuthScapeApp
|
|
82
|
-
Component={Component}
|
|
83
|
-
pageProps={pageProps}
|
|
84
|
-
enforceLoggedIn={false}
|
|
85
|
-
enableAuth={true}
|
|
86
|
-
/>
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export default MyApp;
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## Documentation
|
|
94
|
-
|
|
95
|
-
- [AuthScape Docs](https://authscape.com/docs) - Complete documentation
|
|
96
|
-
|
|
97
|
-
## Support
|
|
98
|
-
|
|
99
|
-
For issues or questions, contact AuthScape support or visit [authscape.com](https://authscape.com).
|
|
100
|
-
|
|
101
|
-
## License
|
|
102
|
-
|
|
103
|
-
ISC
|
|
1
|
+
# AuthScape NPM Package
|
|
2
|
+
|
|
3
|
+
Complete authentication and user management solution for Next.js applications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install authscape
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
See the main [AuthScape Documentation](https://authscape.com/docs) for complete setup instructions.
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
### Core Features
|
|
18
|
+
- OAuth2/PKCE Authentication
|
|
19
|
+
- Multi-tenant support
|
|
20
|
+
- User management
|
|
21
|
+
- Role-based permissions
|
|
22
|
+
- Analytics integration (GA4, Microsoft Clarity)
|
|
23
|
+
- Material-UI components
|
|
24
|
+
|
|
25
|
+
### Components
|
|
26
|
+
- Document Manager
|
|
27
|
+
- File Uploader
|
|
28
|
+
- Rich Text Editor
|
|
29
|
+
- Data Tables
|
|
30
|
+
- Stripe Payment Integration
|
|
31
|
+
- Google Maps Integration
|
|
32
|
+
- And more...
|
|
33
|
+
|
|
34
|
+
## Additional Features
|
|
35
|
+
|
|
36
|
+
### Sitemap Generation (NEW!)
|
|
37
|
+
|
|
38
|
+
Automatically generate SEO-friendly sitemaps for your Next.js application.
|
|
39
|
+
|
|
40
|
+
**Automatic setup on install:**
|
|
41
|
+
|
|
42
|
+
When you run `npm install authscape`, a sitemap is automatically configured at `/sitemap.xml` that syncs with your AuthScape content.
|
|
43
|
+
|
|
44
|
+
- Supports both Pages Router and App Router
|
|
45
|
+
- Automatically detects your Next.js project structure
|
|
46
|
+
- Works with both `pages/` and `src/pages/` layouts
|
|
47
|
+
- Works with both `app/` and `src/app/` layouts
|
|
48
|
+
|
|
49
|
+
**To disable:** Simply delete the auto-generated file:
|
|
50
|
+
- Pages Router: `pages/sitemap.xml.js`
|
|
51
|
+
- App Router: `app/sitemap.xml/route.js`
|
|
52
|
+
|
|
53
|
+
## Environment Variables
|
|
54
|
+
|
|
55
|
+
Required environment variables in your `.env.local`:
|
|
56
|
+
|
|
57
|
+
```env
|
|
58
|
+
apiUri=https://your-authscape-api.com
|
|
59
|
+
authorityUri=https://your-auth-server.com
|
|
60
|
+
client_id=your-client-id
|
|
61
|
+
client_secret=your-client-secret
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Optional analytics:
|
|
65
|
+
|
|
66
|
+
```env
|
|
67
|
+
googleAnalytics4=G-XXXXXXXXXX
|
|
68
|
+
microsoftClarityTrackingCode=xxxxxxxxxx
|
|
69
|
+
enableDatabaseAnalytics=true
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Usage Example
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
// pages/_app.js
|
|
76
|
+
import { AuthScapeApp } from 'authscape';
|
|
77
|
+
import 'react-toastify/dist/ReactToastify.css';
|
|
78
|
+
|
|
79
|
+
function MyApp({ Component, pageProps }) {
|
|
80
|
+
return (
|
|
81
|
+
<AuthScapeApp
|
|
82
|
+
Component={Component}
|
|
83
|
+
pageProps={pageProps}
|
|
84
|
+
enforceLoggedIn={false}
|
|
85
|
+
enableAuth={true}
|
|
86
|
+
/>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default MyApp;
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Documentation
|
|
94
|
+
|
|
95
|
+
- [AuthScape Docs](https://authscape.com/docs) - Complete documentation
|
|
96
|
+
|
|
97
|
+
## Support
|
|
98
|
+
|
|
99
|
+
For issues or questions, contact AuthScape support or visit [authscape.com](https://authscape.com).
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
ISC
|
|
@@ -60,6 +60,7 @@ export function AuthScapeApp({
|
|
|
60
60
|
Component,
|
|
61
61
|
layout,
|
|
62
62
|
loadingLayout,
|
|
63
|
+
signInLoadingComponent,
|
|
63
64
|
pageProps,
|
|
64
65
|
muiTheme = {},
|
|
65
66
|
store = {},
|
|
@@ -69,6 +70,7 @@ export function AuthScapeApp({
|
|
|
69
70
|
const [frontEndLoadedState, setFrontEndLoadedState] = useState(false);
|
|
70
71
|
const [isLoadingShow, setIsLoadingShow] = useState(false);
|
|
71
72
|
const [signedInUserState, setSignedInUserState] = useState(null);
|
|
73
|
+
const [isSigningIn, setIsSigningIn] = useState(false);
|
|
72
74
|
|
|
73
75
|
const loadingAuth = useRef(false);
|
|
74
76
|
const signedInUser = useRef(null);
|
|
@@ -79,6 +81,9 @@ export function AuthScapeApp({
|
|
|
79
81
|
const queryCode = searchParams.get("code");
|
|
80
82
|
const pathname = usePathname();
|
|
81
83
|
|
|
84
|
+
// Check if we're on the signin-oidc page
|
|
85
|
+
const isOnSignInPage = pathname === "/signin-oidc";
|
|
86
|
+
|
|
82
87
|
// ----- PKCE Sign-in (browser-only) -----
|
|
83
88
|
const signInValidator = async (codeFromQuery) => {
|
|
84
89
|
if (queryCodeUsed.current === codeFromQuery) return;
|
|
@@ -86,8 +91,15 @@ export function AuthScapeApp({
|
|
|
86
91
|
|
|
87
92
|
if (typeof window === "undefined") return;
|
|
88
93
|
|
|
94
|
+
setIsSigningIn(true);
|
|
95
|
+
|
|
89
96
|
const codeVerifier = window.localStorage.getItem("verifier");
|
|
90
|
-
if (!codeFromQuery || !codeVerifier)
|
|
97
|
+
if (!codeFromQuery || !codeVerifier) {
|
|
98
|
+
// No code or verifier - redirect to login
|
|
99
|
+
window.localStorage.clear();
|
|
100
|
+
module.exports.authService().login();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
91
103
|
|
|
92
104
|
const headers = { "Content-Type": "application/x-www-form-urlencoded" };
|
|
93
105
|
|
|
@@ -131,11 +143,30 @@ export function AuthScapeApp({
|
|
|
131
143
|
secure: true,
|
|
132
144
|
});
|
|
133
145
|
|
|
134
|
-
const redirectUri = window.localStorage.getItem("redirectUri");
|
|
146
|
+
const redirectUri = window.localStorage.getItem("redirectUri") || "/";
|
|
135
147
|
window.localStorage.clear();
|
|
136
|
-
|
|
148
|
+
|
|
149
|
+
// Use history.replaceState to change URL without a page reload, then fetch user
|
|
150
|
+
window.history.replaceState({}, "", redirectUri);
|
|
151
|
+
|
|
152
|
+
// Now load the current user and update state
|
|
153
|
+
try {
|
|
154
|
+
const usr = await module.exports.apiService().GetCurrentUser();
|
|
155
|
+
signedInUser.current = ensureUserHelpers(usr);
|
|
156
|
+
setSignedInUserState(signedInUser.current);
|
|
157
|
+
setFrontEndLoadedState(true);
|
|
158
|
+
|
|
159
|
+
// Trigger a soft navigation using Next.js router
|
|
160
|
+
Router.replace(redirectUri, undefined, { shallow: false });
|
|
161
|
+
} catch (userErr) {
|
|
162
|
+
// If we can't get user, still navigate
|
|
163
|
+
Router.replace(redirectUri);
|
|
164
|
+
}
|
|
137
165
|
} catch (exp) {
|
|
138
166
|
console.error("PKCE sign-in failed", exp);
|
|
167
|
+
// Invalid code - clear storage and redirect to login
|
|
168
|
+
window.localStorage.clear();
|
|
169
|
+
module.exports.authService().login();
|
|
139
170
|
}
|
|
140
171
|
};
|
|
141
172
|
|
|
@@ -246,6 +277,53 @@ export function AuthScapeApp({
|
|
|
246
277
|
const useStore = create(() => store);
|
|
247
278
|
|
|
248
279
|
// ----- Render (SSR-safe; always output page so <title> is visible) -----
|
|
280
|
+
|
|
281
|
+
// Default sign-in loading component if none provided
|
|
282
|
+
const defaultSignInLoading = (
|
|
283
|
+
<div style={{
|
|
284
|
+
display: 'flex',
|
|
285
|
+
flexDirection: 'column',
|
|
286
|
+
alignItems: 'center',
|
|
287
|
+
justifyContent: 'center',
|
|
288
|
+
height: '100vh',
|
|
289
|
+
width: '100%',
|
|
290
|
+
backgroundColor: '#f5f5f5'
|
|
291
|
+
}}>
|
|
292
|
+
<div style={{
|
|
293
|
+
width: '40px',
|
|
294
|
+
height: '40px',
|
|
295
|
+
border: '4px solid #e0e0e0',
|
|
296
|
+
borderTop: '4px solid #3498db',
|
|
297
|
+
borderRadius: '50%',
|
|
298
|
+
animation: 'spin 1s linear infinite'
|
|
299
|
+
}} />
|
|
300
|
+
<p style={{ marginTop: '16px', color: '#666' }}>Signing in...</p>
|
|
301
|
+
<style>{`
|
|
302
|
+
@keyframes spin {
|
|
303
|
+
0% { transform: rotate(0deg); }
|
|
304
|
+
100% { transform: rotate(360deg); }
|
|
305
|
+
}
|
|
306
|
+
`}</style>
|
|
307
|
+
</div>
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
// Show loading screen when on signin-oidc page
|
|
311
|
+
if (isOnSignInPage || isSigningIn) {
|
|
312
|
+
return (
|
|
313
|
+
<>
|
|
314
|
+
<Head>
|
|
315
|
+
<meta
|
|
316
|
+
name="viewport"
|
|
317
|
+
content="width=device-width, initial-scale=0.86, maximum-scale=5.0, minimum-scale=0.86"
|
|
318
|
+
/>
|
|
319
|
+
</Head>
|
|
320
|
+
<ThemeProvider theme={muiTheme}>
|
|
321
|
+
{signInLoadingComponent || defaultSignInLoading}
|
|
322
|
+
</ThemeProvider>
|
|
323
|
+
</>
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
249
327
|
const pageContent = layout
|
|
250
328
|
? layout({
|
|
251
329
|
children: (
|