Skip to main content

Aspect Development

This guide covers the CLI workflow for Aspect development: choosing a template, previewing it locally, and submitting it for review. For the platform model, template catalog, and security model, this guide links out — see the documentation map below.

Documentation map
If you want…Go to
What an Aspect is, web vs mobile, context-less vs context-awareAspects Overview
The full template catalog with patterns, presets, and "what the user sees"Template Families
The runtime contract — dbk.sessionInfo(), dbk.loadScript(), OIDC token exchangeWeb Technical Reference
Security model, threat tables, defense layersSecurity Architecture and Security model
The 60-question vendor questionnaire + per-template completed responsesSecurity Questionnaire
Which CLI flag maps to which security control§ CLI Flag → Security Control below

This guide is the canonical reference for CLI flags and the preview / submit workflow only.

Templates

The CLI ships a curated catalog of Aspect templates organized by platform (web / mobile / both), category (context-less / context-aware), and contextMethod (global-variable / oidc / jsbridge-token). For the full pattern descriptions, presets, and "production examples it replaces" see Template Families.

Browse the catalog from the CLI:

Bash
forge aspect templates                              # list all templates with name + description
forge aspect templates --id welcome-banner # details for a specific template
forge aspect templates --id banner --preview-code # view the generated JavaScript
forge aspect templates --platform web # filter by platform
forge aspect templates --context-aware # filter by category
forge aspect templates --format ids # one template id per line (for scripts)
forge aspect templates --format preset-ids # one preset id per line

Presets and mock partners

Presets are named bundles of default URLs and options (no real FI or vendor secrets) that map common integration shapes onto generic templates — for example a vendor script loader preset that points at a local mock SDK URL.

  • Presets are listed in forge aspect templates and enumerated with --format preset-ids.
  • Use --preset <id> with forge aspect preview --template <template-id> so the CLI merges preset defaults before your flags and prompts. If a preset does not apply to the chosen template, the CLI exits with an error.
  • For code preview only, combine forge aspect templates --id <template> --preset <id> --preview-code to print generated JavaScript with the preset applied.

