⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .changeset/rich-cows-try.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
'@forgerock/journey-client': minor
'@forgerock/sdk-oidc': minor
'@forgerock/sdk-utilities': minor
'@forgerock/davinci-client': patch
'@forgerock/oidc-client': patch
---

### @forgerock/journey-client

Add well-known OIDC endpoint discovery support. The journey client can now fetch configuration from the `.well-known/openid-configuration` endpoint:

```typescript
const client = await journey({
serverConfig: {
baseUrl: 'https://am.example.com/am/',
wellknown:
'https://am.example.com/am/oauth2/realms/root/realms/alpha/.well-known/openid-configuration',
},
});
```

The realm path can be automatically inferred from the well-known issuer URL.

### @forgerock/sdk-oidc

Add shared well-known module with RTK Query API for OIDC endpoint discovery:

- `wellknownApi` - RTK Query API for fetching well-known configuration
- `createWellknownSelector` - Selector factory for cached well-known data
- `createWellknownError` - Typed error creation from fetch failures
- Re-exports pure utilities from `@forgerock/sdk-utilities`

### @forgerock/sdk-utilities

Add pure well-known utilities:

- `inferRealmFromIssuer` - Extract realm path from AM issuer URLs
- `isValidWellknownUrl` - Validate well-known URLs (HTTPS required, HTTP allowed for localhost)

### @forgerock/davinci-client

Refactored to use shared well-known module from `@forgerock/sdk-oidc`.

### @forgerock/oidc-client

Refactored to use shared well-known module from `@forgerock/sdk-oidc`.
43 changes: 43 additions & 0 deletions .changeset/wellknown-only-config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
'@forgerock/journey-client': major
---

BREAKING: Unify journey-client around wellknown-only configuration

This release simplifies the configuration API by requiring the `wellknown` URL and automatically inferring `baseUrl` and `realmPath`.

## Breaking Changes

- **Removed `baseUrl` from `JourneyServerConfig`**: The `baseUrl` is now always inferred from the wellknown URL. If inference fails (non-AM server), an error is returned.
- **Removed `hasWellknownConfig` export**: This type guard is no longer needed since all configs use wellknown.

## Migration

**Before:**
```typescript
journey({
config: {
serverConfig: { baseUrl: 'https://am.example.com/am/' },
realmPath: 'alpha',
},
});
```

**After:**
```typescript
journey({
config: {
serverConfig: {
wellknown: 'https://am.example.com/am/oauth2/alpha/.well-known/openid-configuration',
},
// realmPath is now optional - inferred from wellknown issuer
},
});
```

## Features

- Automatic `baseUrl` inference from wellknown URL (extracts path before `/oauth2/`)
- Automatic `realmPath` inference from wellknown issuer
- Improved error messages for non-AM servers, guiding users to appropriate clients
- Updated README with comprehensive API documentation
8 changes: 5 additions & 3 deletions e2e/am-mock-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
"author": "",
"main": "./index.js",
"dependencies": {
"@types/express": "^4.17.17",
"body-parser": "^2.2.0",
"body-parser": "^2.2.2",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"express": "^4.21.2",
"express": "^5.2.1",
"superagent": "^10.2.3",
"uuid": "^13.0.0"
},
"devDependencies": {
"@types/express": "^5.0.0"
}
}
5 changes: 5 additions & 0 deletions e2e/am-mock-api/src/app/routes.auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,11 @@ export default function (app) {
res.send(wellKnownForgeRock);
});

// Standard AM wellknown endpoint path (used by journey-client wellknown discovery)
app.get('/am/oauth2/realms/root/.well-known/openid-configuration', (req, res) => {
res.send(wellKnownForgeRock);
});

