Skip to content

SaaSdemo: a minimal third-party SaaS integration ​

SaaSdemo demonstrates GoodVision sign-in, subscription, and payment integration for third-party SaaS products. The example provides its own business pages and sign-in session. GoodVision's customer workspace provides plan, subscription, payment, billing, and entitlement management.

SaaSdemo displays currently published free or paid plans with monthly/yearly selection, Credits, seats, FAQs and original order recovery. It queries free activation, payment, allowance and product access separately and keeps no independent balance or eligibility table.

Store upgrade state separately by subscription ID. Check current member access after the old free subscription ends.

Example boundary

SaaSdemo is an independent reference integration for third-party SaaS teams, not a GoodVision internal micro-application, service, or operations demo. It demonstrates published OIDC integration and page functions. Before calling commercial APIs, confirm the application’s SaaS Billing API Product in Developer Console and use its paths, scopes, audiences and event schemas.

Page functions ​

CapabilitySaaSdemoGoodVision platform
Registration, sign-in, sign-outProvides entry points and a same-origin BFF sessionGoodVision's managed identity service owns identity, credentials, and the OIDC session
Partner product pagesRenders the third party's own product featuresDoes not host partner product features
Plans, subscriptions, payments, billsProvides a platform link onlyThe customer workspace renders and executes commercial operations
Applications, API Products, webhooksProvides a Developer Platform link onlyDeveloper Console owns technical integration
API parameters and errorsFollow the current specificationAPI Product supplies version-specific OpenAPI/AsyncAPI

The platform manages plans, orders, payments, billing and access. Third-party pages cannot maintain a separate result or simulate these states with localStorage.

Account header and current-user information ​

The example header provides Developer Console, applications and sign-in controls. Signed-in users see their avatar, name and email, and can read their profile, change language, sign in to another account or sign out. Application links open server-registered independent origins without transferring a session or permissions.

These routes belong to SaaSdemo's own same-origin BFF as implementation examples; they are not new platform business APIs:

RoutePurpose
GET /auth/sessionCheck sign-in and read the current user projection and application CSRF information
GET /api/meRecheck the current session and application scope, then read name, email, local user ID, open_id and union_id
GET /auth/login?switch_account=trueConfirm another account through managed sign-in and return to the original page
POST /auth/logoutValidate the application's CSRF token and clear the current session
js
const response = await fetch('/api/me', {
  credentials: 'same-origin',
  cache: 'no-store',
  headers: { Accept: 'application/json' },
});
if (!response.ok) throw new Error(`Profile unavailable: ${response.status}`);
const { user } = await response.json();

The profile route reads only the signed-in user and accepts no user, organization or application overrides. It returns 401 for missing authentication, 403 for denied scope and 503 for an unavailable dependency, without returning stale profile data. Closing the profile dialog or changing users clears its temporary data. Tokens stay on the server; application access and subscriptions remain subject to their platform APIs.

OIDC configuration ​

SaaSdemo uses user identity permissions with Authorization Code + PKCE (S256) for sign-in. Enable application identity permissions separately only when scheduled jobs or backend APIs are also required. The two purposes use different clients, and Sandbox never shares clients with Production.

SettingExample or source
IssuerCurrent environment’s GOODVISION_IDENTITY_ISSUER
Client IDClient ID shown under User identity permissions in Developer Console
Client SecretNone; user identity uses a public client with PKCE
Redirect URIExact /auth/callback URL on the third-party domain
Post-logout URIRegistered third-party product home page
Scopesopenid profile email plus the least-privilege scopes approved for user identity
Token storageServer-side BFF session; the browser receives only an HttpOnly cookie

The BFF validates state, nonce, PKCE, issuer, audience, azp, exp, and iat. Tokens must never appear in browser code, static environment variables, URLs, logs, or analytics. Only the optional application identity has a Client Secret, and it must remain in controlled server-side secret storage.

Get integration settings from Developer Console ​

Open the target Application and obtain SaaSdemo's server-side settings from the relevant module:

