@forgerock/login-widget 1.0.0 → 1.0.2-beta.1
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/LICENSE +2 -9
- package/README.md +456 -335
- package/package.json +9 -6
- package/CHANGELOG.md +0 -335
- package/index.cjs +0 -36261
- package/index.cjs.map +0 -1
- package/index.js +0 -36252
- package/index.js.map +0 -1
- package/types.d.ts +0 -2385
- package/widget.css +0 -1632
package/README.md
CHANGED
|
@@ -3,33 +3,33 @@
|
|
|
3
3
|
[](http://commitizen.github.io/cz-cli/)
|
|
4
4
|
[](https://github.com/semantic-release/semantic-release)
|
|
5
5
|
|
|
6
|
-
## WARNING: VAPORWARE
|
|
7
|
-
|
|
8
|
-
**This is a prototype of a development framework for generating a ForgeRock Login App for self-hosting or JavaScript Widget into an existing self-hosted SPA (React, Vue, Angular, etc.). This project is not officially supported and is not recommended for any project development. If you use this, you accept all the risks that come with completely unsupported software.**
|
|
9
|
-
|
|
10
6
|
## Table of Contents
|
|
11
7
|
|
|
12
8
|
- [Overview](#overview)
|
|
9
|
+
- [Requirements](#requirements)
|
|
13
10
|
- [Quick Start: Using the Widget in Your App](#quick-start-using-the-widget-in-your-app)
|
|
11
|
+
- [Installing the package](#installing-the-package)
|
|
14
12
|
- [Adding the Widget's CSS](#adding-the-widgets-css)
|
|
15
|
-
- [Using the
|
|
16
|
-
|
|
13
|
+
- [Using the Widget component](#using-the-widget-component)
|
|
14
|
+
- [What you need to know](#what-you-need-to-know)
|
|
15
|
+
- [Import the API Object](#import-the-api-object)
|
|
16
|
+
- [Call API method to initiate observable](#call-api-method-to-initiate-observable)
|
|
17
|
+
- [Use the subscribe method](#use-the-subscribe-method)
|
|
18
|
+
- [Unsubscribing from an Observable](#unsubscribing-from-an-observable)
|
|
19
|
+
- [Getting the current, local value](#getting-the-current-local-value)
|
|
20
|
+
- [Requesting values from the ForgeRock platform](#requesting-values-from-the-forgerock-platform)
|
|
21
|
+
- [User Promises](#using-promises)
|
|
17
22
|
- [Complete Widget API](#complete-widget-api)
|
|
18
23
|
- [Widget](#widget)
|
|
24
|
+
- [Configuration](#configuration)
|
|
19
25
|
- [Journey](#journey)
|
|
26
|
+
- [Component](#component)
|
|
20
27
|
- [User](#user)
|
|
21
28
|
- [Request](#request)
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
- [Currently unsupported](#currently-unsupported)
|
|
27
|
-
- [Widget customization (future)](#widget-customization-future)
|
|
28
|
-
- [Additional modal events (future)](#additional-modal-events-future)
|
|
29
|
-
- [Quick Start: Internal Login Framework Development](#quick-start-internal-login-framework-development)
|
|
30
|
-
- [Technical requirements](#technical-requirements)
|
|
31
|
-
- [Knowledge requirements](#knowledge-requirements)
|
|
32
|
-
- [Instal, build & run](#instal-build--run)
|
|
29
|
+
- [Styling configuration](#styling-configuration)
|
|
30
|
+
- [Links configuration](#links-configuration)
|
|
31
|
+
- [Content configuration](#content-configuration)
|
|
32
|
+
- [Currently unsupported](#currently-unsupported)
|
|
33
33
|
- [Disclaimer](#disclaimer)
|
|
34
34
|
- [License](#license)
|
|
35
35
|
|
|
@@ -39,68 +39,29 @@ The Login Widget produced by this framework is intended to be an all-inclusive,
|
|
|
39
39
|
|
|
40
40
|
This Widget uses the ForgeRock JavaScript SDK internally. It adds a UI rendering layer on top of the SDK to help eliminate the need to develop and maintain the UI components necessary for providing complex authentication flows. Although this rendering layer is developed with Svelte and Tailwind, it is "compiled away" and has no runtime dependencies. It is library and framework agnostic.
|
|
41
41
|
|
|
42
|
-
This Widget can be
|
|
42
|
+
This Widget can be rendered in two different types (or "form factors"):
|
|
43
43
|
|
|
44
|
-
1. **Modal**
|
|
45
|
-
2. **Inline**
|
|
44
|
+
1. **Modal** type: this is the default and the recommended way to use the widget at first. It renders the form elements inside a modal dialog that can be opened and closed. This component is mounted _outside_ of your app's controlled DOM.
|
|
45
|
+
2. **Inline** type: this is just the form elements themselves, no container. This component is intended to be rendered _inside_ your app's controlled DOM.
|
|
46
46
|
|
|
47
|
-
Both components provide the same authentication,
|
|
47
|
+
Both components provide the same authentication, OAuth/OIDC and user features. The only difference is how the component is rendered within your app.
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
It is highly recommended to start with the Modal form factor when in the experimenting or prototyping phase. It provides the quickest development experience for providing login and registration flows into your app with the least disruption to your existing codebase. The Modal will be controlled within your app, but rendered in its own DOM root node and visual layer.
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
## Requirements
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
<html lang="en">
|
|
56
|
-
<head></head>
|
|
57
|
-
<body>
|
|
58
|
-
<div id="react-root">
|
|
59
|
-
<!--
|
|
60
|
-
Contents of this div are controlled by React or Vue via the Virtual DOM
|
|
61
|
-
-->
|
|
62
|
-
</div>
|
|
63
|
-
<!--
|
|
64
|
-
Outside of React or Vue's controlled DOM
|
|
65
|
-
-->
|
|
66
|
-
<div id="widget-root"></div>
|
|
67
|
-
</body>
|
|
68
|
-
</html>
|
|
69
|
-
```
|
|
53
|
+
1. A EcmaScript Module or CommonJS enable client-side JavaScript app
|
|
54
|
+
2. A "modern", fully-supported browser: Chrome, Firefox, Safari, Chromium Edge (see below for example of what's not supported)
|
|
70
55
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
For example:
|
|
74
|
-
|
|
75
|
-
```html
|
|
76
|
-
<!DOCTYPE html>
|
|
77
|
-
<html lang="en">
|
|
78
|
-
<head></head>
|
|
79
|
-
<body>
|
|
80
|
-
<div id="react-root">
|
|
81
|
-
<!--
|
|
82
|
-
Contents of this div are controlled by React or Vue via the Virtual DOM
|
|
83
|
-
|
|
84
|
-
Widget's root will need to be _mounted_ inside this "controlled" div by
|
|
85
|
-
React or Vue **before** instantiating Widget
|
|
86
|
-
-->
|
|
87
|
-
</div>
|
|
88
|
-
</body>
|
|
89
|
-
</html>
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
More details will be discussed below in the [Inline section](#using-the-inline-component).
|
|
56
|
+
What's not supported? Internet Explorer, Legacy Edge, WebView, Electron and other modified, browser-like environments are _not_ supported.
|
|
93
57
|
|
|
94
58
|
## Quick Start: Using the Widget in Your App
|
|
95
59
|
|
|
96
|
-
|
|
60
|
+
### Installing the package
|
|
97
61
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
4. `npm run build:widget`
|
|
102
|
-
5. Copy the built `package/` directory with its contents and paste (or drag-n-drop) it into your project
|
|
103
|
-
6. Import the Widget by directory reference, since it's local to your project; e.g. `import Widget from '../path/to/package/modal';`
|
|
62
|
+
```shell
|
|
63
|
+
npm install @forgerock/login-widget
|
|
64
|
+
```
|
|
104
65
|
|
|
105
66
|
### Adding the Widget's CSS
|
|
106
67
|
|
|
@@ -108,7 +69,7 @@ There are a few ways to add the Widget's CSS to your product:
|
|
|
108
69
|
|
|
109
70
|
1. Import it into your JavaScript project as a module
|
|
110
71
|
2. Import it using a CSS preprocessor, like Sass, Less or PostCSS
|
|
111
|
-
3. Copy
|
|
72
|
+
3. Copy the CSS file from the package and link it into your HTML
|
|
112
73
|
|
|
113
74
|
If you decide to import the CSS into your JavaScript, make sure your bundler knows how to import and process the CSS as a module. If using a CSS preprocessor, ensure you configure your preprocessor to access files from within your `package/` directory.
|
|
114
75
|
|
|
@@ -117,23 +78,26 @@ Copying the file and pasting it into your project for linking in the HTML is the
|
|
|
117
78
|
Importing into your JavaScript:
|
|
118
79
|
|
|
119
80
|
```js
|
|
120
|
-
|
|
81
|
+
// app.js
|
|
82
|
+
import '@forgerock/login-widget/widget.css';
|
|
121
83
|
```
|
|
122
84
|
|
|
123
85
|
Importing into your CSS:
|
|
124
86
|
|
|
125
87
|
```css
|
|
126
|
-
|
|
88
|
+
/* style.css */
|
|
89
|
+
@import '@forgerock/login-widget/widget.css';
|
|
127
90
|
```
|
|
128
91
|
|
|
129
|
-
Linking CSS in HTML example:
|
|
92
|
+
Linking CSS in HTML example (you may have to copy the CSS file out of the npm module and into your static files directory):
|
|
130
93
|
|
|
131
94
|
```html
|
|
95
|
+
<!-- index.html -->
|
|
132
96
|
<!DOCTYPE html>
|
|
133
97
|
<html lang="en">
|
|
134
98
|
<head>
|
|
135
99
|
<!-- ... -->
|
|
136
|
-
<link rel="stylesheet" href="/path/to/
|
|
100
|
+
<link rel="stylesheet" href="/path/to/file/widget.css" />
|
|
137
101
|
</head>
|
|
138
102
|
<body>
|
|
139
103
|
<!-- ... -->
|
|
@@ -143,7 +107,7 @@ Linking CSS in HTML example:
|
|
|
143
107
|
|
|
144
108
|
#### Controlling the CSS cascade
|
|
145
109
|
|
|
146
|
-
|
|
110
|
+
Though not required, this helps solve common style issues that may pop up related to the CSS cascade. Using `@layer` will ensure the browser applies the CSS in the way you intend, regardless of the order you import or declare the CSS in your project. You can [read more about this new browser feature in the Mozilla docs](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer).
|
|
147
111
|
|
|
148
112
|
Steps recommended:
|
|
149
113
|
|
|
@@ -172,7 +136,7 @@ Steps recommended:
|
|
|
172
136
|
|
|
173
137
|
It's important to note that none of the CSS imported for the Widget will overwrite any of your app's CSS. It's all namespaced to ensure there are no collisions. Unless, that is, you use the exact same selector naming convention we use.
|
|
174
138
|
|
|
175
|
-
### Using the
|
|
139
|
+
### Using the Widget component
|
|
176
140
|
|
|
177
141
|
#### Add element to your HTML file
|
|
178
142
|
|
|
@@ -189,98 +153,175 @@ Example:
|
|
|
189
153
|
<body>
|
|
190
154
|
<!-- Root element for main app -->
|
|
191
155
|
<div id="root"></div>
|
|
156
|
+
|
|
192
157
|
<!-- Root element for Widget -->
|
|
193
158
|
<div id="widget-root"></div>
|
|
159
|
+
|
|
194
160
|
<!-- scripts ... -->
|
|
195
161
|
</body>
|
|
196
162
|
</html>
|
|
197
163
|
```
|
|
198
164
|
|
|
199
|
-
NOTE: We do not recommend
|
|
165
|
+
NOTE: We do not recommend mounting the Widget on a dynamic element that's inside your main application's "controlled DOM". If you're not experienced with mixed rendering types in the Virtual DOM, you may find this challenging at first. So, to ensure success at the start, manually adding it outside of your application's controlled DOM is best. It's recommended to put the element for Widget mounting in your static HTML file as a child of the `<body>` tag.
|
|
200
166
|
|
|
201
|
-
#### Instantiate the Widget
|
|
167
|
+
#### Instantiate the Widget
|
|
202
168
|
|
|
203
|
-
|
|
169
|
+
You can import the Widget into your app wherever you would like as a modal dialog (aka "lightbox"), this form factor is the default. Once the Widget is imported, you will need to instantiate it.
|
|
204
170
|
|
|
205
171
|
```js
|
|
206
172
|
// As modal dialog
|
|
207
|
-
import Widget from 'forgerock
|
|
173
|
+
import Widget from '@forgerock/login-widget';
|
|
208
174
|
|
|
209
175
|
// ...
|
|
210
176
|
|
|
177
|
+
// Grab the root element added to your HTML file
|
|
178
|
+
const widgetRootEl = document.getElementById('widget-root');
|
|
179
|
+
|
|
180
|
+
// Instantiate Widget with the `new` keyword
|
|
211
181
|
new Widget({
|
|
212
|
-
target:
|
|
213
|
-
props: {
|
|
214
|
-
config: {}, // Your JS SDK configuration; see below
|
|
215
|
-
},
|
|
182
|
+
target: widgetRootEl, // Any existing element from static HTML file
|
|
216
183
|
});
|
|
217
184
|
```
|
|
218
185
|
|
|
219
|
-
This mounts
|
|
186
|
+
This instantiates the component and mounts the Widget into the DOM. By default, it will be the Modal version, and will therefore be be hidden at first. Component controls will be discussed shortly.
|
|
220
187
|
|
|
221
188
|
Note: [See additional documentation about configuring the JS SDK](https://backstage.forgerock.com/docs/sdks/3.3/javascript/configuring/configuring-forgerock-sdk-settings-for-your-javascript-app.html).
|
|
222
189
|
|
|
223
|
-
####
|
|
190
|
+
#### The component lifecycle
|
|
224
191
|
|
|
225
|
-
|
|
192
|
+
When using the default Modal form factor, the first thing you'll want to do is open it. To do this, you need to import the `component` function. Executing this function will return a `componentEvents` object, you can name this whatever you'd like. Calling the `componentEvents.open` method will trigger the modal to animate into view.
|
|
226
193
|
|
|
227
194
|
```js
|
|
228
|
-
import Widget, {
|
|
195
|
+
import Widget, { component } from '@forgerock/login-widget';
|
|
229
196
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
197
|
+
// ...
|
|
198
|
+
|
|
199
|
+
const componentEvents = component();
|
|
200
|
+
|
|
201
|
+
new Widget({ target: widgetRootEl }); // Instantiate the Widget
|
|
202
|
+
|
|
203
|
+
componentEvents.open(); // Ensure this is called after the Widget has been instantiated
|
|
204
|
+
|
|
205
|
+
// A more realistic pattern is calling this within a button click
|
|
206
|
+
const loginButton = document.getElementById('loginButton');
|
|
207
|
+
loginButton.addEventListener('click', () => {
|
|
208
|
+
componentEvents.open();
|
|
235
209
|
});
|
|
210
|
+
```
|
|
236
211
|
|
|
237
|
-
|
|
238
|
-
journey.start();
|
|
212
|
+
NOTE: Opening the modal by itself will just reveal the modal with a loading spinner. This is because the Widget has no data to inform it on what to render. We will solve this in the "Starting a journey" section.
|
|
239
213
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
214
|
+
In addition to being able to open the modal, you'll likely want to know when it's mounted, or closed by the user or upon completed authentication. This is done via the same API. A `subscribe` method will be on this `componentEvents` object (which technically makes this an observable), and all component related events will trigger the `subscribe` function to be called passing the `event` state to your callback function.
|
|
215
|
+
|
|
216
|
+
```js
|
|
217
|
+
componentEvents.subscribe((event) => {
|
|
218
|
+
if (event.mounted) {
|
|
219
|
+
console.log('Widget is mounted!');
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
When the user successfully authenticates, the modal will close itself and emit an event. You can detect this within your `subscribe` callback function and the `event` object.
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
componentEvents.subscribe((event) => {
|
|
228
|
+
if (event.mounted) {
|
|
229
|
+
console.log('Widget is mounted!');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (event.open === false) {
|
|
233
|
+
console.log(event.reason); // The reason for closing will be provided
|
|
234
|
+
}
|
|
243
235
|
});
|
|
244
236
|
```
|
|
245
237
|
|
|
246
|
-
|
|
238
|
+
If you'd like to close the modal programmatically, you can via the `componentEvents.close` method.
|
|
239
|
+
|
|
240
|
+
#### Configuring the Widget
|
|
247
241
|
|
|
248
|
-
|
|
242
|
+
Before the Widget can interact with the ForgeRock platform, it will need to be configured. We have a `configuration` function for this API.
|
|
249
243
|
|
|
250
|
-
|
|
244
|
+
First, import the `configuration` function from the module and call it to receive the config API. This API has a single method called `set`. Let's start with the minimal configuration.
|
|
251
245
|
|
|
252
246
|
```js
|
|
253
|
-
|
|
254
|
-
|
|
247
|
+
import { configuration } from '@forgerock/login-widget';
|
|
248
|
+
|
|
249
|
+
const config = configuration();
|
|
250
|
+
config.set({
|
|
251
|
+
forgerock: {
|
|
252
|
+
serverConfig: {
|
|
253
|
+
baseUrl: 'https://example.forgeblocks.com/am/', // This needs to be your AM URL
|
|
254
|
+
timeout: 3000, // In milliseconds; 3 to 5 seconds should be fine
|
|
255
|
+
},
|
|
256
|
+
},
|
|
255
257
|
});
|
|
256
258
|
```
|
|
257
259
|
|
|
258
|
-
|
|
260
|
+
NOTE: It's best to configure the Widget at the top level of your application, like its `index.js` or `app.js` file. This will ensure the Widget has the configuration needed to call out to the ForgeRock platform whenever you use the other Widget APIs.
|
|
259
261
|
|
|
260
|
-
####
|
|
262
|
+
#### Starting a journey
|
|
261
263
|
|
|
262
|
-
To
|
|
264
|
+
For the Widget to display the appropriate form fields, a request needs to be made to ForgeRock for the first step of the journey. To render the first step, you'll need to import the `journey` function and execute it to receive the `journeyEvents` object (you'll notice this is a pattern throughout the Widget API). Once you have this `journeyEvents` object, you can call the `journeyEvents.start` method. Calling `start` makes the initial request to the ForgeRock server for the initial form fields.
|
|
263
265
|
|
|
264
266
|
```js
|
|
265
|
-
import Widget, {
|
|
267
|
+
import Widget, { journey } from '@forgerock/login-widget';
|
|
268
|
+
|
|
269
|
+
const journeyEvents = journey();
|
|
266
270
|
|
|
267
271
|
// ...
|
|
268
272
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
273
|
+
new Widget({
|
|
274
|
+
target: widgetRootEl, // Any existing element in the DOM
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// Ensure you call `.start` *AFTER* instantiating the Widget
|
|
278
|
+
journeyEvents.start();
|
|
279
|
+
|
|
280
|
+
// OR, in a more typical situation, call on button click
|
|
281
|
+
buttonElement.addEventListener('click', (event) => {
|
|
282
|
+
journeyEvents.start();
|
|
272
283
|
});
|
|
273
284
|
```
|
|
274
285
|
|
|
275
|
-
|
|
286
|
+
NOTE: This `journeyEvents.start` method can be called anywhere in your application, or anytime, as long as it's _after_ calling the configuration's `set` method and _after_ instantiating the Widget (which mounts it to the DOM) as both are requirements for a journey.
|
|
276
287
|
|
|
277
|
-
|
|
288
|
+
#### Getting a session
|
|
278
289
|
|
|
279
|
-
|
|
290
|
+
By default, the Widget is going to do more than just get a user's session. It will also get OAuth/OIDC tokens and retrieve user information. But, let's start small.
|
|
280
291
|
|
|
281
|
-
|
|
292
|
+
Let's only ask for session information, and disable OAuth and user info. This will simplify our initial setup. To do this, call the `journey` function passing false for `oauth` and `user`.
|
|
282
293
|
|
|
283
|
-
|
|
294
|
+
```js
|
|
295
|
+
const journeyEvents = journey({ oauth: false, user: false });
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Now, when you call `journeyEvents.start()`, you will only get session information upon successful authentication.
|
|
299
|
+
|
|
300
|
+
NOTE: It's also worth nothing that if you don't declare what journey you want to use, the ForgeRock platform will use what is marked as the default journey, usually just the basic Login journey.
|
|
301
|
+
|
|
302
|
+
#### Listening for journey completion
|
|
303
|
+
|
|
304
|
+
Use the `journeyEvents.subscribe` method (this is the observable part) to know when a user has completed their journey. Pass a callback function into this method to run on journey related events (there will be a quite a few of them). You will receive an event object with a lot of data in it. You'll want to conditionally check for the events you're interested in and ignore what you don't need.
|
|
305
|
+
|
|
306
|
+
```js
|
|
307
|
+
// ...
|
|
308
|
+
|
|
309
|
+
journeyEvents.subscribe((event) => {
|
|
310
|
+
// Will be called multiple times, so narrowing what you're interested in is important
|
|
311
|
+
if (event.journey.successful) {
|
|
312
|
+
// Will log once to the console when authentication has succeeded and returned session data
|
|
313
|
+
console.log(event);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
And, that's it. You now can mount, display, and authenticate users through the ForgeRock Login Widget. There are addition features documented below for a more complete implementation.
|
|
319
|
+
|
|
320
|
+
### Want to inline the Widget into your app (no modal)?
|
|
321
|
+
|
|
322
|
+
The Widget requires a real DOM element on which to mount. Since the inline type will be mounted within your application's controlled DOM, it's important to understand the lifecycle of how your framework mounts elements to the DOM.
|
|
323
|
+
|
|
324
|
+
React, for example, uses the Virtual DOM, and the inline component cannot mount to a Virtual DOM element. So, you will need to wait until the element has been property mounted to the real DOM before instantiating the Widget.
|
|
284
325
|
|
|
285
326
|
#### Instantiate the Widget (Inline)
|
|
286
327
|
|
|
@@ -288,14 +329,14 @@ Now, import the Widget where you'd like to mount it. In whatever way your framew
|
|
|
288
329
|
|
|
289
330
|
```js
|
|
290
331
|
// As inline
|
|
291
|
-
import Widget from 'forgerock
|
|
332
|
+
import Widget from '@forgerock/login-widget';
|
|
292
333
|
|
|
293
334
|
// ...
|
|
294
335
|
|
|
295
336
|
new Widget({
|
|
296
337
|
target: mountedDomElement, // ensure this is a reference to a real DOM element
|
|
297
338
|
props: {
|
|
298
|
-
|
|
339
|
+
type: 'inline', // Your JS SDK configuration; see below
|
|
299
340
|
},
|
|
300
341
|
});
|
|
301
342
|
```
|
|
@@ -304,41 +345,106 @@ This mounts your Widget into the DOM. If you choose the modal version, it will b
|
|
|
304
345
|
|
|
305
346
|
Note: [See additional documentation about configuring the JS SDK](https://backstage.forgerock.com/docs/sdks/3.3/javascript/configuring/configuring-forgerock-sdk-settings-for-your-javascript-app.html).
|
|
306
347
|
|
|
307
|
-
|
|
348
|
+
## What you need to know
|
|
349
|
+
|
|
350
|
+
Most of this Widget's APIs are asynchronous. As with many things in the JavaScript world, there are multiple patterns to handle asynchronous behavior. We've decided to centralize the Widget's APIs around the event-centric, Observable pattern. Since this Widget is powered by Svelte's compiler, we use Svelte's simplified, but standard Observable implementation called a "store". You can [read more about the Svelte store contract in their docs](https://svelte.dev/docs#component-format-script-4-prefix-stores-with-$-to-access-their-values-store-contract).
|
|
351
|
+
|
|
352
|
+
We believe this is an optimal pattern for UI development as it allows for a more dynamic, user experience. Your application will be updated with each event from emitted from within the Widget. These events could be "loading", "completed", "success" or "failure". To help illustrate this, let's take a look at one of the `user` APIs:
|
|
308
353
|
|
|
309
|
-
|
|
354
|
+
### Import the API object
|
|
310
355
|
|
|
311
356
|
```js
|
|
312
|
-
import
|
|
357
|
+
import { user } from '@forgerock/login-widget';
|
|
358
|
+
```
|
|
313
359
|
|
|
314
|
-
|
|
315
|
-
new Widget({
|
|
316
|
-
target: actualDomElement, // ensure this is a reference to a real DOM element
|
|
317
|
-
props: {
|
|
318
|
-
config: {}, // Your JS SDK configuration; see below
|
|
319
|
-
},
|
|
320
|
-
});
|
|
321
|
-
journey.start();
|
|
360
|
+
### Call API method to initiate observable
|
|
322
361
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
362
|
+
Create a variable and assign the created observable:
|
|
363
|
+
|
|
364
|
+
```js
|
|
365
|
+
const userInfoEvents = user.info();
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Use the subscribe method
|
|
369
|
+
|
|
370
|
+
It's important to note that an observable is a "stream" of events over time. This means that the callback function in a subscribe will be called for each and every event until you unsubscribe from it (more on this later).
|
|
371
|
+
|
|
372
|
+
```js
|
|
373
|
+
userInfoEvents.subscribe((event) => {
|
|
374
|
+
if (event.loading) {
|
|
375
|
+
console.log('User info is being requested from server');
|
|
376
|
+
} else if (event.success) {
|
|
377
|
+
console.log('User info request was successful');
|
|
378
|
+
console.log(event.response);
|
|
379
|
+
} else if (event.error) {
|
|
380
|
+
console.error('User info request failed');
|
|
381
|
+
console.error(event.error.message);
|
|
382
|
+
}
|
|
326
383
|
});
|
|
327
384
|
```
|
|
328
385
|
|
|
329
|
-
|
|
386
|
+
### Unsubscribing from an Observable
|
|
330
387
|
|
|
331
|
-
|
|
388
|
+
Observables are not like a Promise in that Observables don't resolve and get "torn-down" after completion. Observables need to be unsubscribed from if they are no longer needed. This is especially important if you are subscribing to Observables in a component that gets created and destroyed many times over. Subscribing to an Observable over and over without unsubscribing will create a memory leak.
|
|
332
389
|
|
|
333
|
-
|
|
390
|
+
To unsubscribe, you assign a function that is returned from calling the subscribe method to a variable that can be called at a later time.
|
|
334
391
|
|
|
335
392
|
```js
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
393
|
+
const unsubUserInfoEvents = userInfoEvents.subscribe((event) => console.log(event));
|
|
394
|
+
|
|
395
|
+
// ...
|
|
396
|
+
|
|
397
|
+
// Unsubscribe when no longer needed
|
|
398
|
+
unsubUserInfoEvents();
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
NOTE: If you're subscribing at a top-level component in your app that's initiated once and is retained over the lifetime of your application, then unsubscribing is not needed. A good example of this would be your app's central, state management component/module. This is a perfect place to `subscribe` to an Observable and preserve that subscription.
|
|
402
|
+
|
|
403
|
+
### Getting the current, local value
|
|
404
|
+
|
|
405
|
+
Sometimes you just want the current value stored within the Widget and are not interested in future events and their resulting state changes. To do this, you can call `subscribe` and then immediately call the unsubscribe method.
|
|
406
|
+
|
|
407
|
+
```js
|
|
408
|
+
// Create variable for user info
|
|
409
|
+
let userInfo;
|
|
410
|
+
// Call subscribe, grab the current, local value, and then immediately call the returned function
|
|
411
|
+
userInfoEvents.subscribe((event) => (userinfo = event.response))(); // <-- notice the second pair of parentheses
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
What does "current, local value" mean? Good question. The Widget internally stores a lot of these important values, so you can ask the Widget for the values that it already has stored.
|
|
415
|
+
|
|
416
|
+
### Requesting values from the ForgeRock platform
|
|
417
|
+
|
|
418
|
+
You can ask the Widget to request new, fresh values from the ForgeRock server, rather than just what it has stored locally. This is done by calling the Observables action methods, like `get`.
|
|
419
|
+
|
|
420
|
+
```js
|
|
421
|
+
userInfoEvents.get();
|
|
339
422
|
```
|
|
340
423
|
|
|
341
|
-
|
|
424
|
+
If you're using the Observable pattern, you can call this method and forget about it. The `subscribe` callback function you have for this Observable will receive the events and new state from this `get` call. The `subscribe` can exist before or after this `get` call, and it will still capture the resulting events.
|
|
425
|
+
|
|
426
|
+
### Using Promises
|
|
427
|
+
|
|
428
|
+
We recommend Observables, but the choice is up to you. All of the Widget's APIs that involve network calls have an alternative Promise implementation that can be used. Let's take the `get` method on `userInfoEvents` we saw above as a way to fetch new user info, and convert it into a Promise.
|
|
429
|
+
|
|
430
|
+
```js
|
|
431
|
+
// async-await
|
|
432
|
+
let userInfo;
|
|
433
|
+
async function example() {
|
|
434
|
+
try {
|
|
435
|
+
userInfo = await userInfoEvents.get();
|
|
436
|
+
} catch (err) {
|
|
437
|
+
console.log(err);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Promise
|
|
442
|
+
let userInfo;
|
|
443
|
+
userInfoEvents
|
|
444
|
+
.get()
|
|
445
|
+
.then((data) => (userInfo = data))
|
|
446
|
+
.catch((err) => console.log(err));
|
|
447
|
+
```
|
|
342
448
|
|
|
343
449
|
## Complete Widget API
|
|
344
450
|
|
|
@@ -347,88 +453,106 @@ The Widget comes with methods and event handlers used to control the lifecycle o
|
|
|
347
453
|
### Widget
|
|
348
454
|
|
|
349
455
|
```js
|
|
350
|
-
|
|
351
|
-
import Widget from 'forgerock-web-login-widget/modal';
|
|
352
|
-
|
|
353
|
-
// OR, as embedded
|
|
354
|
-
import Widget from 'forgerock-web-login-widget/inline';
|
|
456
|
+
import Widget from '@forgerock/login-widget';
|
|
355
457
|
|
|
356
458
|
// Instantiate Widget
|
|
357
459
|
const widget = new Widget({
|
|
358
|
-
target:
|
|
460
|
+
target: widgetRootEl, // REQUIRED; Element mounted in DOM
|
|
359
461
|
props: {
|
|
462
|
+
type: 'modal', // OPTIONAL; "modal" or "inline"; "modal" is default
|
|
463
|
+
},
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
// OPTIONAL; Remove widget from DOM and destroy component listeners
|
|
467
|
+
widget.$destroy();
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
NOTE: Calling `$destroy()` is important if the instantiation of the Widget is done within a portion of your application that is frequently created and destroyed. Though, we _strongly_ encourage developers to instantiate the Widget higher up in the application code closer to the top-level file, in a component that is created once and preserved.
|
|
471
|
+
|
|
472
|
+
### Configuration
|
|
473
|
+
|
|
474
|
+
This configuration function produces a config API, and its `set` method is required for the underlying JavaScript SDK to interaction with the ForgeRock platform or access stored tokens.
|
|
475
|
+
|
|
476
|
+
```js
|
|
477
|
+
import { configuration } from '@forgerock/login-widget';
|
|
478
|
+
|
|
479
|
+
const config = configuration();
|
|
480
|
+
config.set({
|
|
481
|
+
forgerock: {
|
|
360
482
|
/**
|
|
361
483
|
* REQUIRED; SDK configuration object
|
|
362
484
|
*/
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
},
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* OPTIONAL, *BUT ENCOURAGED*, CONFIGURATION
|
|
370
|
-
* Remaining config is optional with fallback values shown
|
|
371
|
-
*/
|
|
372
|
-
clientId: 'WebLoginWidgetClient', // OPTIONAL; Uses 'WebLoginWidgetClient', if not provided
|
|
373
|
-
realmPath: 'alpha', // OPTIONAL; Uses 'alpha', if not provided
|
|
374
|
-
redirectUri: window.location.href, // OPTIONAL; falls back to `window.location.href`
|
|
375
|
-
scope: 'openid email', // OPTIONAL; falls back to minimal 'openid email'
|
|
376
|
-
tree: 'Login', // OPTIONAL; falls back to default Login journey provided in ForgeRock
|
|
485
|
+
serverConfig: {
|
|
486
|
+
baseUrl: 'https://customer.forgeblocks.com/am',
|
|
487
|
+
timeout: 3000, // Number (in milliseconds); 3 to 5 seconds should be fine
|
|
377
488
|
},
|
|
378
|
-
|
|
379
489
|
/**
|
|
380
|
-
* OPTIONAL
|
|
490
|
+
* OPTIONAL, *BUT ENCOURAGED*, CONFIGURATION
|
|
491
|
+
* Remaining config is optional with fallback values shown
|
|
381
492
|
*/
|
|
382
|
-
|
|
383
|
-
|
|
493
|
+
clientId: 'WebLoginWidgetClient', // String; defaults to 'WebLoginWidgetClient'
|
|
494
|
+
realmPath: 'alpha', // String; defaults to 'alpha'
|
|
495
|
+
redirectUri: window.location.href, // URL string; defaults to `window.location.href`
|
|
496
|
+
scope: 'openid email', // String; defaults to 'openid email'
|
|
384
497
|
/**
|
|
385
|
-
*
|
|
498
|
+
* NOT RECOMMENDED
|
|
499
|
+
* Rather, configure a journey/tree through the `.start({ journey: 'Login' })` options object,
|
|
500
|
+
* avoid setting it here
|
|
386
501
|
*/
|
|
387
|
-
|
|
502
|
+
tree: 'Login', // String, but NOT recommended.
|
|
388
503
|
},
|
|
504
|
+
/**
|
|
505
|
+
* OPTIONAL; See below for the Content Configuration section
|
|
506
|
+
*/
|
|
507
|
+
content: {},
|
|
508
|
+
/**
|
|
509
|
+
* OPTIONAL; See below for the Links Configuration section
|
|
510
|
+
*/
|
|
511
|
+
links: {},
|
|
512
|
+
/**
|
|
513
|
+
* OPTIONAL; See below for Styling Configuration section
|
|
514
|
+
*/
|
|
515
|
+
style: {},
|
|
389
516
|
});
|
|
390
|
-
|
|
391
|
-
// OPTIONAL; Remove widget from DOM and destroy all listeners
|
|
392
|
-
widget.$destroy();
|
|
393
517
|
```
|
|
394
518
|
|
|
395
519
|
NOTE: For more SDK configuration options, please [see our SDK's configuration document](https://backstage.forgerock.com/docs/sdks/3.3/javascript/configuring/configuring-forgerock-sdk-settings-for-your-javascript-app.html), or you can [see our API docs for more developer detail](https://backstage.forgerock.com/docs/sdks/3.3/_attachments/javascript/api-reference-core/interfaces/configoptions.html).
|
|
396
520
|
|
|
397
|
-
NOTE: For content schema, please [use the example en-US locale file](/src/locales/us/en/index.ts).
|
|
398
|
-
|
|
399
521
|
### Journey
|
|
400
522
|
|
|
401
523
|
The `journey` object:
|
|
402
524
|
|
|
403
525
|
```js
|
|
404
|
-
import { journey } from 'forgerock
|
|
405
|
-
// OR, import { journey } from 'forgerock-web-login-widget/inline';
|
|
526
|
+
import { journey } from '@forgerock/login-widget';
|
|
406
527
|
|
|
407
528
|
// Call to start the journey
|
|
408
529
|
// Optional config can be passed in, see below for more details
|
|
409
|
-
journey
|
|
410
|
-
|
|
411
|
-
//
|
|
412
|
-
// See below for more details on `response`
|
|
413
|
-
journey.onSuccess((response) => {
|
|
414
|
-
/* Run anything you want */
|
|
530
|
+
const journeyEvents = journey({
|
|
531
|
+
oauth: true, // OPTIONAL; defaults to true; uses OAuth flow for acquiring tokens
|
|
532
|
+
user: true, // OPTIONAL; default to true; returns user information from `userinfo` endpoint
|
|
415
533
|
});
|
|
416
|
-
|
|
417
|
-
|
|
534
|
+
|
|
535
|
+
// Start a journey
|
|
536
|
+
journeyEvents.start({
|
|
537
|
+
forgerock: {}, // OPTIONAL; configuration overrides
|
|
538
|
+
journey: 'Login', // OPTIONAL; choice the journey or tree you want to start
|
|
539
|
+
resumeUrl: window.location.href, // OPTIONAL; the full URL for resuming a tree (see resuming a journey section)
|
|
418
540
|
});
|
|
419
|
-
```
|
|
420
541
|
|
|
421
|
-
|
|
542
|
+
// Change a journey
|
|
543
|
+
journeyEvents.change({
|
|
544
|
+
forgerock: {}, // OPTIONAL; configuration overrides
|
|
545
|
+
journey: 'Registration', // OPTIONAL; choice the journey or tree you want to start
|
|
546
|
+
});
|
|
422
547
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
user: true, // OPTIONAL; default to true and returns user information from `userinfo` endpoint
|
|
548
|
+
// Listeners for journey events
|
|
549
|
+
// See below for more details on `event`
|
|
550
|
+
journey.subscribe((event) => {
|
|
551
|
+
/* Run anything you want */
|
|
428
552
|
});
|
|
429
553
|
```
|
|
430
554
|
|
|
431
|
-
|
|
555
|
+
Schema for user `event`:
|
|
432
556
|
|
|
433
557
|
```js
|
|
434
558
|
// response
|
|
@@ -458,36 +582,119 @@ NOTE: Schema for `response`
|
|
|
458
582
|
}
|
|
459
583
|
```
|
|
460
584
|
|
|
461
|
-
###
|
|
585
|
+
### Component
|
|
462
586
|
|
|
463
|
-
The `
|
|
587
|
+
The named `component` import provides methods for both listening (modal and inline type) as well as controlling (modal type only) the widget component. After initializing the component API via `component()`, you will receive an observable. Subscribing to this observable will allow you to listen and react to the state of the component.
|
|
464
588
|
|
|
465
589
|
```js
|
|
466
|
-
import {
|
|
467
|
-
// OR, import { user } from 'forgerock-web-login-widget/inline';
|
|
590
|
+
import { component } from '@forgerock/login-widget';
|
|
468
591
|
|
|
469
|
-
//
|
|
470
|
-
|
|
471
|
-
await user.authorized({ remote: true }); // do we have valid tokens (remote)?
|
|
592
|
+
// Initiate the component API
|
|
593
|
+
const componentEvents = component();
|
|
472
594
|
|
|
473
|
-
//
|
|
474
|
-
|
|
475
|
-
|
|
595
|
+
// Know when the component, both modal and inline has been mounted.
|
|
596
|
+
// When using the modal type, you will also receive open and close events.
|
|
597
|
+
// The property `reason` will be either "auto", "external", or "user" (see below)
|
|
598
|
+
componentEvents.subscribe((event) => {
|
|
599
|
+
/* Run anything you want */
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
// Open the modal
|
|
603
|
+
componentEvents.open();
|
|
604
|
+
|
|
605
|
+
// Close the modal
|
|
606
|
+
componentEvents.close();
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
Schema for component `event`:
|
|
610
|
+
|
|
611
|
+
```js
|
|
612
|
+
{
|
|
613
|
+
error: null, // null or object with `code`, `message` and `step` that failed
|
|
614
|
+
mounted: false, // boolean
|
|
615
|
+
open: null, // boolean or null, depending on the Widget type: e.g. "modal" or "inline"
|
|
616
|
+
reason: null, // string to describe the reason for the event
|
|
617
|
+
type: null, // 'modal' or 'inline'
|
|
618
|
+
}
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
The `reason` value is used for communicating why the modal has closed. The below are the potential values:
|
|
622
|
+
|
|
623
|
+
1. `"user"`: user closed the dialog via UI
|
|
624
|
+
2. `"auto"`: the modal was closed because user successfully authenticated
|
|
625
|
+
3. `"external"`: the application itself called the `modal.close` function
|
|
626
|
+
|
|
627
|
+
### User
|
|
628
|
+
|
|
629
|
+
```js
|
|
630
|
+
import { user } from '@forgerock/login-widget';
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* User info API
|
|
634
|
+
*/
|
|
635
|
+
const userEvents = user.info();
|
|
636
|
+
// Subscribe to user info changes
|
|
637
|
+
userEvents.subscribe((event) => {
|
|
638
|
+
// Will return current, *local*, user info and future state changes
|
|
639
|
+
console.log(event);
|
|
640
|
+
});
|
|
641
|
+
// Fetch/get fresh user info from ForgeRock server
|
|
642
|
+
userEvents.get(); // New state will be returned in your `userEvents.subscribe` callback function
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* User tokens API
|
|
646
|
+
*/
|
|
647
|
+
const tokenEvents = user.tokens();
|
|
648
|
+
// Subscribe to user info changes
|
|
649
|
+
tokenEvents.subscribe((event) => {
|
|
650
|
+
// Will return current, *local*, user tokens and future state changes
|
|
651
|
+
console.log(event);
|
|
652
|
+
});
|
|
653
|
+
// Fetch/get fresh user tokens from ForgeRock server
|
|
654
|
+
tokenEvents.get(); // New state will be returned in your tokenEvents.subscribe` callback function
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Logout
|
|
658
|
+
* Log user out and clear user data (info and tokens)
|
|
659
|
+
*/
|
|
660
|
+
user.logout(); // Resets user and emits event to your info and tokens' `.subscribe` callback function
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
Schema for user info `event`:
|
|
476
664
|
|
|
477
|
-
|
|
478
|
-
|
|
665
|
+
```js
|
|
666
|
+
{
|
|
667
|
+
completed: false, // boolean
|
|
668
|
+
error: null, // null or object with `code`, `message` and `step` that failed
|
|
669
|
+
loading: false, // boolean
|
|
670
|
+
successful: false, // boolean
|
|
671
|
+
response: null, // object returned from the `/userinfo` endpoint configured in ForgeRock
|
|
672
|
+
}
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
Schema for token `event`:
|
|
676
|
+
|
|
677
|
+
```js
|
|
678
|
+
{
|
|
679
|
+
completed: false, // boolean
|
|
680
|
+
error: null, // null or object with `code`, `message` and `step` that failed
|
|
681
|
+
loading: false, // boolean
|
|
682
|
+
successful: false, // boolean
|
|
683
|
+
response: null, // object returned from the `/access_token` endpoint configured in ForgeRock
|
|
684
|
+
}
|
|
479
685
|
```
|
|
480
686
|
|
|
481
687
|
### Request
|
|
482
688
|
|
|
483
689
|
The Widget has an alias to the JavaScript SDK's `HttpClient.request`, which is a convenience wrapper around the native `fetch`. All this does is auto-inject the Access Token into the `Authorization` header and manage some of the lifecycle around the token.
|
|
484
690
|
|
|
691
|
+
NOTE: This request function is just a wrapper around the native `fetch` API. It's purely promise based and the [response object is the native `Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response). The response is not persisted locally within the Widget.
|
|
692
|
+
|
|
485
693
|
```js
|
|
486
|
-
import
|
|
487
|
-
// OR, import { request } from 'forgerock-web-login-widget/inline';
|
|
694
|
+
import Widget from '@forgerock/login-widget';
|
|
488
695
|
|
|
489
696
|
// See below for more details on the options
|
|
490
|
-
request({ init: { method: 'GET' }, url: 'https://protected.resource.com' });
|
|
697
|
+
const response = await request({ init: { method: 'GET' }, url: 'https://protected.resource.com' });
|
|
491
698
|
```
|
|
492
699
|
|
|
493
700
|
The full `options` object:
|
|
@@ -509,89 +716,32 @@ The full `options` object:
|
|
|
509
716
|
|
|
510
717
|
For the full type definition of this, please [view our SDK API documentation](https://backstage.forgerock.com/docs/sdks/3.3/_attachments/javascript/api-reference-core/interfaces/httpclientrequestoptions.html).
|
|
511
718
|
|
|
512
|
-
###
|
|
513
|
-
|
|
514
|
-
The named `modal` import provides controls of the modal component.
|
|
515
|
-
|
|
516
|
-
```js
|
|
517
|
-
import { modal } from 'forgerock-web-login-widget/modal';
|
|
518
|
-
|
|
519
|
-
// Know when the modal auto-closes, not when the modal is
|
|
520
|
-
// The property `reason` will be either "auto", "external", or "user" (see below)
|
|
521
|
-
modal.onClose(({ reason }) => {
|
|
522
|
-
/* Run anything you want */
|
|
523
|
-
});
|
|
524
|
-
// Know when the modal has mounted
|
|
525
|
-
modal.onMount((dialogElement, formElement) => {
|
|
526
|
-
/* Run anything you want */
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
// "Open" the modal (this implicitly calls `journey.start()`)
|
|
530
|
-
modal.open();
|
|
531
|
-
|
|
532
|
-
// "Close" the modal
|
|
533
|
-
modal.close();
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
It's worth noting that if the Widget has already mounted before the `onMount` statement, it will never run. It won't retroactively run the callback function.
|
|
537
|
-
|
|
538
|
-
`onClose` and the `reason` value:
|
|
539
|
-
|
|
540
|
-
1. `"user"`: user closed the dialog via UI
|
|
541
|
-
2. `"auto"`: the modal was closed because user successfully authenticated
|
|
542
|
-
3. `"external"`: the application itself called the `modal.close` function
|
|
543
|
-
|
|
544
|
-
### Inline
|
|
545
|
-
|
|
546
|
-
The named `form` import provides a simple `onMount` event.
|
|
547
|
-
|
|
548
|
-
```js
|
|
549
|
-
import { form } from 'forgerock-web-login-widget/inline';
|
|
550
|
-
|
|
551
|
-
// Know when the inline form has mounted
|
|
552
|
-
form.onMount((formElement) => {
|
|
553
|
-
/* Run anything you want */
|
|
554
|
-
});
|
|
555
|
-
```
|
|
556
|
-
|
|
557
|
-
It's worth noting that if the Widget has already mounted before the `onMount` statement, it will never run. It won't retroactively run the callback function.
|
|
558
|
-
|
|
559
|
-
### Styling API
|
|
719
|
+
### Styling Configuration
|
|
560
720
|
|
|
561
721
|
The Widget can be configured for styling purposes via the JavaScript API. This allows you to choose the type of labels used or providing a logo for the modal.
|
|
562
722
|
|
|
563
723
|
Example:
|
|
564
724
|
|
|
565
725
|
```js
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
726
|
+
const config = configuration();
|
|
727
|
+
|
|
728
|
+
config.set({
|
|
729
|
+
style: {
|
|
730
|
+
checksAndRadios: 'animated', // OPTIONAL; choices are 'animated' or 'standard'
|
|
731
|
+
labels: 'floating', // OPTIONAL; choices are 'floating' or 'stacked'
|
|
732
|
+
logo: {
|
|
733
|
+
// OPTIONAL; only used with modal form factor
|
|
734
|
+
dark: 'https://example.com/img/white-logo.png', // OPTIONAL; used if theme has a dark variant
|
|
735
|
+
light: 'https://example.com/img/black-logo.png', // REQUIRED if logo property is provided; full URL
|
|
736
|
+
height: 300, // OPTIONAL; number of pixels for providing additional controls to logo display
|
|
737
|
+
width: 400, // OPTIONAL; number of pixels for providing additional controls to logo display
|
|
571
738
|
},
|
|
572
|
-
|
|
573
|
-
|
|
739
|
+
sections: {
|
|
740
|
+
// OPTIONAL; only used with modal form factor
|
|
741
|
+
header: false, // OPTIONAL; uses a modal "header" section that displays logo
|
|
574
742
|
},
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
*/
|
|
578
|
-
style: {
|
|
579
|
-
checksAndRadios: 'animated', // OPTIONAL; choices are 'animated' or 'standard'
|
|
580
|
-
labels: 'floating', // OPTIONAL; choices are 'floating' or 'stacked'
|
|
581
|
-
logo: {
|
|
582
|
-
// OPTIONAL; only used with modal form factor
|
|
583
|
-
dark: 'https://example.com/img/white-logo.png', // OPTIONAL; used if theme has a dark variant
|
|
584
|
-
light: 'https://example.com/img/black-logo.png', // REQUIRED if logo property is provided; full URL
|
|
585
|
-
height: '300px', // OPTIONAL; provides additional controls to logo display
|
|
586
|
-
width: '400px', // OPTIONAL; provides additional controls to logo display
|
|
587
|
-
},
|
|
588
|
-
sections: {
|
|
589
|
-
// OPTIONAL; only used with modal form factor
|
|
590
|
-
header: false, // OPTIONAL; uses a modal "header" section that displays logo
|
|
591
|
-
},
|
|
592
|
-
stage: {
|
|
593
|
-
icon: true, // OPTIONAL; displays generic icons for the provided stages
|
|
594
|
-
},
|
|
743
|
+
stage: {
|
|
744
|
+
icon: true, // OPTIONAL; displays generic icons for the provided stages
|
|
595
745
|
},
|
|
596
746
|
},
|
|
597
747
|
});
|
|
@@ -599,81 +749,52 @@ const widget = new Widget({
|
|
|
599
749
|
|
|
600
750
|
Note that the `logo` and `section` property only apply to the "modal" form factor, and not the "inline".
|
|
601
751
|
|
|
602
|
-
|
|
752
|
+
### Links Configuration
|
|
603
753
|
|
|
604
|
-
|
|
754
|
+
Use this configuration option to set the URL for your site or app's Terms & Conditions page. This supports the the `TermsAndConditionsCallback` that's commonly found in a registration flow.
|
|
605
755
|
|
|
606
|
-
|
|
607
|
-
2. Push Authentication
|
|
608
|
-
3. Recaptcha
|
|
609
|
-
4. QR Code display
|
|
610
|
-
5. TextOutputCallback with scripts
|
|
611
|
-
6. Device Profile
|
|
612
|
-
7. Email Suspend (Forgot Password/Username flows)
|
|
613
|
-
8. Social Login
|
|
614
|
-
9. Central Login
|
|
615
|
-
10. SAML
|
|
616
|
-
|
|
617
|
-
### Widget customization (future)
|
|
756
|
+
Example:
|
|
618
757
|
|
|
619
758
|
```js
|
|
620
|
-
|
|
621
|
-
// ... previous config properties ...
|
|
759
|
+
const config = configuration();
|
|
622
760
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
modalBackdrop: true, // boolean; display modal backdrop
|
|
627
|
-
modalAutoClose: true, // boolean; automatically close modal on success
|
|
761
|
+
config.set({
|
|
762
|
+
links: {
|
|
763
|
+
termsAndConditions: 'https://example.com/terms', // Full canonical URL for your app's terms and conditions page
|
|
628
764
|
},
|
|
629
765
|
});
|
|
630
766
|
```
|
|
631
767
|
|
|
632
|
-
###
|
|
633
|
-
|
|
634
|
-
```js
|
|
635
|
-
modal.onClose((event) => {
|
|
636
|
-
/* anything you want */
|
|
637
|
-
});
|
|
638
|
-
```
|
|
639
|
-
|
|
640
|
-
## Quick Start: Internal Login Framework Development
|
|
641
|
-
|
|
642
|
-
### Technical requirements
|
|
643
|
-
|
|
644
|
-
1. Node.js v16
|
|
645
|
-
2. npm v8
|
|
646
|
-
|
|
647
|
-
### Knowledge requirements
|
|
648
|
-
|
|
649
|
-
1. JavaScript & TypeScript
|
|
650
|
-
2. Svelte
|
|
651
|
-
3. Tailwind
|
|
652
|
-
4. ES Modules
|
|
768
|
+
### Content Configuration
|
|
653
769
|
|
|
654
|
-
|
|
770
|
+
This configuration setting is for passing custom content to the Widget, replacing its default content. For the full content schema, please [use the example en-US locale file](/src/locales/us/en/index.ts).
|
|
655
771
|
|
|
656
|
-
|
|
657
|
-
2. `npm run build`
|
|
658
|
-
3. `npm run dev` (leave running)
|
|
772
|
+
Example:
|
|
659
773
|
|
|
660
|
-
|
|
774
|
+
```js
|
|
775
|
+
const config = configuration();
|
|
661
776
|
|
|
662
|
-
|
|
777
|
+
config.set({
|
|
778
|
+
content: {}, // Custom content that overrides Widget default content
|
|
779
|
+
});
|
|
780
|
+
```
|
|
663
781
|
|
|
664
|
-
|
|
782
|
+
## Future Support (not yet implemented)
|
|
665
783
|
|
|
666
|
-
|
|
784
|
+
### Planned for a future, minor release
|
|
667
785
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
```
|
|
786
|
+
1. WebAuthn
|
|
787
|
+
2. Device Profile
|
|
671
788
|
|
|
672
|
-
|
|
789
|
+
### Planned for a future, major release
|
|
673
790
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
791
|
+
1. Push Authentication
|
|
792
|
+
2. ReCAPTCHA
|
|
793
|
+
3. QR Code display
|
|
794
|
+
4. TextOutputCallback with scripts
|
|
795
|
+
5. Central Login
|
|
796
|
+
6. SAML
|
|
797
|
+
7. NumberAttributeInputCallback
|
|
677
798
|
|
|
678
799
|
## Disclaimer
|
|
679
800
|
|
|
@@ -688,6 +809,6 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
|
688
809
|
|
|
689
810
|
---
|
|
690
811
|
|
|
691
|
-
© Copyright
|
|
812
|
+
© Copyright 2022-2023 ForgeRock AS. All Rights Reserved.
|
|
692
813
|
|
|
693
814
|
[forgerock-logo]: https://www.forgerock.com/themes/custom/forgerock/images/fr-logo-horz-color.svg 'ForgeRock Logo'
|