This directory demonstrates how to embed authenticated Nobl9 console content via iframes while acquiring and injecting tokens from the parent page.
This demo provides a production-ready example of:
- Token Acquisition: Obtaining authentication tokens via OAuth redirect or popup flows
- Token Injection: Securely passing tokens to embedded Nobl9 iframes using postMessage protocol
- Iframe Authentication: Automatically authenticating embedded Nobl9 content without requiring users to log in separately
This script requires the okta-auth-js library to be loaded before use.
The sample assumes you already have an active authenticated session with the Identity Provider (IdP) configured for your Nobl9 tenant. If the session does not exist when the page loads:
- The script will initiate an authentication flow
- You will be prompted to log in to Nobl9 before tokens can be injected into the iframes
Configuration is stored in a separate n9-config.js file. Copy the example file and fill in your values:
cp n9-config.example.js n9-config.jsThen edit n9-config.js with your settings:
window.N9_CONFIG = {
auth: {
issuer: 'https://your-n9-auth-domain/oauth2/default',
clientId: 'your-client-id',
redirectUri: window.location.origin + '/sample/dashboard.html',
scopes: ['openid', 'profile', 'email'],
pkce: true,
tokenManager: {
storage: 'localStorage',
key: 'n9Auth'
}
},
iframes: {
'panel-1': 'https://example.com/reports/details/report-1?embedMode=minimal&waitExternalAuth=true',
// 'panel-2': 'https://example.com/reports/details/report-2?embedMode=minimal&waitExternalAuth=true',
},
targetOrigin: 'https://app.nobl9.com',
authMode: 'redirect',
};auth: Okta auth server settings (issuer, clientId, redirectUri, scopes, etc.)targetOrigin: Must match the domain of your embedded iframes for secure postMessage communication.authMode: Authentication mode —'redirect'(default) or'popup'(see Two Authentication Methods).iframes: Map of panel IDs to iframe URLs. Set a value tonullto disable a panel.
waitExternalAuth=true— required to force N9 app to wait for tokens via postMessage before rendering (see Token Message Protocol Specification below). Note:wait=trueis deprecated.embedMode=minimal— optional, hides the Nobl9 header and sidebar in the embedded view.
The JavaScript (n9-iframe-auth.js) supports two acquisition modes controlled by the authMode setting in n9-config.js:
- If tokens are not already present in the URL, the page triggers an OAuth redirect.
- The browser navigates to the IdP, the user session is validated, then returns with tokens in the URL.
- On reload,
parseRedirectTokens()extracts tokens, cleans the URL, and proceeds to create iframes. - Recommendation: Start the Nobl9 authentication early (before heavy app bootstrapping) to minimize perceived load time. Avoid delaying the redirect until after large bundles load.
- Opens an OAuth popup and resolves when tokens are received.
- Requires that the browser allows popups; the script tests this via
checkPopupAllowed(). - Provides a smoother experience if you want to keep the main app context intact (no full-page navigation), but demands explicit user consent (browser UI permitting the popup).
- Fails fast with a clear alert if popups are blocked.
Set authMode: 'redirect' (default) or 'popup' in your n9-config.js.
Use redirect when you want maximal reliability and simplicity; use popup when uninterrupted SPA flow is preferred and you can guarantee popups are allowed.
The parent page and embedded iframes communicate using the window.postMessage() API. All messages must be sent to the correct targetOrigin for security. The embedded iframe MUST implement this protocol to receive authentication tokens.
Sent by: N9 iframe When: After iframe loads and is ready to receive tokens
Message Structure:
{
type: "IFRAME_READY"
}Sent by: Parent page (n9-iframe-auth.js) When: After receiving IFRAME_READY signal What: Sends OAuth tokens to iframe for authentication (tokens obtained via redirect or popup oauth flow)
Message Structure:
{
type: "INJECT_TOKENS",
payload: {
version: "2", // Protocol version
accessToken: "eyJhbGc...", // OAuth access token (JWT)
idToken: "eyJhbGc...", // OAuth ID token (JWT)
scopes: ["openid", "profile", "email"], // Granted scopes array
source: "dashboard-sample" // Source identifier
}
}Field Descriptions: Tokens obtained via redirect or popup oauth flow
version: Protocol version string (currently "2")accessToken: JWT access token for API authenticationidToken: JWT ID token containing user claimsscopes: Array of OAuth scopes granted during authenticationsource: Identifier of the embedding application
Sent by: N9 iframe When: After processing INJECT_TOKENS message
Success Response:
{
type: "INJECT_TOKENS_ACK",
payload: {
success: true
}
}Error Response:
{
type: "INJECT_TOKENS_ACK",
payload: {
success: false,
error: "Description of what went wrong"
}
}Sent by: N9 iframe When: User navigates within the iframe (route changes)
Message Structure:
{
type: "NAVIGATION_CHANGE",
payload: {
url: "https://app.nobl9.com/reports/details/123", // Full URL
path: "/reports/details/123", // Path without query/hash
fullPath: "/reports/details/123?org=demo", // Path with query/hash
routeName: "ReportDetails" // Route name
}
}Field Descriptions:
url: Complete URL of the current iframe locationpath: URL path without query parameters or hashfullPath: URL path including query parameters and hashrouteName: Internal route name from the iframe's router
Usage: Parent page can track navigation history and implement back/forward functionality for each iframe.
Sent by: Parent page When: Parent wants to trigger navigation inside the iframe
Message Structure:
{
type: "NAVIGATE_TO",
payload: {
url: "https://app.nobl9.com/services/.../slos?org=nobl9-dev&embedMode=compact", // Full URL (path extracted automatically)
// OR
path: "/services/.../slos?org=nobl9-dev&embedMode=compact", // Relative path
replace: false // Optional, default false - use router.replace instead of router.push
}
}Field Descriptions:
url: Complete URL to navigate to (path will be extracted automatically)path: Relative path to navigate to (alternative to url)replace: Optional boolean - when true, uses router.replace instead of router.push
Note: At least one of url or path is required. If url is provided, the handler extracts pathname + query + hash from it.
Purpose: Enables client-side Vue Router navigation inside the iframe without full page reloads, avoiding auth race conditions that occur with iframe.src changes.
Parent Page N9 Embedded Iframe
| |
|-- Creates iframe with src ------->|
| |
| |-- Loads & initializes
| |
|<------- IFRAME_READY -------------|
| |
| |
|------- INJECT_TOKENS ------------>|
| |
| |-- Stores tokens
| |-- Initializes app
| |
|<----- INJECT_TOKENS_ACK ----------|
| (success: true) |
| |
| |-- Fully authenticated
| |
| |-- User navigates
| |
|<--- NAVIGATION_CHANGE ------------|
| |
|-- Tracks navigation history |
| |
| |
|------- NAVIGATE_TO -------------->|
| (trigger client-side nav) |
| |
| |-- Vue Router navigates
Port 8080 has been configured as an allowed authentication issuer / redirect origin in this example setup. To serve these files locally:
# From repository root (adjust path if already inside the directory)
python3 -m http.server 8080Then open:
http://localhost:8080/sample/dashboard.html
| File | Purpose |
|---|---|
sample/dashboard.html |
Sample page containing panel containers where iframes will be injected. |
sample/style.css |
Minimal styling for layout (optional). |
n9-config.example.js |
Example configuration file — copy to n9-config.js and fill in your values. |
n9-config.js |
Your local configuration (gitignored). Loaded before n9-iframe-auth.js. |
n9-iframe-auth.js |
Handles token acquisition (redirect/popup) and posts tokens to iframes. |
README.md |
This documentation. |
- Integrate token refresh / expiration handling for long-lived sessions