docs/releases/v1.48.0-next.1-changelog.md
Upgrade Helper: https://backstage.github.io/upgrade-helper/?to=1.48.0-next.1
startTestBackend to support factory-based extension points (v1.1 format) in addition to the existing direct implementation format.zod-to-json-schema to latest versionexpress from 4.21.2 to 4.22.0textextensions dependency for text-extensions.TestDatabases by pinning the data directoryexpress from 4.21.2 to 4.22.0textextensions dependency for text-extensions.TestDatabases by pinning the data directoryd57b13b: Added support for Postgres 18 to the available TestDatabases.
Note that the set of default databases to test against for users of the TestDatabases class was also updated to include Postgres 14 and 18, instead of 13 and 17. If you need to override this, you can pass in an explicit ids argument, for example ids: ['POSTGRES_17', 'POSTGRES_13', 'SQLITE_3'].
erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.d57b13b: Added support for Postgres 18 to the available TestDatabases.
Note that the set of default databases to test against for users of the TestDatabases class was also updated to include Postgres 14 and 18, instead of 13 and 17. If you need to override this, you can pass in an explicit ids argument, for example ids: ['POSTGRES_17', 'POSTGRES_13', 'SQLITE_3'].
erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.mockServices.rootConfig() instance now has an update method that can be used to test configuration subscriptions and updates.mockServices.rootConfig() instance now has an update method that can be used to test configuration subscriptions and updates.mockServices.scheduler to use a mocked implementation instead of the default scheduler implementation. This implementation runs any scheduled tasks immediately on startup, as long as they don't have an initial delay or a manual trigger. After the initial run, the tasks are never run again unless manually triggered.279e1f7: Updated the type definition of mockErrorHandler to ensure that it is used correctly.
// This is wrong and will now result in a type error
app.use(mockErrorHandler);
// This is the correct usage
app.use(mockErrorHandler());
3a7dad9: Updated better-sqlite3 to v12
Updated dependencies
better-sqlite3 to v12toString on credentials objectstoString on credentials objects6dfb7be: Added mockServices.permissions() that can return actual results.
c999c25: Added an actionsRegistryServiceMock and actionsServiceMock to /alpha export for the experimental services.
This allows you to write tests for your actions by doing something similar to the following:
import { actionsRegistryServiceMock } from '@backstage/backend-test-utils/alpha';
const mockActionsRegistry = actionsRegistryServiceMock();
const mockCatalog = catalogServiceMock({
entities: [
...
],
});
createGetCatalogEntityAction({
catalog: mockCatalog,
actionsRegistry: mockActionsRegistry,
});
await expect(
mockActionsRegistry.invoke({
id: 'test:get-catalog-entity',
input: { name: 'test' },
}),
).resolves.toEqual(...)
user credentials mock behave more like productionuser credentials mock behave more like productionActionsService and ActionsRegistryServicemockServices.events()mockServices.events()actor property to BackstageUserPrincipal containing the subject of the last service (if any) who performed authentication on behalf of the user.@types/jest to devDependencies.@types/jest to devDependencies.PermissionsRegistryService.auditor service.require for lazy-loading dependency.@backstage/backend-app-api.getPermissionRuleset method to mockServices.permissionsRegistry.getPermissionRuleset method to mockServices.permissionsRegistry.PermissionsRegistryService.auditor service.require for lazy-loading dependency.@backstage/backend-app-api.de6f280: BREAKING Upgraded @keyv/redis and keyv packages to resolve a bug related to incorrect resolution of cache keys.
This is a breaking change for clients using the redis store for cache with useRedisSets option set to false since cache keys will be calculated differently (without the sets:namespace: prefix). For clients with default configuration (or useRedisSets set to false) the cache keys will stay the same, but since @keyv/redis library no longer supports redis sets they won't be utilised anymore.
If you were using useRedisSets option in configuration make sure to remove it from app-config.yaml:
backend:
cache:
store: redis
connection: redis://user:[email protected]:6379
- useRedisSets: false
RootLifecycleService.addBeforeShutdownHook method.RootLifecycleService.addBeforeShutdownHook method.de6f280: BREAKING Upgraded @keyv/redis and keyv packages to resolve a bug related to incorrect resolution of cache keys.
This is a breaking change for clients using the redis store for cache with useRedisSets option set to false since cache keys will be calculated differently (without the sets:namespace: prefix). For clients with default configuration (or useRedisSets set to false) the cache keys will stay the same, but since @keyv/redis library no longer supports redis sets they won't be utilised anymore.
If you were using useRedisSets option in configuration make sure to remove it from app-config.yaml:
backend:
cache:
store: redis
connection: redis://user:[email protected]:6379
- useRedisSets: false
mockServices.database with a given knex instancemockServices.discovery.factory() factory now uses the mocked discovery service as its implementation, avoid the need for configuration.msw dependency.mockServices.database with a given knex instancemockServices.discovery.factory() factory now uses the mocked discovery service as its implementation, avoid the need for configuration.msw dependency.cookie from 0.6.0 to 0.7.0createMockDirectory cleanup strategy has been changed, no longer requiring it to be called outside individual tests.cookie from 0.6.0 to 0.7.0ec1b4be: Release 1.0 of the new backend system! :tada:
The backend system is finally getting promoted to 1.0.0. This means that the API is now stable and breaking changes should not occur until version 2.0.0, see our package versioning policy for more information what this means.
This release also marks the end of the old backend system based on createRouter exports. Going forward backend plugins packages will start to deprecate and later this year remove exports supporting the old backend system. If you would like to help out with this transition, see https://github.com/backstage/backstage/issues/26353 or consult the migration guide.
19ff127: BREAKING: Removed service mocks for the identity and token manager services, which have been removed from @backstage/backend-plugin-api.
d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
mockServices.rootConfig.mock, and fixed the definition of mockServices.rootHttpRouter.factory to not have a duplicate callback.mockErrorHandler utility to help in mocking the error middleware in tests.supertest to ^7.0.0.ec1b4be: Release 1.0 of the new backend system! :tada:
The backend system is finally getting promoted to 1.0.0. This means that the API is now stable and breaking changes should not occur until version 2.0.0, see our package versioning policy for more information what this means.
This release also marks the end of the old backend system based on createRouter exports. Going forward backend plugins packages will start to deprecate and later this year remove exports supporting the old backend system. If you would like to help out with this transition, see https://github.com/backstage/backstage/issues/26353 or consult the migration guide.
supertest to ^7.0.0.mockServices.rootConfig.mock, and fixed the definition of mockServices.rootHttpRouter.factory to not have a duplicate callback.19ff127: BREAKING: Removed service mocks for the identity and token manager services, which have been removed from @backstage/backend-plugin-api.
d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
mockErrorHandler utility to help in mocking the error middleware in tests.861f162: BREAKING: Removed these deprecated helpers:
setupRequestMockHandlers is removed; use registerMswTestHooks instead.MockDirectoryOptions is removed; use CreateMockDirectoryOptions instead.Stopped exporting the deprecated and internal isDockerDisabledForTests helper.
Removed get method from ServiceFactoryTester which is replaced by getSubject
BackendFeautures from @backstage/backend-plugin-api.ServiceFactoryTester to be able to test services that enables multi implementation installation.startTestBackend and ServiceFactoryTester now includes the Root Health Service.BackendFeautures from @backstage/backend-plugin-api.ServiceFactoryTester to be able to test services that enables multi implementation installation.startTestBackend and ServiceFactoryTester now includes the Root Health Service.ServiceFactoryTest.get method was deprecated and the ServiceFactoryTest.getSubject should be used instead. The getSubject method has the same behavior, but has a better method name to indicate that the service instance returned is the subject currently being tested.isDockerDisabledForTests is deprecated and will no longer be exported in the near future as it should only be used internally.mockServices.startTestBackend and ServiceFactoryTester to only accept plain service factory or backend feature objects, no longer supporting the callback form. This lines up with the changes to @backstage/backend-plugin-api and should not require any code changes.setupRequestMockHandlers methods to registerMswTestHooks.mockServices.httpAuth.factory to allow it to still be constructed with options, but without declaring options via createServiceFactory.mockServices.TestCaches that functions just like TestDatabasesBackendFeature contract change.mockCredentials.serviceMockDirectoryOptions was renamed to CreateMockDirectoryOptions so that it's clear these options are exclusive to the mock directory factory.TestDatabases to no longer depend on backend-commonundefined from the child method.MockDirectoryOptions was renamed to CreateMockDirectoryOptions so that it's clear these options are exclusive to the mock directory factory.TestDatabases to no longer depend on backend-commonTestCaches that functions just like TestDatabasesmockCredentials.serviceundefined from the child method.backend-common to the backend-plugin-api package.eventsServiceFactory to defaultServiceFactories to resolve issue where different instances of the EventsServices could be usedeventsServiceFactory to defaultServiceFactories to resolve issue where different instances of the EventsServices could be usedstartTestBackend will now add placeholder plugins when a modules are provided without their parent plugin.listPublicServiceKeys method for AuthService.startTestBackend will now add placeholder plugins when a modules are provided without their parent plugin.listPublicServiceKeys method for AuthService.4a3d434: Added support for the new auth and httpAuth services that were created as part of BEP-0003. These services will be present by default in test apps, and you can access mocked versions of their features under mockServices.auth and mockServices.httpAuth if you want to inspect or replace their behaviors.
There is also a new mockCredentials that you can use for acquiring mocks of the various types of credentials that are used in the new system.
9802004: Added mockServices.userInfo, which now also automatically is made available in test backends.
fd61d39: Updated dependency testcontainers to ^10.0.0.
ff40ada: Updated dependency mysql2 to ^3.0.0.
0fb419b: Updated dependency uuid to ^9.0.0.
Updated dependency @types/uuid to ^9.0.0.
Updated dependencies
4a3d434: Added support for the new auth and httpAuth services that were created as part of BEP-0003. These services will be present by default in test apps, and you can access mocked versions of their features under mockServices.auth and mockServices.httpAuth if you want to inspect or replace their behaviors.
There is also a new mockCredentials that you can use for acquiring mocks of the various types of credentials that are used in the new system.
9802004: Added mockServices.userInfo, which now also automatically is made available in test backends.
fd61d39: Updated dependency testcontainers to ^10.0.0.
ff40ada: Updated dependency mysql2 to ^3.0.0.
0fb419b: Updated dependency uuid to ^9.0.0.
Updated dependency @types/uuid to ^9.0.0.
Updated dependencies
fs-extra to ^11.2.0.
Updated dependency @types/fs-extra to ^11.0.0.cc4228e: Switched module ID to use kebab-case.
b7de76a: Added support for PostgreSQL versions 15 and 16
Also introduced a new setDefaults(options: { ids?: TestDatabaseId[] }) static method that can be added to the setupTests.ts file to define the default database ids you want to use throughout your package. Usage would look like this: TestDatabases.setDefaults({ ids: ['POSTGRES_12','POSTGRES_16'] }) and would result in PostgreSQL versions 12 and 16 being used for your tests.
Updated dependencies
knex has been bumped to major version 3 and better-sqlite3 to major version 9, which deprecate node 16 support.#20570 013611b42e Thanks @freben! - knex has been bumped to major version 3 and better-sqlite3 to major version 9, which deprecate node 16 support.
Updated dependencies
createMockDirectory() to help out with file system mocking in tests.MockInstance, in order to be compatible with older versions of @types/jest.HostDiscovery from @backstage/backend-app-api.createMockDirectory() to help out with file system mocking in tests.HostDiscovery from @backstage/backend-app-api.MockInstance, in order to be compatible with older versions of @types/jest.ServiceFactoryTester.startTestBackend({ features: [import('my-plugin')] }).mockService to also include mocked variants, for example mockServices.lifecycle.mock(). The returned mocked implementation will have a factory property which is a service factory for itself. You can also pass a partial implementation of the service to the mock function to use a mock implementation of specific methods.startTestBackend({ features: [import('my-plugin')] }).ServiceFactoryTester.mockService to also include mocked variants, for example mockServices.lifecycle.mock(). The returned mocked implementation will have a factory property which is a service factory for itself. You can also pass a partial implementation of the service to the mock function to use a mock implementation of specific methods.b9c57a4f857e: BREAKING: Renamed mockServices.config to mockServices.rootConfig.
a6d7983f349c: BREAKING: Removed the services option from createBackend. Service factories are now BackendFeatures and should be installed with backend.add(...) instead. The following should be migrated:
const backend = createBackend({ services: [myCustomServiceFactory] });
To instead pass the service factory via backend.add(...):
const backend = createBackend();
backend.add(customRootLoggerServiceFactory);
mockServices.config to mockServices.rootConfig.POSTGRES_11 and POSTGRES_12 as supported test database IDs.POSTGRES_11 and POSTGRES_12 as supported test database IDs./alpha exports.msw to ^1.0.0.msw to ^1.0.0./alpha exports.@backstage/cli dependency.yarn add --cwd for app & backendmockServices.config().mockServices.rootLogger options to accept a single level option instead.BackendFeature type.*ServiceFactory exports from @backstage/backend-app-apiServiceFactory.ref from all mockServices.mockServices export.LogMeta.@backstage/cli dependency.mockServices.config().mockServices.rootLogger options to accept a single level option instead.BackendFeature type.*ServiceFactory exports from @backstage/backend-app-apiref from all mockServices.LogMeta.mockServices export.rootLifecycleServiceRef.startTestBackend setup now includes default implementations for all core services.createServiceFactory from @backstage/backend-plugin-api.startTestBackend now has default implementations of all core services. It now also returns a TestBackend instance, which provides access to the underlying server that can be used with testing libraries such as supertest.better-sqlite3 to ^8.0.0.startTestBackend setup now includes default implementations for all core services.better-sqlite3 to ^8.0.0.rootLifecycleServiceRef.startTestBackend are now automatically stopped after all tests have run.msw to ^0.49.0.msw to ^0.49.0.msw to ^0.48.0.startTestBackend.startTestBackend.ServiceFactory formats.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.ServiceFactory.ServiceFactory formats.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.ServiceFactory.msw to ^0.43.0.msw to ^0.44.0.knex to ^2.0.0.msw to ^0.43.0.knex to ^2.0.0.msw to ^0.41.0.msw to ^0.41.0.TestDatabases.create will no longer set up an afterAll test handler if no databases are supported.TestDatabases.create will no longer set up an afterAll test handler if no databases are supported.better-sqlite3 instead of @vscode/sqlite3better-sqlite3 driver, to maybe eventually replace @vscode/sqlite3 (#9912)setupRequestMockHandlers which sets up a good msw server foundation, copied from @backstage/test-utils which is a frontend-only package and should not be used from backends.better-sqlite3 driver, to maybe eventually replace @vscode/sqlite3 (#9912)setupRequestMockHandlers which sets up a good msw server foundation, copied from @backstage/test-utils which is a frontend-only package and should not be used from backends.backstage.role to package.json2441d1cf59: chore(deps): bump knex from 0.95.6 to 1.0.2
This also replaces sqlite3 with @vscode/sqlite3 5.0.7
Updated dependencies
2441d1cf59: chore(deps): bump knex from 0.95.6 to 1.0.2
This also replaces sqlite3 with @vscode/sqlite3 5.0.7
Updated dependencies
testcontainers dependency to version 8.1.2testcontainers module in order to avoid side-effects.dockerode and testcontainersTestDatabases.create()
don't collide.772dbdb51: Deprecates SingleConnectionDatabaseManager and provides an API compatible database
connection manager, DatabaseManager, which allows developers to configure database
connections on a per plugin basis.
The backend.database config path allows you to set prefix to use an
alternate prefix for automatically generated database names, the default is
backstage_plugin_. Use backend.database.plugin.<pluginId> to set plugin
specific database connection configuration, e.g.
backend:
database:
client: 'pg',
prefix: 'custom_prefix_'
connection:
host: 'localhost'
user: 'foo'
password: 'bar'
plugin:
catalog:
connection:
database: 'database_name_overriden'
scaffolder:
client: 'sqlite3'
connection: ':memory:'
Migrate existing backstage installations by swapping out the database manager in the
packages/backend/src/index.ts file as shown below:
import {
- SingleConnectionDatabaseManager,
+ DatabaseManager,
} from '@backstage/backend-common';
// ...
function makeCreateEnv(config: Config) {
// ...
- const databaseManager = SingleConnectionDatabaseManager.fromConfig(config);
+ const databaseManager = DatabaseManager.fromConfig(config);
// ...
}
Updated dependencies
AlertApiForwarder to buffer and replay recent alerts to new subscribers, preventing missed alerts that were posted before subscription.AlertApiForwarder to buffer and replay recent alerts to new subscribers, preventing missed alerts that were posted before subscription.erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.OpenShiftAuth helper to create default OAuth flow for OpenShift.1e0230e: Support custom AuthConnector for OAuth2.
A user can pass their own AuthConnector implementation in OAuth2 constructor.
In which case the session manager will use that instead of the DefaultAuthConnector to interact with the
authentication provider.
A custom AuthConnector may call the authentication provider from the front-end, store and retrieve tokens
in the session storage, for example, and otherwise send custom requests to the authentication provider and
handle its responses.
Note, that if the custom AuthConnector transforms scopes returned from the authentication provider,
the transformation must be the same as OAuth2CreateOptions#scopeTransform passed to OAuth2 constructor.
See creating DefaultAuthConnector in OAuth2#create(...) for an example.
I18nextTranslationApi to support interpolation of JSX elements.OAuthRequestDialog to re-render on mount.1e0230e: Support custom AuthConnector for OAuth2.
A user can pass their own AuthConnector implementation in OAuth2 constructor.
In which case the session manager will use that instead of the DefaultAuthConnector to interact with the
authentication provider.
A custom AuthConnector may call the authentication provider from the front-end, store and retrieve tokens
in the session storage, for example, and otherwise send custom requests to the authentication provider and
handle its responses.
Note, that if the custom AuthConnector transforms scopes returned from the authentication provider,
the transformation must be the same as OAuth2CreateOptions#scopeTransform passed to OAuth2 constructor.
See creating DefaultAuthConnector in OAuth2#create(...) for an example.
OAuthRequestDialog to re-render on mount.I18nextTranslationApi to support interpolation of JSX elements.a47fd39: Removes instances of default React imports, a necessary update for the upcoming React 19 migration.
https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html
Updated dependencies
a47fd39: Removes instances of default React imports, a necessary update for the upcoming React 19 migration.
https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html
Updated dependencies
FetchApi will now also take configuration under discovery.endpoints into consideration when deciding whether to include credentials or not.discovery.endpoints configuration no longer requires both internal and external target when using the object form, instead falling back to the default.FetchApi will now also take configuration under discovery.endpoints into consideration when deciding whether to include credentials or not.discovery.endpoints configuration no longer requires both internal and external target when using the object form, instead falling back to the default.process.env.APP_CONFIG to be set, allowing config to be read from other sources instead.@types/react to a peer dependency.@types/react to a peer dependency.bindRoutes option by passing false as the route target. This also fixes a bug where route bindings in config were incorrectly prioritized above the ones in code in certain situations.defaultConfigLoader now also reads configuration from scripts tags with type="backstage.io/config". The tag is expected to contain a JSON-serialized array of AppConfig objects. If any of these script tags are present, the injected runtime configuration in the static assets will no longer be used.star and unstarred icon overrides. See how to override existing icons in the Backstage documentation.@testing-library/react to ^16.0.0.defaultConfigLoader now also reads configuration from scripts tags with type="backstage.io/config". The tag is expected to contain a JSON-serialized array of AppConfig objects. If any of these script tags are present, the injected runtime configuration in the static assets will no longer be used.star and unstarred icon overrides. See how to override existing icons in the Backstage documentation.@testing-library/react to ^16.0.0.fetch rather than FetchApi. This fixes a bug where the app would immediately try to sign-in again when removing the cookie during logout.fetch rather than FetchApi. This fixes a bug where the app would immediately try to sign-in again when removing the cookie during logout.d3c39fc: Allow for the disabling of external routes through config, which was rendered impossible after the introduction of default targets.
app:
routes:
bindings:
# This has the effect of removing the button for registering new
# catalog entities in the scaffolder template list view
scaffolder.registerComponent: false
d3c39fc: Allow for the disabling of external routes through config, which was rendered impossible after the introduction of default targets.
app:
routes:
bindings:
# This has the effect of removing the button for registering new
# catalog entities in the scaffolder template list view
scaffolder.registerComponent: false
35fbe09: Added support for configuration of route bindings through static configuration, and default targets for external route refs.
In addition to configuring route bindings through code, it is now also possible to configure route bindings under the app.routes.bindings key, for example:
app:
routes:
bindings:
catalog.createComponent: catalog-import.importPage
Each key in the route binding object is of the form <plugin-id>.<externalRouteName>, where the route name is key used in the externalRoutes object passed to createPlugin. The value is of the same form, but with the name taken from the plugin routes option instead.
The equivalent of the above configuration in code is the following:
const app = createApp({
// ...
bindRoutes({ bind }) {
bind(catalogPlugin.externalRoutes, {
createComponent: catalogImportPlugin.routes.importPage,
});
},
});
Updated dependencies
35fbe09: Added support for configuration of route bindings through static configuration, and default targets for external route refs.
In addition to configuring route bindings through code, it is now also possible to configure route bindings under the app.routes.bindings key, for example:
app:
routes:
bindings:
catalog.createComponent: catalog-import.importPage
Each key in the route binding object is of the form <plugin-id>.<externalRouteName>, where the route name is key used in the externalRoutes object passed to createPlugin. The value is of the same form, but with the name taken from the plugin routes option instead.
The equivalent of the above configuration in code is the following:
const app = createApp({
// ...
bindRoutes({ bind }) {
bind(catalogPlugin.externalRoutes, {
createComponent: catalogImportPlugin.routes.importPage,
});
},
});
Updated dependencies
app-backend with a separate public and protected bundles. When in protected mode the app will now continuously refresh the session cookie, as well as clear the cookie if the user signs out.@testing-library/react to ^15.0.0.@testing-library/dom to ^10.0.0.app-backend with a separate public and protected bundles. When in protected mode the app will now continuously refresh the session cookie, as well as clear the cookie if the user signs out.@backstage/core-plugin-api and @backstage/frontend-plugin-api packages, the
implementation is in @backstage/core-app-api and a factory has been added to
@backstage/app-defaults.--cwd as the first yarn argument@types/react dependency range to include version 18.defaultScopes for Bitbucket auth from invalid team to account.@backstage/core-plugin-api and @backstage/frontend-plugin-api packages, the
implementation is in @backstage/core-app-api and a factory has been added to
@backstage/app-defaults.--cwd as the first yarn argument@types/react dependency range to include version 18.defaultScopes for Bitbucket auth from invalid team to account.core.type marker for AppRouter and FlatRoutes.core.type marker for AppRouter and FlatRoutes.RouteResolver (and therefore useRouteRef)AppRouter to determine the correct signOutTargetUrl if app.baseUrl contains a basePath<Suspense>, enabling support for using translations outside plugins.@testing-library/jest-dom to ^6.0.0.@testing-library/dom to ^9.0.0.TranslationApi implementation where in some cases it wouldn't notify subscribers of language changes.RouteResolver (and therefore useRouteRef)<Suspense>, enabling support for using translations outside plugins.OAuth2Session type represents the underlying data. The expiresAt and backstageIdentity are now both optional, since that's what they are in practice. This is not considered a breaking change since it was effectively a bug in the modelling of the state that this type represents, and the type was not used in any other external contract.OAuth class which is used by all OAuth providers will now consider both the session expiration of both the Backstage identity as well as the upstream identity provider, and refresh the session with either of them is about to expire.@types/node dependency@types/node dependencyOAuth2Session type represents the underlying data. The expiresAt and backstageIdentity are now both optional, since that's what they are in practice. This is not considered a breaking change since it was effectively a bug in the modelling of the state that this type represents, and the type was not used in any other external contract.OAuth class which is used by all OAuth providers will now consider both the session expiration of both the Backstage identity as well as the upstream identity provider, and refresh the session with either of them is about to expire.navigate analytics events to be misattributed to the plugin mounted on the root route (e.g. the home plugin at /) when the route that was navigated to wasn't associated with a routable extension.navigate analytics events to be misattributed to the plugin mounted on the root route (e.g. the home plugin at /) when the route that was navigated to wasn't associated with a routable extension.navigate analytics events when users visited pages constructed with <EntityLayout>, <TabbedLayout>, and similar components that are used to gather one or more routable extensions under a given path.PropsWithChildren to usages of ComponentType, in preparation for React 18 where the children are no longer implicit.PropsWithChildren to usages of ComponentType, in preparation for React 18 where the children are no longer implicit.navigate event will now include the route parameters as attributes of the navigate eventFrontendHostDiscovery for config driven discovery implementationnavigate event will now include the route parameters as attributes of the navigate eventFrontendHostDiscovery for config driven discovery implementationenableExperimentalRedirectFlow. When enabled, auth will happen with an in-window redirect flow rather than through a popup window.AuthConnector interface now supports specifying a set of scopes when
refreshing a session. The DefaultAuthConnector implementation passes the
scope query parameter to the auth-backend plugin appropriately. The
RefreshingAuthSessionManager passes any scopes in its GetSessionRequest
appropriately.zod and zod-to-json-schema dependencies.AuthConnector interface now supports specifying a set of scopes when
refreshing a session. The DefaultAuthConnector implementation passes the
scope query parameter to the auth-backend plugin appropriately. The
RefreshingAuthSessionManager passes any scopes in its GetSessionRequest
appropriately.zod and zod-to-json-schema dependencies.enableExperimentalRedirectFlow. When enabled, auth will happen with an in-window redirect flow rather than through a popup window.456eaa8cf83: OAuth2 now gets ID tokens from a session with the openid scope explicitly
requested.
This should not be considered a breaking change, because spec-compliant OIDC
providers will already be returning ID tokens if and only if the openid scope
is granted.
This change makes the dependence explicit, and removes the burden on
OAuth2-based providers which require an ID token (e.g. this is done by various
default auth handlers) to add
openid to their default scopes. That could carry another indirect benefit:
by removing openid from the default scopes for a provider, grants for
resource-specific access tokens can avoid requesting excess ID token-related
scopes.
msw to ^1.0.0.456eaa8cf83: OAuth2 now gets ID tokens from a session with the openid scope explicitly
requested.
This should not be considered a breaking change, because spec-compliant OIDC
providers will already be returning ID tokens if and only if the openid scope
is granted.
This change makes the dependence explicit, and removes the burden on
OAuth2-based providers which require an ID token (e.g. this is done by various
default auth handlers) to add
openid to their default scopes. That could carry another indirect benefit:
by removing openid from the default scopes for a provider, grants for
resource-specific access tokens can avoid requesting excess ID token-related
scopes.
msw to ^1.0.0.e0d9c9559a: Added a new AppRouter component and app.createRoot() method that replaces app.getRouter() and app.getProvider(), which are now deprecated. The new AppRouter component is a drop-in replacement for the old router component, while the new app.createRoot() method is used instead of the old provider component.
An old app setup might look like this:
const app = createApp(/* ... */);
const AppProvider = app.getProvider();
const AppRouter = app.getRouter();
const routes = ...;
const App = () => (
<AppProvider>
<AlertDisplay />
<OAuthRequestDialog />
<AppRouter>
<Root>{routes}</Root>
</AppRouter>
</AppProvider>
);
export default App;
With these new APIs, the setup now looks like this:
import { AppRouter } from '@backstage/core-app-api';
const app = createApp(/* ... */);
const routes = ...;
export default app.createRoot(
<>
<AlertDisplay />
<OAuthRequestDialog />
<AppRouter>
<Root>{routes}</Root>
</AppRouter>
</>,
);
Note that app.createRoot() accepts a React element, rather than a component.
zod dependency to a version that does not collide with other librariesmsw to ^0.49.0.zen-observable to ^0.9.0.zen-observable to ^0.10.0.WebStorage notify its subscribers when localStorage values change in other tabs/windowsapp.baseUrl configuration to match the current location.origin. The backend.baseUrl will also be rewritten in the same way when the app.baseUrl and backend.baseUrl have matching origins. This will reduce the need for separate frontend builds for different environments.e0d9c9559a: Added a new AppRouter component and app.createRoot() method that replaces app.getRouter() and app.getProvider(), which are now deprecated. The new AppRouter component is a drop-in replacement for the old router component, while the new app.createRoot() method is used instead of the old provider component.
An old app setup might look like this:
const app = createApp(/* ... */);
const AppProvider = app.getProvider();
const AppRouter = app.getRouter();
const routes = ...;
const App = () => (
<AppProvider>
<AlertDisplay />
<OAuthRequestDialog />
<AppRouter>
<Root>{routes}</Root>
</AppRouter>
</AppProvider>
);
export default App;
With these new APIs, the setup now looks like this:
import { AppRouter } from '@backstage/core-app-api';
const app = createApp(/* ... */);
const routes = ...;
export default app.createRoot(
<>
<AlertDisplay />
<OAuthRequestDialog />
<AppRouter>
<Root>{routes}</Root>
</AppRouter>
</>,
);
Note that app.createRoot() accepts a React element, rather than a component.
zod dependency to a version that does not collide with other librariesWebStorage notify its subscribers when localStorage values change in other tabs/windowsapp.baseUrl configuration to match the current location.origin. The backend.baseUrl will also be rewritten in the same way when the app.baseUrl and backend.baseUrl have matching origins. This will reduce the need for separate frontend builds for different environments.zen-observable to ^0.10.0.msw to ^0.49.0.zen-observable to ^0.9.0.basename property of the router components in React Router v6 stable. To implement this, a new optional basename property has been added to the Router app component, which can be forwarded to the concrete router implementation in order to support this new behavior. This is done by default in any app that does not have a Router component override.homepage config as the component that used it - HomepageTimer - has been removed and replaced by the HeaderWorldClock in the home pluginbasename property of the router components in React Router v6 stable. To implement this, a new optional basename property has been added to the Router app component, which can be forwarded to the concrete router implementation in order to support this new behavior. This is done by default in any app that does not have a Router component override.homepage config as the component that used it - HomepageTimer - has been removed and replaced by the HeaderWorldClock in the home plugin817f3196f6: Updated React Router dependencies to be peer dependencies.
f9ec4e46e3: When using React Router v6 stable, it is now possible for components within the Route element tree to have path props, although they will be ignored.
7d47def9c4: Removed dependency on @types/jest.
744fea158b: Added getSystemIcons() function to the AppContext available through useApp that will pull a list of all the icons that have been registered in the App.
667d917488: Updated dependency msw to ^0.47.0.
87ec2ba4d6: Updated dependency msw to ^0.46.0.
bf5e9030eb: Updated dependency msw to ^0.45.0.
8448b53dd6: Clarify that the WebStorage observable returns JsonValue items.
70299c99d5: Updated FlatRoutes to be compatible with React Router v6 stable.
e9d40ebf54: If you'd like to send analytics events to multiple implementations, you may now
do so using the MultipleAnalyticsApi implementation provided by this package.
import { MultipleAnalyticsApi } from '@backstage/core-app-api';
import {
analyticsApiRef,
configApiRef,
storageApiRef,
identityApiRef,
} from '@internal/backstage/core-plugin-api';
import { CustomAnalyticsApi } from '@internal/analytics';
import { VendorAnalyticsApi } from '@vendor/analytics';
createApiFactory({
api: analyticsApiRef,
deps: { configApi: configApiRef, identityApi: identityApiRef, storageApi: storageApiRef },
factory: ({ configApi, identityApi, storageApi }) =>
MultipleAnalyticsApi.fromApis([
VendorAnalyticsApi.fromConfig(configApi, { identityApi }),
CustomAnalyticsApi.fromConfig(configApi, { identityApi, storageApi }),
]),
}),
Updated dependencies
@types/jest.f9ec4e46e3: When using React Router v6 stable, it is now possible for components within the Route element tree to have path props, although they will be ignored.
667d917488: Updated dependency msw to ^0.47.0.
87ec2ba4d6: Updated dependency msw to ^0.46.0.
e9d40ebf54: If you'd like to send analytics events to multiple implementations, you may now
do so using the MultipleAnalyticsApi implementation provided by this package.
import { MultipleAnalyticsApi } from '@backstage/core-app-api';
import {
analyticsApiRef,
configApiRef,
storageApiRef,
identityApiRef,
} from '@internal/backstage/core-plugin-api';
import { CustomAnalyticsApi } from '@internal/analytics';
import { VendorAnalyticsApi } from '@vendor/analytics';
createApiFactory({
api: analyticsApiRef,
deps: { configApi: configApiRef, identityApi: identityApiRef, storageApi: storageApiRef },
factory: ({ configApi, identityApi, storageApi }) =>
MultipleAnalyticsApi.fromApis([
VendorAnalyticsApi.fromConfig(configApi, { identityApi }),
CustomAnalyticsApi.fromConfig(configApi, { identityApi, storageApi }),
]),
}),
Updated dependencies
FlatRoutes to be compatible with React Router v6 stable.getSystemIcons() function to the AppContext available through useApp that will pull a list of all the icons that have been registered in the App.msw to ^0.45.0.BackstagePlugin type.signOut method of the IdentityApi will now navigate the user back to the base URL of the app as indicated by the app.baseUrl config.msw to ^0.43.0.msw to ^0.44.0.BackstagePlugin type.msw to ^0.43.0.signOut method of the IdentityApi will now navigate the user back to the base URL of the app as indicated by the app.baseUrl config.msw to ^0.41.0.fetchApi, when using the plugin: protocolmsw to ^0.41.0.@testing-library/react-hooks from 7.0.2 to 8.0.0@testing-library/user-event from 13.5.0 to 14.0.0@types/node v16@testing-library/user-event from 13.5.0 to 14.0.0@types/node v16@testing-library/react from 11.2.6 to 12.1.3get method from StorageAPI and its implementations, this method has been replaced by the snapshot method. The return value from snapshot no longer includes newValue which has been replaced by value. For getting notified when a value changes, use `observe# @backstage/core-app-api.GithubSession and SamlSession which are only used internally.auth0AuthApiRef, oauth2ApiRef, samlAuthApiRef and oidcAuthApiRef as these APIs are too generic to be useful. Instructions for how to migrate can be found at https://backstage.io/docs/api/deprecations#generic-auth-api-refs.GithubAuth.normalizeScopes method.node-fetch to version 2.6.7 and cross-fetch to version 3.1.5backstage.role to package.json40775bd263: Switched out the GithubAuth implementation to use the common OAuth2 implementation. This relies on the simultaneous change in @backstage/plugin-auth-backend that enabled access token storage in cookies rather than the current solution that's based on LocalStorage.
NOTE: Make sure you upgrade the
auth-backenddeployment before or at the same time as you deploy this change.
40775bd263: Switched out the GithubAuth implementation to use the common OAuth2 implementation. This relies on the simultaneous change in @backstage/plugin-auth-backend that enabled access token storage in cookies rather than the current solution that's based on LocalStorage.
NOTE: Make sure you upgrade the
auth-backenddeployment before or at the same time as you deploy this change.
f959c22787: Asynchronous methods on the identity API can now reliably be called at any time, including early in the bootstrap process or prior to successful sign-in.
Previously in such situations, a Tried to access IdentityApi before app was loaded error would be thrown. Now, those methods will wait and resolve eventually (as soon as a concrete identity API is provided).
SignInResult type, which was replaced with the new onSignInSuccess callback.allowUrl callback option to FetchMiddlewares.injectIdentityAuthSignInResult type, which was replaced with the new onSignInSuccess callback.ApiRegistry export.34442cd5cf: Fixed an issue where valid SAML and GitHub sessions would be considered invalid and not be stored.
Deprecated the SamlSession and GithubSession types.
784d8078ab: Removed direct and transitive Material UI dependencies.
Updated dependencies
react-use imports to use react-use/lib/* instead.WebStorageApi to reflect the StorageApi changes in @backstage/core-plugin-api.createApp from @backstage/core-app-api which has been replaced by @backstage/app-defaults#createApp
BackstagePluginWithAnyOutputGithubAuth, OAuth2, and SamlAuth as the create method should be used insteadtheme from AppTheme of the AppThemeApi
theme in the app-defaults default AppThemeAppThemeProvider that creates ThemeProvider from appTheme.themeFetchApi and related fetchApiRef which implement fetch, with an added Backstage token header when available.Auth0Auth, pointing to using OAuth2 directly instead.OAuthRequestApi types from @backstage/core-plugin-api.a036b65c2f: BREAKING CHANGE
The app SignInPage component has been updated to switch out the onResult callback for a new onSignInSuccess callback. This is an immediate breaking change without any deprecation period, as it was deemed to be the way of making this change that had the lowest impact.
The new onSignInSuccess callback directly accepts an implementation of an IdentityApi, rather than a SignInResult. The SignInPage from @backstage/core-component has been updated to fit this new API, and as long as you pass on props directly you should not see any breakage.
However, if you implement your own custom SignInPage, then this will be a breaking change and you need to migrate over to using the new callback. While doing so you can take advantage of the UserIdentity.fromLegacy helper from @backstage/core-components to make the migration simpler by still using the SignInResult type. This helper is also deprecated though and is only provided for immediate migration. Long-term it will be necessary to build the IdentityApi using for example UserIdentity.create instead.
The following is an example of how you can migrate existing usage immediately using UserIdentity.fromLegacy:
onResult(signInResult);
// becomes
onSignInSuccess(UserIdentity.fromLegacy(signInResult));
The following is an example of how implement the new onSignInSuccess callback of the SignInPage using UserIdentity.create:
const identityResponse = await authApi.getBackstageIdentity();
// Profile is optional and will be removed, but allows the
// synchronous getProfile method of the IdentityApi to be used.
const profile = await authApi.getProfile();
onSignInSuccess(
UserIdentity.create({
identity: identityResponse.identity,
authApi,
profile,
}),
);
peerDependencies and allow both React v16 and v17 to be used.useRouteRef would fail in situations where relative navigation was needed and the app was is mounted on a sub-path. This would typically show up as a failure to navigate to a tab on an entity page.bab752e2b3: Change default port of backend from 7000 to 7007.
This is due to the AirPlay Receiver process occupying port 7000 and preventing local Backstage instances on MacOS to start.
You can change the port back to 7000 or any other value by providing an app-config.yaml with the following values:
backend:
listen: 0.0.0.0:7123
baseUrl: http://localhost:7123
More information can be found here: https://backstage.io/docs/conf/writing
000190de69: The ApiRegistry from @backstage/core-app-api class has been deprecated and will be removed in a future release. To replace it, we have introduced two new helpers that are exported from @backstage/test-utils, namely TestApiProvider and TestApiRegistry.
These two new helpers are more tailored for writing tests and development setups, as they allow for partial implementations of each of the APIs.
When migrating existing code it is typically best to prefer usage of TestApiProvider when possible, so for example the following code:
render(
<ApiProvider
apis={ApiRegistry.from([
[identityApiRef, mockIdentityApi as unknown as IdentityApi]
])}
>
{...}
</ApiProvider>
)
Would be migrated to this:
render(
<TestApiProvider apis={[[identityApiRef, mockIdentityApi]]}>
{...}
</TestApiProvider>
)
In cases where the ApiProvider is used in a more standalone way, for example to reuse a set of APIs across multiple tests, the TestApiRegistry can be used instead. Note that the TestApiRegistry only has a single static factory method, .from(), and it is slightly different from the existing .from() method on ApiRegistry in that it doesn't require the API pairs to be wrapped in an outer array.
Usage that looks like this:
const apis = ApiRegistry.with(
identityApiRef,
mockIdentityApi as unknown as IdentityApi,
).with(configApiRef, new ConfigReader({}));
OR like this:
const apis = ApiRegistry.from([
[identityApiRef, mockIdentityApi as unknown as IdentityApi],
[configApiRef, new ConfigReader({})],
]);
Would be migrated to this:
const apis = TestApiRegistry.from(
[identityApiRef, mockIdentityApi],
[configApiRef, new ConfigReader({})],
);
If your app is still using the ApiRegistry to construct the apis for createApp, we recommend that you move over to use the new method of supplying API factories instead, using createApiFactory.
Updated dependencies
createApp TypeScript type to match the one before version 0.1.21, as it was an accidental breaking change.0b1de52732: Migrated to using new ErrorApiError and ErrorApiErrorContext names.
ecd1fcb80a: Deprecated the BackstagePluginWithAnyOutput type.
32bfbafb0f: Start exporting and marking several types as public to address errors in the API report.
014cbf8cb9: The createApp function from @backstage/core-app-api has been deprecated, with two new options being provided as a replacement.
The first and most commonly used one is createApp from the new @backstage/app-defaults package, which behaves just like the existing createApp. In the future this method is likely to be expanded to add more APIs and other pieces into the default setup, for example the Utility APIs from @backstage/integration-react.
The other option that we now provide is to use createSpecializedApp from @backstage/core-app-api. This is a more low-level API where you need to provide a full set of options, including your own components, icons, defaultApis, and themes. The createSpecializedApp way of creating an app is particularly useful if you are not using @backstage/core-components or Material UI, as it allows you to avoid those dependencies completely.
475edb5bc5: move the BehaviorSubject init into the constructor
Updated dependencies
@backstage/types@backstage/types package. Initially, this means using the Observable and Json* types from there. The types also remain in their old places but deprecated, and will be removed in a future release.@public where necessary and tweaking some comments202f322927: Atlassian auth provider
36e67d2f24: Internal updates to apply more strict checks to throw errors.
Updated dependencies
@material-ui/core.d9fd798cc8: The Core App API now automatically instruments all route location changes using
the new Analytics API. Each location change triggers a navigate event, which
is an analogue of a "pageview" event in traditional web analytics systems. In
addition to the path, these events provide plugin-level metadata via the
analytics context, which can be useful for analyzing plugin usage:
{
"action": "navigate",
"subject": "/the-path/navigated/to?with=params#and-hashes",
"context": {
"extension": "App",
"pluginId": "id-of-plugin-that-exported-the-route",
"routeRef": "associated-route-ref-id"
}
}
These events can be identified and handled by checking for the action
navigate and the extension App.
4c3eea7788: Bitbucket Cloud authentication - based on the existing GitHub authentication + changes around BB apis and updated scope.
d6ad46eb22: Stop calling connector.removeSession in StaticAuthSessionManager, instead just discarding the session locally.
Updated dependencies
cfcb486aa: Add system icons for the built-in entity types and use them in the entity list of the catalog-import plugin.
392b36fa1: Added support for using authenticating via GitHub Apps in addition to GitHub OAuth Apps. It used to be possible to use GitHub Apps, but they did not handle session refresh correctly.
Note that GitHub Apps handle OAuth scope at the app installation level, meaning that the scope parameter for getAccessToken has no effect. When calling getAccessToken in open source plugins, one should still include the appropriate scope, but also document in the plugin README what scopes are required in the case of GitHub Apps.
In addition, the authHandler and signInResolver options have been implemented for the GitHub provider in the auth backend.
Updated dependencies
/, which is enabled by including the path in app.baseUrl.@types/react dependency to request * rather than a specific version.material-ui/core version to at least 4.12.2 as they made some breaking changes in later versions which broke Pagination of the Table.
material-table to @material-table/core for support for the later versions of material-ui/core@backstage/core-components as the interface for Table re-exports the prop from the underlying Table components.onChangeRowsPerPage has been renamed to onRowsPerPageChangeonChangePage has been renamed to onPageChangeFlatRoutes that prevented outlets from working with the root route, as well as matching root routes too broadly.defaultConfigLoader.FeatureFlag component and treating FeatureFlags as first class citizens to composability API9bca2a252: Fixes a type bug where supplying all app icons to createApp was required, rather than just a partial list.
75b8537ce: This change adds automatic error boundaries around extensions.
This means that all exposed parts of a plugin are wrapped in a general error boundary component, that is plugin aware. The default design for the error box is borrowed from @backstage/errors. To override the default "fallback", one must provide a component named ErrorBoundaryFallback to createApp, like so:
const app = createApp({
components: {
ErrorBoundaryFallback: props => {
// a custom fallback component
return (
<>
<h1>Oops.</h1>
<h2>
The plugin {props.plugin.getId()} failed with{' '}
{props.error.message}
</h2>
<button onClick={props.resetError}>Try again</button>
</>
);
},
},
});
The props here include:
error. An Error object or something that inherits it that represents the error that was thrown from any inner component.resetError. A callback that will simply attempt to mount the children of the error boundary again.plugin. A BackstagePlugin that can be used to look up info to be presented in the error message. For instance, you may want to keep a map of your internal plugins and team names or slack channels and present these when an error occurs. Typically, you'll do that by getting the plugin ID with plugin.getId().da8cba44f: Deprecate and disable the extension creation methods, which were added to this package by mistake and should only exist within @backstage/core-plugin-api.
9bca2a252: Update createApp options to allow plugins with unknown output types in order to improve forwards and backwards compatibility.
Updated dependencies [e47336ea4]
Updated dependencies [75b8537ce]
Updated dependencies [da8cba44f]
pluginId field rather than id to better align with naming conventions used throughout the frontend and backend systems. The old field is still present but marked as deprecated. All internal code has been updated to prefer pluginId while maintaining backward compatibility by falling back to id when needed.useApp and useRouteRef functions are now forwards compatible with the new frontend system. Along with the previous route reference changes this means that there is no longer a need to use compatWrapper from @backstage/core-compat-api to make code based on @backstage/core-plugin-api compatible with @backstage/frontend-plugin-api APIs.@backstage/core-plugin-api and the new @backstage/frontend-plugin-api. Previously, the a lot of API definitions and utilities where defined in the old and re-exported from the old, but this change flips that around so that they now reside in the new package and are re-exported from the old. The external API of both packages remain the same, but this is a step towards being able to add further compatibility with the new frontend system built into the old.useApp and useRouteRef functions are now forwards compatible with the new frontend system. Along with the previous route reference changes this means that there is no longer a need to use compatWrapper from @backstage/core-compat-api to make code based on @backstage/core-plugin-api compatible with @backstage/frontend-plugin-api APIs.@backstage/core-plugin-api and the new @backstage/frontend-plugin-api. Previously, the a lot of API definitions and utilities where defined in the old and re-exported from the old, but this change flips that around so that they now reside in the new package and are re-exported from the old. The external API of both packages remain the same, but this is a step towards being able to add further compatibility with the new frontend system built into the old.@backstage/frontend-plugin-api. This means they no longer need to be converted with convertLegacyRouteRef or convertLegacyRouteRefs from @backstage/core-compat-api.erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.openshiftAuthApiRef available in @backstage/core-plugin-api.TranslationApi now supports interpolation of JSX elements by passing them directly as values to the translation function. If any of the provided interpolation values are JSX elements, the translation function will return a JSX element instead of a string.TranslationApi now supports interpolation of JSX elements by passing them directly as values to the translation function. If any of the provided interpolation values are JSX elements, the translation function will return a JSX element instead of a string.a47fd39: Removes instances of default React imports, a necessary update for the upcoming React 19 migration.
https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html
Updated dependencies
a47fd39: Removes instances of default React imports, a necessary update for the upcoming React 19 migration.
https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html
Updated dependencies
BootErrorPage app component.Expand and ExpandRecursive to @backstage/typesExpand and ExpandRecursive to @backstage/typesbfd4bec: BREAKING PRODUCERS: The IconComponent no longer accepts fontSize="default". This has effectively been removed from Material-UI since its last two major versions, and has not worked properly for them in a long time.
This change should not have an effect on neither users of MUI4 nor MUI5/6, since the updated interface should still let you send the respective SvgIcon types into interfaces where relevant (e.g. as app icons).
@types/react to a peer dependency.ParamKeys leading to type mismatches across versions@types/react to a peer dependency.bfd4bec: BREAKING PRODUCERS: The IconComponent no longer accepts fontSize="default". This has effectively been removed from Material-UI since its last two major versions, and has not worked properly for them in a long time.
This change should not have an effect on neither users of MUI4 nor MUI5/6, since the updated interface should still let you send the respective SvgIcon types into interfaces where relevant (e.g. as app icons).
@testing-library/react to ^16.0.0.@testing-library/react to ^16.0.0.defaultTarget option has been added to createExternalRouteRef. This allows one to specify a default target of the route by name, for example 'catalog.catalogIndex', which will be used if the target route is present in the app and there is no explicit route binding.defaultTarget option to createExternalRouteRef. I lets you specify a default target of the route by name, for example 'catalog.catalogIndex', which will be used if the target route is present in the app and there is no explicit route binding.@testing-library/react to ^15.0.0.@testing-library/dom to ^10.0.0.@backstage/core-plugin-api and @backstage/frontend-plugin-api packages, the
implementation is in @backstage/core-app-api and a factory has been added to
@backstage/app-defaults.@types/react dependency range to include version 18.NotImplementedError when an API implementation cannot be found.@backstage/core-plugin-api and @backstage/frontend-plugin-api packages, the
implementation is in @backstage/core-app-api and a factory has been added to
@backstage/app-defaults.@types/react dependency range to include version 18.NotImplementedError when an API implementation cannot be found.i18next dependency.i18next dependency.convertLegacyRouteRef utility, which as been moved to @backstage/core-compat-apicreateTranslationRef function from the /alpha subpath can now also accept a nested object structure of default translation messages, which will be flatted using . separators.createTranslationRef function from the /alpha subpath can now also accept a nested object structure of default translation messages, which will be flatted using . separators.convertLegacyRouteRef utility, which as been moved to @backstage/core-compat-apiIconComponent can now have a fontSize of inherit, which is useful for in-line icons.AnyRouteRefParams as a replacement for AnyParams, which is now deprecated./alpha export convertLegacyRouteRef, which is a temporary utility to allow existing route refs to be used with the new experimental packages.IconComponent can now have a fontSize of inherit, which is useful for in-line icons.AnyRouteRefParams as a replacement for AnyParams, which is now deprecated./alpha export convertLegacyRouteRef, which is a temporary utility to allow existing route refs to be used with the new experimental packages.__experimentalReconfigure() from the plugin options as well as the __experimentalConfigure() method on plugin instances have both been removed.@testing-library/jest-dom to ^6.0.0.@testing-library/dom to ^9.0.0.__experimentalReconfigure() from the plugin options as well as the __experimentalConfigure() method on plugin instances have both been removed.expiresAt field that may now be part of a BackstageIdentityResponse.@types/node dependency@types/node dependencyexpiresAt field that may now be part of a BackstageIdentityResponse.IconComponent type to be compatible with Material UI v5 icons.IconComponent type to be compatible with Material UI v5 icons.navigate analytics events when users visited pages constructed with <EntityLayout>, <TabbedLayout>, and similar components that are used to gather one or more routable extensions under a given path.PropsWithChildren to usages of ComponentType, in preparation for React 18 where the children are no longer implicit.PropsWithChildren to usages of ComponentType, in preparation for React 18 where the children are no longer implicit./alpha exports.msw to ^1.0.0.msw to ^1.0.0./alpha exports.9a1864976a: Added a new display property to the AlertMessage which can accept the values permanent or transient.
Here's a rough example of how to trigger an alert using the new display property:
import { alertApiRef, useApi } from '@backstage/core-plugin-api';
const ExampleTransient = () => {
const alertApi = useApi(alertApiRef);
alertApi.post({
message: 'Example of Transient Alert',
severity: 'success',
display: 'transient',
});
};
msw to ^0.49.0.zen-observable to ^0.9.0.zen-observable to ^0.10.0.9a1864976a: Added a new display property to the AlertMessage which can accept the values permanent or transient.
Here's a rough example of how to trigger an alert using the new display property:
import { alertApiRef, useApi } from '@backstage/core-plugin-api';
const ExampleTransient = () => {
const alertApi = useApi(alertApiRef);
alertApi.post({
message: 'Example of Transient Alert',
severity: 'success',
display: 'transient',
});
};
zen-observable to ^0.10.0.msw to ^0.49.0.zen-observable to ^0.9.0.Router component now accepts an optional basename property.Router component now accepts an optional basename property.@types/jest.getSystemIcons() function to the AppContext available through useApp that will pull a list of all the icons that have been registered in the App.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.getSystemIcons() function to the AppContext available through useApp that will pull a list of all the icons that have been registered in the App.msw to ^0.45.0.80da5162c7: Introduced a new experimental feature that allows you to declare plugin-wide options for your plugin by defining
__experimentalConfigure in your createPlugin options. See https://backstage.io/docs/plugins/customization.md for more information.
This is an experimental feature and it will have breaking changes in the future.
87649a06bf: Add a note that the fetchApi utility should not be used on sign-in page implementations and similar.
80da5162c7: Introduced a new experimental feature that allows you to declare plugin-wide options for your plugin by defining
__experimentalConfigure in your createPlugin options. See https://backstage.io/docs/plugins/customization.md for more information.
This is an experimental feature and it will have breaking changes in the future.
BackstagePlugin type.msw to ^0.43.0.msw to ^0.44.0.@backstage/core-plugin-api/alpha entry point.BackstagePlugin type.msw to ^0.43.0.@backstage/core-plugin-api/alpha entry point.msw to ^0.41.0.msw to ^0.41.0.@alpha. Since the @backstage/core-plugin-api has no /alpha entrypoint, the only effect of marking the APIs as @alpha was to hide them in documentation. They are still expected to be widely used and there will be a migration path if they are changed in the future.@alpha. Since the @backstage/core-plugin-api has no /alpha entrypoint, the only effect of marking the APIs as @alpha was to hide them in documentation. They are still expected to be widely used and there will be a migration path if they are changed in the future.@testing-library/react-hooks from 7.0.2 to 8.0.0@testing-library/user-event from 13.5.0 to 14.0.0@types/node v16@testing-library/user-event from 13.5.0 to 14.0.0@types/node v16@testing-library/react from 11.2.6 to 12.1.3get method from StorageAPI and its implementations, this method has been replaced by the snapshot method. The return value from snapshot no longer includes newValue which has been replaced by value. For getting notified when a value changes, use `observe# @backstage/core-plugin-api.auth0AuthApiRef, oauth2ApiRef, samlAuthApiRef and oidcAuthApiRef as these APIs are too generic to be useful. Instructions for how to migrate can be found at https://backstage.io/docs/api/deprecations#generic-auth-api-refs.createAuthRequester.AnyAnalyticsContext type which is replaced by AnalyticsContextValuenode-fetch to version 2.6.7 and cross-fetch to version 3.1.5backstage.role to package.jsonceebe25391: Removed deprecated IdentityApi methods: getUserId, getIdToken, and getProfile.
Existing usage of getUserId can be replaced by getBackstageIdentity, more precisely the equivalent of the previous userId can be retrieved like this:
import { parseEntityRef } from '@backstage/catalog-model';
const identity = await identityApi.getBackstageIdentity();
const { name: userId } = parseEntityRef(identity.userEntityRef);
Note that it is recommended to consume the entire userEntityRef rather than parsing out just the name, in order to support namespaces.
Existing usage of getIdToken can be replaced by getCredentials, like this:
const { token } = await identityApi.getCredentials();
And existing usage of getProfile is replaced by getProfileInfo, which returns the same profile object, but is now async.
ceebe25391: Removed deprecated SignInResult type, which was replaced with the new onSignInSuccess callback.
d879072b0c: Removed the deprecated id field of BackstageIdentityResponse.
Existing usage can be replaced by parsing the name of the identity.userEntityRef with parseEntityRef from @backstage/catalog-model, although note that it is recommended to consume the entire userEntityRef in order to support namespaces.
94c02b4246: Removed deprecated BackstageIdentity type, which was replaced by BackstageIdentityResponse.
234a36405b: Removed deprecated OAuthRequestApi types: AuthProvider, AuthRequesterOptions, AuthRequester, and PendingAuthRequest.
ceebe25391: Removed deprecated IdentityApi methods: getUserId, getIdToken, and getProfile.
Existing usage of getUserId can be replaced by getBackstageIdentity, more precisely the equivalent of the previous userId can be retrieved like this:
import { parseEntityRef } from '@backstage/catalog-model';
const identity = await identityApi.getBackstageIdentity();
const { name: userId } = parseEntityRef(identity.userEntityRef);
Note that it is recommended to consume the entire userEntityRef rather than parsing out just the name, in order to support namespaces.
Existing usage of getIdToken can be replaced by getCredentials, like this:
const { token } = await identityApi.getCredentials();
And existing usage of getProfile is replaced by getProfileInfo, which returns the same profile object, but is now async.
ceebe25391: Removed deprecated SignInResult type, which was replaced with the new onSignInSuccess callback.
d879072b0c: Removed the deprecated id field of BackstageIdentityResponse.
Existing usage can be replaced by parsing the name of the identity.userEntityRef with parseEntityRef from @backstage/catalog-model, although note that it is recommended to consume the entire userEntityRef in order to support namespaces.
94c02b4246: Removed deprecated BackstageIdentity type, which was replaced by BackstageIdentityResponse.
234a36405b: Removed deprecated OAuthRequestApi types: AuthProvider, AuthRequesterOptions, AuthRequester, and PendingAuthRequest.
784d8078ab: Removed the deprecated OldIconComponent type.
e2eb92c109: Removed previously deprecated exports: PluginHooks, PluginOutput, and FeatureFlagOutput.
The deprecated register method of PluginConfig has been removed, as well as the deprecated output method of BackstagePlugin.
OldIconComponent. Existing usage should be replaced with IconComponent.a195284c7b: BREAKING CHANGE The StorageApi has received several updates that fills in gaps for some use-cases and makes it easier to avoid mistakes:
StorageValueChange type has been renamed to StorageValueSnapshot, the newValue property has been renamed to value, the stored value type has been narrowed to JsonValue, and it has received a new presence property that is 'unknown', 'absent', or 'present'.get method has been deprecated in favor of a new snapshot method, which returns a StorageValueSnapshot.observe# @backstage/core-plugin-api method has had its contract changed. It should now emit values when thepresenceof a key changes, this may for example happen when remotely stored values are requested on page load and the presence switches from'unknown'to either'absent'or'present'`.The above changes have been made with deprecations in place to maintain much of the backwards compatibility for consumers of the StorageApi. The only breaking change is the narrowing of the stored value type, which may in some cases require the addition of an explicit type parameter to the get and `observe# @backstage/core-plugin-api methods.
f6722d2458: - Removed deprecated option description from ApiRefConfig
path, icon, and title in createRouteRefError and ErrorContext from ErrorApi68f8b10ccd: - Removed deprecation configuration option theme from AppTheme of the AppThemeApi
theme in the app-defaults default AppThemeAppThemeProvider that creates ThemeProvider from appTheme.theme6b69b44862: Removed deprecated types ApiRefType and ApiRefsToTypes
FetchApi and related fetchApiRef which implement fetch, with an added Backstage token header when available.18d4f500af: Deprecated the AnyAnalyticsContext type and mark the AnalyticsApi experimental.
8a7372cfd5: Deprecated auth0AuthApiRef, oauth2ApiRef, oidcAuthApiRef, samlAuthApiRef, and marked the rest of the auth ApiRefs as experimental. For more information on how to address the deprecations, see https://backstage.io/docs/api/deprecations#generic-auth-api-refs.
760791a642: Renamed AuthProvider to AuthProviderInfo and add a required 'id' property to match the majority of usage. The AuthProvider type without the id property still exists but is deprecated, and all usage of it without an id is deprecated as well. For example, calling createAuthRequest without a provider.id is deprecated and it will be required in the future.
The following types have been renamed. The old names are still exported but deprecated, and are scheduled for removal in a future release.
AuthRequesterOptions to OAuthRequesterOptionsAuthRequester to OAuthRequesterPendingAuthRequest to PendingOAuthRequesta036b65c2f: The IdentityApi has received several updates. The getUserId, getProfile, and getIdToken have all been deprecated.
The replacement for getUserId is the new getBackstageIdentity method, which provides both the userEntityRef as well as the ownershipEntityRefs that are used to resolve ownership. Existing usage of the user ID would typically be using a fixed entity kind and namespace, for example `user:default/${identityApi.getUserId()}`, this kind of usage should now instead use the userEntityRef directly.
The replacement for getProfile is the new async getProfileInfo.
The replacement for getIdToken is the new getCredentials method, which provides an optional token to the caller like before, but it is now wrapped in an object for forwards compatibility.
The deprecated idToken field of the BackstageIdentity type has been removed, leaving only the new token field, which should be used instead. The BackstageIdentity also received a new identity field, which is a decoded version of the information within the token. Furthermore the BackstageIdentity has been renamed to BackstageIdentityResponse, with the old name being deprecated.
We expect most of the breaking changes in this update to have low impact since the IdentityApi implementation is provided by the app, but it is likely that some tests need to be updated.
Another breaking change is that the SignInPage props have been updated, and the SignInResult type is now deprecated. This is unlikely to have any impact on the usage of this package, but it is an important change that you can find more information about in the @backstage/core-app-api CHANGELOG.md.
peerDependencies and allow both React v16 and v17 to be used.createRouteRef to hopefully make it more clear.950b36393c: Deprecated register option of createPlugin and the outputs methods of the plugin instance.
Introduces the featureFlags property to define your feature flags instead.
UserFlags type.RouteOptions and RoutePath).title icon and path as they are no longer controlled when creating routeRefstheme property on AppTheme, replacing it with Provider. See https://backstage.io/docs/api/deprecations#app-theme for more details.Error and ErrorContext types, replacing them with identical ErrorApiError and ErrorApiErrorContext types.@backstage/types package. Initially, this means using the Observable and Json* types from there. The types also remain in their old places but deprecated, and will be removed in a future release.202f322927: Atlassian auth provider
36e67d2f24: Internal updates to apply more strict checks to throw errors.
829bc698f4: Introducing the Analytics API: a lightweight way for plugins to instrument key events that could help inform a Backstage Integrator how their instance of Backstage is being used. The API consists of the following:
useAnalytics(), a hook to be used inside plugin components which retrieves
an Analytics Tracker.tracker.captureEvent(), a method on the tracker used to instrument key
events. The method expects an action (the event name) and a subject (a unique
identifier of the object the action is being taken on).<AnalyticsContext />, a way to declaratively attach additional information
to any/all events captured in the underlying React tree. There is also a
withAnalyticsContext() HOC utility.tracker.captureEvent() method also accepts an attributes option for
providing additional run-time information about an event, as well as a
value option for capturing a numeric/metric value.By default, captured events are not sent anywhere. In order to collect and
redirect events to an analytics system, the analyticsApi will need to be
implemented and instantiated by an App Integrator.
4c3eea7788: Bitbucket Cloud authentication - based on the existing GitHub authentication + changes around BB apis and updated scope.
react-hot-loader.@types/react dependency to request * rather than a specific version.token instead of the deprecated idToken fieldmaterial-ui/core version to at least 4.12.2 as they made some breaking changes in later versions which broke Pagination of the Table.
material-table to @material-table/core for support for the later versions of material-ui/core@backstage/core-components as the interface for Table re-exports the prop from the underlying Table components.onChangeRowsPerPage has been renamed to onRowsPerPageChangeonChangePage has been renamed to onPageChangeFeatureFlag component and treating FeatureFlags as first class citizens to composability API75b8537ce: This change adds automatic error boundaries around extensions.
This means that all exposed parts of a plugin are wrapped in a general error boundary component, that is plugin aware. The default design for the error box is borrowed from @backstage/errors. To override the default "fallback", one must provide a component named ErrorBoundaryFallback to createApp, like so:
const app = createApp({
components: {
ErrorBoundaryFallback: props => {
// a custom fallback component
return (
<>
<h1>Oops.</h1>
<h2>
The plugin {props.plugin.getId()} failed with{' '}
{props.error.message}
</h2>
<button onClick={props.resetError}>Try again</button>
</>
);
},
},
});
The props here include:
error. An Error object or something that inherits it that represents the error that was thrown from any inner component.resetError. A callback that will simply attempt to mount the children of the error boundary again.plugin. A BackstagePlugin that can be used to look up info to be presented in the error message. For instance, you may want to keep a map of your internal plugins and team names or slack channels and present these when an error occurs. Typically, you'll do that by getting the plugin ID with plugin.getId().da8cba44f: Apply fixes to the extension creation API that were mistakenly applied to @backstage/core-app-api instead.
icon fields compatible with the IconComponent type from @backstage/core in order to smooth out the migration.express from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.@backstage/backend-common, please migrate to the new backend system.backstage-cli package schema openapi generate --server.backstage-cli package schema openapi generate --server./alpha export is now also available via the main entry point, which means that you can remove the /alpha suffix from the import.BackendFeature, not a function that returns a feature.supertest to ^7.0.0.supertest to ^7.0.0.BackendFeature, not a function that returns a feature.AuthorizedSearchEngine will now ignore the deprecated token option, and treat it as an unauthorized request. This will not have any effect in practice, since credentials are always provided by the router.BackendFeature contract change.package.json.package.json.LoggerServiceauth services, it now accepts an optional discovery service option to get credentials for the permission service.auth services, it now accepts an optional discovery service option to get credentials for the permission service.info.title instead of package name.info.title instead of package name.supertest pass through from @backstage/backend-openapi-utils.supertest pass through from @backstage/backend-openapi-utils.search.maxTermLength in the config file.71114ac50e02: The export for the new backend system has been moved to be the default export.
For example, if you are currently importing the plugin using the following pattern:
import { examplePlugin } from '@backstage/plugin-example-backend';
backend.add(examplePlugin);
It should be migrated to this:
backend.add(import('@backstage/plugin-example-backend'));
Updated dependencies
71114ac50e02: The export for the new backend system has been moved to be the default export.
For example, if you are currently importing the plugin using the following pattern:
import { examplePlugin } from '@backstage/plugin-example-backend';
backend.add(examplePlugin);
It should be migrated to this:
backend.add(import('@backstage/plugin-example-backend'));
Updated dependencies
@backstage/backend-openapi-utils. Error responses for invalid input, like "a" instead of a number, may have changed.coreServices.rootConfig instead of coreService.configconfigSchema to package.jsoncoreServices.rootConfig instead of coreService.configconfigSchema to package.json@backstage/backend-openapi-utils. Error responses for invalid input, like "a" instead of a number, may have changed.zod and zod-to-json-schema dependencies.zod and zod-to-json-schema dependencies.zod dependency to a version that does not collide with other librarieszod dependency to a version that does not collide with other libraries16c853a6ed: Be less restrictive with unknown keys on query endpoint
a799972bb1: The query received by search engines now contains a property called pageLimit, it specifies how many results to return per page when sending a query request to the search backend.
Example: Returns up to 30 results per page
GET /query?pageLimit=30
The search backend validates the page limit and this value must not exceed 100, but it doesn't set a default value for the page limit parameter, it leaves it up to each search engine to set this, so Lunr, Postgres and Elastic Search set 25 results per page as a default value.
response.json rather than response.send where appropriate, as outlined in SECURITY.mdresponse.json rather than response.send where appropriate, as outlined in SECURITY.md16c853a6ed: Be less restrictive with unknown keys on query endpoint
a799972bb1: The query received by search engines now contains a property called pageLimit, it specifies how many results to return per page when sending a query request to the search backend.
Example: Returns up to 30 results per page
GET /query?pageLimit=30
The search backend validates the page limit and this value must not exceed 100, but it doesn't set a default value for the page limit parameter, it leaves it up to each search engine to set this, so Lunr, Postgres and Elastic Search set 25 results per page as a default value.
MissingIndexError we return a 400 response with a more clear error message.MissingIndexError we return a 400 response with a more clear error message.RouterOptions and createRouter now marked as public exportsrank value to all results.RouterOptions and createRouter now marked as public exportsPermissionEvaluator instance check that would cause unexpected "invalid union" errors.PermissionEvaluator instance check that would cause unexpected "invalid union" errors.authorization property is no longer returned on search results when queried. Note: this will only result in a breaking change if you have custom code in your frontend that relies on the authorization.resourceRef property on documents.PermissionEvaluator instead of PermissionAuthorizer, which is now deprecated.IndexableResultSet type as return type of query method in SearchEngine implementation.@backstage/plugin-permission-commonPermissionEvaluator instead of PermissionAuthorizer, which is now deprecated.@backstage/plugin-permission-commonauthorization property is no longer returned on search results when queried. Note: this will only result in a breaking change if you have custom code in your frontend that relies on the authorization.resourceRef property on documents.IndexableResultSet type as return type of query method in SearchEngine implementation.@backstage/plugin-search-common package instead of @backstage/search-common.@backstage/plugin-search-common package instead of @backstage/search-common.backstage.role to package.jsongetBearerTokenFromAuthorizationHeader from @backstage/plugin-auth-node instead of the deprecated IdentityClient method.bbfbc755aa: BREAKING Added three additional required properties to createRouter to support filtering search results based on permissions. To make this change to an existing app, add the required parameters to the createRouter call in packages/backend/src/plugins/search.ts:
export default async function createPlugin({
logger,
+ permissions,
discovery,
config,
tokenManager,
}: PluginEnvironment) {
/* ... */
return await createRouter({
engine: indexBuilder.getSearchEngine(),
+ types: indexBuilder.getDocumentTypes(),
+ permissions,
+ config,
logger,
});
}
a41fbfe739: Search result location filtering
This change introduces a filter for search results based on their location protocol. The intention is to filter out unsafe or malicious values before they can be consumed by the frontend. By default locations must be http/https URLs (or paths).
bab752e2b3: Change default port of backend from 7000 to 7007.
This is due to the AirPlay Receiver process occupying port 7000 and preventing local Backstage instances on MacOS to start.
You can change the port back to 7000 or any other value by providing an app-config.yaml with the following values:
backend:
listen: 0.0.0.0:7123
baseUrl: http://localhost:7123
More information can be found here: https://backstage.io/docs/conf/writing
Updated dependencies
a13f21cdc: Implement optional pageCursor based paging in search.
To use paging in your app, add a <SearchResultPager /> to your
SearchPage.tsx.
Updated dependencies
yarn dev respect the PLUGIN_PORT environment variable.5aff84759: This release represents a move out of a pre-alpha phase of the Backstage Search plugin, into an alpha phase. With this release, you gain more control over the layout of your search page on the frontend, as well as the ability to extend search on the backend to encompass everything Backstage users may want to find.
If you are updating to version v0.4.0 of @backstage/plugin-search from a
prior release, you will need to make modifications to your app backend.
First, navigate to your backend package and install the two related search backend packages:
cd packages/backend
yarn add @backstage/plugin-search-backend @backstage/plugin-search-backend-node
Wire up these new packages into your app backend by first creating a new
search.ts file at src/plugins/search.ts with contents like the following:
import { useHotCleanup } from '@backstage/backend-common';
import { createRouter } from '@backstage/plugin-search-backend';
import {
IndexBuilder,
LunrSearchEngine,
} from '@backstage/plugin-search-backend-node';
import { PluginEnvironment } from '../types';
import { DefaultCatalogCollator } from '@backstage/plugin-catalog-backend';
export default async function createPlugin({
logger,
discovery,
}: PluginEnvironment) {
// Initialize a connection to a search engine.
const searchEngine = new LunrSearchEngine({ logger });
const indexBuilder = new IndexBuilder({ logger, searchEngine });
// Collators are responsible for gathering documents known to plugins. This
// particular collator gathers entities from the software catalog.
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
collator: new DefaultCatalogCollator({ discovery }),
});
// The scheduler controls when documents are gathered from collators and sent
// to the search engine for indexing.
const { scheduler } = await indexBuilder.build();
// A 3 second delay gives the backend server a chance to initialize before
// any collators are executed, which may attempt requests against the API.
setTimeout(() => scheduler.start(), 3000);
useHotCleanup(module, () => scheduler.stop());
return await createRouter({
engine: indexBuilder.getSearchEngine(),
logger,
});
}
Then, ensure the search plugin you configured above is initialized by modifying
your backend's index.ts file in the following ways:
+import search from './plugins/search';
// ...
+const searchEnv = useHotMemoize(module, () => createEnv('search'));
// ...
+apiRouter.use('/search', await search(searchEnv));
// ...
backend-common, and the correct version of express-promise-routerbb9b471: Plugin IDs that do not match the standard format are deprecated (letters, digits, and dashes only, starting with a letter). Plugin IDs that do no match this format will be rejected in a future release.
In addition, plugin IDs that don't match the legacy pattern that also allows underscores, with be rejected.
API_FACTORY_CONFLICT warning is now treated as an error and will prevent the app from starting.bb9b471: Plugin IDs that do not match the standard format are deprecated (letters, digits, and dashes only, starting with a letter). Plugin IDs that do no match this format will be rejected in a future release.
10ebed4: BREAKING: Removed type support for multiple attachment points in the ExtensionDefinitionAttachTo type. Extensions can no longer specify an array of attachment points in the attachTo property.
The runtime still supports multiple attachment points for backward compatibility with existing compiled code, but new code will receive type errors if attempting to use this pattern.
Extensions that previously used multiple attachment points should migrate to using a Utility API pattern instead. See the Sharing Extensions Across Multiple Locations guide for the recommended approach.
058ffd9: BREAKING: Removed large size variant from Button component as it was never implemented.
Migration:
- <Button size="large">Click me</Button>
+ <Button size="medium">Click me</Button>
Affected components: Button
110fec0: BREAKING: Removed link and tint color tokens, added new status foreground tokens, and improved Link component styling
The following color tokens have been removed:
--bui-fg-link (and all related tokens: -hover, -pressed, -disabled)--bui-fg-tint (and all related tokens: -hover, -pressed, -disabled)--bui-bg-tint (and all related tokens: -hover, -pressed, -disabled)--bui-border-tint (and all related tokens)New Status Tokens:
Added dedicated tokens for status colors that distinguish between usage on status backgrounds vs. standalone usage:
--bui-fg-danger-on-bg / --bui-fg-danger--bui-fg-warning-on-bg / --bui-fg-warning--bui-fg-success-on-bg / --bui-fg-success--bui-fg-info-on-bg / --bui-fg-infoThe -on-bg variants are designed for text on colored backgrounds, while the base variants are for standalone status indicators with improved visibility and contrast.
Migration:
For link colors, migrate to one of the following alternatives:
.custom-link {
- color: var(--bui-fg-link);
+ color: var(--bui-fg-info); /* For informational links */
+ /* or */
+ color: var(--bui-fg-primary); /* For standard text links */
}
For tint colors (backgrounds, foregrounds, borders), migrate to appropriate status or neutral colors:
.info-section {
- background: var(--bui-bg-tint);
+ background: var(--bui-bg-info); /* For informational sections */
+ /* or */
+ background: var(--bui-bg-neutral-on-surface-0); /* For neutral emphasis */
}
If you're using status foreground colors on colored backgrounds, update to the new -on-bg tokens:
.error-badge {
- color: var(--bui-fg-danger);
+ color: var(--bui-fg-danger-on-bg);
background: var(--bui-bg-danger);
}
Affected components: Link
4d1b7f4: Fixed CSS Module syntax to comply with Next.js 16 Turbopack validation by flattening nested dark theme selectors.
Affected components: Popover, Tooltip
2c219b9: Added destructive prop to Button for dangerous actions like delete or remove. Works with all variants (primary, secondary, tertiary).
Affected components: Button
5af9e14: Fixed useDefinition hook adding literal "undefined" class name when no className prop was passed.
74c5a76: Fixed Switch component disabled state styling to show not-allowed cursor and disabled text color.
Affected components: Switch
express from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
supertest to ^7.0.0.supertest to ^7.0.0.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
signIn to authentication provider configuration schemasignIn to authentication provider configuration schemascope and scopes config options have been removed and replaced by the standard additionalScopes config. In addition, the offline_access, read:jira-work, and read:jira-user scopes have been set to required and will always be present.BackendFeature contract change.package.json.scope and scopes config options have been removed and replaced by the standard additionalScopes config. In addition, the offline_access, read:jira-work, and read:jira-user scopes have been set to required and will always be present.package.json.repository field in package.json.repository field in package.json.@backstage/plugin-auth-backend that adds an atlassian auth providerpassport to ^0.7.0.passport to ^0.7.0.@backstage/plugin-auth-backend that adds an atlassian auth providerexpress from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.fullProfile will no longer have the its username or email converted to lowercase. This is to ensure unique handling of the users. You may need to update and configure a custom sign-in resolver or profile transform as a result.fullProfile will no longer have the its username or email converted to lowercase. This is to ensure unique handling of the users. You may need to update and configure a custom sign-in resolver or profile transform as a result.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
c8f1cae: Add signIn to authentication provider configuration schema
4ea354f: Added a signer configuration option to validate against the token claims. We strongly recommend that you set this value (typically on the format arn:aws:elasticloadbalancing:us-east-2:123456789012:loadbalancer/app/my-load-balancer/1234567890123456) to ensure that the auth provider can safely check the authenticity of any incoming tokens.
Example:
auth:
providers:
awsalb:
# this is the URL of the IdP you configured
issuer: 'https://example.okta.com/oauth2/default'
# this is the ARN of your ALB instance
+ signer: 'arn:aws:elasticloadbalancing:us-east-2:123456789012:loadbalancer/app/my-load-balancer/1234567890123456'
# this is the region where your ALB instance resides
region: 'us-west-2'
signIn:
resolvers:
# typically you would pick one of these
- resolver: emailMatchingUserEntityProfileEmail
- resolver: emailLocalPartMatchingUserEntityName
93095ee: Make sure node-fetch is version 2.7.0 or greater
Updated dependencies
signIn to authentication provider configuration schemaBackendFeature contract change.package.json.package.json.f286d59: Added support for AWS GovCloud (US) regions
30f5a51: Added authModuleAwsAlbProvider as a default export.
It can now be used like this in your backend: backend.add(import('@backstage/plugin-auth-backend-module-aws-alb-provider'));
Updated dependencies
30f5a51: Added authModuleAwsAlbProvider as a default export.
It can now be used like this in your backend: backend.add(import('@backstage/plugin-auth-backend-module-aws-alb-provider'));
Updated dependencies
jose to v5providerInfo not being set properly for some proxy providers, by making providerInfo an explicit optional return from authenticatejose to v5providerInfo not being set properly for some proxy providers, by making providerInfo an explicit optional return from authenticate@backstage/plugin-auth-backend-module-aws-alb-provider module package.jose library for JWT handling.jose library for JWT handling.@backstage/plugin-auth-backend-module-aws-alb-provider module package.express from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
BackendFeature contract change.package.json.package.json.azure-easyauth provider. Note that as part of this change the default provider ID has been changed from easyAuth to azureEasyAuth, which means that if you switch to this new module you need to update your app config as well as the provider prop of the ProxiedSignInPage in the frontend.express from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
supertest to ^7.0.0.supertest to ^7.0.0.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
signIn to authentication provider configuration schemasignIn to authentication provider configuration schemaBackendFeature contract change.additionalScopes configuration. In addition, the account scope has been set to required and will always be present.package.json.additionalScopes configuration. In addition, the account scope has been set to required and will always be present.package.json.@backstage/plugin-auth-backend-module-bitbucket-provider module package.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.@backstage/plugin-auth-backend that adds a Bitbucket Server auth provider.supertest to ^7.0.0.@backstage/plugin-auth-backend that adds a Bitbucket Server auth provider.express from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.cfIdentity instead of claims when constructing user profile in order to support Cloudflare Service Tokens.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
signIn to authentication provider configuration schemasignIn to authentication provider configuration schemaBackendFeature contract change.package.json.node-fetch instead of native fetch, as per https://backstage.io/docs/architecture-decisions/adrs-adr013package.json.node-fetch instead of native fetch, as per https://backstage.io/docs/architecture-decisions/adrs-adr013express from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
signIn to authentication provider configuration schemasignIn to authentication provider configuration schemaBackendFeature contract change.package.json.package.json.google-auth-library to ^9.0.0.providerInfo not being set properly for some proxy providers, by making providerInfo an explicit optional return from authenticategoogle-auth-library to ^9.0.0.providerInfo not being set properly for some proxy providers, by making providerInfo an explicit optional return from authenticategcpIapAuthenticator.initialize() is no longer asyncgcpIapAuthenticator.initialize() is no longer async@backstage/plugin-auth-backend that adds a GCP IAP auth provider.71114ac50e02: The export for the new backend system has been moved to be the default export.
For example, if you are currently importing the plugin using the following pattern:
import { examplePlugin } from '@backstage/plugin-example-backend';
backend.add(examplePlugin);
It should be migrated to this:
backend.add(import('@backstage/plugin-example-backend'));
Updated dependencies
71114ac50e02: The export for the new backend system has been moved to be the default export.
For example, if you are currently importing the plugin using the following pattern:
import { examplePlugin } from '@backstage/plugin-example-backend';
backend.add(examplePlugin);
It should be migrated to this:
backend.add(import('@backstage/plugin-example-backend'));
Updated dependencies
@backstage/plugin-auth-backend that adds a GCP IAP auth provider.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.includeGrantedScopes in order to persist scopes across refresh callsincludeGrantedScopes in order to persist scopes across refresh callsallowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
supertest to ^7.0.0.supertest to ^7.0.0.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
signIn to authentication provider configuration schemasignIn to authentication provider configuration schemaBackendFeature contract change.additionalScopes configuration. In addition, the openid, userinfo.email, and userinfo.profile scopes have been set to required and will always be present.package.json.additionalScopes configuration. In addition, the openid, userinfo.email, and userinfo.profile scopes have been set to required and will always be present.package.json.google-auth-library to ^9.0.0.google-auth-library to ^9.0.0.@backstage/plugin-auth-backend that adds a Google auth provider.71114ac50e02: The export for the new backend system has been moved to be the default export.
For example, if you are currently importing the plugin using the following pattern:
import { examplePlugin } from '@backstage/plugin-example-backend';
backend.add(examplePlugin);
It should be migrated to this:
backend.add(import('@backstage/plugin-example-backend'));
Updated dependencies
71114ac50e02: The export for the new backend system has been moved to be the default export.
For example, if you are currently importing the plugin using the following pattern:
import { examplePlugin } from '@backstage/plugin-example-backend';
backend.add(examplePlugin);
It should be migrated to this:
backend.add(import('@backstage/plugin-example-backend'));
Updated dependencies
@backstage/plugin-auth-backend that adds a Google auth provider.express from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.auth.microsoft.signIn.resolvers config def to include the userIdMatchingUserEntityAnnotation resolver.auth.microsoft.signIn.resolvers config def to include the userIdMatchingUserEntityAnnotation resolver.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.skipUserProfile config flag to Microsoft authenticatorallowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.skipUserProfile config flag to Microsoft authenticatord425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
msgraph catalog plugin and add userIdMatchingUserEntityAnnotation sign-in resolver for the Microsoft auth provider to support sign-in for users without defined email.supertest to ^7.0.0.supertest to ^7.0.0.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
msgraph catalog plugin and add userIdMatchingUserEntityAnnotation sign-in resolver for the Microsoft auth provider to support sign-in for users without defined email.signIn to authentication provider configuration schemasignIn to authentication provider configuration schemaBackendFeature contract change.additionalScopes configuration.package.json.additionalScopes configuration.package.json.jose to v5jose to v5repository field in package.json.repository field in package.json.authModuleMicrosoftProvider export. A default export is now available and should be used like this in your backend: backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));passport to ^0.7.0.passport to ^0.7.0.a3236ad0ca: Fix link to the repository in README.md.
3979524c74: Added support for specifying a domain hint on the Microsoft authentication provider configuration.
fde212dd10: Re-add the missing profile photo as well as access token retrieval for foreign scopes.
Additionally, we switch from previously 48x48 to 96x96 which is the size used at the profile card.
5aeb14f035: Correctly mark the client secret in configuration as secret
2817115d09: Removed prompt=consent from start method to fix #20641
Updated dependencies
#20706 fde212dd10 Thanks @pjungermann! - Re-add the missing profile photo
as well as access token retrieval for foreign scopes.
Additionally, we switch from previously 48x48 to 96x96 which is the size used at the profile card.
Updated dependencies
prompt=consent from start method to fix #20641@backstage/plugin-auth-backend-module-microsoft-provider module package.@backstage/plugin-auth-backend-module-microsoft-provider module package.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.README.mdREADME.mdauth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
supertest to ^7.0.0.supertest to ^7.0.0.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
signIn to authentication provider configuration schemasignIn to authentication provider configuration schemascope config option have been removed and replaced by the standard additionalScopes config.BackendFeature contract change.package.json.scope config option have been removed and replaced by the standard additionalScopes config.package.json.repository field in package.json.repository field in package.json.passport to ^0.7.0.passport to ^0.7.0.@backstage/plugin-auth-backend that adds a oauth2 auth provider.@backstage/plugin-auth-backend that adds a oauth2 auth provider.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
BackendFeature contract change.package.json.package.json.jose to v5providerInfo not being set properly for some proxy providers, by making providerInfo an explicit optional return from authenticatejose to v5providerInfo not being set properly for some proxy providers, by making providerInfo an explicit optional return from authenticaterepository field in package.json.repository field in package.json.oauth2-proxy-provider pluginfeatureDiscoveryServiceFactory()oauth2ProxyProvider to oauth2ProxyfeatureDiscoveryServiceFactory()oauth2ProxyProvider to oauth2Proxyoauth2-proxy-provider pluginstartUrlSearchParams config property)startUrlSearchParams config property)express from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.7495edf: Added custom timeout setting for oidc provider
Here is an example of how to use a custom timeout with the configuration:
auth:
oidc:
production:
clientId: ${AUTH_GOOGLE_CLIENT_ID}
clientSecret: ${AUTH_GOOGLE_CLIENT_SECRET}
timeout:
seconds: 30
Updated dependencies
7495edf: Added custom timeout setting for oidc provider
Here is an example of how to use a custom timeout with the configuration:
auth:
oidc:
production:
clientId: ${AUTH_GOOGLE_CLIENT_ID}
clientSecret: ${AUTH_GOOGLE_CLIENT_SECRET}
timeout:
seconds: 30
Updated dependencies
README.mdREADME.mdauth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.start method in the authenticator to just return the helper promiseauth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
supertest to ^7.0.0.supertest to ^7.0.0.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
signIn to authentication provider configuration schemasignIn to authentication provider configuration schemascope config option have been removed and replaced by the standard additionalScopes config. In addition, openid, profile, and email scopes have been set to required and will always be present.BackendFeature contract change.package.json.scope config option have been removed and replaced by the standard additionalScopes config. In addition, openid, profile, and email scopes have been set to required and will always be present.package.json.jose to v5jose to v5@backstage/plugin-auth-backend-module-oidc-provider module package to house oidc auth provider migration.repository field in package.json.passport to ^0.7.0.repository field in package.json.@backstage/plugin-auth-backend-module-oidc-provider module package to house oidc auth provider migration.passport to ^0.7.0.express from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0@davidzemon/passport-okta-oauth to ^0.0.7.@davidzemon/passport-okta-oauth to ^0.0.7.@davidzemon/passport-okta-oauth to ^0.0.6.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.README.mdREADME.mdauth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
supertest to ^7.0.0.supertest to ^7.0.0.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
signIn to authentication provider configuration schemasignIn to authentication provider configuration schemaBackendFeature contract change.additionalScopes configuration, which means it can now also be specified as an array. In addition, the openid, email, profile, and offline_access scopes have been set to required and will always be present.package.json.additionalScopes configuration, which means it can now also be specified as an array. In addition, the openid, email, profile, and offline_access scopes have been set to required and will always be present.package.json.additionalScopes option to configuration schema.repository field in package.json.repository field in package.json.additionalScopes option to configuration schema.passport to ^0.7.0.passport to ^0.7.0.express from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.dangerouslyAllowSignInWithoutUserInCatalog auth resolver config.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.allowedDomains option for the emailLocalPartMatchingUserEntityName sign-in resolver.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
supertest to ^7.0.0.supertest to ^7.0.0.d425fc4: BREAKING: The return values from createBackendPlugin, createBackendModule, and createServiceFactory are now simply BackendFeature and ServiceFactory, instead of the previously deprecated form of a function that returns them. For this reason, createServiceFactory also no longer accepts the callback form where you provide direct options to the service. This also affects all coreServices.* service refs.
This may in particular affect tests; if you were effectively doing createBackendModule({...})() (note the parentheses), you can now remove those extra parentheses at the end. You may encounter cases of this in your packages/backend/src/index.ts too, where you add plugins, modules, and services. If you were using createServiceFactory with a function as its argument for the purpose of passing in options, this pattern has been deprecated for a while and is no longer supported. You may want to explore the new multiton patterns to achieve your goals, or moving settings to app-config.
As part of this change, the IdentityFactoryOptions type was removed, and can no longer be used to tweak that service. The identity service was also deprecated some time ago, and you will want to migrate to the new auth system if you still rely on it.
signIn to authentication provider configuration schemasignIn to authentication provider configuration schemaBackendFeature contract change.package.json.package.json.zod-validation-error to version 4zod-to-json-schema to latest versionexpress from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.332e934: Added the identity property to BackstageSignInResult.
The prepareBackstageIdentityResponse function will now also forward the identity to the response if present in the provided sign-in result.
ab53e6f: Added a new dangerousEntityRefFallback option to the signInWithCatalogUser method in AuthResolverContext. The option will cause the provided entity reference to be used as a fallback in case the user is not found in the catalog. It is up to the caller to provide the fallback entity reference.
Auth providers that include pre-defined sign-in resolvers are encouraged to define a flag named dangerouslyAllowSignInWithoutUserInCatalog in their config, which in turn enables use of the dangerousEntityRefFallback option. For example:
export const usernameMatchingUserEntityName = createSignInResolverFactory({
optionsSchema: z
.object({
dangerouslyAllowSignInWithoutUserInCatalog: z.boolean().optional(),
})
.optional(),
create(options = {}) {
return async (
info: SignInInfo<OAuthAuthenticatorResult<PassportProfile>>,
ctx,
) => {
const { username } = info.result.fullProfile;
if (!username) {
throw new Error('User profile does not contain a username');
}
return ctx.signInWithCatalogUser(
{ entityRef: { name: username } },
{
dangerousEntityRefFallback:
options?.dangerouslyAllowSignInWithoutUserInCatalog
? { entityRef: { name: username } }
: undefined,
},
);
};
},
});
Updated dependencies
ab53e6f: Added a new dangerousEntityRefFallback option to the signInWithCatalogUser method in AuthResolverContext. The option will cause the provided entity reference to be used as a fallback in case the user is not found in the catalog. It is up to the caller to provide the fallback entity reference.
Auth providers that include pre-defined sign-in resolvers are encouraged to define a flag named dangerouslyAllowSignInWithoutUserInCatalog in their config, which in turn enables use of the dangerousEntityRefFallback option. For example:
export const usernameMatchingUserEntityName = createSignInResolverFactory({
optionsSchema: z
.object({
dangerouslyAllowSignInWithoutUserInCatalog: z.boolean().optional(),
})
.optional(),
create(options = {}) {
return async (
info: SignInInfo<OAuthAuthenticatorResult<PassportProfile>>,
ctx,
) => {
const { username } = info.result.fullProfile;
if (!username) {
throw new Error('User profile does not contain a username');
}
return ctx.signInWithCatalogUser(
{ entityRef: { name: username } },
{
dangerousEntityRefFallback:
options?.dangerouslyAllowSignInWithoutUserInCatalog
? { entityRef: { name: username } }
: undefined,
},
);
};
},
});
Updated dependencies
332e934: Added the identity property to BackstageSignInResult.
The prepareBackstageIdentityResponse function will now also forward the identity to the response if present in the provided sign-in result.
Updated dependencies
AuthResolverContext.resolveOwnershipEntityRefs as a way of accessing the default ownership resolution logic in sign-in resolvers, replacing getDefaultOwnershipEntityRefs from @backstage/plugin-auth-backend.AuthResolverContext.resolveOwnershipEntityRefs as a way of accessing the default ownership resolution logic in sign-in resolvers, replacing getDefaultOwnershipEntityRefs from @backstage/plugin-auth-backend.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.error handler to the strategy to reject the executeRedirectStrategyscopeAlreadyGranted property to OAuthAuthenticatorRefreshInput, signaling to the provider whether the requested scope has already been granted when persisting session scope.auth.providers.<providerId>.sessionDuration config for auth providers to allow the lifespan of user sessions to be configured.PluginDatabaseManager and PluginEndpointDiscovery and replace with their equivalent service typesPluginDatabaseManager and PluginEndpointDiscovery and replace with their equivalent service types@types/express version range from * to ^4.17.6.@types/express version range from * to ^4.17.6.allowedDomains option for the common emailLocalPartMatchingUserEntityName sign-in resolver.enableExperimentalRedirectFlow config. If an error is caught during authentication, the user is redirected back to app origin with error query parameter containing the error message.allowedDomains option for the common emailLocalPartMatchingUserEntityName sign-in resolver.PassportOAuthAuthenticatorHelper.authenticate method.supertest to ^7.0.0.emailMatchingUserEntityProfileEmail sign-in resolver will now also try matching emails with plus addressing removed.PassportOAuthAuthenticatorHelper.authenticate method.supertest to ^7.0.0..signIn.resolvers now take precedence over sign-in resolvers passed to signInResolver option of createOAuthProviderFactory. This effectively makes sign-in resolvers passed via the signInResolver the default one, which you can then override through configuration..signIn.resolvers now take precedence over sign-in resolvers passed to signInResolver option of createOAuthProviderFactory. This effectively makes sign-in resolvers passed via the signInResolver the default one, which you can then override through configuration.798ec37: Updated scope management for OAuth providers, where the createOAuthAuthenticator now accepts a new collection of scopes options:
scopes.persist - Whether scopes should be persisted, replaces the shouldPersistScopes option.scopes.required - A list of required scopes that will always be requested.scopes.transform - A function that can be used to transform the scopes before they are requested.The createOAuthProviderFactory has also received a new additionalScopes option, and will also read additionalScopes from the auth provider configuration. Both of these can be used to add additional scopes that should always be requested.
A significant change under the hood that this new scope management brings is that providers that persist scopes will now always merge the already granted scopes with the requested ones. The previous behavior was that the full authorization flow would not include existing scopes, while the refresh flow would only include the existing scopes.
d44a20a: Added additional plugin metadata to package.json.
Updated dependencies
798ec37: Updated scope management for OAuth providers, where the createOAuthAuthenticator now accepts a new collection of scopes options:
scopes.persist - Whether scopes should be persisted, replaces the shouldPersistScopes option.scopes.required - A list of required scopes that will always be requested.scopes.transform - A function that can be used to transform the scopes before they are requested.The createOAuthProviderFactory has also received a new additionalScopes option, and will also read additionalScopes from the auth provider configuration. Both of these can be used to add additional scopes that should always be requested.
A significant change under the hood that this new scope management brings is that providers that persist scopes will now always merge the already granted scopes with the requested ones. The previous behavior was that the full authorization flow would not include existing scopes, while the refresh flow would only include the existing scopes.
d44a20a: Added additional plugin metadata to package.json.
Updated dependencies
AuthOwnershipResolutionExtensionPointAuthOwnershipResolutionExtensionPointtokenTypes export with constants for various Backstage token types.tokenTypes export with constants for various Backstage token types.User when using findCatalogUser with a filter query, unless an explicit kind filter is provided.getBearerTokenFromAuthorizationHeader function, which is being replaced by the new HttpAuthService.jose to v5uuid to ^9.0.0.
Updated dependency @types/uuid to ^9.0.0.providerInfo not being set properly for some proxy providers, by making providerInfo an explicit optional return from authenticategetBearerTokenFromAuthorizationHeader function, which is being replaced by the new HttpAuthService.jose to v5uuid to ^9.0.0.
Updated dependency @types/uuid to ^9.0.0.providerInfo not being set properly for some proxy providers, by making providerInfo an explicit optional return from authenticatedefaultProfileTransform) are requested without the profile scope.makeProfileInfo and PassportHelpers.transformProfile
were refactored to use the jose library.makeProfileInfo and PassportHelpers.transformProfile
were refactored to use the jose library.passport to ^0.7.0.passport to ^0.7.0.ProxyAuthenticator.initialize() method is no longer async to match the way the OAuth equivalent is implemented.ProxyAuthenticator.initialize() method is no longer async to match the way the OAuth equivalent is implemented.8513cd7d00e3: Introduced a new system for building auth providers for @backstage/plugin-auth-backend, which both increases the amount of code re-use across providers, and also works better with the new backend system.
Many existing types have been moved from @backstage/plugin-auth-backend in order to avoid a direct dependency on the plugin from modules.
Auth provider integrations are now primarily implemented through a pattern of creating "authenticators", which are in turn specific to each kind of integrations. Initially there are two types: createOAuthAuthenticator and createProxyAuthenticator. These come paired with functions that let you create the corresponding route handlers, createOAuthRouteHandlers and createProxyAuthRouteHandlers, as well as provider factories, createOAuthProviderFactory and createProxyAuthProviderFactory. This new authenticator pattern allows the sign-in logic to be separated from the auth integration logic, allowing it to be completely re-used across all providers of the same kind.
The new provider factories also implement a new declarative way to configure sign-in resolvers, rather than configuration through code. Sign-in resolvers can now be configured through the resolvers configuration key, where the first resolver that provides an identity will be used, for example:
auth:
providers:
google:
development:
clientId: ...
clientSecret: ...
signIn:
resolvers:
- resolver: emailMatchingUserEntityAnnotation
- resolver: emailLocalPartMatchingUserEntityName
These configurable resolvers are created with a new createSignInResolverFactory function, which creates a sign-in resolver factory, optionally with an options schema that will be used both when configuring the sign-in resolver through configuration and code.
The internal helpers from @backstage/plugin-auth-backend that were used to implement auth providers using passport strategies have now also been made available as public API, through PassportHelpers and PassportOAuthAuthenticatorHelper.
BackstageIdentityResponse interface now has an optional expiresInSeconds field that can be used to signal session expiration. The prepareBackstageIdentityResponse utility will now also read the expiration from the provided token, and include it in the response.8513cd7d00e3: Introduced a new system for building auth providers for @backstage/plugin-auth-backend, which both increases the amount of code re-use across providers, and also works better with the new backend system.
Many existing types have been moved from @backstage/plugin-auth-backend in order to avoid a direct dependency on the plugin from modules.
Auth provider integrations are now primarily implemented through a pattern of creating "authenticators", which are in turn specific to each kind of integrations. Initially there are two types: createOAuthAuthenticator and createProxyAuthenticator. These come paired with functions that let you create the corresponding route handlers, createOAuthRouteHandlers and createProxyAuthRouteHandlers, as well as provider factories, createOAuthProviderFactory and createProxyAuthProviderFactory. This new authenticator pattern allows the sign-in logic to be separated from the auth integration logic, allowing it to be completely re-used across all providers of the same kind.
The new provider factories also implement a new declarative way to configure sign-in resolvers, rather than configuration through code. Sign-in resolvers can now be configured through the resolvers configuration key, where the first resolver that provides an identity will be used, for example:
auth:
providers:
google:
development:
clientId: ...
clientSecret: ...
signIn:
resolvers:
- resolver: emailMatchingUserEntityAnnotation
- resolver: emailLocalPartMatchingUserEntityName
These configurable resolvers are created with a new createSignInResolverFactory function, which creates a sign-in resolver factory, optionally with an options schema that will be used both when configuring the sign-in resolver through configuration and code.
The internal helpers from @backstage/plugin-auth-backend that were used to implement auth providers using passport strategies have now also been made available as public API, through PassportHelpers and PassportOAuthAuthenticatorHelper.
BackstageIdentityResponse interface now has an optional expiresInSeconds field that can be used to signal session expiration. The prepareBackstageIdentityResponse utility will now also read the expiration from the provided token, and include it in the response.msw to ^1.0.0.msw to ^1.0.0.msw to ^0.49.0.msw to ^0.49.0.getIdentity throws an AuthenticationError instead of a NotAllowed error when authentication failsIdentityClient is now deprecated. Please migrate to IdentityApi and DefaultIdentityClient instead. The authenticate function on DefaultIdentityClient is also deprecated. Please use getIdentity instead.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.IdentityClient is now deprecated. Please migrate to IdentityApi and DefaultIdentityClient instead. The authenticate function on DefaultIdentityClient is also deprecated. Please use getIdentity instead.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.43.0.msw to ^0.44.0.msw to ^0.43.0.msw to ^0.41.0.msw to ^0.41.0.jose 4.6.0jose 4.6.0id and entity fields from BackstageSignInResult.id and entity fields from BackstageSignInResult.node-fetch to version 2.6.7 and cross-fetch to version 3.1.5backstage.role to package.json05aac34: Migrated DeleteEntityDialog and EntityOrphanWarning components to Backstage UI.
The deleteEntity.description translation key no longer includes "Click here to delete" text. A new deleteEntity.actionButtonTitle key was added for the action button.
0e9578d: Migrated UnregisterEntityDialog from Material UI to Backstage UI components.
e8258d0: BREAKING: Removed the 'summary' entity card type from EntityCardType. Users should migrate to using 'content' or 'info' card types instead.
TypeScript will now show errors if you try to use type: 'summary' when creating entity cards.
@modelcontextprotocol/sdk from 1.24.3 to 1.25.2@modelcontextprotocol/sdk from 1.24.3 to 1.25.2@cfworker/json-schema as a dependency to this package part of the @modelcontextprotocol/sdk bump as it's required in the typesexpress from 4.21.2 to 4.22.0@cfworker/json-schema as a dependency to this package part of the @modelcontextprotocol/sdk bump as it's required in the typesexpress from 4.21.2 to 4.22.0erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility.erasableSyntaxOnly setting. This internal refactoring maintains all existing functionality while ensuring TypeScript compilation compatibility./.well-known/oauth-authorization-server to /.well-known/openid-configuration on auth-backend when auth.experimentalDynamicClientRegistration.enabled is enabled.isError: true.
The error message can be useful for an LLM to understand and maybe give back to the user.
Previously all errors where thrown out to @modelcontextprotocol/sdk which causes a generic 500./.well-known/oauth-authorization-server to /.well-known/openid-configuration on auth-backend when auth.experimentalDynamicClientRegistration.enabled is enabled.isError: true.
The error message can be useful for an LLM to understand and maybe give back to the user.
Previously all errors where thrown out to @modelcontextprotocol/sdk which causes a generic 500.mcp-actions backendexpress from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0PermissionClient to exhaust the request body size limit too quickly when making many requests.PermissionClient to exhaust the request body size limit too quickly when making many requests./authorize endpoint when a resourceRef is provided alongside a basic permission. Additionally, introduced a clearer error message for cases where users attempt to directly evaluate conditional permissions.@types/express version range from * to ^4.17.6.@types/express version range from * to ^4.17.6./alpha export is now also available via the main entry point, which means that you can remove the /alpha suffix from the import.BackendFeature, not a function that returns a feature.supertest to ^7.0.0.createRouter and its router options in favour of the new backend system.supertest to ^7.0.0.BackendFeature, not a function that returns a feature.createRouter and its router options in favour of the new backend system.ed10fd2: The PermissionPolicy interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the handle method is now of the new PolicyQueryUser type. This type maintains the old fields from the BackstageIdentityResponse, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information:
credentials - A BackstageCredentials object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated token field. See the Auth Service documentation for information about how to create a token using these credentials.info - A BackstageUserInfo object, which contains the same information as the deprecated identity, except for the type field that was redundant.Most existing policies can be updated by replacing the BackstageIdentityResponse type with PolicyQueryUser, which is exported from @backstage/plugin-permission-node, as well as replacing any occurrences of user?.identity with user?.info.
Updated dependencies
BackendFeature contract change.package.json.package.json.LoggerServicePermissionIntegrationClientPermissionIntegrationClientPermissionIntegrationClient4467036: Allow unauthenticated access to health check endpoint.
9802004: Migrated to use the new auth services introduced in BEP-0003.
The createRouter function now accepts auth, httpAuth and userInfo options. Theses are used internally to support the new backend system, and can be ignored.
Updated dependencies
9802004: Migrated to use the new auth services introduced in BEP-0003.
The createRouter function now accepts auth, httpAuth and userInfo options. Theses are used internally to support the new backend system, and can be ignored.
Updated dependencies
71114ac50e02: The export for the new backend system has been moved to be the default export.
For example, if you are currently importing the plugin using the following pattern:
import { examplePlugin } from '@backstage/plugin-example-backend';
backend.add(examplePlugin);
It should be migrated to this:
backend.add(import('@backstage/plugin-example-backend'));
a8a614ba0d07: Minor package.json update.
84ad6fccd4d5: Moved permissionModuleAllowAllPolicy to @backstage/plugin-permission-backend-module-allow-all-policy
Updated dependencies
71114ac50e02: The export for the new backend system has been moved to be the default export.
For example, if you are currently importing the plugin using the following pattern:
import { examplePlugin } from '@backstage/plugin-example-backend';
backend.add(examplePlugin);
It should be migrated to this:
backend.add(import('@backstage/plugin-example-backend'));
a8a614ba0d07: Minor package.json update.
Updated dependencies
permissionModuleAllowAllPolicy to @backstage/plugin-permission-backend-module-allow-all-policycoreServices.rootConfig instead of coreService.configcoreServices.rootConfig instead of coreService.configpermissionPlugin for use in the new backend system, along with a permissionModuleAllowAllPolicy that can be used to allow all requests.zod and zod-to-json-schema dependencies.permissionPlugin for use in the new backend system, along with a permissionModuleAllowAllPolicy that can be used to allow all requests.zod and zod-to-json-schema dependencies.msw to ^1.0.0.msw to ^1.0.0.zod dependency to a version that does not collide with other librariesmsw to ^0.49.0.zod dependency to a version that does not collide with other librariesmsw to ^0.49.0.response.json rather than response.send where appropriate, as outlined in SECURITY.mdresponse.json rather than response.send where appropriate, as outlined in SECURITY.mdmsw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.IdentityApi change to use getIdentity instead of authenticate for retrieving the logged in users identity.msw to ^0.47.0.msw to ^0.46.0.IdentityApi change to use getIdentity instead of authenticate for retrieving the logged in users identity.msw to ^0.45.0.msw to ^0.43.0.msw to ^0.44.0.msw to ^0.43.0.msw to ^0.41.0.msw to ^0.41.0.@backstage/plugin-permission-commonBasicPermission and ResourcePermission instances.@backstage/plugin-permission-commonBasicPermission and ResourcePermission instances.e2cf0662eb: Add a warning if the permission backend is used without setting permission.enabled=true.
BREAKING Permission backend's createRouter now requires a config option.
// packages/backend/src/plugins/permission.ts
...
export default async function createPlugin({
...
+ config,
}: PluginEnvironment) {
return createRouter({
...
+ config,
});
}
node-fetch to version 2.6.7 and cross-fetch to version 3.1.5backstage.role to package.jsongetBearerTokenFromAuthorizationHeader from @backstage/plugin-auth-node instead of the deprecated IdentityClient method.419ca637c0: Optimizations to the integration between the permission backend and plugin-backends using createPermissionIntegrationRouter:
getResource method accepted by createPermissionIntegrationRouter has been replaced with getResources, to allow consumers to make batch requests to upstream data stores. When /apply-conditions is called with a batch of requests, all required resources are requested in a single invocation of getResources.Plugin owners consuming createPermissionIntegrationRouter should replace the getResource method in the options with a getResources method, accepting an array of resourceRefs, and returning an array of the corresponding resources.
a036b65c2f: Updated to use the new BackstageIdentityResponse type from @backstage/plugin-auth-backend.
The BackstageIdentityResponse type is backwards compatible with the BackstageIdentity, and provides an additional identity field with the claims of the user.
Updated dependencies
zod-to-json-schema to latest versionPermissionClient to exhaust the request body size limit too quickly when making many requests.PermissionClient to throw an error when authorizing basic permissions with the permission.EXPERIMENTAL_enableBatchedRequests config enabled.PermissionClient to exhaust the request body size limit too quickly when making many requests.token option from EvaluatorRequestOptions. The PermissionsClient now has its own PermissionClientRequestOptions type that declares the token option instead.package.json.package.json.token option of the PermissionEvaluator methods is now deprecated. The options that only apply to backend implementations have been moved to PermissionsService from @backstage/backend-plugin-api instead.uuid to ^9.0.0.
Updated dependency @types/uuid to ^9.0.0.token option of the PermissionEvaluator methods is now deprecated. The options that only apply to backend implementations have been moved to PermissionsService from @backstage/backend-plugin-api instead.uuid to ^9.0.0.
Updated dependency @types/uuid to ^9.0.0.cross-fetch to ^4.0.0.zod and zod-to-json-schema dependencies.zod and zod-to-json-schema dependencies.msw to ^1.0.0.msw to ^1.0.0.zod dependency to a version that does not collide with other librariesmsw to ^0.49.0.zod dependency to a version that does not collide with other librariesmsw to ^0.49.0.PermissionClientPermissionClient46b4a72cee: BREAKING: When defining permission rules, it's now necessary to provide a ZodSchema that specifies the parameters the rule expects. This has been added to help better describe the parameters in the response of the metadata endpoint and to validate the parameters before a rule is executed.
To help with this, we have also made a change to the API of permission rules. Before, the permission rules toQuery and apply signature expected parameters to be separate arguments, like so...
createPermissionRule({
apply: (resource, foo, bar) => true,
toQuery: (foo, bar) => {},
});
The API has now changed to expect the parameters as a single object
createPermissionRule({
paramSchema: z.object({
foo: z.string().describe('Foo value to match'),
bar: z.string().describe('Bar value to match'),
}),
apply: (resource, { foo, bar }) => true,
toQuery: ({ foo, bar }) => {},
});
One final change made is to limit the possible values for a parameter to primitives and arrays of primitives.
46b4a72cee: BREAKING: When defining permission rules, it's now necessary to provide a ZodSchema that specifies the parameters the rule expects. This has been added to help better describe the parameters in the response of the metadata endpoint and to validate the parameters before a rule is executed.
To help with this, we have also made a change to the API of permission rules. Before, the permission rules toQuery and apply signature expected parameters to be separate arguments, like so...
createPermissionRule({
apply: (resource, foo, bar) => true,
toQuery: (foo, bar) => {},
});
The API has now changed to expect the parameters as a single object
createPermissionRule({
paramSchema: z.object({
foo: z.string().describe('Foo value to match'),
bar: z.string().describe('Bar value to match'),
}),
apply: (resource, { foo, bar }) => true,
toQuery: ({ foo, bar }) => {},
});
One final change made is to limit the possible values for a parameter to primitives and arrays of primitives.
@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.@types/jest.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.43.0.msw to ^0.44.0.msw to ^0.43.0.msw to ^0.41.0.msw to ^0.41.0.8012ac46a0: Add resourceType property to PermissionCondition type to allow matching them with ResourcePermission instances.
c98d271466: Refactor api types into more specific, decoupled names.
AuthorizeDecision to EvaluatePermissionResponseAuthorizeQuery to EvaluatePermissionRequestAuthorizeRequest to EvaluatePermissionRequestBatchAuthorizeResponse to EvaluatePermissionResponseBatchIdentified to IdentifiedPermissionMessagePermissionMessageBatch helper typeConditionalPolicyDecision, DefinitivePolicyDecision, and PolicyDecision types from @backstage/plugin-permission-node90754d4fa9: Removed strict validation from PermissionCriteria schemas to support backward-compatible changes.
2b07063d77: Added PermissionEvaluator, which will replace the existing PermissionAuthorizer interface. This new interface provides stronger type safety and validation by splitting PermissionAuthorizer.authorize() into two methods:
authorize(): Used when the caller requires a definitive decision.authorizeConditional(): Used when the caller can optimize the evaluation of any conditional decisions. For example, a plugin backend may want to use conditions in a database query instead of evaluating each resource in memory.8012ac46a0: Add isPermission helper method.
95284162d6: - Add more specific Permission types.
createPermission helper to infer the appropriate type for some permission input.isResourcePermission helper to refine Permissions to ResourcePermissions.2b07063d77: Added PermissionEvaluator, which will replace the existing PermissionAuthorizer interface. This new interface provides stronger type safety and validation by splitting PermissionAuthorizer.authorize() into two methods:
authorize(): Used when the caller requires a definitive decision.authorizeConditional(): Used when the caller can optimize the evaluation of any conditional decisions. For example, a plugin backend may want to use conditions in a database query instead of evaluating each resource in memory.8012ac46a0: Add resourceType property to PermissionCondition type to allow matching them with ResourcePermission instances.
c98d271466: Refactor api types into more specific, decoupled names.
AuthorizeDecision to EvaluatePermissionResponseAuthorizeQuery to EvaluatePermissionRequestAuthorizeRequest to EvaluatePermissionRequestBatchAuthorizeResponse to EvaluatePermissionResponseBatchIdentified to IdentifiedPermissionMessagePermissionMessageBatch helper typeConditionalPolicyDecision, DefinitivePolicyDecision, and PolicyDecision types from @backstage/plugin-permission-nodeisPermission helper method.Permission types.
createPermission helper to infer the appropriate type for some permission input.isResourcePermission helper to refine Permissions to ResourcePermissions.Permission type properties.PermissionCriteria now requires at least one condition in anyOf and allOf arrays. This addresses some ambiguous behavior outlined in #9280.node-fetch to version 2.6.7 and cross-fetch to version 3.1.5backstage.role to package.jsonb768259244: BREAKING: Authorize API request and response types have been updated. The existing AuthorizeRequest and AuthorizeResponse types now match the entire request and response objects for the /authorize endpoint, and new types AuthorizeQuery and AuthorizeDecision have been introduced for individual items in the request and response batches respectively.
BREAKING: PermissionClient has been updated to use the new request and response format in the latest version of @backstage/plugin-permission-backend.
b768259244: BREAKING: Authorize API request and response types have been updated. The existing AuthorizeRequest and AuthorizeResponse types now match the entire request and response objects for the /authorize endpoint, and new types AuthorizeQuery and AuthorizeDecision have been introduced for individual items in the request and response batches respectively.
BREAKING: PermissionClient has been updated to use the new request and response format in the latest version of @backstage/plugin-permission-backend.
0e8ec6d974: - Add PermissionAuthorizer interface matching PermissionClient to allow alternative implementations like the ServerPermissionClient in @backstage/plugin-permission-node.
Breaking Changes:
const { config, discovery } = options;
- const permissionClient = new PermissionClient({ discoveryApi: discovery, configApi: config });
+ const permissionClient = new PermissionClient({ discovery, config });
zod-to-json-schema to latest versionexpress from 4.21.2 to 4.22.0express from 4.21.2 to 4.22.0PermissionClient to exhaust the request body size limit too quickly when making many requests.PermissionClient to exhaust the request body size limit too quickly when making many requests.ServerPermissionClient can no longer be instantiated with a tokenManager and must instead be instantiated with an auth service. If you are still on the legacy backend system, use createLegacyAuthAdapters() from @backstage/backend-common to create a compatible auth service.PermissionResourceRef to createPermissionRule.createPermissionIntegrationRouter and related types, which has been replaced by PermissionRegistryService. For more information, including how to migrate existing plugins, see the service docs.PermissionResourceRef to createPermissionRule.createPermissionIntegrationRouter is now mutable, allowing for permissions and resources to be added after creation of the router.PermissionRuleset type that encapsulates a lookup function for permission rules, which can be created by the new PermissionsRegistryService via the getPermissionRuleset method. The createConditionTransformer and createConditionAuthorizer functions have been adapted to receive these accessors as arguments, with their older counterparts being deprecated.createPermissionResourceRef utility that encapsulates the constants and types related to a permission resource types. The createConditionExports and createPermissionRule functions have also been adapted to accept these references as arguments, deprecating their older counterparts.PermissionRuleset type that encapsulates a lookup function for permission rules, which can be created by the new PermissionsRegistryService via the getPermissionRuleset method. The createConditionTransformer and createConditionAuthorizer functions have been adapted to receive these accessors as arguments, with their older counterparts being deprecated.createPermissionResourceRef utility that encapsulates the constants and types related to a permission resource types. The createConditionExports and createPermissionRule functions have also been adapted to accept these references as arguments, deprecating their older counterparts.createPermissionIntegrationRouter is now mutable, allowing for permissions and resources to be added after creation of the router.createPermissionIntegrationRouter function now detects and prevents the exposure of duplicate permissions.createPermissionIntegrationRouter function now detects and prevents the exposure of duplicate permissions.supertest to ^7.0.0.supertest to ^7.0.0.ServerPermissionClient to match the new PermissionsService interface, where the deprecated token option has been removed and the options are now required.ed10fd2: The PermissionPolicy interface has been updated to align with the recent changes to the Backstage auth system. The second argument to the handle method is now of the new PolicyQueryUser type. This type maintains the old fields from the BackstageIdentityResponse, which are now all deprecated. Instead, two new fields have been added, which allows access to the same information:
credentials - A BackstageCredentials object, which is useful for making requests to other services on behalf of the user as part of evaluating the policy. This replaces the deprecated token field. See the Auth Service documentation for information about how to create a token using these credentials.info - A BackstageUserInfo object, which contains the same information as the deprecated identity, except for the type field that was redundant.Most existing policies can be updated by replacing the BackstageIdentityResponse type with PolicyQueryUser, which is exported from @backstage/plugin-permission-node, as well as replacing any occurrences of user?.identity with user?.info.
28b2cfb: Fix invalid cross-reference in API Reference docs
Updated dependencies
package.json.tokenManager definition from @backstage/backend-plugin-apipackage.json.tokenManager definition from @backstage/backend-plugin-apiServerPermissionClient to generate an invalid token for authorizing permissions against the permission backend.ServerPermissionClient has been migrated to implement the PermissionsService interface, now accepting the new BackstageCredentials object in addition to the token option, which is now deprecated. It now also optionally depends on the new AuthService.ServerPermissionClient has been migrated to implement the PermissionsService interface, now accepting the new BackstageCredentials object in addition to the token option, which is now deprecated. It now also optionally depends on the new AuthService.package.json update.package.json update.a788e715cfc: createPermissionIntegrationRouter now accepts rules and permissions for multiple resource types. Example:
createPermissionIntegrationRouter({
resources: [
{
resourceType: 'resourceType-1',
permissions: permissionsResourceType1,
rules: rulesResourceType1,
},
{
resourceType: 'resourceType-2',
permissions: permissionsResourceType2,
rules: rulesResourceType2,
},
],
});
Updated dependencies
a788e715cfc: createPermissionIntegrationRouter now accepts rules and permissions for multiple resource types. Example:
createPermissionIntegrationRouter({
resources: [
{
resourceType: 'resourceType-1',
permissions: permissionsResourceType1,
rules: rulesResourceType1,
},
{
resourceType: 'resourceType-2',
permissions: permissionsResourceType2,
rules: rulesResourceType2,
},
],
});
Updated dependencies
policyExtensionPoint for use in the new backend system.zod and zod-to-json-schema dependencies.policyExtensionPoint for use in the new backend system.zod and zod-to-json-schema dependencies.createPermissionIntegrationRouter API to allow getResources, resourceType and rules to be optionalmsw to ^1.0.0.createPermissionIntegrationRouter API to allow getResources, resourceType and rules to be optionalmsw to ^1.0.0.zod dependency to a version that does not collide with other librariesmsw to ^0.49.0.zod dependency to a version that does not collide with other librariesmsw to ^0.49.0.46b4a72cee: BREAKING: When defining permission rules, it's now necessary to provide a ZodSchema that specifies the parameters the rule expects. This has been added to help better describe the parameters in the response of the metadata endpoint and to validate the parameters before a rule is executed.
To help with this, we have also made a change to the API of permission rules. Before, the permission rules toQuery and apply signature expected parameters to be separate arguments, like so...
createPermissionRule({
apply: (resource, foo, bar) => true,
toQuery: (foo, bar) => {},
});
The API has now changed to expect the parameters as a single object
createPermissionRule({
paramSchema: z.object({
foo: z.string().describe('Foo value to match'),
bar: z.string().describe('Bar value to match'),
}),
apply: (resource, { foo, bar }) => true,
toQuery: ({ foo, bar }) => {},
});
One final change made is to limit the possible values for a parameter to primitives and arrays of primitives.
46b4a72cee: BREAKING: When defining permission rules, it's now necessary to provide a ZodSchema that specifies the parameters the rule expects. This has been added to help better describe the parameters in the response of the metadata endpoint and to validate the parameters before a rule is executed.
To help with this, we have also made a change to the API of permission rules. Before, the permission rules toQuery and apply signature expected parameters to be separate arguments, like so...
createPermissionRule({
apply: (resource, foo, bar) => true,
toQuery: (foo, bar) => {},
});
The API has now changed to expect the parameters as a single object
createPermissionRule({
paramSchema: z.object({
foo: z.string().describe('Foo value to match'),
bar: z.string().describe('Bar value to match'),
}),
apply: (resource, { foo, bar }) => true,
toQuery: ({ foo, bar }) => {},
});
One final change made is to limit the possible values for a parameter to primitives and arrays of primitives.
msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.47.0.msw to ^0.46.0.msw to ^0.45.0.msw to ^0.43.0.msw to ^0.44.0.msw to ^0.43.0.58426f9c0f: Added a new endpoint for aggregating permission metadata from a plugin backend: /.well-known/backstage/permissions/metadata
By default, the metadata endpoint will return information about the permission rules supported by the plugin. Plugin authors can also provide an optional permissions parameter to createPermissionIntegrationRouter. If provided, these Permission objects will be included in the metadata returned by this endpoint. The permissions parameter will eventually be required in a future breaking change.
8f7b1835df: Updated dependency msw to ^0.41.0.
Updated dependencies
msw to ^0.41.0.8012ac46a0: BREAKING: Stronger typing in PermissionPolicy 🎉.
Previously, it was entirely the responsibility of the PermissionPolicy author to only return CONDITIONAL decisions for permissions that are associated with a resource, and to return the correct kind of PermissionCondition instances inside the decision. Now, the policy authoring helpers provided in this package now ensure that the decision and permission match.
For policy authors: rename and adjust api of createConditionExports. Previously, the function returned a factory for creating conditional decisions named createPolicyDecision, which had a couple of drawbacks:
PermissionPolicy#handle for resource permissions, but there was nothing in the API that encoded this constraint.This change addresses the drawbacks above by making the following changes for policy authors:
createPolicyDecision method has been renamed to createConditionalDecision.ResourcePermission. This is expected to be the handled permission in PermissionPolicy#handle, whose type must first be narrowed using methods like isPermission and isResourcePermission:class TestPermissionPolicy implements PermissionPolicy {
async handle(
request: PolicyQuery<Permission>,
_user?: BackstageIdentityResponse,
): Promise<PolicyDecision> {
if (
// Narrow type of `request.permission` to `ResourcePermission<'catalog-entity'>
isResourcePermission(request.permission, RESOURCE_TYPE_CATALOG_ENTITY)
) {
return createCatalogConditionalDecision(
request.permission,
catalogConditions.isEntityOwner(
_user?.identity.ownershipEntityRefs ?? [],
),
);
}
return {
result: AuthorizeResult.ALLOW,
};
BREAKING: when creating PermissionRules, provide a resourceType.
export const isEntityOwner = createCatalogPermissionRule({
name: 'IS_ENTITY_OWNER',
description: 'Allow entities owned by the current user',
+ resourceType: RESOURCE_TYPE_CATALOG_ENTITY,
apply: (resource: Entity, claims: string[]) => {
if (!resource.relations) {
return false;
}
return resource.relations
.filter(relation => relation.type === RELATION_OWNED_BY)
.some(relation => claims.includes(relation.targetRef));
},
toQuery: (claims: string[]) => ({
key: 'relations.ownedBy',
values: claims,
}),
});
c98d271466: BREAKING:
PolicyAuthorizeQuery to PolicyQueryPolicyDecision, DefinitivePolicyDecision, and ConditionalPolicyDecision. These types are now exported from @backstage/plugin-permission-common322b69e46a: BREAKING: ServerPermissionClient now implements PermissionEvaluator, which moves out the capabilities for evaluating conditional decisions from authorize() to authorizeConditional() method.
PermissionCriteria schemas to support backward-compatible changes.ServerPermissionClient now implements PermissionEvaluator, which moves out the capabilities for evaluating conditional decisions from authorize() to authorizeConditional() method.8012ac46a0: BREAKING: Stronger typing in PermissionPolicy 🎉.
Previously, it was entirely the responsibility of the PermissionPolicy author to only return CONDITIONAL decisions for permissions that are associated with a resource, and to return the correct kind of PermissionCondition instances inside the decision. Now, the policy authoring helpers provided in this package now ensure that the decision and permission match.
For policy authors: rename and adjust api of createConditionExports. Previously, the function returned a factory for creating conditional decisions named createPolicyDecision, which had a couple of drawbacks:
PermissionPolicy#handle for resource permissions, but there was nothing in the API that encoded this constraint.This change addresses the drawbacks above by making the following changes for policy authors:
createPolicyDecision method has been renamed to createConditionalDecision.ResourcePermission. This is expected to be the handled permission in PermissionPolicy#handle, whose type must first be narrowed using methods like isPermission and isResourcePermission:class TestPermissionPolicy implements PermissionPolicy {
async handle(
request: PolicyQuery<Permission>,
_user?: BackstageIdentityResponse,
): Promise<PolicyDecision> {
if (
// Narrow type of `request.permission` to `ResourcePermission<'catalog-entity'>
isResourcePermission(request.permission, RESOURCE_TYPE_CATALOG_ENTITY)
) {
return createCatalogConditionalDecision(
request.permission,
catalogConditions.isEntityOwner(
_user?.identity.ownershipEntityRefs ?? [],
),
);
}
return {
result: AuthorizeResult.ALLOW,
};
BREAKING: when creating PermissionRules, provide a resourceType.
export const isEntityOwner = createCatalogPermissionRule({
name: 'IS_ENTITY_OWNER',
description: 'Allow entities owned by the current user',
+ resourceType: RESOURCE_TYPE_CATALOG_ENTITY,
apply: (resource: Entity, claims: string[]) => {
if (!resource.relations) {
return false;
}
return resource.relations
.filter(relation => relation.type === RELATION_OWNED_BY)
.some(relation => claims.includes(relation.targetRef));
},
toQuery: (claims: string[]) => ({
key: 'relations.ownedBy',
values: claims,
}),
});
c98d271466: BREAKING:
PolicyAuthorizeQuery to PolicyQueryPolicyDecision, DefinitivePolicyDecision, and ConditionalPolicyDecision. These types are now exported from @backstage/plugin-permission-common580f4e1df8: Export some utility functions for parsing PermissionCriteria
isAndCriteria, isOrCriteria, isNotCriteria are now exported.
Updated dependencies
PermissionCriteria now requires at least one condition in anyOf and allOf arrays. This addresses some ambiguous behavior outlined in #9280.backstage.role to package.jsonPolicyAuthorizeRequest type has been renamed to PolicyAuthorizeQuery.
BREAKING: Update to use renamed request and response types from @backstage/plugin-permission-common.PolicyAuthorizeRequest type has been renamed to PolicyAuthorizeQuery.
BREAKING: Update to use renamed request and response types from @backstage/plugin-permission-common.419ca637c0: Optimizations to the integration between the permission backend and plugin-backends using createPermissionIntegrationRouter:
getResource method accepted by createPermissionIntegrationRouter has been replaced with getResources, to allow consumers to make batch requests to upstream data stores. When /apply-conditions is called with a batch of requests, all required resources are requested in a single invocation of getResources.Plugin owners consuming createPermissionIntegrationRouter should replace the getResource method in the options with a getResources method, accepting an array of resourceRefs, and returning an array of the corresponding resources.
2f8a9b665f: Add ServerPermissionClient, which implements PermissionAuthorizer from @backstage/plugin-permission-common. This implementation skips authorization entirely when the supplied token is a valid backend-to-backend token, thereby allowing backend-to-backend systems to communicate without authorization.
The ServerPermissionClient should always be used over the standard PermissionClient in plugin backends.
Updated dependencies
dcd1a0c3f4: Minor improvement to the API reports, by not unpacking arguments directly
a036b65c2f: Updated to use the new BackstageIdentityResponse type from @backstage/plugin-auth-backend.
The BackstageIdentityResponse type is backwards compatible with the BackstageIdentity, and provides an additional identity field with the claims of the user.
Updated dependencies
search.defaultType option in app-config.yaml. This applies to both the legacy and new frontend systems. If not set, the default is empty, which means searching for "all" types.elasticsearchAuthExtensionPoint to enable dynamic authentication mechanisms such as bearer tokens with automatic rotation.connection.type: azure in database client to use Microsoft Entra authentication with Azure database for PostgreSQLpeerModules metadata field in package.json. This field allows plugin packages to declare modules that should be installed alongside them for cross-plugin integrations. The field is validated by backstage-cli repo fix --publish.peerModules metadata field in package.json. This field allows plugin packages to declare modules that should be installed alongside them for cross-plugin integrations. The field is validated by backstage-cli repo fix --publish.22864b7: Added an apis option to createExtensionTester, renderInTestApp, and renderTestApp to override APIs when testing extensions. Use the mockApis helpers to create mock implementations:
import { identityApiRef } from '@backstage/frontend-plugin-api';
import { mockApis } from '@backstage/frontend-test-utils';
// Override APIs in createExtensionTester
const tester = createExtensionTester(myExtension, {
apis: [
[
identityApiRef,
mockApis.identity({ userEntityRef: 'user:default/guest' }),
],
],
});
// Override APIs in renderInTestApp
renderInTestApp(<MyComponent />, {
apis: [
[
identityApiRef,
mockApis.identity({ userEntityRef: 'user:default/guest' }),
],
],
});
// Override APIs in renderTestApp
renderTestApp({
extensions: [myExtension],
apis: [
[
identityApiRef,
mockApis.identity({ userEntityRef: 'user:default/guest' }),
],
],
});
Updated dependencies
peerModules metadata declaring recommended modules for cross-plugin integrations.a88c437: Updated MUI to BUI theme converter to align with latest token changes
Changes:
--bui-fg-link, --bui-fg-link-hover, --bui-fg-tint, --bui-fg-tint-disabled, --bui-bg-tint and all its variantsinfo status tokens: --bui-fg-info, --bui-fg-info-on-bg, --bui-bg-info, --bui-border-info-on-bg variants for danger, warning, success, and info.main for standalone variants and .dark for -on-bg variants, providing better visual hierarchyThe converter now generates tokens that match the updated BUI design system structure, with clear distinction between status colors for standalone use vs. use on colored backgrounds.
Updated dependencies
peerModules metadata declaring recommended modules for cross-plugin integrations.peerModules metadata declaring recommended modules for cross-plugin integrations.gitlab:user:info scaffolder action that retrieves information about a GitLab user. The action can fetch either the current authenticated user or a specific user by ID.numberOfResults count with search query responsespeerModules metadata declaring recommended modules for cross-plugin integrations.