From a19ef483f14a8930c130c493d10788ab1004d4c4 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 10 Feb 2024 09:53:37 +0100 Subject: [PATCH] backend-{plugin,app}-api: refactored auth APIs to use principals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Co-authored-by: Carl-Erik Bergström Co-authored-by: blam Signed-off-by: Patrik Oldsberg --- .../auth/authServiceFactory.test.ts | 43 ++++--- .../auth/authServiceFactory.ts | 104 ++++++++++----- .../httpAuth/httpAuthServiceFactory.ts | 121 +++++++++++------- .../userInfo/userInfoServiceFactory.ts | 9 +- packages/backend-plugin-api/api-report.md | 84 +++++++----- .../src/services/definitions/AuthService.ts | 51 ++++++-- .../services/definitions/HttpAuthService.ts | 39 +++--- .../services/definitions/UserInfoService.ts | 6 +- .../src/services/definitions/index.ts | 9 +- 9 files changed, 296 insertions(+), 170 deletions(-) diff --git a/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.test.ts b/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.test.ts index 9dc64212de..64c2bed2a9 100644 --- a/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.test.ts +++ b/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.test.ts @@ -19,12 +19,15 @@ import { mockServices, } from '@backstage/backend-test-utils'; import { - InternalBackstageServiceCredentials, - InternalBackstageUserCredentials, + InternalBackstageCredentials, authServiceFactory, } from './authServiceFactory'; import { decodeJwt } from 'jose'; import { discoveryServiceFactory } from '../discovery'; +import { + BackstageServicePrincipal, + BackstageUserPrincipal, +} from '@backstage/backend-plugin-api'; // TODO: Ship discovery mock service in the service factory tester const mockDeps = [ @@ -48,18 +51,22 @@ describe('authServiceFactory', () => { const searchAuth = await tester.get('search'); const catalogAuth = await tester.get('catalog'); - const { token: searchToken } = await searchAuth.issueServiceToken(); + const { token: searchToken } = await searchAuth.issueToken({}); await expect(searchAuth.authenticate(searchToken)).resolves.toEqual( expect.objectContaining({ - type: 'service', - subject: 'external:backstage-plugin', + principal: { + type: 'service', + subject: 'external:backstage-plugin', + }, }), ); await expect(catalogAuth.authenticate(searchToken)).resolves.toEqual( expect.objectContaining({ - type: 'service', - subject: 'external:backstage-plugin', + principal: { + type: 'service', + subject: 'external:backstage-plugin', + }, }), ); }); @@ -72,14 +79,17 @@ describe('authServiceFactory', () => { const catalogAuth = await tester.get('catalog'); await expect( - catalogAuth.issueServiceToken({ + catalogAuth.issueToken({ forward: { $$type: '@backstage/BackstageCredentials', version: 'v1', - type: 'user', - userEntityRef: 'user:default/alice', + authMethod: 'token', token: 'alice-token', - } as InternalBackstageUserCredentials, + principal: { + type: 'user', + userEntityRef: 'user:default/alice', + }, + } as InternalBackstageCredentials, }), ).resolves.toEqual({ token: 'alice-token' }); }); @@ -91,14 +101,17 @@ describe('authServiceFactory', () => { const catalogAuth = await tester.get('catalog'); - const { token } = await catalogAuth.issueServiceToken({ + const { token } = await catalogAuth.issueToken({ forward: { $$type: '@backstage/BackstageCredentials', version: 'v1', - type: 'service', - subject: 'external:backstage-plugin', + authMethod: 'token', token: 'some-upstream-service-token', - } as InternalBackstageServiceCredentials, + principal: { + type: 'service', + subject: 'external:upstream-service', + }, + } as InternalBackstageCredentials, }); expect(decodeJwt(token)).toEqual( diff --git a/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.ts b/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.ts index a21829b228..5190b90e7e 100644 --- a/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/auth/authServiceFactory.ts @@ -18,8 +18,10 @@ import { ServerTokenManager, TokenManager } from '@backstage/backend-common'; import { AuthService, BackstageCredentials, - BackstageServiceCredentials, - BackstageUserCredentials, + BackstagePrincipalTypes, + BackstageServicePrincipal, + BackstageNonePrincipal, + BackstageUserPrincipal, IdentityService, coreServices, createServiceFactory, @@ -32,58 +34,76 @@ import { import { decodeJwt } from 'jose'; /** @internal */ -export type InternalBackstageServiceCredentials = - BackstageServiceCredentials & { +export type InternalBackstageCredentials = + BackstageCredentials & { version: string; - token: string; + token?: string; + authMethod: 'token' | 'cookie' | 'none'; }; -function createServiceCredentials( +export function createCredentialsWithServicePrincipal( sub: string, token: string, -): BackstageServiceCredentials { +): InternalBackstageCredentials { return { $$type: '@backstage/BackstageCredentials', version: 'v1', token, - type: 'service', - subject: sub, - } as InternalBackstageServiceCredentials; + principal: { + type: 'service', + subject: sub, + }, + authMethod: 'token', + }; } -/** @internal */ -export type InternalBackstageUserCredentials = BackstageUserCredentials & { - version: string; - token: string; -}; - -function createUserCredentials( +export function createCredentialsWithUserPrincipal( sub: string, token: string, -): BackstageUserCredentials { + authMethod: 'token' | 'cookie' = 'token', +): InternalBackstageCredentials { return { $$type: '@backstage/BackstageCredentials', version: 'v1', token, - type: 'user', - userEntityRef: sub, - } as InternalBackstageUserCredentials; + principal: { + type: 'user', + userEntityRef: sub, + }, + authMethod, + }; +} + +export function createCredentialsWithNonePrincipal(): InternalBackstageCredentials { + return { + $$type: '@backstage/BackstageCredentials', + version: 'v1', + principal: { + type: 'none', + }, + authMethod: 'none', + }; } export function toInternalBackstageCredentials( credentials: BackstageCredentials, -): InternalBackstageServiceCredentials | InternalBackstageUserCredentials { +): InternalBackstageCredentials< + BackstageUserPrincipal | BackstageServicePrincipal | BackstageNonePrincipal +> { if (credentials.$$type !== '@backstage/BackstageCredentials') { throw new Error('Invalid credential type'); } - const internalCredentials = credentials as - | InternalBackstageServiceCredentials - | InternalBackstageUserCredentials; + + const internalCredentials = credentials as InternalBackstageCredentials< + BackstageUserPrincipal | BackstageServicePrincipal | BackstageNonePrincipal + >; + if (internalCredentials.version !== 'v1') { throw new Error( `Invalid credential version ${internalCredentials.version}`, ); } + return internalCredentials; } @@ -100,7 +120,10 @@ class DefaultAuthService implements AuthService { // Legacy service-to-service token if (sub === 'backstage-server' && !aud) { await this.tokenManager.authenticate(token); - return createServiceCredentials('external:backstage-plugin', token); + return createCredentialsWithServicePrincipal( + 'external:backstage-plugin', + token, + ); } // User Backstage token @@ -111,21 +134,42 @@ class DefaultAuthService implements AuthService { } as IdentityApiGetIdentityRequest); if (!identity) { - throw new AuthenticationError('No identity found'); + throw new AuthenticationError('Invalid user token'); } - return createUserCredentials(identity.identity.userEntityRef, token); + return createCredentialsWithUserPrincipal( + identity.identity.userEntityRef, + token, + ); } - async issueServiceToken(options?: { + isPrincipal( + credentials: BackstageCredentials, + type: TType, + ): credentials is BackstageCredentials { + const principal = credentials.principal as + | BackstageUserPrincipal + | BackstageServicePrincipal; + + if (principal.type !== type) { + return false; + } + + return true; + } + + async issueToken(options?: { forward?: BackstageCredentials; }): Promise<{ token: string }> { const internalForward = options?.forward && toInternalBackstageCredentials(options.forward); if (internalForward) { - const { type } = internalForward; + const { type } = internalForward.principal; if (type === 'user') { + if (!internalForward.token) { + throw new Error('User credentials is unexpectedly missing token'); + } return { token: internalForward.token }; } else if (type !== 'service') { throw new AuthenticationError( diff --git a/packages/backend-app-api/src/services/implementations/httpAuth/httpAuthServiceFactory.ts b/packages/backend-app-api/src/services/implementations/httpAuth/httpAuthServiceFactory.ts index 02b9975a47..c7525acebb 100644 --- a/packages/backend-app-api/src/services/implementations/httpAuth/httpAuthServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/httpAuth/httpAuthServiceFactory.ts @@ -16,19 +16,21 @@ import { AuthService, - BackstageCredentialTypes, BackstageCredentials, - BackstageUnauthorizedCredentials, + BackstageHttpAccessToPrincipalTypesMapping, DiscoveryService, HttpAuthService, coreServices, createServiceFactory, } from '@backstage/backend-plugin-api'; -import { NotAllowedError } from '@backstage/errors'; +import { AuthenticationError, NotAllowedError } from '@backstage/errors'; import { parse as parseCookie } from 'cookie'; import { Request, Response } from 'express'; import { decodeJwt } from 'jose'; -import { toInternalBackstageCredentials } from '../auth/authServiceFactory'; +import { + createCredentialsWithNonePrincipal, + toInternalBackstageCredentials, +} from '../auth/authServiceFactory'; const BACKSTAGE_AUTH_COOKIE = 'backstage-auth'; @@ -58,20 +60,9 @@ function getTokenFromRequest(req: Request) { const credentialsSymbol = Symbol('backstage-credentials'); type RequestWithCredentials = Request & { - [credentialsSymbol]?: Promise<{ - credentials: BackstageCredentials | BackstageUnauthorizedCredentials; - // TODO: This is temporary and should be removed once we have proper cookie handling in place - isCookie: boolean; - }>; + [credentialsSymbol]?: Promise; }; -function createUnauthorizedCredentials(): BackstageUnauthorizedCredentials { - return { - $$type: '@backstage/BackstageCredentials', - type: 'unauthorized', - }; -} - class DefaultHttpAuthService implements HttpAuthService { constructor( private readonly auth: AuthService, @@ -79,63 +70,94 @@ class DefaultHttpAuthService implements HttpAuthService { private readonly pluginId: string, ) {} - async #getCredentials(req: Request) { + async #extractCredentialsFromRequest(req: Request) { const { token, isCookie } = getTokenFromRequest(req); - // TODO: Is this where we match against configured rules? if (!token) { - return { credentials: createUnauthorizedCredentials(), isCookie }; + return createCredentialsWithNonePrincipal(); } - return { credentials: await this.auth.authenticate(token), isCookie }; - } - async #getCredentialsCached(req: /* */ RequestWithCredentials) { - return (req[credentialsSymbol] ??= this.#getCredentials(req)); - } - - async credentials( - req: RequestWithCredentials, - options: { - allow: TAllowed[]; - }, - ): Promise { - const { credentials, isCookie } = await this.#getCredentialsCached(req); - - if (credentials.type === 'user' && isCookie) { - if (options.allow.includes('user-cookie' as TAllowed)) { - return credentials as BackstageCredentialTypes[TAllowed]; + const credentials = toInternalBackstageCredentials( + await this.auth.authenticate(token), + ); + if (isCookie) { + if (credentials.principal.type !== 'user') { + throw new AuthenticationError( + 'Refusing to authenticate non-user principal with cookie auth', + ); } - throw new NotAllowedError( - `This endpoint does not allow 'user-cookie' credentials`, - ); + credentials.authMethod = 'cookie'; } - if (!options.allow.includes(credentials.type as TAllowed)) { - throw new NotAllowedError( - `This endpoint does not allow '${credentials.type}' credentials`, - ); - } - - return credentials as BackstageCredentialTypes[TAllowed]; + return credentials; } - async requestHeaders(options?: { + async #getCredentials(req: /* */ RequestWithCredentials) { + return (req[credentialsSymbol] ??= + this.#extractCredentialsFromRequest(req)); + } + + async credentials< + TAllowed extends + | keyof BackstageHttpAccessToPrincipalTypesMapping + | undefined = undefined, + >( + req: Request, + options?: { + allow: Array; + }, + ): Promise< + BackstageCredentials< + TAllowed extends keyof BackstageHttpAccessToPrincipalTypesMapping + ? BackstageHttpAccessToPrincipalTypesMapping[TAllowed] + : unknown + > + > { + const credentials = toInternalBackstageCredentials( + await this.#getCredentials(req), + ); + + // TODO break out into more readable function as we always + // want to check cookie regardless if options are set or not + // Probably asserts function that ensures authMethod = 'token' after cookie check + if (credentials.authMethod === 'cookie') { + if (options && !options.allow.includes('user-cookie' as TAllowed)) { + throw new NotAllowedError( + `This endpoint does not allow 'user-cookie' credentials`, + ); + } + } else if ( + options && + !options.allow.includes(credentials.principal.type as TAllowed) + ) { + throw new NotAllowedError( + `This endpoint does not allow '${credentials.principal.type}' credentials`, + ); + } + + return credentials as any; + } + + async requestHeaders(options: { forward?: BackstageCredentials; }): Promise> { return { - Authorization: `Bearer ${await this.auth.issueServiceToken(options)}`, + Authorization: `Bearer ${await this.auth.issueToken(options)}`, }; } async issueUserCookie(res: Response): Promise { const credentials = await this.credentials(res.req, { allow: ['user'] }); - // https://backstage.spotify.net/api/catalog + // https://backstage.example.com/api/catalog const externalBaseUrlStr = await this.discovery.getExternalBaseUrl( this.pluginId, ); const externalBaseUrl = new URL(externalBaseUrlStr); const { token } = toInternalBackstageCredentials(credentials); + if (!token) { + throw new Error('User credentials is unexpectedly missing token'); + } // TODO: Proper refresh and expiration handling const expires = decodeJwt(token).exp!; @@ -149,6 +171,7 @@ class DefaultHttpAuthService implements HttpAuthService { priority: 'high', sameSite: 'lax', // TBD }); + throw new Error('Method not implemented.'); } } diff --git a/packages/backend-app-api/src/services/implementations/userInfo/userInfoServiceFactory.ts b/packages/backend-app-api/src/services/implementations/userInfo/userInfoServiceFactory.ts index a177f2442b..a74b8b7002 100644 --- a/packages/backend-app-api/src/services/implementations/userInfo/userInfoServiceFactory.ts +++ b/packages/backend-app-api/src/services/implementations/userInfo/userInfoServiceFactory.ts @@ -15,11 +15,11 @@ */ import { - BackstageUserCredentials, UserInfoService, BackstageUserInfo, coreServices, createServiceFactory, + BackstageCredentials, } from '@backstage/backend-plugin-api'; import { toInternalBackstageCredentials } from '../auth/authServiceFactory'; import { decodeJwt } from 'jose'; @@ -27,12 +27,15 @@ import { decodeJwt } from 'jose'; // TODO: The intention is for this to eventually be replaced by a call to the auth-backend export class DefaultUserInfoService implements UserInfoService { async getUserInfo( - credentials: BackstageUserCredentials, + credentials: BackstageCredentials, ): Promise { const internalCredentials = toInternalBackstageCredentials(credentials); - if (internalCredentials.type !== 'user') { + if (internalCredentials.principal.type !== 'user') { throw new Error('Only user credentials are supported'); } + if (!internalCredentials.token) { + throw new Error('User credentials is unexpectedly missing token'); + } const { sub: userEntityRef, ent: ownershipEntityRefs = [] } = decodeJwt( internalCredentials.token, ); diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index 302a3d37d4..81579fb0e9 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -22,7 +22,12 @@ export interface AuthService { // (undocumented) authenticate(token: string): Promise; // (undocumented) - issueServiceToken(options?: { forward?: BackstageCredentials }): Promise<{ + isPrincipal( + credentials: BackstageCredentials, + type: TType, + ): credentials is BackstageCredentials; + // (undocumented) + issueToken(options: { forward?: BackstageCredentials }): Promise<{ token: string; }>; } @@ -89,36 +94,35 @@ export interface BackendPluginRegistrationPoints { } // @public (undocumented) -export type BackstageCredentials = - | BackstageUserCredentials - | BackstageServiceCredentials; - -// @public (undocumented) -export type BackstageCredentialTypes = { - user: BackstageUserCredentials; - 'user-cookie': BackstageUserCredentials; - service: BackstageServiceCredentials; - unauthorized: BackstageUnauthorizedCredentials; +export type BackstageCredentials = { + $$type: '@backstage/BackstageCredentials'; + principal: TPrincipal; }; // @public (undocumented) -export type BackstageServiceCredentials = { - $$type: '@backstage/BackstageCredentials'; +export type BackstageHttpAccessToPrincipalTypesMapping = { + user: BackstageUserPrincipal; + 'user-cookie': BackstageUserPrincipal; + service: BackstageServicePrincipal; + unauthenticated: BackstageNonePrincipal; +}; + +// @public (undocumented) +export type BackstageNonePrincipal = { + type: 'none'; +}; + +// @public (undocumented) +export type BackstagePrincipalTypes = { + user: BackstageUserPrincipal; + service: BackstageServicePrincipal; +}; + +// @public (undocumented) +export type BackstageServicePrincipal = { type: 'service'; subject: string; -}; - -// @public (undocumented) -export type BackstageUnauthorizedCredentials = { - $$type: '@backstage/BackstageCredentials'; - type: 'unauthorized'; -}; - -// @public (undocumented) -export type BackstageUserCredentials = { - $$type: '@backstage/BackstageCredentials'; - type: 'user'; - userEntityRef: string; + permissions?: string[]; }; // @public (undocumented) @@ -129,6 +133,12 @@ export interface BackstageUserInfo { userEntityRef: string; } +// @public (undocumented) +export type BackstageUserPrincipal = { + type: 'user'; + userEntityRef: string; +}; + // @public export interface CacheService { delete(key: string): Promise; @@ -281,14 +291,22 @@ export interface ExtensionPointConfig { // @public (undocumented) export interface HttpAuthService { // (undocumented) - createHttpPluginRouterMiddleware(): Handler; - // (undocumented) - credentials( + credentials< + TAllowed extends + | keyof BackstageHttpAccessToPrincipalTypesMapping + | undefined = undefined, + >( req: Request_2, - options: { + options?: { allow: Array; }, - ): Promise; + ): Promise< + BackstageCredentials< + TAllowed extends keyof BackstageHttpAccessToPrincipalTypesMapping + ? BackstageHttpAccessToPrincipalTypesMapping[TAllowed] + : unknown + > + >; // (undocumented) issueUserCookie(res: Response_2): Promise; // (undocumented) @@ -547,8 +565,6 @@ export interface UrlReaderService { // @public (undocumented) export interface UserInfoService { // (undocumented) - getUserInfo( - credentials: BackstageUserCredentials, - ): Promise; + getUserInfo(credentials: BackstageCredentials): Promise; } ``` diff --git a/packages/backend-plugin-api/src/services/definitions/AuthService.ts b/packages/backend-plugin-api/src/services/definitions/AuthService.ts index d4ab8456a8..8a946e5c91 100644 --- a/packages/backend-plugin-api/src/services/definitions/AuthService.ts +++ b/packages/backend-plugin-api/src/services/definitions/AuthService.ts @@ -17,9 +17,7 @@ /** * @public */ -export type BackstageUserCredentials = { - $$type: '@backstage/BackstageCredentials'; - +export type BackstageUserPrincipal = { type: 'user'; userEntityRef: string; @@ -28,27 +26,54 @@ export type BackstageUserCredentials = { /** * @public */ -export type BackstageServiceCredentials = { - $$type: '@backstage/BackstageCredentials'; - - type: 'service'; - - subject: string; +export type BackstageNonePrincipal = { + type: 'none'; }; /** * @public */ -export type BackstageCredentials = - | BackstageUserCredentials - | BackstageServiceCredentials; +export type BackstageServicePrincipal = { + type: 'service'; + + // Exact format TBD, possibly 'plugin:' or 'external:' + subject: string; + + // Not implemented in the first iteration, but this is how we might extend this in the future + permissions?: string[]; +}; + +/** + * @public + */ +export type BackstageCredentials = { + $$type: '@backstage/BackstageCredentials'; + + principal: TPrincipal; +}; + +/** + * @public + */ +export type BackstagePrincipalTypes = { + user: BackstageUserPrincipal; + service: BackstageServicePrincipal; +}; /** * @public */ export interface AuthService { authenticate(token: string): Promise; - issueServiceToken(options?: { + + isPrincipal( + credentials: BackstageCredentials, + type: TType, + ): credentials is BackstageCredentials; + + // TODO: should the caller provide the target plugin ID? + // TODO: how can we make it very difficult to forget to forward credentials + issueToken(options: { forward?: BackstageCredentials; }): Promise<{ token: string }>; } diff --git a/packages/backend-plugin-api/src/services/definitions/HttpAuthService.ts b/packages/backend-plugin-api/src/services/definitions/HttpAuthService.ts index d5c5cb9613..f84234932b 100644 --- a/packages/backend-plugin-api/src/services/definitions/HttpAuthService.ts +++ b/packages/backend-plugin-api/src/services/definitions/HttpAuthService.ts @@ -16,36 +16,39 @@ import { Request, Response } from 'express'; import { - BackstageUserCredentials, - BackstageServiceCredentials, BackstageCredentials, + BackstageServicePrincipal, + BackstageNonePrincipal, + BackstageUserPrincipal, } from './AuthService'; /** @public */ -export type BackstageUnauthorizedCredentials = { - $$type: '@backstage/BackstageCredentials'; - - type: 'unauthorized'; -}; - -/** @public */ -export type BackstageCredentialTypes = { - user: BackstageUserCredentials; - 'user-cookie': BackstageUserCredentials; - service: BackstageServiceCredentials; - unauthorized: BackstageUnauthorizedCredentials; +export type BackstageHttpAccessToPrincipalTypesMapping = { + user: BackstageUserPrincipal; + 'user-cookie': BackstageUserPrincipal; + service: BackstageServicePrincipal; + unauthenticated: BackstageNonePrincipal; }; /** @public */ export interface HttpAuthService { - credentials( + credentials< + TAllowed extends + | keyof BackstageHttpAccessToPrincipalTypesMapping + | undefined = undefined, + >( req: Request, - options: { + options?: { allow: Array; }, - ): Promise; + ): Promise< + BackstageCredentials< + TAllowed extends keyof BackstageHttpAccessToPrincipalTypesMapping + ? BackstageHttpAccessToPrincipalTypesMapping[TAllowed] + : unknown + > + >; - // TODO: Keep an eye on this, might not be needed requestHeaders(options?: { forward?: BackstageCredentials; }): Promise>; diff --git a/packages/backend-plugin-api/src/services/definitions/UserInfoService.ts b/packages/backend-plugin-api/src/services/definitions/UserInfoService.ts index b789116ffb..90f5306a58 100644 --- a/packages/backend-plugin-api/src/services/definitions/UserInfoService.ts +++ b/packages/backend-plugin-api/src/services/definitions/UserInfoService.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { BackstageUserCredentials } from './AuthService'; +import { BackstageCredentials } from './AuthService'; /** @public */ export interface BackstageUserInfo { @@ -24,7 +24,5 @@ export interface BackstageUserInfo { /** @public */ export interface UserInfoService { - getUserInfo( - credentials: BackstageUserCredentials, - ): Promise; + getUserInfo(credentials: BackstageCredentials): Promise; } diff --git a/packages/backend-plugin-api/src/services/definitions/index.ts b/packages/backend-plugin-api/src/services/definitions/index.ts index 420c722a4d..810f1754b7 100644 --- a/packages/backend-plugin-api/src/services/definitions/index.ts +++ b/packages/backend-plugin-api/src/services/definitions/index.ts @@ -18,8 +18,10 @@ export { coreServices } from './coreServices'; export type { AuthService, BackstageCredentials, - BackstageServiceCredentials, - BackstageUserCredentials, + BackstageUserPrincipal, + BackstageServicePrincipal, + BackstagePrincipalTypes, + BackstageNonePrincipal, } from './AuthService'; export type { CacheService, @@ -35,8 +37,7 @@ export type { } from './HttpRouterService'; export type { HttpAuthService, - BackstageCredentialTypes, - BackstageUnauthorizedCredentials, + BackstageHttpAccessToPrincipalTypesMapping, } from './HttpAuthService'; export type { LifecycleService,