Vendor-oriented presets expect a mock partner HTTP server (for example on http://localhost:4011) that serves stub scripts and JSON. The CLI auto-detects a running mock partner when possible; you can also set MOCK_PARTNERS_URL or MOCK_PARTNERS_PORT so previews resolve the right host.

Example preset ids (see the CLI output for the authoritative list): glia, link-live-retail, link-live-business, gtm, iframe-sso, salesforce-chat, five9, acquire, fab-help, mobile-ujet, mobile-salesforce.

Bash
forge aspect preview --template vendor-script-loader --preset glia
forge aspect templates --id vendor-script-loader --preset glia --preview-code

Creating an Aspect

Run forge aspect create or forge aspect preview to interactively select a template and enter your message:

Bash
forge aspect create

If no template is specified, the CLI prompts you to choose one (or paste custom source code, or open an empty playground).

Previewing an Aspect

OLB Docker Playground (Default)

Bash
forge aspect preview --template banner --message 'Summer savings!'

This generates the Aspect JavaScript, starts the OLB Docker playground, registers the Aspect in-memory, and opens the banking shell at http://localhost:4200. Reload the page to see the Aspect.

Local Mock Dashboard

Bash
forge aspect preview --template banner --message 'Quick preview' --no-playground

The --no-playground flag starts a lightweight local mock banking dashboard instead of the full Docker environment. This is useful for rapid iteration instead of deploying Docker.

From a File

Preview a hand-written JavaScript file with live reload:

Bash
forge aspect preview --code-file ./aspects/my-aspect.js

The preview server watches the file for changes and reloads automatically.

Mobile Preview

Bash
forge aspect preview --template banner --message 'Mobile promo' --platform mobile

Mobile Aspects are saved as .html documents and opened in a browser for manual testing. See the Mobile Aspects Technical Reference section for the native bridge API.

Interactive prompting

When you run forge aspect preview without content flags, the CLI prompts for:

  1. Source — Use a built-in template, load from a JavaScript file, or open the playground shell only (add Aspects manually in the UI)
  2. Template (when you pick a template) — Choose from the filtered list for your --platform
  3. Message — Enter copy where the template uses a message (some templates skip this prompt)

Multiline Messages

From bash or zsh, use ANSI-C quoting ($'...') so \n is interpreted as a real newline:

Bash
forge aspect preview --template banner --message $'Drive smarter with auto loans.\nLower rates, flexible terms.'
warning

Plain single quotes ('...\n...') pass a literal backslash-n, not a newline. This is a common source of "banner not showing" issues.

OIDC-Authenticated Aspects

The oidc-snippet template scaffolds a complete OIDC authorization code flow:

Bash
# Auto-starts the local OIDC Toolkit (zero config)
forge aspect preview --template oidc-snippet

# Production scaffold with real FI credentials
forge aspect preview --template oidc-snippet --client-id my-app --fi-domain acmebank

When the OIDC Toolkit is running (forge oidc up), the CLI auto-detects it, fetches the auto-generated client_id and client_secret, and wires them into the generated snippet.

For the full OIDC integration workflow, see OIDC local development.

Submitting an Aspect

From a Template

Bash
forge aspect submit "summer sale" --template banner --message 'Summer savings!' --platform web --wait

From a File

Bash
forge aspect submit "summer sale" --code-file ./aspects/summer-sale.js --platform web --wait

Updating an Existing PR

If a submission PR fails checks, edit the file and resubmit to the same PR:

Bash
forge aspect submit "summer sale" --code-file ./aspects/summer-sale.js --pr 3 --platform web

Key Submit Flags

FlagDescription
--template <id>Use a built-in template
--message <text>Message text for the template (use $'...' for newlines)
--cta-text <text>CTA button text (requires --template)
--cta-url <url>CTA button URL (requires --template)
--integrity <hash>SRI hash for the vendor JS tag (vendor-loader templates)
--crossorigin <anonymous|use-credentials>crossorigin paired with --integrity
--css-integrity <hash>SRI hash for the vendor CSS <link> tag (vendor-script-with-config)
--css-crossorigin <anonymous|use-credentials>crossorigin paired with --css-integrity
--iframe-sandbox <tokens>iframe sandbox tokens for hidden-iframe-sso
--allowed-origins <list>Extra trusted postMessage origins for hidden-iframe-sso
--timeout-ms <n>Fetch timeout (oidc-snippet, mobile-vendor-chat-jsbridge)
--max-retries <n>Max retries on 5xx / network errors (0 – 5)
--retry-delay-ms <n>Initial retry backoff in ms (100 – 10 000)
--csp-nonce <value>CSP nonce stamped on every emitted inline <style>
--correlation-id <value>Correlation id for oidc-snippet / mobile-vendor-chat-jsbridge / hidden-iframe-sso log lines
--code-file <path>Submit from a JavaScript file
--code <snippet>Submit an inline JavaScript snippet
--description <text>Aspect description (used in the PR body)
--platform <web|mobile|both>Target platform (validated against creation-time metadata)
--iframe / --no-iframeRender the Aspect in an iframe (default: --iframe)
--pr <number>Update an existing PR instead of creating a new one
--env <env>Submission environment override
--forceSkip platform and metadata validation
--waitPoll until the GitHub PR is created
--save / --no-saveSave generated code locally (default: --save)

Tracking, Publishing, and Deploying

Bash
forge submission list                          # list all submissions
forge submission list --status ALL # include all statuses
forge submission dashboard # aggregated stats
forge submission publish summer-sale-aspect # merge approved PR + trigger CI deploy
forge submission deploy summer-sale-aspect # promote the published Aspect to production

Lifecycle: Submit → PR Created → In Review → Approved → Publish (merge PR + CI deploy) → Deploy (production)

Web vs. Mobile Aspects

WebMobile
Submit platform flag--platform web--platform mobile
Preview modeOLB Docker playground (default) or local mock dashboard (--no-playground)HTML opened in a browser

For the platform model itself (DOM injection vs WebView execution, auth via dbk.sessionInfo() vs JSBridge, layout management), see Aspects Overview — Web vs. Mobile and the Mobile Technical Reference.

Security: CLI Flag → Security Control Lookup

Every Forge-CLI-emitted snippet ships with a layered set of security controls. Most are applied automatically; a handful are opt-in via flags when the FI's deployment requires them. This section is the flag-to-control index — for the full threat model, defense rationale, and per-template coverage, see the canonical references:

Always-on (no flag required)

ControlTemplatesWhat it does
Session validator (__cdxValidateSession)welcome-banner, personalized-toast, vendor-sdk-personalizedType / length / Unicode allowlist / expiry on dbk.sessionInfo(); falls back to safe default.
HTML escape (__cdxEsc)All UI templatesEncodes &<>"'/ before innerHTML.
URL protocol allowlist (__cdxValidateHttpUrl)modal, cardOnly http: / https: for --cta-url.
addEventListener (no inline onclick=)All templatesSnippet runs under script-src 'self' without 'unsafe-inline'.
Iframe sandbox + postMessage origin allowlist + token-schema validationhidden-iframe-ssoSee SSO iframe hardening.
Fetch timeout + retry-with-backoff (__cdxFetch)oidc-snippet, mobile-vendor-chat-jsbridgeDefault 10 s timeout, 3 retries on 5xx, no retry on 4xx.
Correlation IDs in log statementsoidc-snippet, mobile-vendor-chat-jsbridge, hidden-iframe-ssoEvery console.* line tagged [cdx-aspect:<id>].

Opt-in flags

FlagTemplatesPurposeValidation
--integrity <hash>All vendor-loader templates¹SRI on the vendor JS tagsha256/384/512-<base64> format + length; bad hashes fail open with console.error
--crossorigin <anonymous|use-credentials>Samecrossorigin paired with --integrityDefault: anonymous
--css-integrity <hash>vendor-script-with-configSRI on the CSS <link> tagSame as --integrity
--css-crossorigin <anonymous|use-credentials>vendor-script-with-configcrossorigin paired with --css-integrityDefault: anonymous
--iframe-sandbox <tokens>hidden-iframe-ssoWhitespace-separated WHATWG sandbox tokensDefault: "allow-same-origin allow-scripts"; bad tokens fall back to default with console.error
--allowed-origins <list>hidden-iframe-ssoExtra trusted postMessage origins (comma/whitespace-separated; supports *.subdomain)Iframe origin always trusted; bad entries dropped silently
--timeout-ms <n>oidc-snippet, mobile-vendor-chat-jsbridgeFetch timeout (ms)Range [1000, 60000]; out-of-range values silently fall back to 10 000
--max-retries <n>SameRetries on 5xx / network errorsRange [0, 5]; 4xx never retried
--retry-delay-ms <n>SameInitial backoff (ms); doubles each attempt, capped at 8 000 msRange [100, 10000]
--csp-nonce <value>All UI templates with <style>CSP nonce stamped on every emitted <style> element1-256 chars, no whitespace/quotes/brackets; bad values fall back to no attribute
--correlation-id <value>oidc-snippet, mobile-vendor-chat-jsbridge, hidden-iframe-ssoOverride the auto-generated correlation id4-128 chars, alphanumerics + .-_

¹ vendor-script-loader, vendor-script-with-config, tag-manager, vendor-sdk-personalized, mobile-vendor-chat-jsbridge.

Worked Examples

Bash
# Pin a vendor SDK to a known SHA-384 hash; bypass dbk.loadScript automatically
forge aspect preview --template vendor-script-loader \
--integrity 'sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/ux0SLFR4GWnIyaI8KZRcU7xY7AN5xOo'

# Generate the hash from the published vendor SDK
curl -s https://cdn.your-vendor.com/sdk.js \
| openssl dgst -sha384 -binary \
| openssl base64 -A \
| sed 's/^/sha384-/'

# Federated SSO IdP — extend the postMessage origin allowlist
forge aspect preview --template hidden-iframe-sso \
--iframe-src 'https://sso.bank.example.com/handoff' \
--allowed-origins 'https://idp.partner.com, *.federation.example.com'

# Generous timeout / extra retries for a slow staging OIDC endpoint
forge aspect preview --template oidc-snippet \
--client-id my-app --fi-domain acmebank \
--timeout-ms 30000 --max-retries 5 --retry-delay-ms 2000

# Strict CSP — pass the host page's per-request nonce + a release-tracked correlation id
forge aspect submit "auth-handoff" --template oidc-snippet \
--client-id my-app --fi-domain acmebank \
--csp-nonce "$REQUEST_NONCE" \
--correlation-id "$RELEASE_ID" \
--platform web --wait
Quick verification

After generating an Aspect, confirm the always-on controls landed via forge aspect verify — it codifies the manual grep recipes from the Deployment Security Checklist into a single command.

Bash
forge aspect preview --template welcome-banner --message 'Hi' --no-playground
forge aspect verify ./aspects/welcome-banner.js --template welcome-banner

Verifying an Aspect Snippet

forge aspect verify <file> checks an Aspect JavaScript file against the security questionnaire's mechanical controls — useful after editing a generated snippet (or before submitting a hand-authored one) to confirm every always-on control is still present.

The command codifies the same grep recipes the Deployment Security Checklist describes manually, so AppSec teams and developers run the same checks.

Modes

ModeInvocationBehavior
Best-effort (no template)forge aspect verify <file>Scans against every known control. All findings reported as informational (⚠). Exit 0. Use for inspection of hand-authored aspects.
Template-scopedforge aspect verify <file> --template <id>Checks only the controls the template promises. Failures shown red (✗) but exit 0. Use during development.
Strict (CI-gated)forge aspect verify <file> --template <id> --strictSame as template-scoped, but exits non-zero on any required-control failure. Use in CI pipelines.

Add --format json to any mode for machine-readable output.

Examples

Bash
# Best-effort: scan a file, report what's there
forge aspect verify ./aspects/welcome-banner.js
# ⚠ Q24 URL protocol allowlist — pattern not found (template doesn't need it)
# ✓ Q14 Session validator inlined
# ✓ Q23 HTML escape helper inlined
# ...
# Result: best-effort scan — 7 controls present, 7 not found.

# Template-scoped: check only the controls welcome-banner promises
forge aspect verify ./aspects/welcome-banner.js --template welcome-banner
# ✓ Q14 Session validator inlined
# ✓ Q23 HTML escape helper inlined
# ✓ Q24 No inline onclick= attributes
# ...
# Result: 7 of 7 required controls satisfied.

# Strict: fail the run if a developer edit broke a control
forge aspect verify ./aspects/edited.js --template welcome-banner --strict
# ✗ Q23 HTML escape helper inlined — Pattern not found: "__cdxEsc"
# Hint: User-controlled strings must pass through __cdxEsc before
# innerHTML insertion. Removing it allows DOM XSS.
# Result: 1 of 7 required controls FAILED.
# Exit 1

CI integration

Add to your pipeline before forge aspect submit:

- name: Verify aspect security controls
run: |
forge aspect verify ./aspects/${{ inputs.aspect-name }}.js \
--template ${{ inputs.template }} \
--strict

A non-zero exit blocks the pipeline. Use --format json if your CI parses results structurally.

What verify does not check

  • Vendor SDK behavior (vendor-script-loader, vendor-script-with-config, etc.) — the vendor SDK runs after the Forge IIFE; its security is the vendor's responsibility.
  • Opt-in flag artifacts — controls only present when --integrity / --csp-nonce are set are not part of any template's expectedControls. Verify confirms the always-on baseline.
  • Runtime correctness — verify is a static fingerprint check. It can confirm __cdxValidateSession is present; it can't confirm the code path executes correctly. Combine with snapshot testing in your own pipeline.

Preview flags reference

FlagDescription
--platform <web|mobile>Target platform (default: web)
--playground / --no-playgroundOLB Docker playground (default) or local mock dashboard
--open / --no-openOpen the OLB shell after registering (playground flows; default: open)
--pullPull fresh Docker images before starting the playground
--template <id>Built-in Aspect template
--preset <id>Preset bundle (requires --template)
--message <text>Template message (use $'...' in bash/zsh for real newlines)
--cta-text / --cta-urlCTA label and URL when supported
--client-id <id>OIDC client ID (for oidc-snippet)
--fi-domain <domain>FI domain for OIDC auth URL (for oidc-snippet)
--integrity <hash>SRI hash for the vendor JS tag (vendor-loader templates)
--crossorigin <anonymous|use-credentials>crossorigin attribute paired with --integrity
--css-integrity <hash>SRI hash for the vendor CSS <link> tag (vendor-script-with-config only)
--css-crossorigin <anonymous|use-credentials>crossorigin attribute paired with --css-integrity
--iframe-sandbox <tokens>iframe sandbox tokens for hidden-iframe-sso (default: "allow-same-origin allow-scripts")
--allowed-origins <list>Extra trusted postMessage origins for hidden-iframe-sso (comma/whitespace-separated, supports *.subdomain)
--timeout-ms <n>Fetch timeout in ms for oidc-snippet / mobile-vendor-chat-jsbridge (1 000 – 60 000, default 10 000)
--max-retries <n>Max retries on 5xx / network errors (0 – 5, default 3). 4xx is never retried.
--retry-delay-ms <n>Initial retry backoff in ms (100 – 10 000, default 1 000); capped at 8 000 ms
--csp-nonce <value>CSP nonce stamped on every emitted inline <style> (1 – 256 chars, no whitespace/quotes)
--correlation-id <value>Override the auto-generated correlation id for oidc-snippet, mobile-vendor-chat-jsbridge, hidden-iframe-sso (4 – 128 chars; alphanumerics + .-_)
--code-file <path>Preview a JavaScript file with live reload
--code <snippet>Preview an inline JavaScript snippet
--save <path>Custom save path (default: ./aspects/<template>.js)
--no-saveDo not write generated code to disk
--port <n>Mock dashboard port for --no-playground only (default: 3456)
MOCK_PARTNERS_URL / MOCK_PARTNERS_PORTOptional; point the CLI at your mock partner server

Next Steps