From 095729d6fa439cca8aa948265cd907f2661fc2e3 Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Wed, 8 Oct 2025 22:47:30 +0200 Subject: [PATCH] [PM-23189] Add client managed token provider (#15408) * Add client managed token provider * Change token service to accept user id * Resolve breaking changes in the SDK * Fix tests * Update sdk * Fix type * Fix types * Fix cli * Fix browser * Add optional userId to refreshIdentityToken * Fix merge issues * Fix tests --- .../browser/src/background/main.background.ts | 1 + .../service-container/service-container.ts | 1 + .../src/services/jslib-services.module.ts | 1 + libs/common/src/abstractions/api.service.ts | 2 +- .../services/sdk/default-sdk.service.spec.ts | 6 ++++- .../services/sdk/default-sdk.service.ts | 22 ++++++++++++++----- 6 files changed, 26 insertions(+), 7 deletions(-) diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index fef0181352c..bd28ddfbbbf 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -830,6 +830,7 @@ export default class MainBackground { this.accountService, this.kdfConfigService, this.keyService, + this.apiService, this.stateProvider, this.configService, ); diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts index 8fb48fbc1ee..c2fffef6685 100644 --- a/apps/cli/src/service-container/service-container.ts +++ b/apps/cli/src/service-container/service-container.ts @@ -612,6 +612,7 @@ export class ServiceContainer { this.accountService, this.kdfConfigService, this.keyService, + this.apiService, this.stateProvider, this.configService, customUserAgent, diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index df135dcc0ef..15f52d0e65c 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -1523,6 +1523,7 @@ const safeProviders: SafeProvider[] = [ AccountServiceAbstraction, KdfConfigService, KeyService, + ApiServiceAbstraction, StateProvider, ConfigService, ], diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index aea52d7310d..1cab48148e9 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -163,7 +163,7 @@ export abstract class ApiService { ): Promise< IdentityTokenResponse | IdentityTwoFactorResponse | IdentityDeviceVerificationResponse >; - abstract refreshIdentityToken(): Promise; + abstract refreshIdentityToken(userId?: UserId): Promise; abstract getProfile(): Promise; abstract getUserSubscription(): Promise; diff --git a/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts b/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts index 2f6c32aa78d..7165e845885 100644 --- a/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts +++ b/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts @@ -8,11 +8,12 @@ import { KdfConfigService, KeyService, PBKDF2KdfConfig } from "@bitwarden/key-ma import { BitwardenClient } from "@bitwarden/sdk-internal"; import { + ObservableTracker, FakeAccountService, FakeStateProvider, mockAccountServiceWith, - ObservableTracker, } from "../../../../spec"; +import { ApiService } from "../../../abstractions/api.service"; import { AccountInfo } from "../../../auth/abstractions/account.service"; import { EncryptedString } from "../../../key-management/crypto/models/enc-string"; import { UserId } from "../../../types/guid"; @@ -46,6 +47,7 @@ describe("DefaultSdkService", () => { let service!: DefaultSdkService; let accountService!: FakeAccountService; let fakeStateProvider!: FakeStateProvider; + let apiService!: MockProxy; beforeEach(async () => { await new TestSdkLoadService().loadAndInit(); @@ -55,6 +57,7 @@ describe("DefaultSdkService", () => { platformUtilsService = mock(); kdfConfigService = mock(); keyService = mock(); + apiService = mock(); const mockUserId = Utils.newGuid() as UserId; accountService = mockAccountServiceWith(mockUserId); fakeStateProvider = new FakeStateProvider(accountService); @@ -72,6 +75,7 @@ describe("DefaultSdkService", () => { accountService, kdfConfigService, keyService, + apiService, fakeStateProvider, configService, ); diff --git a/libs/common/src/platform/services/sdk/default-sdk.service.ts b/libs/common/src/platform/services/sdk/default-sdk.service.ts index 2713aaf8f4b..ec57783e02f 100644 --- a/libs/common/src/platform/services/sdk/default-sdk.service.ts +++ b/libs/common/src/platform/services/sdk/default-sdk.service.ts @@ -27,6 +27,7 @@ import { UnsignedSharedKey, } from "@bitwarden/sdk-internal"; +import { ApiService } from "../../../abstractions/api.service"; import { AccountInfo, AccountService } from "../../../auth/abstractions/account.service"; import { DeviceType } from "../../../enums/device-type.enum"; import { EncryptedString, EncString } from "../../../key-management/crypto/models/enc-string"; @@ -43,7 +44,7 @@ import { StateProvider } from "../../state"; import { initializeState } from "./client-managed-state"; -// A symbol that represents an overriden client that is explicitly set to undefined, +// A symbol that represents an overridden client that is explicitly set to undefined, // blocking the creation of an internal client for that user. const UnsetClient = Symbol("UnsetClient"); @@ -51,10 +52,17 @@ const UnsetClient = Symbol("UnsetClient"); * A token provider that exposes the access token to the SDK. */ class JsTokenProvider implements TokenProvider { - constructor() {} + constructor( + private apiService: ApiService, + private userId?: UserId, + ) {} async get_access_token(): Promise { - return undefined; + if (this.userId == null) { + return undefined; + } + + return await this.apiService.getActiveBearerToken(this.userId); } } @@ -68,7 +76,10 @@ export class DefaultSdkService implements SdkService { concatMap(async (env) => { await SdkLoadService.Ready; const settings = this.toSettings(env); - const client = await this.sdkClientFactory.createSdkClient(new JsTokenProvider(), settings); + const client = await this.sdkClientFactory.createSdkClient( + new JsTokenProvider(this.apiService), + settings, + ); await this.loadFeatureFlags(client); return client; }), @@ -87,6 +98,7 @@ export class DefaultSdkService implements SdkService { private accountService: AccountService, private kdfConfigService: KdfConfigService, private keyService: KeyService, + private apiService: ApiService, private stateProvider: StateProvider, private configService: ConfigService, private userAgent: string | null = null, @@ -173,7 +185,7 @@ export class DefaultSdkService implements SdkService { const settings = this.toSettings(env); const client = await this.sdkClientFactory.createSdkClient( - new JsTokenProvider(), + new JsTokenProvider(this.apiService, userId), settings, );