@backstage/core-app-api 1.17.2-next.0 → 1.18.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @backstage/core-app-api
2
2
 
3
+ ## 1.18.0-next.1
4
+
5
+ ### Minor Changes
6
+
7
+ - 5ddc0fe: if session exists and refresh fails, then create a new session if not instant popup
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @backstage/core-plugin-api@1.10.9-next.0
13
+
3
14
  ## 1.17.2-next.0
4
15
 
5
16
  ### Patch Changes
@@ -22,11 +22,13 @@ class RefreshingAuthSessionManager {
22
22
  this.helper = new SessionScopeHelper({ sessionScopes, defaultScopes });
23
23
  }
24
24
  async getSession(options) {
25
+ let alreadyTriedToRefreshSession = false;
25
26
  if (this.helper.sessionExistsAndHasScope(this.currentSession, options.scopes)) {
26
27
  const shouldRefresh = this.sessionShouldRefreshFunc(this.currentSession);
27
28
  if (!shouldRefresh) {
28
29
  return this.currentSession;
29
30
  }
31
+ alreadyTriedToRefreshSession = true;
30
32
  try {
31
33
  const refreshedSession = await this.collapsedSessionRefresh(
32
34
  options.scopes
@@ -38,18 +40,19 @@ class RefreshingAuthSessionManager {
38
40
  }
39
41
  return refreshedSession;
40
42
  } catch (error) {
43
+ this.removeLocalSession();
41
44
  if (options.optional) {
42
45
  return void 0;
43
46
  }
44
- throw error;
45
47
  }
46
48
  }
47
- if (!options.instantPopup) {
49
+ if (!alreadyTriedToRefreshSession) {
48
50
  try {
49
51
  const newSession = await this.collapsedSessionRefresh(options.scopes);
50
52
  this.currentSession = newSession;
51
53
  return this.getSession(options);
52
54
  } catch {
55
+ this.removeLocalSession();
53
56
  }
54
57
  }
55
58
  if (options.optional) {
@@ -62,6 +65,17 @@ class RefreshingAuthSessionManager {
62
65
  this.stateTracker.setIsSignedIn(true);
63
66
  return this.currentSession;
64
67
  }
68
+ /**
69
+ * Sets `undefined` to this.{@link currentSession} and tells this.{@link stateTracker}, session state tracker,
70
+ * that a user has signed out.
71
+ *
72
+ * Does not propagate session removal to the connector like {@link removeSession}().
73
+ *
74
+ */
75
+ removeLocalSession() {
76
+ this.currentSession = void 0;
77
+ this.stateTracker.setIsSignedIn(false);
78
+ }
65
79
  async removeSession() {
66
80
  this.currentSession = void 0;
67
81
  await this.connector.removeSession();
@@ -1 +1 @@
1
- {"version":3,"file":"RefreshingAuthSessionManager.esm.js","sources":["../../../src/lib/AuthSessionManager/RefreshingAuthSessionManager.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SessionManager,\n SessionScopesFunc,\n SessionShouldRefreshFunc,\n GetSessionOptions,\n} from './types';\nimport { AuthConnector } from '../AuthConnector';\nimport { SessionScopeHelper, hasScopes } from './common';\nimport { SessionStateTracker } from './SessionStateTracker';\n\ntype Options<T> = {\n /** The connector used for acting on the auth session */\n connector: AuthConnector<T>;\n /** Used to get the scope of the session */\n sessionScopes: SessionScopesFunc<T>;\n /** Used to check if the session needs to be refreshed */\n sessionShouldRefresh: SessionShouldRefreshFunc<T>;\n /** The default scopes that should always be present in a session, defaults to none. */\n defaultScopes?: Set<string>;\n};\n\n/**\n * RefreshingAuthSessionManager manages an underlying session that has\n * and expiration time and needs to be refreshed periodically.\n */\nexport class RefreshingAuthSessionManager<T> implements SessionManager<T> {\n private readonly connector: AuthConnector<T>;\n private readonly helper: SessionScopeHelper<T>;\n private readonly sessionScopesFunc: SessionScopesFunc<T>;\n private readonly sessionShouldRefreshFunc: SessionShouldRefreshFunc<T>;\n private readonly stateTracker = new SessionStateTracker();\n\n private refreshPromise?: Promise<T>;\n private currentSession: T | undefined;\n\n constructor(options: Options<T>) {\n const {\n connector,\n defaultScopes = new Set(),\n sessionScopes,\n sessionShouldRefresh,\n } = options;\n\n this.connector = connector;\n this.sessionScopesFunc = sessionScopes;\n this.sessionShouldRefreshFunc = sessionShouldRefresh;\n this.helper = new SessionScopeHelper({ sessionScopes, defaultScopes });\n }\n\n async getSession(options: GetSessionOptions): Promise<T | undefined> {\n if (\n this.helper.sessionExistsAndHasScope(this.currentSession, options.scopes)\n ) {\n const shouldRefresh = this.sessionShouldRefreshFunc(this.currentSession!);\n if (!shouldRefresh) {\n return this.currentSession!;\n }\n\n try {\n const refreshedSession = await this.collapsedSessionRefresh(\n options.scopes,\n );\n const currentScopes = this.sessionScopesFunc(this.currentSession!);\n const refreshedScopes = this.sessionScopesFunc(refreshedSession);\n if (hasScopes(refreshedScopes, currentScopes)) {\n this.currentSession = refreshedSession;\n }\n return refreshedSession;\n } catch (error) {\n if (options.optional) {\n return undefined;\n }\n throw error;\n }\n }\n\n // The user may still have a valid refresh token in their cookies. Attempt to\n // initiate a fresh session through the backend using that refresh token.\n //\n // We skip this check if an instant login popup is requested, as we need to\n // stay in a synchronous call stack from the user interaction. The downside\n // is that the user will sometimes be requested to log in even if they\n // already had an existing session.\n if (!options.instantPopup) {\n try {\n const newSession = await this.collapsedSessionRefresh(options.scopes);\n this.currentSession = newSession;\n // The session might not have the scopes requested so go back and check again\n return this.getSession(options);\n } catch {\n // If the refresh attempt fails we assume we don't have a session, so continue to create one.\n }\n }\n\n // If we continue here we will show a popup, so exit if this is an optional session request.\n if (options.optional) {\n return undefined;\n }\n\n // We can call authRequester multiple times, the returned session will contain all requested scopes.\n this.currentSession = await this.connector.createSession({\n ...options,\n scopes: this.helper.getExtendedScope(this.currentSession, options.scopes),\n });\n this.stateTracker.setIsSignedIn(true);\n return this.currentSession;\n }\n\n async removeSession() {\n this.currentSession = undefined;\n await this.connector.removeSession();\n this.stateTracker.setIsSignedIn(false);\n }\n\n sessionState$() {\n return this.stateTracker.sessionState$();\n }\n\n private async collapsedSessionRefresh(scopes?: Set<string>): Promise<T> {\n if (this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.refreshPromise = this.connector.refreshSession({\n scopes: this.helper.getExtendedScope(this.currentSession, scopes),\n });\n\n try {\n const session = await this.refreshPromise;\n if (!this.helper.sessionExistsAndHasScope(session, scopes)) {\n throw new Error(\n 'Refreshed session did not receive the required scopes',\n );\n }\n this.stateTracker.setIsSignedIn(true);\n return session;\n } finally {\n delete this.refreshPromise;\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RefreshingAuthSessionManager.esm.js","sources":["../../../src/lib/AuthSessionManager/RefreshingAuthSessionManager.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n SessionManager,\n SessionScopesFunc,\n SessionShouldRefreshFunc,\n GetSessionOptions,\n} from './types';\nimport { AuthConnector } from '../AuthConnector';\nimport { SessionScopeHelper, hasScopes } from './common';\nimport { SessionStateTracker } from './SessionStateTracker';\n\ntype Options<T> = {\n /** The connector used for acting on the auth session */\n connector: AuthConnector<T>;\n /** Used to get the scope of the session */\n sessionScopes: SessionScopesFunc<T>;\n /** Used to check if the session needs to be refreshed */\n sessionShouldRefresh: SessionShouldRefreshFunc<T>;\n /** The default scopes that should always be present in a session, defaults to none. */\n defaultScopes?: Set<string>;\n};\n\n/**\n * RefreshingAuthSessionManager manages an underlying session that has\n * and expiration time and needs to be refreshed periodically.\n */\nexport class RefreshingAuthSessionManager<T> implements SessionManager<T> {\n private readonly connector: AuthConnector<T>;\n private readonly helper: SessionScopeHelper<T>;\n private readonly sessionScopesFunc: SessionScopesFunc<T>;\n private readonly sessionShouldRefreshFunc: SessionShouldRefreshFunc<T>;\n private readonly stateTracker = new SessionStateTracker();\n\n private refreshPromise?: Promise<T>;\n private currentSession: T | undefined;\n\n constructor(options: Options<T>) {\n const {\n connector,\n defaultScopes = new Set(),\n sessionScopes,\n sessionShouldRefresh,\n } = options;\n\n this.connector = connector;\n this.sessionScopesFunc = sessionScopes;\n this.sessionShouldRefreshFunc = sessionShouldRefresh;\n this.helper = new SessionScopeHelper({ sessionScopes, defaultScopes });\n }\n\n async getSession(options: GetSessionOptions): Promise<T | undefined> {\n let alreadyTriedToRefreshSession = false;\n if (\n this.helper.sessionExistsAndHasScope(this.currentSession, options.scopes)\n ) {\n const shouldRefresh = this.sessionShouldRefreshFunc(this.currentSession!);\n if (!shouldRefresh) {\n return this.currentSession!;\n }\n\n alreadyTriedToRefreshSession = true;\n\n try {\n const refreshedSession = await this.collapsedSessionRefresh(\n options.scopes,\n );\n const currentScopes = this.sessionScopesFunc(this.currentSession!);\n const refreshedScopes = this.sessionScopesFunc(refreshedSession);\n if (hasScopes(refreshedScopes, currentScopes)) {\n this.currentSession = refreshedSession;\n }\n return refreshedSession;\n } catch (error) {\n this.removeLocalSession();\n\n if (options.optional) {\n return undefined;\n }\n // If the refresh attempt fails we assume we don't have a session, so continue to create one\n }\n }\n\n // The user may still have a valid refresh token in their cookies. Attempt to\n // initiate a fresh session through the backend using that refresh token.\n //\n // We can still try to refresh even if client requested instant popup.\n // With instant popup option, the client is responsible for providing the user login prompt modal window.\n // If control flow executes this code and client requested instant popup, it means that\n // must have clicked sign in on the login prompt. The browser allows asynchronous code to open a popup\n // if it is caused by a user interaction, clicking on a sign-in button, for example.\n if (!alreadyTriedToRefreshSession) {\n try {\n const newSession = await this.collapsedSessionRefresh(options.scopes);\n this.currentSession = newSession;\n // The session might not have the scopes requested so go back and check again\n return this.getSession(options);\n } catch {\n this.removeLocalSession();\n // If the refresh attempt fails we assume we don't have a session, so continue to create one.\n }\n }\n\n // If we continue here we will show a popup, so exit if this is an optional session request.\n if (options.optional) {\n return undefined;\n }\n\n // We can call authRequester multiple times, the returned session will contain all requested scopes.\n this.currentSession = await this.connector.createSession({\n ...options,\n scopes: this.helper.getExtendedScope(this.currentSession, options.scopes),\n });\n this.stateTracker.setIsSignedIn(true);\n return this.currentSession;\n }\n\n /**\n * Sets `undefined` to this.{@link currentSession} and tells this.{@link stateTracker}, session state tracker,\n * that a user has signed out.\n *\n * Does not propagate session removal to the connector like {@link removeSession}().\n *\n */\n removeLocalSession() {\n this.currentSession = undefined;\n this.stateTracker.setIsSignedIn(false);\n }\n\n async removeSession() {\n this.currentSession = undefined;\n await this.connector.removeSession();\n this.stateTracker.setIsSignedIn(false);\n }\n\n sessionState$() {\n return this.stateTracker.sessionState$();\n }\n\n private async collapsedSessionRefresh(scopes?: Set<string>): Promise<T> {\n if (this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.refreshPromise = this.connector.refreshSession({\n scopes: this.helper.getExtendedScope(this.currentSession, scopes),\n });\n\n try {\n const session = await this.refreshPromise;\n if (!this.helper.sessionExistsAndHasScope(session, scopes)) {\n throw new Error(\n 'Refreshed session did not receive the required scopes',\n );\n }\n this.stateTracker.setIsSignedIn(true);\n return session;\n } finally {\n delete this.refreshPromise;\n }\n }\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/core-app-api",
3
- "version": "1.17.2-next.0",
3
+ "version": "1.18.0-next.1",
4
4
  "description": "Core app API used by Backstage apps",
5
5
  "backstage": {
6
6
  "role": "web-library"
@@ -64,8 +64,8 @@
64
64
  "zod": "^3.22.4"
65
65
  },
66
66
  "devDependencies": {
67
- "@backstage/cli": "0.33.1-next.1",
68
- "@backstage/test-utils": "1.7.10-next.1",
67
+ "@backstage/cli": "0.33.1-next.2",
68
+ "@backstage/test-utils": "1.7.10-next.2",
69
69
  "@testing-library/dom": "^10.0.0",
70
70
  "@testing-library/jest-dom": "^6.0.0",
71
71
  "@testing-library/react": "^16.0.0",