app.get('/as/.well-known/new-oidc-configuration', (req, res) => {
res.send(newPiWellKnown);
});
Expand Down
4 changes: 2 additions & 2 deletions e2e/am-mock-api/src/app/routes.resource.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ async function authorization(req, res, next) {

export default function (app) {
// Passthrough route that enforces authentication
app.all('/resource/*', async (req, res, next) => {
app.all('/resource/{*splat}', async (req, res, next) => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed when i rebased open-deps (part of this express upgrade)

if (env.NODE_ENV === 'LIVE' && req.hostname === FORGEOPS) {
// Only enforce authentication if IG is not used
// In other words, the call comes directly from app
Expand Down Expand Up @@ -156,7 +156,7 @@ export default function (app) {
}
});

app.get('/resource/rest/*', wait, authorization, async (req, res) => {
app.get('/resource/rest/{*splat}', wait, authorization, async (req, res) => {
if (env.NODE_ENV === 'live') {
if (req.access.actions && req.access.actions.GET) {
res.json({ message: 'Successfully retrieved resource!' });
Expand Down
14 changes: 7 additions & 7 deletions e2e/davinci-app/package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
{
"name": "@forgerock/davinci-app",
"version": "0.0.0",
"private": true,
"description": "Ping DaVinci Client Test App",
"type": "module",
"private": true,
"nx": {
"tags": ["scope:e2e"]
},
"scripts": {
"build": "pnpm nx nxBuild",
"lint": "pnpm nx nxLint",
Expand All @@ -16,8 +13,11 @@
"dependencies": {
"@forgerock/davinci-client": "workspace:*",
"@forgerock/javascript-sdk": "4.7.0",
"@forgerock/sdk-logger": "workspace:*",
"@forgerock/protect": "workspace:*"
"@forgerock/protect": "workspace:*",
"@forgerock/sdk-logger": "workspace:*"
},
"devDependencies": {}
"devDependencies": {},
"nx": {
"tags": ["scope:e2e"]
}
}
9 changes: 0 additions & 9 deletions e2e/davinci-app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,6 @@
"skipLibCheck": true
},
"references": [
{
"path": "../../packages/sdk-effects/logger"
},
{
"path": "../../packages/protect"
},
{
"path": "../../packages/davinci-client"
},
{
"path": "./tsconfig.app.json"
},
Expand Down
6 changes: 3 additions & 3 deletions e2e/device-client-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
"@forgerock/javascript-sdk": "4.7.0",
"effect": "^3.12.7"
},
"nx": {
"tags": ["scope:e2e"]
},
"devDependencies": {
"@effect/language-service": "^0.20.0"
},
"nx": {
"tags": ["scope:e2e"]
}
}
3 changes: 0 additions & 3 deletions e2e/device-client-app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
"files": [],
"include": [],
"references": [
{
"path": "../../packages/device-client"
},
{
"path": "./tsconfig.app.json"
}
Expand Down
17 changes: 14 additions & 3 deletions e2e/journey-app/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
import './style.css';

import { journey } from '@forgerock/journey-client';
import { journey, isJourneyClient } from '@forgerock/journey-client';

import type { RequestMiddleware } from '@forgerock/journey-client/types';

Expand Down Expand Up @@ -51,12 +51,23 @@ if (searchParams.get('middleware') === 'true') {
}

(async () => {
const journeyClient = await journey({ config: config, requestMiddleware });

const errorEl = document.getElementById('error') as HTMLDivElement;
const formEl = document.getElementById('form') as HTMLFormElement;
const journeyEl = document.getElementById('journey') as HTMLDivElement;

const journeyClientResult = await journey({ config: config, requestMiddleware });
if (!isJourneyClient(journeyClientResult)) {
console.error('Failed to initialize journey client:', journeyClientResult.message);
errorEl.textContent = journeyClientResult.message ?? 'Unknown error';
return;
}
/**
* Re-assign to a new const after type narrowing.
* TypeScript's type narrowing doesn't persist into closures (event handlers, callbacks)
* because it can't prove the variable wasn't reassigned between the guard and closure execution.
* Creating a new const binding after the guard preserves the narrowed type for nested functions.
*/
const journeyClient = journeyClientResult;
let step = await journeyClient.start({ journey: journeyName });

function renderComplete() {
Expand Down
8 changes: 4 additions & 4 deletions e2e/journey-app/package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
{
"name": "@forgerock/journey-app",
"version": "1.3.0",
"private": true,
"description": "Ping Journey Client Test App",
"type": "module",
"private": true,
"nx": {
"tags": ["scope:e2e"]
},
"scripts": {
"build": "pnpm nx nxBuild",
"lint": "pnpm nx nxLint",
Expand All @@ -18,5 +15,8 @@
"@forgerock/oidc-client": "workspace:*",
"@forgerock/protect": "workspace:*",
"@forgerock/sdk-logger": "workspace:*"
},
"nx": {
"tags": ["scope:e2e"]
}
}
18 changes: 14 additions & 4 deletions e2e/journey-app/server-configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,27 @@
*/
import type { JourneyClientConfig } from '@forgerock/journey-client/types';

/**
* Server configurations for E2E tests.
*
* Both baseUrl and realmPath are automatically inferred from the wellknown URL:
* - baseUrl: extracted from the path before `/oauth2/`
* - realmPath: extracted from the issuer URL in the wellknown response
*/
export const serverConfigs: Record<string, JourneyClientConfig> = {
basic: {
serverConfig: {
baseUrl: 'http://localhost:9443/am',
wellknown: 'http://localhost:9443/am/oauth2/realms/root/.well-known/openid-configuration',
// baseUrl inferred: http://localhost:9443/am/
// realmPath inferred from issuer: 'root'
},
realmPath: 'root',
},
tenant: {
serverConfig: {
baseUrl: 'https://openam-sdks.forgeblocks.com/am',
wellknown:
'https://openam-sdks.forgeblocks.com/am/oauth2/realms/root/realms/alpha/.well-known/openid-configuration',
// baseUrl inferred: https://openam-sdks.forgeblocks.com/am/
// realmPath inferred from issuer: 'alpha'
},
realmPath: 'alpha',
},
};
12 changes: 0 additions & 12 deletions e2e/journey-app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,6 @@
"skipLibCheck": true
},
"references": [
{
"path": "../../packages/sdk-effects/logger"
},
{
"path": "../../packages/oidc-client"
},
{
"path": "../../packages/protect"
},
{
"path": "../../packages/journey-client"
},
{
"path": "./tsconfig.app.json"
},
Expand Down
3 changes: 2 additions & 1 deletion e2e/mock-api-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"nanoid": "5.1.6"
},
"devDependencies": {
"@effect/vitest": "catalog:effect"
"@effect/vitest": "catalog:effect",
"vitest": "catalog:vitest"
},
"nx": {
"tags": ["scope:e2e"],
Expand Down
3 changes: 0 additions & 3 deletions e2e/oidc-app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
"files": [],
"include": [],
"references": [
{
"path": "../../packages/oidc-client"
},
{
"path": "./tsconfig.app.json"
}
Expand Down
2 changes: 1 addition & 1 deletion e2e/protect-app/package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "@forgerock/protect-app",
"version": "0.0.0",
"description": "Ping Protect Test Apps",
"private": true,
"description": "Ping Protect Test Apps",
"type": "module",
"scripts": {
"build": "pnpm nx nxBuild",
Expand Down
3 changes: 0 additions & 3 deletions e2e/protect-app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
"skipLibCheck": true
},
"references": [
{
"path": "../../packages/protect"
},
{
"path": "./tsconfig.app.json"
},
Expand Down
8 changes: 7 additions & 1 deletion nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@
"buildTargetName": "nxBuild",
"serveTargetName": "nxServe",
"previewTargetName": "nxPreview",
"testTargetName": "nxTest",
"serveStaticTargetName": "serve-static",
"typecheckTargetName": "typecheck",
"buildDepsTargetName": "vite:build-deps",
Expand All @@ -146,6 +145,13 @@
"configName": "tsconfig.lib.json"
}
}
},
{
"plugin": "@nx/vitest",
"options": {
"testTargetName": "nxTest"
},
"include": ["packages/**/**/*", "e2e/**/**/*", "tools/**/**/*"]
}
Comment on lines +150 to 155
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the full nx.json file to see targetDefaults structure
cat nx.json | head -200

Repository: ForgeRock/ping-javascript-sdk

Length of output: 4536


🏁 Script executed:

# Search for testTargetName and nxTest references
rg -n "testTargetName|nxTest" .

Repository: ForgeRock/ping-javascript-sdk

Length of output: 2267


🏁 Script executed:

# Look for test target references in CI workflows
find .github/workflows -type f -name "*.yml" -o -name "*.yaml" | head -20

Repository: ForgeRock/ping-javascript-sdk

Length of output: 200


🏁 Script executed:

# Search for nx test/affected calls in workflows and scripts
rg -n "nx\s+(affected|run-many|test)" .github/workflows/ 2>/dev/null || echo "No matches in workflows"
rg -n "\bnx\s+test\b|\bnx\s+affected.*test" . --type yml --type yaml 2>/dev/null || echo "Checking workflows separately"

Repository: ForgeRock/ping-javascript-sdk

Length of output: 292


🏁 Script executed:

# Check for targetDefaults entries for test-related targets
rg -n -A5 '"targetDefaults"' nx.json

Repository: ForgeRock/ping-javascript-sdk

Length of output: 222


CI workflow will not run vitest tests due to target name mismatch.

The @nx/vitest plugin generates targets named nxTest, but .github/workflows/ci-fork.yml:58 explicitly calls nx affected -t ... test ..., which refers to a target named test that doesn't exist. This means vitest tests won't execute in CI.

Additionally, targetDefaults only includes test, test:watch, and test:coverage with no corresponding nxTest entries, so the generated nxTest targets won't inherit the cache, inputs, or outputs settings defined for test.

Choose one approach:

  1. Rename testTargetName to test and update all package.json test scripts to call nx test instead of nx nxTest, OR
  2. Update CI workflow to call nx affected -t ... nxTest ... and add targetDefaults.nxTest entries mirroring the test defaults (inputs, outputs, cache, dependsOn).
🤖 Prompt for AI Agents
In `@nx.json` around lines 150 - 155, The CI is invoking the wrong target name:
the Vitest plugin configured testTargetName as "nxTest" but the workflow and
targetDefaults use "test", so CI won't run tests and nxTest won't inherit
cache/settings; either change the plugin option testTargetName to "test" and
update package.json scripts that call "nx nxTest" to "nx test", or update the CI
workflow command to use "nxTest" and add corresponding targetDefaults entries
for "nxTest" (copy inputs, outputs, dependsOn, cache settings from the existing
"test" defaults) so the generated nxTest targets run in CI and inherit the same
configuration.

],
"parallel": 1,
Expand Down
Loading
Loading