Developer Console moduleSaaSdemo settings
OAuth/OIDC configurationUser identity GOODVISION_IDENTITY_ISSUER, GOODVISION_USER_CLIENT_ID, redirect URI, and post-logout URI; no Client Secret
Credentials and basic informationOnly for optional backend API access: application identity GOODVISION_SERVICE_CLIENT_ID, plus dedicated reveal or rotation of GOODVISION_SERVICE_CLIENT_SECRET
APIs and permissionsFirst select user or application identity, then copy that identity's approved GOODVISION_API_BASE, operation paths, audience, and scopes
Events and webhooksGOODVISION_WEBHOOK_PATH, GOODVISION_WEBHOOK_SECRET_VERSION, and signing-secret delivery state

Copy API bases, operation paths, audiences, and scopes only from the API access grant approved for the current environment and identity. Bulk copy contains non-sensitive settings only and excludes OAuth Client Secrets, Webhook Secrets, and tokens.

After delivery starts, use the delivery log under Events and Webhooks to inspect event_id, delivery_id, and correlation_id. Deduplicate by event_id, locate a concrete retry by delivery_id, and correlate payment, subscription, and access processing by correlation_id. The log exposes redacted status only and never displays the payload, signing secret, Authorization header, or cookie.

Demo BFF routes ​

These routes belong to the example project. They are not GoodVision Open APIs:

RoutePurpose
GET /auth/loginGenerate an OIDC sign-in request
GET /auth/registerGenerate a registration request with prompt=create
GET /auth/callbackExchange the authorization code and establish a same-origin session
GET /auth/sessionReturn necessary user details; anonymous state also returns 200
GET /auth/configReturn redacted Application, OIDC, security, and platform-entry configuration
POST /auth/logoutValidate CSRF, destroy the session, and return the managed identity service logout URL

/auth/config may return only clientSecretConfigured: true|false. It must never return the secret value.

Configure subscription and billing links ​

SaaSdemo reads these entries from server-side runtime configuration:

text
platform.subscriptionUrl       # Subscription and billing in the customer workspace
platform.billingUrl            # Paid invoices in the customer workspace
platform.developerConsoleUrl   # Developer Console
platform.developerPortalOrigin # Developer documentation

SaaSdemo's /app/pricing hosts the platform /console/pricing iframe inside the workspace sidebar for prices, comparisons and FAQs. The sidebar's Pricing item opens this route. /pricing remains a separate host page with the public site header. Both entries share the same pricing iframe; “My subscription” embeds /console/subscription in a dialog, with independent links available. Published scope selectors are application=<slug>, environment=sandbox|production and optional product=<code>; display parameters are embed=1, locale=zh-CN|en-US, view=subscription|billing and theme=light|dark. They select an already authorized scope and cannot change the instance's server-side binding. Invalid or duplicate scope input is refused. The Production enum does not enable Production API access. Do not append:

  • application_id, organization_id, or product_tenant_id;
  • plan_code, amount, currency, provider, or payment status;
  • an arbitrary return_url, token, client secret, or webhook secret.

Independent pages use the platform session. Approved embedding may use auth=parent-bff through the host's same-origin BFF; services still verify the current user, organization, application, environment and capability. Both sides verify the exact Origin and original iframe. Tokens, cookies, CSRF secrets and third-party handoff tokens never cross URLs or messages.

  1. An unauthenticated iframe sends goodvision.customer-billing.auth_required.
  2. SaaSdemo completes GoodVision sign-in in the top-level window using a fixed targetOrigin, then refreshes the iframe.
  3. Payments started in an iframe open Stripe Hosted Checkout in the top-level window.

The browser cannot specify Organization, ProductTenant, plan, amount, currency, Provider, Token, Secret or arbitrary return URLs. Published application scope selectors grant no permission.

Minimal implementation flow ​

  1. Request an Application for the target environment and enable user identity permissions. Enable application identity permissions only when backend API access is required.
  2. Implement Authorization Code + PKCE, server-side session storage, and CSRF in the third-party BFF.
  3. After sign-in, render product pages and the platform pricing host page. New customers first create an organization, submit their customer profile, and complete platform review and independent commercial preparation.
  4. Keep pricing on a separate page and embed subscription management in a dialog. Also offer independent platform.subscriptionUrl and platform.billingUrl links; use platform.developerConsoleUrl for technical configuration.
  5. After returning to the product, query ProductAccess/Entitlement through enabled APIs. Confirm product access before enabling features.
  6. Implement backend APIs or signed webhook consumption only after the corresponding identity's API access grant is approved.

