关于 ping-orchestration-javascript-sdk
为 Web 应用集成 Ping Orchestration JavaScript SDK 认证提供引导式技能。它收集流程与应用配置,再转交 React Journey 或 DaVinci 技能,或生成 OIDC 及框架无关的接入代码。
主要功能
- 01Journey、DaVinci 与 OIDC 流程指引
- 02三步配置向导
- 03React 技能交接
- 04框架检测与路由
- 05SDK 安装及构建工具指引
适用场景
- 01在 React 应用中配置 Ping Journey 认证
- 02使用统一配置接入 DaVinci 登录
- 03生成集中式 OIDC 登录接入代码
- 04将 SDK 接入适配到占位框架
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ pingidentity/ ping-sdk-agent-skills --skill ping-orchestration-javascript-sdk安装后在 Claude Code 中输入/ping-orchestration-javascript-sdk确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/.gitignore.templateoidc-centralized-reference.mdassets/angular/README.mdassets/react/.env.templateoidc-app.jsx.templateoidc-callback.jsx.templateoidc-home.jsx.templateoidc-login.jsx.templateassets/vanilla/README.mdassets/vue/README.mdreferences/sdk-packages.md详细介绍
Ping JavaScript SDK
使用 Ping Orchestration JavaScript SDK(@forgerock/journey-client、@forgerock/davinci-client、@forgerock/oidc-client)构建 Web 应用的首选入口。支持三种身份验证流程:
- Journey — 针对 PingAM 或 PingOne AIC 的基于回调的身份验证 → 委托给
ping-orchestration-reactjs-journey-sdk - DaVinci — 针对 PingOne DaVinci 的基于收集器的身份验证 → 委托给
ping-orchestration-reactjs-davinci-sdk - OIDC centralized login — OAuth2 授权码流程(浏览器重定向)→ 内联处理
运行三步向导(W1 → W2 → W3),以确定流程类型、检测框架、收集通用配置,然后交接或生成代码。
框架注册表
此表是框架路由的唯一事实来源。决策树会引用其中的 Status。添加新框架:将其状态从 placeholder 更改为 active,添加委托技能名称,填写 OIDC 模板目录,并在“构建工具配置”小节中添加任何特定于构建工具的指导。
| 框架 | Journey 委托项 | DaVinci 委托项 | OIDC 模板 | 状态 |
|---|---|---|---|---|
| React | ping-orchestration-reactjs-journey-sdk | ping-orchestration-reactjs-davinci-sdk | assets/react/ | active |
| Angular | — | — | assets/angular/ | placeholder |
| Vue | — | — | assets/vue/ | placeholder |
| Vanilla JS | — | — | assets/vanilla/ | placeholder |
向导
每次调用此技能时,若未提供 create-sample 参数,都要运行以下三个步骤。
W1 — 流程类型
询问:
你要构建哪种流程?
- Journey — 针对 PingAM 或 PingOne AIC 的基于回调的身份验证
- DaVinci — 针对 PingOne DaVinci 的基于收集器的身份验证
- OIDC centralized login — OAuth2/OIDC 授权码流程(浏览器重定向,无需自定义 UI)
W1b — 框架检测
收集配置前,检测或询问用户使用的框架。
如果存在 package.json,运行:
grep -E '"(react|vue|@angular/core|vite)"' package.json
- 找到
react→ 检测到 React → 继续执行 W2。 - 找到
vue或@angular/core→ 宣布这是占位框架,并提供选项:“专用的
ping-orchestration-vue-sdk/ping-orchestration-angular-sdk技能即将推出。我可以:- 生成框架无关的 SDK 接入代码 — 客户端初始化、令牌交换和路由守卫伪代码,你可以根据框架的惯用模式进行调整。
- 转到 React 技能(
ping-orchestration-reactjs-journey-sdk/ping-orchestration-reactjs-davinci-sdk),将其作为可移植的参考实现。
你希望选择哪一种?”
- 如果用户选择选项 1 → 继续执行 W2,然后使用下方的通用(占位框架)路径。
- 如果用户选择选项 2 → 继续执行 W2,并委托给 React 技能。
- 找到
react-native(单独检查)→ 告知用户ping-orchestration-react-native-sdk即将推出;目前没有临时替代方案。 - 未找到任何内容,或不存在
package.json→ 询问:“你使用的是哪种 JavaScript 框架?”列出框架注册表中的活跃框架。如果用户指定占位框架,提供上述相同的两个选项。
W2 — 共享配置
收集以下参数。跳过用户已在消息中提供的参数。
| 参数 | 适用于 | 备注 |
|---|---|---|
wellknown | 所有流程 | 完整的 OIDC 发现 URL,以 .well-known/openid-configuration 结尾 |
clientId | 所有流程 | 在 PingOne/AIC 中注册的 OAuth 客户端 ID |
redirectUri | 所有流程 | 必须与注册值完全一致——包含 /callback 路径后缀 |
scope | 所有流程 | 以空格分隔;必须包含 openid |
appName | 所有流程 | 用于项目/目录命名 |
journeyName | 仅 Journey | 身份验证树名称(例如,Login) |
acrValues | 仅 DaVinci/OIDC | 可选的 ACR 值字符串 |
进入 W3 前的验证:
wellknown必须以.well-known/openid-configuration结尾scope必须包含openid——如果缺少,请将其添加并告知用户redirectUri必须是以http://或https://开头的绝对 URL
W3 — 确认并移交
显示摘要表:
| 参数 | 值 |
|---|---|
| 流程 | <journey | davinci | oidc-centralized> |
| 框架 | <React> |
| Well-known URL | <wellknown> |
| 客户端 ID | <clientId> |
| 重定向 URI | <redirectUri> |
| Scope | <scope> |
| 应用名称 | <appName> |
| Journey 名称 (仅 Journey) | <journeyName> |
| ACR 值 (DaVinci/OIDC,若已提供) | <acrValues> |
询问:“看起来正确吗?要继续吗?”
确认后:
- Journey(活动框架) → 通过 Skill 工具,从 Framework Registry 调用 Journey delegate。在调用上下文中传入收集到的配置。不要内联该 skill 的内容。注意:Journey delegate 使用自己的环境变量命名方式(
VITE_WELLKNOWN_URL、VITE_WEB_OAUTH_CLIENT等)——delegate 会处理这些;请传入 W2 中的逻辑值。 - DaVinci(活动框架) → 通过 Skill 工具,从 Framework Registry 调用 DaVinci delegate。传入收集到的配置。不要内联该 skill 的内容。注意:DaVinci delegate 使用自己的环境变量命名方式(
VITE_CLIENT_ID、VITE_DISCOVERY_ENDPOINT等)——请传入 W2 中的逻辑值。 - OIDC centralized(活动框架) → 读取
assets/oidc-centralized-reference.md,然后继续下方的 OIDC Centralized Login 部分。使用框架OIDC Templates目录中的模板。 - 任何流程(占位框架,通用路径) → 继续下方的 Generic (Placeholder Framework) Path 部分。
通用(占位框架)路径
当 Framework Registry 中用户的框架为 placeholder,且用户在 W1b 中选择了与框架无关的 SDK 接线方式时,使用此路径。SDK 软件包是纯 JavaScript,不依赖任何框架——此路径提供集成接线方式,无需使用特定框架的组件渲染。
生成内容
针对每种流程类型,生成一个用户可适配到其框架中的集成模块:
Journey:
import { journey, callbackType } from '@forgerock/journey-client';
import { oidc } from '@forgerock/oidc-client';
// 1. Initialise OIDC client (for token management after Journey completes)
const oidcClient = await oidc({ config: {
serverConfig: { wellknown: '<wellknown>' },
clientId: '<clientId>',
redirectUri: '<redirectUri>',
scope: '<scope>',
} });
// 2. Start Journey
const client = await journey({
serverConfig: { wellknown: '<wellknown>' },
journeyName: '<journeyName>',
});
let step = await client.start();
// 3. Loop: render callbacks, collect input, submit
while (step.type === 'Step') {
for (const cb of step.callbacks) {
// Inspect cb.type (callbackType.NameCallback, callbackType.PasswordCallback, etc.)
// Collect user input and call cb.setInput(value) or equivalent setter
}
step = await client.next(step);
}
// 4. Handle outcome
if (step.type === 'SuccessStep') {
// Journey complete — tokens available via oidcClient.token.get()
} else {
// step.type === 'FailureStep' — display error
}
DaVinci:
import { davinci } from '@forgerock/davinci-client';
const client = await davinci({
serverConfig: { wellknown: '<wellknown>' },
clientId: '<clientId>',
redirectUri: '<redirectUri>',
scope: '<scope>',
});
let node = await client.start();
// Loop: render collectors, collect input, submit
while (node.status === 'continue') {
const collectors = node.client.collectors;
for (const collector of collectors) {
// Inspect collector.type (TextCollector, PasswordCollector, SubmitCollector, etc.)
// Set value: collector.value = userInput;
}
node = await client.next();
}
if (node.status === 'success') {
// Auth complete — session established
} else {
// node.status === 'error' — display node.error
}
OIDC centralized:
import { oidc } from '@forgerock/oidc-client';
const CONFIG = {
serverConfig: { wellknown: '<wellknown>' },
clientId: '<clientId>',
redirectUri: '<redirectUri>',
scope: '<scope>',
};
const client = await oidc({ config: CONFIG });
// Login: redirect to authorization endpoint
const url = await client.authorize.url();
window.location.href = url;
// Callback page: exchange code for tokens
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const state = params.get('state');
if (code && state) {
await client.token.exchange(code, state);
window.location.replace('/');
}
// Check auth state
const tokens = await client.token.get();
// Logout
await client.user.logout();
应包含的指导
生成集成模块后:
- 说明哪些部分对应框架相关逻辑(渲染循环 → 组件树;身份验证检查 → 路由守卫;回调页面 → 专用路由)。
- 指向 React delegate skill,作为可供研究的完整参考实现。
- 如果用户分享其应用结构,可提供帮助,将该模块接入其特定框架的模式中。
共享设置指南
本节适用于所有流程类型和框架。请在委派或生成代码前提供此指南。
SDK 设置(所有框架)
完整的软件包参考:references/sdk-packages.md
仅安装流程所需的软件包:
# Journey
npm install @forgerock/journey-client @forgerock/oidc-client
# DaVinci
npm install @forgerock/davinci-client
# Add @forgerock/oidc-client if you need token management beyond DaVinci's built-in session
# OIDC centralized login
npm install @forgerock/oidc-client
# Optional add-ons (any flow)
npm install @forgerock/protect # PingOne Protect / behavioral signals
npm install @forgerock/device-client # Device profile, OATH, Push, WebAuthn management
常见问题(SDK 级别)
redirectUri不匹配:该值必须与 PingOne/AIC 中注册的值完全一致——尾部斜杠、端口号和路径都很重要。- 缺少
openidscope:@forgerock/oidc-client要求 scope 中包含openid,否则令牌交换会失败。 - CORS:well-known 端点必须在服务器的 CORS 策略中包含应用的来源。如果出现预检失败,请检查 PingOne/AIC 的 CORS 设置。
wellknown与serverConfig:新 SDK(@forgerock/journey-clientv2+)仅使用wellknown。不支持旧版serverConfig.baseUrl。
构建工具配置
应用与检测到的框架相匹配的部分。每个项目仅适用一部分。
占位框架说明(Angular、Vue、Vanilla JS): 这些框架的完整技能支持尚未启用。以下部分介绍正确的构建工具惯例,以便你在使用通用占位框架路径时正确配置环境。占位框架不会生成 OIDC 模板——请手动调整这些模式。
React + Vite
环境变量使用 VITE_ 前缀(Vite 要求使用此名称,才能在客户端公开):
VITE_PING_WELLKNOWN=https://auth.example.com/am/oauth2/alpha/.well-known/openid-configuration
VITE_PING_CLIENT_ID=my-app
VITE_PING_REDIRECT_URI=http://localhost:5173/callback
VITE_PING_SCOPE=openid profile
# Journey only:
VITE_PING_JOURNEY_NAME=Login
# DaVinci/OIDC optional:
VITE_PING_ACR_VALUES=
参考:assets/react/.env.template
Vite 特有问题:
- 只有带
VITE_前缀的变量才会公开到浏览器包中。仅供服务器使用的机密信息必须不带此前缀。 - 不要添加包含内联
oidc().token.exchange()脚本的静态public/callback.html。 当@forgerock/oidc-client调用authorize.background()进行静默令牌续期时,它会打开一个隐藏的 iframe,访问授权端点并重定向回redirectUri。如果该 URL 上的静态脚本实例化了第二个 OIDC 客户端并开始交换代码,就会劫持 iframe,导致 iframe 超时错误。请改为在 React 应用中将回调作为普通路由处理(参见oidc-callback.jsx.template)。
Angular CLI
环境变量放在 src/environments/environment.ts 中:
export const environment = {
pingWellknown: 'https://auth.example.com/am/oauth2/alpha/.well-known/openid-configuration',
pingClientId: 'my-app',
pingRedirectUri: 'http://localhost:4200/callback',
pingScope: 'openid profile',
// Journey only:
pingJourneyName: 'Login',
};
Angular 特有说明:
- 使用
environment.ts/environment.prod.ts配置——Angular 不会向浏览器公开process.env。 - 回调路由是普通的 Angular 路由组件——由于 Angular 的路由器会处理回调,因此无需使用静态 HTML 变通方案。
Vue CLI / Vite
环境变量使用与你的构建工具相匹配的前缀:
- Vite →
VITE_前缀(与上文 React + Vite 相同) - Vue CLI(webpack) →
VUE_APP_前缀
VUE_APP_PING_WELLKNOWN=https://auth.example.com/am/oauth2/alpha/.well-known/openid-configuration
VUE_APP_PING_CLIENT_ID=my-app
VUE_APP_PING_REDIRECT_URI=http://localhost:8080/callback
VUE_APP_PING_SCOPE=openid profile
使用 process.env.VUE_APP_*(Vue CLI)或 import.meta.env.VITE_*(Vite)访问。
Vanilla JS / 其他
没有框架专用的环境变量惯例。可选择适合项目的任意方式:
- 导出常量的
config.js文件 - 在构建时通过
dotenv加载.env - 在零构建设置中使用内联
<script>变量
create-sample 命令
/ping-orchestration-javascript-sdk create-sample "<description>"
步骤:
- 分析描述,确定流程类型(journey / davinci / oidc-centralized)和框架。
- 如果流程类型不明确,提出一个澄清问题。
- 如果框架不是 React,且无法从项目中检测到,请询问用户。
- 从 W2 中收集描述无法推断出的所有缺失必需参数。
- 如果框架在 Framework Registry 中标记为
active:- Journey → 使用 Skill 工具,通过预填配置调用 Journey delegate。
- DaVinci → 使用 Skill 工具,通过预填配置调用 DaVinci delegate。
- OIDC centralized → 读取
assets/oidc-centralized-reference.md,并从框架的OIDC Templates目录中生成模板,同时替换占位符。
- 如果框架标记为
placeholder→ 使用 Generic(Placeholder Framework)路径。
模板占位符(仅适用于 OIDC centralized):
| 占位符 | 值 |
|---|---|
PLACEHOLDER_APP_NAME | appName |
PLACEHOLDER_WELLKNOWN | wellknown |
PLACEHOLDER_CLIENT_ID | clientId |
PLACEHOLDER_REDIRECT_URI | redirectUri |
PLACEHOLDER_SCOPE | scope |
PLACEHOLDER_ACR_VALUES | acrValues — 如果未提供,则省略该行 |
OIDC Centralized 登录
直接内联处理,无需委派。直接使用 @forgerock/oidc-client。完整 API 参考:assets/oidc-centralized-reference.md。
流程
- 用户进入登录页面 → 调用
client.authorize.url()生成授权 URL → 重定向浏览器。 - 用户在 PingOne/AIC 上完成身份验证 → 浏览器重定向回
redirectUri。 - 回调页面从 URL 中读取
code和state→ 调用client.token.exchange(code, state)→ 存储令牌。 - 应用调用
client.token.get()读取令牌 → 用户已通过身份验证,渲染受保护内容。 - 后台续期:调用
client.token.get({ backgroundRenew: true }),通过隐藏的 iframe 保持会话有效。 - 登出:调用
client.user.logout()→ 撤销访问令牌并结束服务器上的会话。
客户端初始化
import { oidc } from '@forgerock/oidc-client';
const CONFIG = {
serverConfig: {
wellknown: import.meta.env.VITE_PING_WELLKNOWN,
},
clientId: import.meta.env.VITE_PING_CLIENT_ID,
redirectUri: import.meta.env.VITE_PING_REDIRECT_URI,
scope: import.meta.env.VITE_PING_SCOPE,
// acrValues: import.meta.env.VITE_PING_ACR_VALUES, // uncomment if needed
};
const client = await oidc({ config: CONFIG });
令牌交换(回调页面)
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const state = params.get('state');
if (code && state) {
await client.token.exchange(code, state);
window.location.replace('/'); // redirect to home after successful exchange
}
路由守卫模式
所有框架的路由守卫逻辑都相同,只有组件包装器会变化。
核心逻辑(与框架无关):
async function checkAuth(client) {
const tokens = await client.token.get();
if (!tokens) {
const url = await client.authorize.url();
window.location.href = url;
return null;
}
return tokens;
}
React 包装器:
import { useEffect, useState } from 'react';
export function ProtectedRoute({ children }) {
const [isAuthenticated, setIsAuthenticated] = useState(null);
useEffect(() => {
client.token.get().then((tokens) => {
setIsAuthenticated(!!tokens);
});
}, []);
if (isAuthenticated === null) return <div>Loading…</div>;
if (!isAuthenticated) {
client.authorize.url().then((url) => { window.location.href = url; });
return null;
}
return children;
}
对于其他框架,使用相同的 checkAuth 逻辑,根据框架的守卫机制调整包装器(例如 Angular CanActivate、Vue beforeEach 导航守卫等)。
模板
当流程类型为 oidc-centralized 时,生成以下文件。从 Framework Registry 的 OIDC Templates 列中指定的活动框架子目录读取模板(例如,React 对应 assets/react/)。替换占位符,并将文件写入用户的项目目录。
React(assets/react/):
| 模板文件 | 输出路径 | 用途 |
|---|---|---|
assets/react/.env.template | .env | 环境变量(Vite VITE_ 前缀) |
assets/react/oidc-app.jsx.template | src/App.jsx | 包含 OIDC 上下文和受保护路由的应用外壳 |
assets/react/oidc-login.jsx.template | src/pages/Login.jsx | 登录触发器(authorize.url() → 重定向) |
assets/react/oidc-callback.jsx.template | src/pages/Callback.jsx | 代码交换处理器(通过 React 组件调用 token.exchange) |
assets/react/oidc-home.jsx.template | src/pages/Home.jsx | 包含登录 CTA、用户信息和登出功能的主页 |
其他框架: 当其 OIDC Templates 目录中包含模板时,遵循相同模式——从框架的 assets/<framework>/ 目录读取。
常见问题(OIDC)
state不匹配:切勿手动构造授权 URL。始终使用client.authorize.url()——它会自动生成并存储state和code_verifier(PKCE)。调用token.exchange时,如果传入的state与已存储的状态不匹配,就会抛出state_mismatch。- 后台续期需要允许 iframe:
backgroundRenew: true会打开一个指向授权端点的隐藏 iframe。如果 CSP 阻止了frame-src,续期会静默失败。请将 PingOne/AIC 域名添加到frame-src。 - PKCE 始终启用:
@forgerock/oidc-client默认使用 PKCE,且不提供切换选项。OAuth 客户端注册必须启用 PKCE(或将其设为可选)。