@forgerock/login-widget

中文文档
2.2.0发布于 2026/11/13MITTypeScriptES Module构建来源已验证近 30 天下载 3643

npm version [Commitizen friendly](http

原始使用文档
文档目录29 节
  1. ForgeRock Login Widget
  2. Table of Contents
  3. Overview
  4. Requirements
  5. Quick Start
  6. Install
  7. Add CSS
  8. Mount the Widget
  9. Observables Pattern
  10. Subscribe to Events
  11. Unsubscribe
  12. Get Current Values
  13. Request Fresh Values
  14. Use Promises
  15. Complete Widget API
  16. Widget
  17. Configuration
  18. Journey
  19. Component
  20. User
  21. Calling protected resources
  22. Styling Configuration
  23. Links Configuration
  24. Content Configuration
  25. CAPTCHA Configuration
  26. Scripted Text Output
  27. Supported Callbacks
  28. Disclaimer
  29. License

npm version Commitizen friendly

ForgeRock Logo

ForgeRock Login Widget

npm · Support · Docs


Table of Contents

Overview

The Login Widget is an all-inclusive UI component for handling login, registration, and related user flows in any modern JavaScript app. It works with React, Vue, Angular, Svelte, or vanilla JavaScript — it does not currently support Node.js or server-side rendering (SSR).

The widget uses Journey Client for journey execution, and OIDC Client for OAuth/OIDC tokens and user info. It adds a UI rendering layer on top of these SDKs to eliminate the need to develop and maintain UI components for complex authentication flows. Although this rendering layer is developed with Svelte and Tailwind, both are "compiled away" and have no runtime dependencies. The resulting widget is library- and framework-agnostic.

The widget can be rendered in two form factors:

  1. Modal (default): Renders form elements inside a modal dialog that opens and closes. Mounted outside your app's controlled DOM.
  2. Inline: Just the form elements with no container. Mounted inside your app's controlled DOM.

Both form factors provide the same authentication, OAuth/OIDC, and user features. Start with Modal — it provides the quickest path to adding login/registration with minimal disruption to your existing codebase.

Requirements

  • An ECMAScript module or CommonJS enabled client-side JavaScript app
  • A modern, fully-supported browser: Chrome, Firefox, Safari, or Chromium Edge

Not supported: Internet Explorer, Legacy Edge, WebView, Electron, and other modified browser-like environments.

Quick Start

Install

npm install @forgerock/login-widget

Add CSS

Import into your JavaScript:

import '@forgerock/login-widget/widget.css';

Import into your CSS:

@import '@forgerock/login-widget/widget.css';

Or link in HTML (copy the CSS file from the npm module into your static files):

<link rel="stylesheet" href="/path/to/file/widget.css" />

Controlling the CSS Cascade

Though not required, using @layer ensures the browser applies CSS in the intended order regardless of import order. Read more about @layer.

  1. Wrap your CSS in a layer:

    @layer app {
      /* Your app's CSS */
    }
    
  2. Declare layer order in your HTML before any CSS loads:

    <style type="text/css">
      @layer app;
      @layer 'fr-widget.base';
      @layer 'fr-widget.utilities';
      @layer 'fr-widget.components';
      @layer 'fr-widget.variants';
    </style>
    

    Widget CSS is fully namespaced — it will not overwrite your app's CSS unless you use the same selector naming convention.

Mount the Widget

Add a dedicated element to your HTML file as a direct child of <body>, separate from your main app root:

<body>
  <div id="root"></div>
  <div id="widget-root"></div>
</body>

Tip: Do not mount the modal form factor on a dynamic element inside your app's Virtual DOM. Hard-code it in your static HTML file.

Import, configure, and instantiate:

import Widget, { configure, journey } from '@forgerock/login-widget';

// 1. Configure — async; awaiting it ensures both clients are ready before use
await configure({
  // REQUIRED — the well-known URL, shared by the journey and OIDC clients
  serverConfig: {
    wellknown:
      'https://your-tenant.forgeblocks.com/am/oauth2/alpha/.well-known/openid-configuration',
  },
  // REQUIRED if you use OAuth/OIDC tokens, user info, or logout
  oidcClient: {
    clientId: 'YourOauthClient',
    redirectUri: `${window.location.origin}/callback`,
    scope: 'openid profile email', // OPTIONAL — defaults to 'openid'
  },
});

// 2. Instantiate
const widgetRootEl = document.getElementById('widget-root');
new Widget({ target: widgetRootEl });

// 3. Start a journey
const journeyEvents = journey();
journeyEvents.start();

Tip: configure() is async — always await it at the top level of your application (index.js or app.js) before calling journey().start() or any other Widget API. This ensures both the OIDC and journey clients are fully constructed before any fetch is attempted.

Observables Pattern

Most Widget APIs are asynchronous and use an event-centric observable pattern. The widget uses Svelte's simplified, standard observable implementation called a "store" — these are embedded in the widget and are not a dependency your app needs to manage.

Read more about the Svelte store contract.

Subscribe to Events

import { user } from '@forgerock/login-widget';

const userInfoEvents = user.info();

userInfoEvents.subscribe((event) => {
  if (event.loading) {
    console.log('User info is being requested from server');
  } else if (event.successful) {
    console.log('User info request was successful');
    console.log(event.response);
  } else if (event.error) {
    console.error('User info request failed');
    console.error(event.error.message);
  }
});

Unsubscribe

Observables are not like Promises — they don't resolve and get cleaned up. You must unsubscribe when no longer needed, especially in components that are created and destroyed frequently:

const unsubscribe = userInfoEvents.subscribe((event) => console.log(event));

// Later, when no longer needed:
unsubscribe();

Note: If subscribing at a top-level component that persists over the lifetime of your app, unsubscribing is not needed.

Get Current Values

To get the current value stored within the Widget without subscribing to future events, call subscribe and immediately call the returned unsubscribe function:

let userInfo;
userInfoEvents.subscribe((event) => (userInfo = event.response))();

Request Fresh Values

Call action methods like get to request new values from the server. Any active subscribe callbacks will receive the resulting events:

userInfoEvents.get();

Use Promises

All Widget APIs that involve network calls also support Promises:

// async/await
const userInfo = await userInfoEvents.get();

// Promise chain
userInfoEvents
  .get()
  .then((data) => console.log(data))
  .catch((err) => console.error(err));

Complete Widget API

Widget

import Widget from '@forgerock/login-widget';

// Instantiate
const widget = new Widget({
  target: widgetRootEl, // REQUIRED; a real DOM element
  props: {
    type: 'modal', // OPTIONAL; "modal" (default) or "inline"
  },
});

// Remove widget from DOM and destroy listeners
widget.$destroy();

Note: Call $destroy() if instantiating the Widget in a component that is frequently created and destroyed. We recommend instantiating higher in your application tree, in a component created once and preserved.

Configuration

import { configure } from '@forgerock/login-widget';

// configure() is async — await it before calling any other Widget API
await configure({
  // REQUIRED — the well-known URL, shared by the journey and OIDC clients
  serverConfig: {
    wellknown:
      'https://your-tenant.forgeblocks.com/am/oauth2/realms/root/realms/alpha/.well-known/openid-configuration',
  },
  // REQUIRED if you use OAuth/OIDC tokens, user info, or logout
  oidcClient: {
    clientId: 'WebOAuthClient',
    redirectUri: `${window.location.origin}/callback`,
    scope: 'openid profile email',
  },
  // OPTIONAL — logger for both clients; `level` gates verbosity and `custom`
  // redirects SDK log output to your own sink. See the full example below.
  logger: { level: 'warn' },
  // OPTIONAL — request middleware for both clients; see the full example below
  middleware: [],
  // OPTIONAL — token storage config; see Storage section below
  storage: { type: 'sessionStorage', name: 'tokens' },
  // OPTIONAL — see dedicated sections below
  content: {},
  links: {},
  style: {},
});

Migration note (2.0.0): The forgerock config object has been replaced by oidcClient. Endpoint discovery is now driven by serverConfig.wellknown, shared by the journey and OIDC clients — baseUrl, realmPath, timeout, and support are no longer used. clientId and redirectUri are required when configuring oidcClient; scope defaults to 'openid'. tokenStore has moved to a top-level storage option.

Logger

The top-level logger option is forwarded to both the journey and OIDC clients.

PropertyTypeDefaultDescription
level'none' | 'error' | 'warn' | 'info' | 'debug''error'Gates SDK log verbosity. 'none' silences all SDK logs.
custom{ error, warn, info, debug }—Sink for SDK log output. When set, the SDK calls your methods instead of the console.
await configure({
  serverConfig: {
    wellknown:
      'https://your-tenant.forgeblocks.com/am/oauth2/alpha/.well-known/openid-configuration',
  },
  logger: {
    level: 'debug',
    // OPTIONAL — route SDK logs to your own sink instead of the console.
    custom: {
      error: (...args) => myLogger.error(...args),
      warn: (...args) => myLogger.warn(...args),
      info: (...args) => myLogger.info(...args),
      debug: (...args) => myLogger.debug(...args),
    },
  },
  oidcClient: {
    clientId: 'WebOAuthClient',
    redirectUri: `${window.location.origin}/callback`,
    scope: 'openid profile email',
  },
});

OIDC Client Options

All properties are nested inside oidcClient.

PropertyTypeDefaultDescription
clientIdstring—Required. OAuth 2.0 client ID.
redirectUristring—Required. URI AM redirects to after authorization.
scopestring'openid'OAuth 2.0 scopes.
oauthThresholdnumber30000Milliseconds before expiry to trigger background renewal.
parbooleanautoUse Pushed Authorization Requests. When omitted, the SDK auto-detects from the authorization server's require_pushed_authorization_requests metadata. Setting false while the server requires PAR is an error.
loginHintstring—Pre-fills the login identifier; bridged onto silent token renewal.
acrValuesstring—Requested ACR values; bridged onto silent token renewal.
queryRecord<string, string>—Extra authorize query params; bridged onto silent token renewal.

Example with all optional OIDC options:

await configure({
  serverConfig: {
    wellknown:
      'https://your-tenant.forgeblocks.com/am/oauth2/alpha/.well-known/openid-configuration',
  },
  logger: { level: 'debug' },
  middleware: [
    (req, action, next) => {
      console.log('[middleware]', action.type, req.url);
      next();
    },
  ],
  storage: { type: 'sessionStorage', name: 'tokens', prefix: 'myapp' },
  oidcClient: {
    clientId: 'WebOAuthClient',
    redirectUri: `${window.location.origin}/callback`,
    scope: 'openid profile email',
    oauthThreshold: 60000,
    par: true,
    loginHint: '[email protected]',
    acrValues: 'urn:acr:2fa',
    query: { ui_locales: 'en-US' },
  },
});

Storage

The top-level storage option configures where the OIDC client persists tokens. It mirrors the SDK's StorageConfig union — type selects a browser store or a custom sink.

PropertyTypeDefaultDescription
type'localStorage' | 'sessionStorage' | 'custom''localStorage'Storage backend. 'custom' requires a custom sink.
namestring—Required. Storage key name.
prefixstring'pic'Key prefix for storage entries.
custom{ get, set, remove }—Required when type: 'custom'. Async functions for your own store.
// Browser store
storage: { type: 'sessionStorage', name: 'tokens', prefix: 'myapp' },

// Custom store
storage: {
  type: 'custom',
  name: 'tokens',
  custom: {
    get: async (key) => myStore.read(key),
    set: async (key, value) => myStore.write(key, value),
    remove: async (key) => myStore.delete(key),
  },
},

Journey

import { journey } from '@forgerock/login-widget';

const journeyEvents = journey({
  oauth: true, // OPTIONAL; default true; use OAuth flow for tokens
  user: true, // OPTIONAL; default true; fetch user info from /userinfo
});

// Start a journey
journeyEvents.start({
  journey: 'Login', // OPTIONAL; journey name (omit to let AM choose the default)
  resumeUrl: window.location.href, // OPTIONAL; URL for resuming a suspended journey
});

// Change to a different journey
journeyEvents.change({
  journey: 'Registration',
});

// Listen for events
journeyEvents.subscribe((event) => {
  if (event.journey.successful) {
    console.log('Authentication succeeded', event);
  }
});

Journey event schema:

{
  journey: {
    completed: false,     // boolean
    error: null,          // null or { code, message, step }
    loading: false,       // boolean
    step: null,           // null or step object from ForgeRock AM
    successful: false,    // boolean
    response: null,       // null or success response from AM
  },
  oauth: {
    completed: false,     // boolean
    error: null,          // null or { code, message }
    loading: false,       // boolean
    successful: false,    // boolean
    response: null,       // null or OAuth/OIDC tokens
  },
  user: {
    completed: false,     // boolean
    error: null,          // null or { code, message }
    loading: false,       // boolean
    successful: false,    // boolean
    response: null,       // null or user info (driven by OAuth scope)
  },
}

Component

The component API controls the widget's lifecycle. For the modal form factor, it provides open and close methods.

import { component } from '@forgerock/login-widget';

const componentEvents = component();

// Open/close the modal
componentEvents.open();
componentEvents.close();

// Listen for lifecycle events
componentEvents.subscribe((event) => {
  if (event.mounted) console.log('Widget is mounted');
  if (event.open === false) console.log('Modal closed:', event.reason);
});

Component event schema:

{
  error: null,    // null or { code, message, step }
  mounted: false, // boolean
  open: null,     // boolean or null (null for inline type)
  reason: null,   // "user" | "auto" | "external"
  type: null,     // "modal" | "inline"
}

Close reasons:

ReasonDescription
"user"User closed the dialog via UI
"auto"Modal closed after successful authentication
"external"Application called componentEvents.close()

User

import { user } from '@forgerock/login-widget';

// User info
const userEvents = user.info();
userEvents.subscribe((event) => console.log(event));
userEvents.get(); // Fetch fresh user info from server

// User tokens
const tokenEvents = user.tokens();
tokenEvents.subscribe((event) => console.log(event));
tokenEvents.get(); // Fetch fresh tokens from server

// Logout
user.logout(); // Clears user data and emits events to subscribers

User info / token event schema:

{
  completed: false,  // boolean
  error: null,       // null or { code, message }
  loading: false,    // boolean
  successful: false, // boolean
  response: null,    // object from /userinfo or /access_token endpoint
}

Calling protected resources

Removed in 2.0.0: The request export (an alias to the legacy HttpClient.request) has been removed. @forgerock/oidc-client does not provide an HTTP client. Get the access token from user.tokens() and call fetch directly, adding the Authorization header yourself:

import { user } from '@forgerock/login-widget';

const tokenEvents = user.tokens();
const { response: tokens } = await tokenEvents.get();

const response = await fetch('https://protected.resource.com', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${tokens.accessToken}`,
  },
});

Note: The legacy request automatically refreshed tokens on a 401 and parsed Identity Gateway policy advice. Those behaviors are not provided by the new SDK and must be implemented by the consumer if needed.

Styling Configuration

Configure the widget's visual appearance:

await configure({
  style: {
    checksAndRadios: 'animated', // OPTIONAL; 'animated' or 'standard'
    labels: 'floating', // OPTIONAL; 'floating' or 'stacked'
    logo: {
      dark: 'https://example.com/img/white-logo.png',
      light: 'https://example.com/img/black-logo.png', // REQUIRED if logo provided
      height: 300,
      width: 400,
    },
    sections: {
      // OPTIONAL; modal only
      header: false, // Display a header section with logo
    },
    stage: {
      icon: true, // OPTIONAL; display generic stage icons
    },
    callbacks: {
      // OPTIONAL; per-callback style rules, keyed by AM callback type name
      // — see "Scripted Text Output"; rules are plain string dictionaries
      TextOutputCallback: [{ type: '4', display: 'hidden' }],
    },
  },
});

Note: The sections.header property only applies to the modal form factor. The logo property applies to all form factors.

Logo CSS custom properties

The logo configuration is applied as root-level CSS custom properties on the widget root element, re-applied after every theme pass. These are the fallback slots; an IDM page-node theme sets the primary --logo-light / --logo-dark slots and takes precedence over them.

PropertyCSS custom propertyNotes
light--fr-logo-light-fallbackConsumed via var(--logo-light, var(--fr-logo-light-fallback))
dark--fr-logo-dark-fallbackConsumed via var(--logo-dark, var(--fr-logo-dark-fallback))
height--fr-logo-heightFalls back to 72px when unset; the dialog header logo stretches to the header height instead
width--fr-logo-widthFalls back to 200px on stages, 100% in the dialog; the dialog header logo stretches to the header height when unset

Valid light / dark values are https:// URLs, data:image/ URIs, or root-relative paths (leading /). Invalid values are dropped by config validation.

Set the URL for your Terms & Conditions page (used by TermsAndConditionsCallback):

await configure({
  links: {
    termsAndConditions: 'https://example.com/terms',
  },
});

Content Configuration

Override the widget's default content with custom text. For the full schema, see the en-US locale file.

await configure({
  content: {
    // Custom content that overrides Widget defaults
  },
});

CAPTCHA Configuration

AM does not signal invisible mode in the callback payload for either ReCaptchaCallback or ReCaptchaEnterpriseCallback. Use the captcha option to configure invisible rendering:

await configure({
  captcha: {
    mode: 'invisible', // 'visible' (default) | 'invisible'
  },
});

Script loading: The widget automatically injects the required CAPTCHA script at mount time — no manual <script> tag is needed. If the provider API (window.grecaptcha / window.hcaptcha) is already present on the page when the widget mounts, injection is skipped.

Scripted Text Output

A journey can return client-side JavaScript as a TextOutputCallback with messageType 4 — for example a tracking or device-fingerprinting snippet. The widget does not execute these scripts, so by default it prints the script source to the screen as text.

Hide them with a per-callback rule list under callbacks:

await configure({
  style: {
    callbacks: {
      // omit for default: prints the script source
      TextOutputCallback: [{ type: '4', display: 'hidden' }],
    },
  },
});

Each rule is a plain string dictionary passed through to that callback's renderer. type selects a TextOutputCallback message type and display: 'hidden' suppresses it. Informational (0), warning (1), and error (2) messages render as usual. The scripts are still not executed either way — the option only controls whether their source is displayed.

Supported Callbacks

The widget supports the following ForgeRock callbacks:

  • Page node
  • Username, Password
  • WebAuthn (registration and login)
  • Push authentication
  • One-time password verification
  • Social login (Apple, Facebook, Google)
  • Email suspend ("magic links")
  • Device profile
  • reCAPTCHA v2 (visible + invisible), reCAPTCHA Enterprise, hCaptcha (visible + invisible)
  • QR codes
  • Ping Protect

Disclaimer

This code is provided by ForgeRock on an "as is" basis, without warranty of any kind, to the fullest extent permitted by law. ForgeRock does not represent or warrant or make any guarantee regarding the use of this code or the accuracy, timeliness or completeness of any data or information relating to this code, and ForgeRock hereby disclaims all warranties whether express, or implied or statutory, including without limitation the implied warranties of merchantability, fitness for a particular purpose, and any warranty of non-infringement. ForgeRock shall not have any liability arising out of or related to any use, implementation or configuration of this code, including but not limited to use for any commercial purpose. Any action or suit relating to the use of the code may be brought only in the courts of a jurisdiction wherein ForgeRock resides or in which ForgeRock conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions.

License

This project is licensed under the MIT License — see the LICENSE file for details.


© Copyright 2022-2026 Ping Identity Corporation. All Rights Reserved.

版本与发布记录

@forgerock/login-widget 共发布 139 个版本,首次发布于 2022/12/11;过去 12 个月发布了 85 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.2.0latest2026/11/133 天前
0.0.0-beta-20261112200918beta2026/11/133 天前
0.0.0-beta-202611092335032026/11/105 天前
0.0.0-beta-202611092306362026/11/105 天前
0.0.0-beta-202610212203562026/10/2225 天前
0.0.0-beta-202610212129242026/10/2225 天前

其他发布通道:alpha → 1.0.0-alpha.12,beta → 0.0.0-beta-20261112200918。

关于 @forgerock/login-widget 的常见问题

@forgerock/login-widget 是什么?

[](http

如何安装 @forgerock/login-widget?

在项目目录运行 npm install @forgerock/login-widget,或使用 pnpm add / yarn add / bun add。

@forgerock/login-widget 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@forgerock/login-widget 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@forgerock/login-widget 可以商用吗?

@forgerock/login-widget 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@forgerock/login-widget 的下载量有多少?

根据 npm 官方下载统计,@forgerock/login-widget 在 2026/10/16 – 2026/11/14 这 30 天内被下载 3,643 次,日均约 121 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@forgerock/login-widget 还在维护吗?

最新版本 2.2.0 发布于 2026/11/13(3 天前);至今共发布 139 个版本,其中过去 12 个月发布了 85 个;首次发布于 2022/12/11。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。