Webhook receiver reference implementation ​

SaaSdemo includes the following runnable server implementations and tests:

  • server/index.mjs: endpoint verification, raw-body receipt, capability and application/environment checks, quick acknowledgement and background access queries;
  • server/integration.mjs: time-window, Nonce, HMAC, Verification Token, optional decryption, closed event Schema, event_id deduplication, version checks and redacted state records;
  • server/integration.test.mjs covers payment, refund, subscription, fulfillment, product activation, and access-invalidation events, including cross-Application and cross-environment denial;
  • server/access-readback.integration.test.mjs: starts the example process to check signed receipt, application Token, access.reconcile.read, restricted access after query failure and necessary permission updates after success;

Process received events in this order:

  1. Validate transport security and the current application/environment.
  2. Persist the event in Inbox and acknowledge quickly.
  3. Query current state in a background task.

oem.product.activated.v1 updates the product summary. For oem.access_context.changed.v1, restrict local access first, then replace the member permission record atomically after a successful query.

Optional fulfillment integration ​

fulfillment.webhook currently supports creating a tenant in the third-party product. The platform delivers oem.fulfillment.requested.v1 to an approved Webhook. After activation, return succeeded, failed or unknown through the server-side result endpoint provided in the integration configuration.

This endpoint is for servers and is unavailable to browsers. Products cannot change the event’s Organization, Application, subscription or Edition references.

The receiver must:

  • deduplicate by event_id and handle ordering gaps with resource_version;
  • submit results using the configured server-side endpoint and Idempotency-Key;
  • return only a redacted product_tenant_id on success, or a stable error code for failure/unknown;
  • keep timeouts, dependency failures, and unknown outcomes unavailable until the platform retries or an operator compensates them;
  • enable protected features after successful activation and confirmed product access.

SaaSdemo provides a reference receiver for this flow. Implement activation for your own product and use the current application’s Profile, Grant and Webhook subscription states to determine available capabilities.

Plans and Credits reference ​

SaaSdemo's separate pricing host page embeds personal/business plans, monthly/annual billing, pricing cards, benefit comparisons, confirmation and FAQs. Subscription management embeds a separate platform page in a dialog. Integrated applications can use the same integration with authorized URL scope selection. Configure prices, Credits, seats and terms in Commerce → Subscription plans in Developer Console, then approve and publish them. The first plan can start from current product/provider configuration without copying another plan. Free must be explicitly configured; paid-only products need not offer it.

For per-seat plans, ask customers to confirm quantity, price per seat and total. Annual plans still release Credits monthly. Applications with an available model catalog and complete commercial configuration can offer one-time add-ons in the same allowance scope.

Use product and original-order values for validity and conversion. Display balances with the declared Credits ratio and retain actual Token usage and deduction details. Clear results after changing organization, application or environment. After payment returns, query the credited allowance.

See SaaS subscription and payment API for requests and recovery.

Paid flow: subscribe → confirmation dialog → top-level Stripe → trusted payment callback → original order/subscription → monthly Credits → signed fulfillment and access readback. Explicit Free acceptance activates without Stripe. A page return proves neither payment, allowance nor access; failures and unknown outcomes retain original-order recovery.

Acceptance checklist ​

  • Sign-in and registration use the environment client, exact callback URI, and PKCE S256.
  • User tokens exist only in the BFF server-side session; user identity has no Client Secret.
  • When application identity is enabled, its Client Secret exists only in controlled server-side secret storage.
  • Pricing host pages and subscription dialogs reuse platform pages without a second source of plan, Checkout, billing or access facts.
  • Platform commercial and Developer Console links come from server configuration, not browser inference.
  • The commercial entry contains no unpublished query parameter, handoff token, or arbitrary return URL.
  • Use current API product specifications for APIs, scopes, Audience, Webhooks and error codes.
  • A payment-page return, successful login, or webhook delivery never directly proves ProductAccess is active.

Continue with Third-party SaaS Billing, Authentication, Copy-ready integration templates, and Integration Entry Points and Permissions.

Customer space in the reference example ​

The reference BFF consumes Users and customer spaces and uses verified customer scope. Space failures preserve verified login and the original operation. Controlled internal readback and organization adapters are not standard third-party APIs; use only contracts enabled for your environment.

Developer documentation. Internal operations access is not required.