From e4516facafa4293981023bb57bf5af74c3d4ad63 Mon Sep 17 00:00:00 2001 From: Charles Lavery Date: Tue, 24 Mar 2026 11:17:31 -0400 Subject: [PATCH 1/3] docs: remove developer preview banner and disclaimer Remove the "Developer Preview" note and disclaimer from the CLI README, the preview banner from the docs site theme, and all associated CSS. --- docs/.vitepress/theme/custom.css | 68 -------------------------------- docs/.vitepress/theme/index.ts | 10 ----- packages/b2c-cli/README.md | 6 --- 3 files changed, 84 deletions(-) diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css index 56da6d7b..1e4e4836 100644 --- a/docs/.vitepress/theme/custom.css +++ b/docs/.vitepress/theme/custom.css @@ -3,79 +3,11 @@ --vp-c-brand-2: #0090c8; --vp-c-brand-3: #007eb0; --vp-c-brand-soft: rgba(0, 161, 224, 0.14); - --vp-banner-height: 38px; /* Hero name gradient (Salesforce blue) */ --vp-home-hero-name-color: transparent; --vp-home-hero-name-background: linear-gradient(135deg, #00A1E0 0%, #0070D2 100%); } -/* Developer Preview Banner */ -.preview-banner { - background: linear-gradient(90deg, #0070d2 0%, #00a1e0 100%); - color: white; - text-align: center; - padding: 8px 16px; - font-size: 14px; - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 60; - min-height: var(--vp-banner-height); - box-sizing: border-box; - display: flex; - align-items: center; - justify-content: center; - flex-wrap: wrap; -} - -.preview-banner a { - color: white; - text-decoration: underline; - margin-left: 8px; -} - -.preview-banner a:hover { - opacity: 0.9; -} - -/* Adjust VitePress layout for banner */ -.VPNav { - top: var(--vp-banner-height) !important; -} - -.VPSidebar { - top: calc(var(--vp-nav-height) + var(--vp-banner-height)) !important; - height: calc(100vh - var(--vp-nav-height) - var(--vp-banner-height)) !important; -} - -.VPContent { - padding-top: calc(var(--vp-nav-height) + var(--vp-banner-height)) !important; -} - -.VPLocalNav { - top: calc(var(--vp-nav-height) + var(--vp-banner-height)) !important; -} - -/* Mobile/tablet: banner scrolls with page when sidebar is hidden */ -@media (max-width: 959px) { - .preview-banner { - position: relative; - } - - .VPNav { - top: 0 !important; - } - - .VPContent { - padding-top: 0 !important; - } - - .VPLocalNav { - top: 0 !important; - } -} - .dark { --vp-c-brand-1: #00A1E0; --vp-c-brand-2: #33b4e6; diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index 9145950c..0810e58e 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -7,16 +7,6 @@ export default { extends: DefaultTheme, Layout() { return h(DefaultTheme.Layout, null, { - 'layout-top': () => - h('div', {class: 'preview-banner'}, [ - h('strong', 'Developer Preview'), - ' — This project is in active development. APIs may change. ', - h( - 'a', - {href: 'https://github.com/SalesforceCommerceCloud/b2c-developer-tooling/issues', target: '_blank'}, - 'Provide feedback', - ), - ]), 'home-features-before': () => h(HomeQuickInstall), }); }, diff --git a/packages/b2c-cli/README.md b/packages/b2c-cli/README.md index aa3b4350..134dc3a3 100644 --- a/packages/b2c-cli/README.md +++ b/packages/b2c-cli/README.md @@ -2,9 +2,6 @@ [![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io) -> [!NOTE] -> This project is currently in **Developer Preview**. Not all features are implemented, and the API may change in future releases. Please provide feedback via GitHub issues. - A command-line interface for Salesforce Agentforce Commerce (formerly Commerce Cloud) B2C instances and platform services. ## Installation @@ -286,6 +283,3 @@ Full documentation is available at: https://salesforcecommercecloud.github.io/b2 This project is licensed under the Apache License 2.0. See [LICENSE.txt](../../LICENSE.txt) for full details. -## Disclaimer - -This project is currently in **Developer Preview** and is provided "as-is" without warranty of any kind. It is not yet generally available (GA) and should not be used in production environments. Features, APIs, and functionality may change without notice in future releases. From 5d02344851708e8dad9715b29630b60c044b9fee Mon Sep 17 00:00:00 2001 From: Charles Lavery Date: Tue, 24 Mar 2026 12:49:37 -0400 Subject: [PATCH 2/3] feat: support implicit OAuth in VS Code remote environments (Codespaces) Add openBrowser and redirectUri options to ImplicitOAuthConfig, AuthCredentials, and CreateOAuthOptions so callers can customize the browser opener and redirect URI for implicit auth flows. The VS Code extension now uses vscode.env.openExternal (opens browser on the client) and vscode.env.asExternalUri (resolves localhost to the Codespaces forwarded port URL) so implicit OAuth works in remote environments where the `open` package cannot reach the user's browser. --- .changeset/implicit-auth-vscode-browser.md | 6 ++++++ .../src/auth/oauth-implicit.ts | 16 +++++++++++--- packages/b2c-tooling-sdk/src/auth/resolve.ts | 2 ++ packages/b2c-tooling-sdk/src/auth/types.ts | 4 ++++ .../src/config/resolved-config.ts | 2 ++ packages/b2c-tooling-sdk/src/config/types.ts | 4 ++++ .../api-browser/api-browser-tree-provider.ts | 3 ++- .../src/api-browser/swagger-webview.ts | 12 +++++++---- .../b2c-vs-extension/src/config-provider.ts | 21 +++++++++++++++++++ .../src/sandbox-tree/sandbox-commands.ts | 13 ++++++------ .../src/sandbox-tree/sandbox-tree-provider.ts | 6 ++++-- 11 files changed, 73 insertions(+), 16 deletions(-) create mode 100644 .changeset/implicit-auth-vscode-browser.md diff --git a/.changeset/implicit-auth-vscode-browser.md b/.changeset/implicit-auth-vscode-browser.md new file mode 100644 index 00000000..72a12935 --- /dev/null +++ b/.changeset/implicit-auth-vscode-browser.md @@ -0,0 +1,6 @@ +--- +'@salesforce/b2c-tooling-sdk': minor +'b2c-vs-extension': patch +--- + +Add `openBrowser` and `redirectUri` options to OAuth strategy creation, allowing callers to customize how the browser is opened and which redirect URI is used during implicit auth. The VS Code extension now uses `vscode.env.openExternal` and `vscode.env.asExternalUri` so implicit OAuth works in Codespaces and other remote environments. diff --git a/packages/b2c-tooling-sdk/src/auth/oauth-implicit.ts b/packages/b2c-tooling-sdk/src/auth/oauth-implicit.ts index b2689688..6d004392 100644 --- a/packages/b2c-tooling-sdk/src/auth/oauth-implicit.ts +++ b/packages/b2c-tooling-sdk/src/auth/oauth-implicit.ts @@ -41,6 +41,12 @@ export interface ImplicitOAuthConfig { * The local server still listens on localPort regardless of this setting. */ redirectUri?: string; + /** + * Custom browser opener. Receives the authorization URL and should open it + * in the user's browser. Useful in environments where the default `open` package + * doesn't work (e.g., VS Code remote/Codespaces where `vscode.env.openExternal` is needed). + */ + openBrowser?: (url: string) => Promise; } /** @@ -70,7 +76,7 @@ function getOauth2RedirectHTML(redirectUri: string): string { * Opens the system default browser to the specified URL. * Dynamically imports 'open' package to handle the browser opening. */ -async function openBrowser(url: string): Promise { +async function openBrowserDefault(url: string): Promise { try { // Dynamic import of 'open' package const open = await import('open'); @@ -325,9 +331,13 @@ export class ImplicitOAuthStrategy implements AuthStrategy { logger.info({url: authorizeUrl}, `Login URL: ${authorizeUrl}`); logger.info('If the URL does not open automatically, copy/paste it into a browser on this machine.'); - // Attempt to open the browser + // Attempt to open the browser (prefer injected opener, fall back to `open` package) logger.debug('[Auth] Attempting to open browser'); - await openBrowser(authorizeUrl); + if (this.config.openBrowser) { + await this.config.openBrowser(authorizeUrl); + } else { + await openBrowserDefault(authorizeUrl); + } return new Promise((resolve, reject) => { const sockets: Set = new Set(); diff --git a/packages/b2c-tooling-sdk/src/auth/resolve.ts b/packages/b2c-tooling-sdk/src/auth/resolve.ts index 243b0011..12e43fdf 100644 --- a/packages/b2c-tooling-sdk/src/auth/resolve.ts +++ b/packages/b2c-tooling-sdk/src/auth/resolve.ts @@ -182,6 +182,8 @@ export function resolveAuthStrategy( clientId: credentials.clientId, scopes: credentials.scopes, accountManagerHost: credentials.accountManagerHost, + redirectUri: credentials.redirectUri, + openBrowser: credentials.openBrowser, }); } break; diff --git a/packages/b2c-tooling-sdk/src/auth/types.ts b/packages/b2c-tooling-sdk/src/auth/types.ts index 98ca9f8a..fcee8e2a 100644 --- a/packages/b2c-tooling-sdk/src/auth/types.ts +++ b/packages/b2c-tooling-sdk/src/auth/types.ts @@ -133,4 +133,8 @@ export interface AuthCredentials { apiKey?: string; /** Header name for API key (defaults to Authorization with Bearer prefix) */ apiKeyHeaderName?: string; + /** Override redirect URI for implicit OAuth flow (e.g., for port forwarding in remote environments) */ + redirectUri?: string; + /** Custom browser opener for implicit OAuth flow. Receives the authorization URL. */ + openBrowser?: (url: string) => Promise; } diff --git a/packages/b2c-tooling-sdk/src/config/resolved-config.ts b/packages/b2c-tooling-sdk/src/config/resolved-config.ts index df15026e..3094d6dc 100644 --- a/packages/b2c-tooling-sdk/src/config/resolved-config.ts +++ b/packages/b2c-tooling-sdk/src/config/resolved-config.ts @@ -82,6 +82,8 @@ export class ResolvedConfigImpl implements ResolvedB2CConfig { clientSecret: this.values.clientSecret, scopes: mergedScopes.length > 0 ? mergedScopes : undefined, accountManagerHost: this.values.accountManagerHost, + redirectUri: options?.redirectUri, + openBrowser: options?.openBrowser, }; return resolveAuthStrategy(credentials, {allowedMethods: options?.allowedMethods}); } diff --git a/packages/b2c-tooling-sdk/src/config/types.ts b/packages/b2c-tooling-sdk/src/config/types.ts index 1ee2037f..cf1061cb 100644 --- a/packages/b2c-tooling-sdk/src/config/types.ts +++ b/packages/b2c-tooling-sdk/src/config/types.ts @@ -326,6 +326,10 @@ export interface CreateOAuthOptions { allowedMethods?: AuthMethod[]; /** Additional OAuth scopes to request beyond those in config */ scopes?: string[]; + /** Override redirect URI for implicit OAuth flow (e.g., for port forwarding in remote environments) */ + redirectUri?: string; + /** Custom browser opener for implicit OAuth flow. Receives the authorization URL. */ + openBrowser?: (url: string) => Promise; } /** diff --git a/packages/b2c-vs-extension/src/api-browser/api-browser-tree-provider.ts b/packages/b2c-vs-extension/src/api-browser/api-browser-tree-provider.ts index dbffeab5..0f303252 100644 --- a/packages/b2c-vs-extension/src/api-browser/api-browser-tree-provider.ts +++ b/packages/b2c-vs-extension/src/api-browser/api-browser-tree-provider.ts @@ -127,7 +127,8 @@ export class ApiBrowserTreeDataProvider implements vscode.TreeDataProvider { - const oauthStrategy = config.createOAuth(); + const oauthOptions = await this.configProvider.getImplicitAuthOptions(); + const oauthStrategy = config.createOAuth(oauthOptions); const schemasClient = createScapiSchemasClient({shortCode, tenantId}, oauthStrategy); const orgId = toOrganizationId(tenantId); const {data, error, response} = await schemasClient.GET('/organizations/{organizationId}/schemas', { diff --git a/packages/b2c-vs-extension/src/api-browser/swagger-webview.ts b/packages/b2c-vs-extension/src/api-browser/swagger-webview.ts index 294b88db..ccd965d6 100644 --- a/packages/b2c-vs-extension/src/api-browser/swagger-webview.ts +++ b/packages/b2c-vs-extension/src/api-browser/swagger-webview.ts @@ -218,7 +218,8 @@ export class SwaggerWebviewManager implements vscode.Disposable { // Resolve external $refs server-side so the webview doesn't have to fetch them if (config.hasOAuthConfig()) { - const oauthStrategy = config.createOAuth(); + const oauthOptions = await this.configProvider.getImplicitAuthOptions(); + const oauthStrategy = config.createOAuth(oauthOptions); const authHeader = await oauthStrategy.getAuthorizationHeader?.(); await resolveExternalRefs(spec, authHeader, this.log); } @@ -308,7 +309,8 @@ export class SwaggerWebviewManager implements vscode.Disposable { const tenantId = deriveTenantId(config.values.hostname); if (!tenantId) throw new Error('Could not derive tenant ID from hostname.'); - const oauthStrategy = config.createOAuth(); + const oauthOptions = await this.configProvider.getImplicitAuthOptions(); + const oauthStrategy = config.createOAuth(oauthOptions); const schemasClient = createScapiSchemasClient({shortCode, tenantId}, oauthStrategy); const orgId = toOrganizationId(tenantId); const {data, error, response} = await schemasClient.GET( @@ -452,7 +454,8 @@ export class SwaggerWebviewManager implements vscode.Disposable { if (!config.hasOAuthConfig()) return null; // Request the specific scopes required by this API spec so the token // includes them (the cache will re-authenticate if scopes are missing) - const oauthStrategy = config.createOAuth({scopes}); + const oauthOptions = await this.configProvider.getImplicitAuthOptions(); + const oauthStrategy = config.createOAuth({...oauthOptions, scopes}); const header = await oauthStrategy.getAuthorizationHeader?.(); if (!header) return null; // Header is "Bearer " — extract the token @@ -510,7 +513,8 @@ export class SwaggerWebviewManager implements vscode.Disposable { try { this.log.appendLine(`[API Browser] Auto-discovering SLAS client for tenant ${tenantId}...`); - const oauthStrategy = config.createOAuth(); + const oauthOptions = await this.configProvider.getImplicitAuthOptions(); + const oauthStrategy = config.createOAuth(oauthOptions); const slasClient = createSlasClient({shortCode}, oauthStrategy); const {data, error} = await slasClient.GET('/tenants/{tenantId}/clients', { diff --git a/packages/b2c-vs-extension/src/config-provider.ts b/packages/b2c-vs-extension/src/config-provider.ts index d176d87f..3238fddc 100644 --- a/packages/b2c-vs-extension/src/config-provider.ts +++ b/packages/b2c-vs-extension/src/config-provider.ts @@ -8,6 +8,7 @@ import { EnvSource, type NormalizedConfig, type ResolvedB2CConfig, + type CreateOAuthOptions, } from '@salesforce/b2c-tooling-sdk/config'; import type {B2CInstance} from '@salesforce/b2c-tooling-sdk/instance'; import * as fs from 'fs'; @@ -234,6 +235,26 @@ export class B2CExtensionConfig implements vscode.Disposable { return resolveConfig(overrides, {workingDirectory}); } + /** + * Returns CreateOAuthOptions with VS Code-specific overrides for implicit auth: + * - Uses `vscode.env.openExternal` to open the browser on the client (works in Codespaces/remote) + * - Uses `vscode.env.asExternalUri` to resolve the redirect URI for port forwarding + * + * Merge with any additional options before passing to `config.createOAuth()`. + */ + async getImplicitAuthOptions(): Promise { + const localPort = parseInt(process.env.SFCC_OAUTH_LOCAL_PORT || '', 10) || 8080; + const localUri = vscode.Uri.parse(`http://localhost:${localPort}`); + const externalUri = await vscode.env.asExternalUri(localUri); + + return { + redirectUri: process.env.SFCC_REDIRECT_URI || externalUri.toString(/* skipEncoding */ true), + openBrowser: async (url: string) => { + await vscode.env.openExternal(vscode.Uri.parse(url)); + }, + }; + } + dispose(): void { this._onDidReset.dispose(); for (const d of this.disposables) { diff --git a/packages/b2c-vs-extension/src/sandbox-tree/sandbox-commands.ts b/packages/b2c-vs-extension/src/sandbox-tree/sandbox-commands.ts index 875a5415..594724b8 100644 --- a/packages/b2c-vs-extension/src/sandbox-tree/sandbox-commands.ts +++ b/packages/b2c-vs-extension/src/sandbox-tree/sandbox-commands.ts @@ -11,13 +11,14 @@ import type {RealmTreeItem, SandboxTreeDataProvider, SandboxTreeItem} from './sa const DEFAULT_ODS_HOST = 'admin.dx.commercecloud.salesforce.com'; -function getOdsClientFromConfig(configProvider: SandboxConfigProvider) { +async function getOdsClientFromConfig(configProvider: SandboxConfigProvider) { const config = configProvider.getConfigProvider().getConfig(); if (!config) throw new Error('No B2C Commerce configuration found. Configure dw.json or SFCC_* env vars.'); if (!config.hasOAuthConfig()) throw new Error('OAuth credentials required. Set clientId and clientSecret in dw.json.'); const host = config.values.sandboxApiHost ?? DEFAULT_ODS_HOST; - return createOdsClient({host}, config.createOAuth()); + const oauthOptions = await configProvider.getConfigProvider().getImplicitAuthOptions(); + return createOdsClient({host}, config.createOAuth(oauthOptions)); } const SANDBOX_DETAIL_SCHEME = 'b2c-sandbox'; @@ -103,7 +104,7 @@ export function registerSandboxCommands( {location: vscode.ProgressLocation.Notification, title: `Creating sandbox in realm ${realm}...`}, async () => { try { - const odsClient = getOdsClientFromConfig(configProvider); + const odsClient = await getOdsClientFromConfig(configProvider); const result = await odsClient.POST('/sandboxes', { body: {realm: realm!, ttl, analyticsEnabled: false}, }); @@ -139,7 +140,7 @@ export function registerSandboxCommands( {location: vscode.ProgressLocation.Notification, title: `Deleting sandbox ${node.sandbox.id}...`}, async () => { try { - const odsClient = getOdsClientFromConfig(configProvider); + const odsClient = await getOdsClientFromConfig(configProvider); const result = await odsClient.DELETE('/sandboxes/{sandboxId}', { params: {path: {sandboxId: node.sandbox.id}}, }); @@ -180,7 +181,7 @@ export function registerSandboxCommands( }, async () => { try { - const odsClient = getOdsClientFromConfig(configProvider); + const odsClient = await getOdsClientFromConfig(configProvider); const result = await odsClient.POST('/sandboxes/{sandboxId}/operations', { params: {path: {sandboxId: node.sandbox.id}}, body: {operation: operationType}, @@ -264,7 +265,7 @@ export function registerSandboxCommands( }, async () => { try { - const odsClient = getOdsClientFromConfig(configProvider); + const odsClient = await getOdsClientFromConfig(configProvider); const result = await odsClient.PATCH('/sandboxes/{sandboxId}', { params: {path: {sandboxId: node.sandbox.id}}, body: {ttl}, diff --git a/packages/b2c-vs-extension/src/sandbox-tree/sandbox-tree-provider.ts b/packages/b2c-vs-extension/src/sandbox-tree/sandbox-tree-provider.ts index 868e236e..42c564f7 100644 --- a/packages/b2c-vs-extension/src/sandbox-tree/sandbox-tree-provider.ts +++ b/packages/b2c-vs-extension/src/sandbox-tree/sandbox-tree-provider.ts @@ -202,7 +202,8 @@ export class SandboxTreeDataProvider implements vscode.TreeDataProvider { const host = config.values.sandboxApiHost ?? DEFAULT_ODS_HOST; - const authStrategy = config.createOAuth(); + const oauthOptions = await configProvider.getImplicitAuthOptions(); + const authStrategy = config.createOAuth(oauthOptions); const odsClient = createOdsClient({host}, authStrategy); const result = await odsClient.GET('/sandboxes', { params: { @@ -234,7 +235,8 @@ export class SandboxTreeDataProvider implements vscode.TreeDataProvider Date: Tue, 24 Mar 2026 13:55:53 -0400 Subject: [PATCH 3/3] fix: thread openBrowser/redirectUri through B2CInstance path The content tree, webdav tree, and log tailing features use configProvider.getInstance() which creates a B2CInstance with its own internal auth resolution. Thread redirectUri and openBrowser through OAuthAuthConfig, AuthConfig, createInstanceFromConfig, and createB2CInstance so these features also use vscode.env.openExternal in remote environments. --- packages/b2c-tooling-sdk/src/auth/types.ts | 4 ++++ packages/b2c-tooling-sdk/src/config/mapping.ts | 14 +++++++++++++- .../b2c-tooling-sdk/src/config/resolved-config.ts | 4 ++-- packages/b2c-tooling-sdk/src/config/types.ts | 3 ++- packages/b2c-tooling-sdk/src/instance/index.ts | 2 ++ packages/b2c-vs-extension/src/config-provider.ts | 3 ++- 6 files changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/b2c-tooling-sdk/src/auth/types.ts b/packages/b2c-tooling-sdk/src/auth/types.ts index fcee8e2a..15bb3316 100644 --- a/packages/b2c-tooling-sdk/src/auth/types.ts +++ b/packages/b2c-tooling-sdk/src/auth/types.ts @@ -51,6 +51,10 @@ export interface OAuthAuthConfig { clientSecret?: string; scopes?: string[]; accountManagerHost?: string; + /** Override redirect URI for implicit OAuth flow (e.g., for port forwarding in remote environments) */ + redirectUri?: string; + /** Custom browser opener for implicit OAuth flow. Receives the authorization URL. */ + openBrowser?: (url: string) => Promise; } /** diff --git a/packages/b2c-tooling-sdk/src/config/mapping.ts b/packages/b2c-tooling-sdk/src/config/mapping.ts index 4e057c5b..01c3d3cc 100644 --- a/packages/b2c-tooling-sdk/src/config/mapping.ts +++ b/packages/b2c-tooling-sdk/src/config/mapping.ts @@ -460,7 +460,10 @@ export function buildAuthConfigFromNormalized(config: NormalizedConfig): AuthCon * await instance.webdav.mkcol('Cartridges/v1'); * ``` */ -export function createInstanceFromConfig(config: NormalizedConfig): B2CInstance { +export function createInstanceFromConfig( + config: NormalizedConfig, + options?: {redirectUri?: string; openBrowser?: (url: string) => Promise}, +): B2CInstance { if (!config.hostname) { throw new Error('Hostname is required. Set in dw.json or provide via overrides.'); } @@ -482,5 +485,14 @@ export function createInstanceFromConfig(config: NormalizedConfig): B2CInstance const authConfig = buildAuthConfigFromNormalized(config); + // Inject implicit auth options into OAuth config when present + if (authConfig.oauth && (options?.redirectUri || options?.openBrowser)) { + authConfig.oauth = { + ...authConfig.oauth, + redirectUri: options.redirectUri, + openBrowser: options.openBrowser, + }; + } + return new B2CInstance(instanceConfig, authConfig); } diff --git a/packages/b2c-tooling-sdk/src/config/resolved-config.ts b/packages/b2c-tooling-sdk/src/config/resolved-config.ts index 3094d6dc..44905ebf 100644 --- a/packages/b2c-tooling-sdk/src/config/resolved-config.ts +++ b/packages/b2c-tooling-sdk/src/config/resolved-config.ts @@ -55,11 +55,11 @@ export class ResolvedConfigImpl implements ResolvedB2CConfig { // Factory methods - createB2CInstance(): B2CInstance { + createB2CInstance(options?: Pick): B2CInstance { if (!this.hasB2CInstanceConfig()) { throw new Error('B2C instance requires hostname'); } - return createInstanceFromConfig(this.values); + return createInstanceFromConfig(this.values, options); } createBasicAuth(): AuthStrategy { diff --git a/packages/b2c-tooling-sdk/src/config/types.ts b/packages/b2c-tooling-sdk/src/config/types.ts index cf1061cb..2d3c3a33 100644 --- a/packages/b2c-tooling-sdk/src/config/types.ts +++ b/packages/b2c-tooling-sdk/src/config/types.ts @@ -426,9 +426,10 @@ export interface ResolvedB2CConfig { /** * Creates a B2CInstance from the resolved configuration. + * @param options - Options for implicit OAuth (redirectUri, openBrowser) * @throws Error if hostname is not configured */ - createB2CInstance(): B2CInstance; + createB2CInstance(options?: Pick): B2CInstance; /** * Creates a Basic auth strategy. diff --git a/packages/b2c-tooling-sdk/src/instance/index.ts b/packages/b2c-tooling-sdk/src/instance/index.ts index 2338e8ff..d365d470 100644 --- a/packages/b2c-tooling-sdk/src/instance/index.ts +++ b/packages/b2c-tooling-sdk/src/instance/index.ts @@ -184,6 +184,8 @@ export class B2CInstance { clientSecret: this.auth.oauth.clientSecret, scopes: this.auth.oauth.scopes, accountManagerHost: this.auth.oauth.accountManagerHost, + redirectUri: this.auth.oauth.redirectUri, + openBrowser: this.auth.oauth.openBrowser, }; // Filter to only OAuth methods (client-credentials, implicit) diff --git a/packages/b2c-vs-extension/src/config-provider.ts b/packages/b2c-vs-extension/src/config-provider.ts index 3238fddc..516afcf5 100644 --- a/packages/b2c-vs-extension/src/config-provider.ts +++ b/packages/b2c-vs-extension/src/config-provider.ts @@ -311,7 +311,8 @@ export class B2CExtensionConfig implements vscode.Disposable { return; } - this.instance = config.createB2CInstance(); + const implicitAuthOpts = await this.getImplicitAuthOptions(); + this.instance = config.createB2CInstance(implicitAuthOpts); this.configError = null; this.log.appendLine(`[Config] Resolved instance: ${this.instance.config.hostname}`); } catch (err) {