@backstage/plugin-auth 0.0.0-nightly-20250910023713

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 ADDED
@@ -0,0 +1,26 @@
1
+ # @backstage/plugin-auth
2
+
3
+ ## 0.0.0-nightly-20250910023713
4
+
5
+ ### Minor Changes
6
+
7
+ - 54ddfef: Initial publish of the `auth` frontend package
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @backstage/frontend-plugin-api@0.0.0-nightly-20250910023713
13
+ - @backstage/core-components@0.0.0-nightly-20250910023713
14
+ - @backstage/errors@1.2.7
15
+ - @backstage/theme@0.6.8
16
+
17
+ ## 0.1.0-next.0
18
+
19
+ ### Minor Changes
20
+
21
+ - 54ddfef: Initial publish of the `auth` frontend package
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies
26
+ - @backstage/core-components@0.17.6-next.1
package/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # @backstage/plugin-auth
2
+
3
+ A Backstage frontend plugin that provides user interface components for authentication flows, specifically for OpenID Connect (OIDC) consent management.
4
+
5
+ ## Installation
6
+
7
+ This plugin is designed to work with the `@backstage/plugin-auth-backend` package that provides OIDC provider functionality.
8
+
9
+ ```bash
10
+ # From your Backstage app directory
11
+ yarn --cwd packages/app add @backstage/plugin-auth
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ The plugin provides the route `/oauth2/authorize/:sessionId` for approving of oauth2 sessions for clients. You should see an approval flow for any sessions created through the `auth-backend`.
@@ -0,0 +1,171 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useParams } from 'react-router-dom';
3
+ import { makeStyles, Box, Card, CardContent, Typography, Divider, CardActions, Button } from '@material-ui/core';
4
+ import { Alert } from '@material-ui/lab';
5
+ import CheckCircleIcon from '@material-ui/icons/CheckCircle';
6
+ import CancelIcon from '@material-ui/icons/Cancel';
7
+ import AppsIcon from '@material-ui/icons/Apps';
8
+ import WarningIcon from '@material-ui/icons/Warning';
9
+ import { EmptyState, Progress, ResponseErrorPanel, Page, Header, Content } from '@backstage/core-components';
10
+ import { useConsentSession } from './useConsentSession.esm.js';
11
+
12
+ const useStyles = makeStyles((theme) => ({
13
+ authCard: {
14
+ maxWidth: 600,
15
+ margin: "0 auto",
16
+ marginTop: theme.spacing(4)
17
+ },
18
+ appHeader: {
19
+ display: "flex",
20
+ alignItems: "center",
21
+ marginBottom: theme.spacing(2)
22
+ },
23
+ appIcon: {
24
+ marginRight: theme.spacing(2),
25
+ fontSize: 40
26
+ },
27
+ appName: {
28
+ fontSize: "1.5rem",
29
+ fontWeight: "bold"
30
+ },
31
+ securityWarning: {
32
+ margin: theme.spacing(2, 0)
33
+ },
34
+ buttonContainer: {
35
+ display: "flex",
36
+ justifyContent: "space-between",
37
+ gap: theme.spacing(2),
38
+ padding: theme.spacing(2)
39
+ },
40
+ callbackUrl: {
41
+ fontFamily: "monospace",
42
+ backgroundColor: theme.palette.background.default,
43
+ padding: theme.spacing(1),
44
+ borderRadius: theme.shape.borderRadius,
45
+ wordBreak: "break-all",
46
+ fontSize: "0.875rem"
47
+ },
48
+ scopeList: {
49
+ backgroundColor: theme.palette.background.default,
50
+ borderRadius: theme.shape.borderRadius,
51
+ padding: theme.spacing(1)
52
+ }
53
+ }));
54
+ const ConsentPageLayout = ({
55
+ title,
56
+ children
57
+ }) => /* @__PURE__ */ jsxs(Page, { themeId: "tool", children: [
58
+ /* @__PURE__ */ jsx(Header, { title }),
59
+ /* @__PURE__ */ jsx(Content, { children })
60
+ ] });
61
+ const ConsentPage = () => {
62
+ const classes = useStyles();
63
+ const { sessionId } = useParams();
64
+ const { state, handleAction } = useConsentSession({ sessionId });
65
+ if (!sessionId) {
66
+ return /* @__PURE__ */ jsx(ConsentPageLayout, { title: "Authorization Error", children: /* @__PURE__ */ jsx(
67
+ EmptyState,
68
+ {
69
+ missing: "data",
70
+ title: "Invalid Request",
71
+ description: "The consent request ID is missing or invalid."
72
+ }
73
+ ) });
74
+ }
75
+ if (state.status === "loading") {
76
+ return /* @__PURE__ */ jsx(ConsentPageLayout, { title: "Authorization Request", children: /* @__PURE__ */ jsx(
77
+ Box,
78
+ {
79
+ display: "flex",
80
+ justifyContent: "center",
81
+ alignItems: "center",
82
+ minHeight: 300,
83
+ children: /* @__PURE__ */ jsx(Progress, {})
84
+ }
85
+ ) });
86
+ }
87
+ if (state.status === "error") {
88
+ return /* @__PURE__ */ jsx(ConsentPageLayout, { title: "Authorization Error", children: /* @__PURE__ */ jsx(ResponseErrorPanel, { error: new Error(state.error) }) });
89
+ }
90
+ if (state.status === "completed") {
91
+ return /* @__PURE__ */ jsx(ConsentPageLayout, { title: "Authorization Complete", children: /* @__PURE__ */ jsx(Card, { className: classes.authCard, children: /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsxs(Box, { textAlign: "center", children: [
92
+ state.action === "approve" ? /* @__PURE__ */ jsx(
93
+ CheckCircleIcon,
94
+ {
95
+ style: { fontSize: 64, color: "green", marginBottom: 16 }
96
+ }
97
+ ) : /* @__PURE__ */ jsx(
98
+ CancelIcon,
99
+ {
100
+ style: { fontSize: 64, color: "red", marginBottom: 16 }
101
+ }
102
+ ),
103
+ /* @__PURE__ */ jsx(Typography, { variant: "h5", gutterBottom: true, children: state.action === "approve" ? "Authorization Approved" : "Authorization Denied" }),
104
+ /* @__PURE__ */ jsx(Typography, { variant: "body1", color: "textSecondary", gutterBottom: true, children: state.action === "approve" ? "You have successfully authorized the application to access your Backstage account." : "You have denied the application access to your Backstage account." }),
105
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: "Redirecting to the application..." })
106
+ ] }) }) }) });
107
+ }
108
+ const session = state.session;
109
+ const isSubmitting = state.status === "submitting";
110
+ const appName = session.clientName ?? session.clientId;
111
+ return /* @__PURE__ */ jsx(ConsentPageLayout, { title: "Authorization Request", children: /* @__PURE__ */ jsxs(Card, { className: classes.authCard, children: [
112
+ /* @__PURE__ */ jsxs(CardContent, { children: [
113
+ /* @__PURE__ */ jsxs(Box, { className: classes.appHeader, children: [
114
+ /* @__PURE__ */ jsx(AppsIcon, { className: classes.appIcon }),
115
+ /* @__PURE__ */ jsxs(Box, { children: [
116
+ /* @__PURE__ */ jsx(Typography, { className: classes.appName, children: appName }),
117
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: "wants to access your Backstage account" })
118
+ ] })
119
+ ] }),
120
+ /* @__PURE__ */ jsx(Divider, {}),
121
+ /* @__PURE__ */ jsxs(
122
+ Alert,
123
+ {
124
+ severity: "warning",
125
+ icon: /* @__PURE__ */ jsx(WarningIcon, {}),
126
+ className: classes.securityWarning,
127
+ children: [
128
+ /* @__PURE__ */ jsxs(Typography, { variant: "body2", children: [
129
+ /* @__PURE__ */ jsx("strong", { children: "Security Notice:" }),
130
+ " By authorizing this application, you are granting it access to your Backstage account. The application will receive an access token that allows it to act on your behalf."
131
+ ] }),
132
+ /* @__PURE__ */ jsxs(Box, { mt: 1, children: [
133
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", children: /* @__PURE__ */ jsx("strong", { children: "Callback URL:" }) }),
134
+ /* @__PURE__ */ jsx(Box, { className: classes.callbackUrl, children: session.redirectUri })
135
+ ] })
136
+ ]
137
+ }
138
+ ),
139
+ /* @__PURE__ */ jsx(Box, { mt: 2, children: /* @__PURE__ */ jsx(Typography, { variant: "body2", color: "textSecondary", children: "Make sure you trust this application and recognize the callback URL above. Only authorize applications you trust." }) })
140
+ ] }),
141
+ /* @__PURE__ */ jsxs(CardActions, { className: classes.buttonContainer, children: [
142
+ /* @__PURE__ */ jsx(
143
+ Button,
144
+ {
145
+ variant: "outlined",
146
+ color: "secondary",
147
+ size: "large",
148
+ disabled: isSubmitting,
149
+ onClick: () => handleAction("reject"),
150
+ startIcon: /* @__PURE__ */ jsx(CancelIcon, {}),
151
+ children: "Cancel"
152
+ }
153
+ ),
154
+ /* @__PURE__ */ jsx(
155
+ Button,
156
+ {
157
+ variant: "contained",
158
+ color: "primary",
159
+ size: "large",
160
+ disabled: isSubmitting,
161
+ onClick: () => handleAction("approve"),
162
+ startIcon: /* @__PURE__ */ jsx(CheckCircleIcon, {}),
163
+ children: isSubmitting ? "Authorizing..." : "Authorize"
164
+ }
165
+ )
166
+ ] })
167
+ ] }) });
168
+ };
169
+
170
+ export { ConsentPage };
171
+ //# sourceMappingURL=ConsentPage.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConsentPage.esm.js","sources":["../../../src/components/ConsentPage/ConsentPage.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport { useParams } from 'react-router-dom';\n\nimport {\n Box,\n Button,\n Card,\n CardContent,\n CardActions,\n Typography,\n makeStyles,\n Divider,\n} from '@material-ui/core';\nimport { Alert } from '@material-ui/lab';\nimport CheckCircleIcon from '@material-ui/icons/CheckCircle';\nimport CancelIcon from '@material-ui/icons/Cancel';\nimport AppsIcon from '@material-ui/icons/Apps';\nimport WarningIcon from '@material-ui/icons/Warning';\nimport {\n Header,\n Page,\n Content,\n Progress,\n EmptyState,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport { useConsentSession } from './useConsentSession';\n\nconst useStyles = makeStyles(theme => ({\n authCard: {\n maxWidth: 600,\n margin: '0 auto',\n marginTop: theme.spacing(4),\n },\n appHeader: {\n display: 'flex',\n alignItems: 'center',\n marginBottom: theme.spacing(2),\n },\n appIcon: {\n marginRight: theme.spacing(2),\n fontSize: 40,\n },\n appName: {\n fontSize: '1.5rem',\n fontWeight: 'bold',\n },\n securityWarning: {\n margin: theme.spacing(2, 0),\n },\n buttonContainer: {\n display: 'flex',\n justifyContent: 'space-between',\n gap: theme.spacing(2),\n padding: theme.spacing(2),\n },\n callbackUrl: {\n fontFamily: 'monospace',\n backgroundColor: theme.palette.background.default,\n padding: theme.spacing(1),\n borderRadius: theme.shape.borderRadius,\n wordBreak: 'break-all',\n fontSize: '0.875rem',\n },\n scopeList: {\n backgroundColor: theme.palette.background.default,\n borderRadius: theme.shape.borderRadius,\n padding: theme.spacing(1),\n },\n}));\n\nconst ConsentPageLayout = ({\n title,\n children,\n}: {\n title: string;\n children: React.ReactNode;\n}) => (\n <Page themeId=\"tool\">\n <Header title={title} />\n <Content>{children}</Content>\n </Page>\n);\n\nexport const ConsentPage = () => {\n const classes = useStyles();\n const { sessionId } = useParams<{ sessionId: string }>();\n const { state, handleAction } = useConsentSession({ sessionId });\n\n if (!sessionId) {\n return (\n <ConsentPageLayout title=\"Authorization Error\">\n <EmptyState\n missing=\"data\"\n title=\"Invalid Request\"\n description=\"The consent request ID is missing or invalid.\"\n />\n </ConsentPageLayout>\n );\n }\n\n if (state.status === 'loading') {\n return (\n <ConsentPageLayout title=\"Authorization Request\">\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n minHeight={300}\n >\n <Progress />\n </Box>\n </ConsentPageLayout>\n );\n }\n\n if (state.status === 'error') {\n return (\n <ConsentPageLayout title=\"Authorization Error\">\n <ResponseErrorPanel error={new Error(state.error)} />\n </ConsentPageLayout>\n );\n }\n\n if (state.status === 'completed') {\n return (\n <ConsentPageLayout title=\"Authorization Complete\">\n <Card className={classes.authCard}>\n <CardContent>\n <Box textAlign=\"center\">\n {state.action === 'approve' ? (\n <CheckCircleIcon\n style={{ fontSize: 64, color: 'green', marginBottom: 16 }}\n />\n ) : (\n <CancelIcon\n style={{ fontSize: 64, color: 'red', marginBottom: 16 }}\n />\n )}\n <Typography variant=\"h5\" gutterBottom>\n {state.action === 'approve'\n ? 'Authorization Approved'\n : 'Authorization Denied'}\n </Typography>\n <Typography variant=\"body1\" color=\"textSecondary\" gutterBottom>\n {state.action === 'approve'\n ? 'You have successfully authorized the application to access your Backstage account.'\n : 'You have denied the application access to your Backstage account.'}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n Redirecting to the application...\n </Typography>\n </Box>\n </CardContent>\n </Card>\n </ConsentPageLayout>\n );\n }\n\n const session = state.session;\n const isSubmitting = state.status === 'submitting';\n const appName = session.clientName ?? session.clientId;\n\n return (\n <ConsentPageLayout title=\"Authorization Request\">\n <Card className={classes.authCard}>\n <CardContent>\n <Box className={classes.appHeader}>\n <AppsIcon className={classes.appIcon} />\n <Box>\n <Typography className={classes.appName}>{appName}</Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n wants to access your Backstage account\n </Typography>\n </Box>\n </Box>\n\n <Divider />\n\n <Alert\n severity=\"warning\"\n icon={<WarningIcon />}\n className={classes.securityWarning}\n >\n <Typography variant=\"body2\">\n <strong>Security Notice:</strong> By authorizing this application,\n you are granting it access to your Backstage account. The\n application will receive an access token that allows it to act on\n your behalf.\n </Typography>\n <Box mt={1}>\n <Typography variant=\"body2\">\n <strong>Callback URL:</strong>\n </Typography>\n <Box className={classes.callbackUrl}>{session.redirectUri}</Box>\n </Box>\n </Alert>\n\n <Box mt={2}>\n <Typography variant=\"body2\" color=\"textSecondary\">\n Make sure you trust this application and recognize the callback\n URL above. Only authorize applications you trust.\n </Typography>\n </Box>\n </CardContent>\n\n <CardActions className={classes.buttonContainer}>\n <Button\n variant=\"outlined\"\n color=\"secondary\"\n size=\"large\"\n disabled={isSubmitting}\n onClick={() => handleAction('reject')}\n startIcon={<CancelIcon />}\n >\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n color=\"primary\"\n size=\"large\"\n disabled={isSubmitting}\n onClick={() => handleAction('approve')}\n startIcon={<CheckCircleIcon />}\n >\n {isSubmitting ? 'Authorizing...' : 'Authorize'}\n </Button>\n </CardActions>\n </Card>\n </ConsentPageLayout>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ import { useApi, alertApiRef, fetchApiRef, discoveryApiRef } from '@backstage/frontend-plugin-api';
2
+ import { useCallback } from 'react';
3
+ import useAsync from 'react-use/esm/useAsync';
4
+ import useAsyncFn from 'react-use/esm/useAsyncFn';
5
+ import { isError } from '@backstage/errors';
6
+
7
+ const useConsentSession = (opts) => {
8
+ const alertApi = useApi(alertApiRef);
9
+ const fetchApi = useApi(fetchApiRef);
10
+ const discoveryApi = useApi(discoveryApiRef);
11
+ const { sessionId } = opts;
12
+ const sessionState = useAsync(async () => {
13
+ if (!sessionId) {
14
+ throw new Error("Session ID is missing");
15
+ }
16
+ const baseUrl = await discoveryApi.getBaseUrl("auth");
17
+ const response = await fetchApi.fetch(
18
+ `${baseUrl}/v1/sessions/${sessionId}`
19
+ );
20
+ if (!response.ok) {
21
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
22
+ }
23
+ return await response.json();
24
+ }, [sessionId]);
25
+ const [actionState, handleActionInternal] = useAsyncFn(
26
+ async (action, session) => {
27
+ const baseUrl = await discoveryApi.getBaseUrl("auth");
28
+ const response = await fetchApi.fetch(
29
+ `${baseUrl}/v1/sessions/${session.id}/${action}`,
30
+ {
31
+ method: "POST",
32
+ headers: {
33
+ "Content-Type": "application/json"
34
+ }
35
+ }
36
+ );
37
+ if (!response.ok) {
38
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
39
+ }
40
+ const result = await response.json();
41
+ if (result.redirectUrl) {
42
+ window.location.href = result.redirectUrl;
43
+ }
44
+ return { action, redirectUrl: result.redirectUrl };
45
+ },
46
+ [discoveryApi, fetchApi]
47
+ );
48
+ const getConsentState = () => {
49
+ if (actionState.value) {
50
+ return { status: "completed", action: actionState.value.action };
51
+ }
52
+ if (actionState.loading && sessionState.value) {
53
+ return {
54
+ status: "submitting",
55
+ session: sessionState.value,
56
+ action: "approve"
57
+ // This will be set properly when called
58
+ };
59
+ }
60
+ if (sessionState.error) {
61
+ return {
62
+ status: "error",
63
+ error: isError(sessionState.error) ? sessionState.error.message : "Failed to load consent request"
64
+ };
65
+ }
66
+ if (sessionState.value) {
67
+ return { status: "loaded", session: sessionState.value };
68
+ }
69
+ return { status: "loading" };
70
+ };
71
+ const state = getConsentState();
72
+ return {
73
+ state,
74
+ handleAction: useCallback(
75
+ async (action) => {
76
+ if (state.status !== "loaded") return;
77
+ try {
78
+ await handleActionInternal(action, state.session);
79
+ } catch (err) {
80
+ alertApi.post({
81
+ message: isError(err) ? err.message : `Failed to ${action} consent`,
82
+ severity: "error"
83
+ });
84
+ }
85
+ },
86
+ [state, handleActionInternal, alertApi]
87
+ )
88
+ };
89
+ };
90
+
91
+ export { useConsentSession };
92
+ //# sourceMappingURL=useConsentSession.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConsentSession.esm.js","sources":["../../../src/components/ConsentPage/useConsentSession.ts"],"sourcesContent":["/*\n * Copyright 2025 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 useApi,\n alertApiRef,\n fetchApiRef,\n discoveryApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { useCallback } from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport useAsyncFn from 'react-use/esm/useAsyncFn';\nimport { isError } from '@backstage/errors';\n\ninterface Session {\n id: string;\n clientName?: string;\n clientId: string;\n redirectUri: string;\n scopes?: string[];\n responseType?: string;\n state?: string;\n nonce?: string;\n codeChallenge?: string;\n codeChallengeMethod?: string;\n expiresAt?: string;\n}\n\ntype ConsentState =\n | { status: 'loading' }\n | { status: 'error'; error: string }\n | { status: 'loaded'; session: Session }\n | { status: 'submitting'; session: Session; action: 'approve' | 'reject' }\n | { status: 'completed'; action: 'approve' | 'reject' };\n\nexport const useConsentSession = (opts: { sessionId?: string }) => {\n const alertApi = useApi(alertApiRef);\n const fetchApi = useApi(fetchApiRef);\n const discoveryApi = useApi(discoveryApiRef);\n const { sessionId } = opts;\n\n const sessionState = useAsync(async () => {\n if (!sessionId) {\n throw new Error('Session ID is missing');\n }\n\n const baseUrl = await discoveryApi.getBaseUrl('auth');\n const response = await fetchApi.fetch(\n `${baseUrl}/v1/sessions/${sessionId}`,\n );\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as Session;\n }, [sessionId]);\n\n const [actionState, handleActionInternal] = useAsyncFn(\n async (action: 'approve' | 'reject', session: Session) => {\n const baseUrl = await discoveryApi.getBaseUrl('auth');\n const response = await fetchApi.fetch(\n `${baseUrl}/v1/sessions/${session.id}/${action}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n },\n );\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const result = await response.json();\n\n if (result.redirectUrl) {\n window.location.href = result.redirectUrl;\n }\n\n return { action, redirectUrl: result.redirectUrl };\n },\n [discoveryApi, fetchApi],\n );\n\n const getConsentState = (): ConsentState => {\n if (actionState.value) {\n return { status: 'completed', action: actionState.value.action };\n }\n if (actionState.loading && sessionState.value) {\n return {\n status: 'submitting',\n session: sessionState.value,\n action: 'approve', // This will be set properly when called\n };\n }\n if (sessionState.error) {\n return {\n status: 'error',\n error: isError(sessionState.error)\n ? sessionState.error.message\n : 'Failed to load consent request',\n };\n }\n if (sessionState.value) {\n return { status: 'loaded', session: sessionState.value };\n }\n return { status: 'loading' };\n };\n\n const state = getConsentState();\n return {\n state,\n handleAction: useCallback(\n async (action: 'approve' | 'reject') => {\n if (state.status !== 'loaded') return;\n\n try {\n await handleActionInternal(action, state.session);\n } catch (err) {\n alertApi.post({\n message: isError(err) ? err.message : `Failed to ${action} consent`,\n severity: 'error',\n });\n }\n },\n [state, handleActionInternal, alertApi],\n ),\n };\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { Routes, Route } from 'react-router-dom';
3
+ import { ConsentPage } from './ConsentPage/ConsentPage.esm.js';
4
+
5
+ const Router = () => {
6
+ return /* @__PURE__ */ jsx(Routes, { children: /* @__PURE__ */ jsx(Route, { path: "/authorize/:sessionId", element: /* @__PURE__ */ jsx(ConsentPage, {}) }) });
7
+ };
8
+
9
+ export { Router };
10
+ //# sourceMappingURL=Router.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Router.esm.js","sources":["../../src/components/Router.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport { Routes, Route } from 'react-router-dom';\nimport { ConsentPage } from './ConsentPage';\n\n/**\n * Router component for the auth plugin\n * @public\n */\nexport const Router = () => {\n return (\n <Routes>\n <Route path=\"/authorize/:sessionId\" element={<ConsentPage />} />\n </Routes>\n );\n};\n"],"names":[],"mappings":";;;;AAsBO,MAAM,SAAS,MAAM;AAC1B,EAAA,uBACE,GAAA,CAAC,MAAA,EAAA,EACC,QAAA,kBAAA,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAK,yBAAwB,OAAA,kBAAS,GAAA,CAAC,WAAA,EAAA,EAAY,CAAA,EAAI,CAAA,EAChE,CAAA;AAEJ;;;;"}
@@ -0,0 +1,29 @@
1
+ import * as react from 'react';
2
+ import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
3
+
4
+ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin<{
5
+ root: _backstage_frontend_plugin_api.RouteRef<undefined>;
6
+ }, {}, {
7
+ "page:auth": _backstage_frontend_plugin_api.ExtensionDefinition<{
8
+ kind: "page";
9
+ name: undefined;
10
+ config: {
11
+ path: string | undefined;
12
+ };
13
+ configInput: {
14
+ path?: string | undefined;
15
+ };
16
+ output: _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
17
+ optional: true;
18
+ }>;
19
+ inputs: {};
20
+ params: {
21
+ defaultPath?: [Error: `Use the 'path' param instead`];
22
+ path: string;
23
+ loader: () => Promise<JSX.Element>;
24
+ routeRef?: _backstage_frontend_plugin_api.RouteRef;
25
+ };
26
+ }>;
27
+ }>;
28
+
29
+ export { _default as default };
@@ -0,0 +1,2 @@
1
+ export { default } from './plugin.esm.js';
2
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { PageBlueprint, createFrontendPlugin } from '@backstage/frontend-plugin-api';
3
+ import { rootRouteRef } from './routes.esm.js';
4
+
5
+ const AuthPage = PageBlueprint.make({
6
+ params: {
7
+ path: "/oauth2",
8
+ routeRef: rootRouteRef,
9
+ loader: () => import('./components/Router.esm.js').then((m) => /* @__PURE__ */ jsx(m.Router, {}))
10
+ }
11
+ });
12
+ var plugin = createFrontendPlugin({
13
+ pluginId: "auth",
14
+ extensions: [AuthPage],
15
+ routes: {
16
+ root: rootRouteRef
17
+ }
18
+ });
19
+
20
+ export { AuthPage, plugin as default };
21
+ //# sourceMappingURL=plugin.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport {\n createFrontendPlugin,\n PageBlueprint,\n} from '@backstage/frontend-plugin-api';\nimport { rootRouteRef } from './routes';\n\nexport const AuthPage = PageBlueprint.make({\n params: {\n path: '/oauth2',\n routeRef: rootRouteRef,\n loader: () => import('./components/Router').then(m => <m.Router />),\n },\n});\n\nexport default createFrontendPlugin({\n pluginId: 'auth',\n extensions: [AuthPage],\n routes: {\n root: rootRouteRef,\n },\n});\n"],"names":[],"mappings":";;;;AAqBO,MAAM,QAAA,GAAW,cAAc,IAAA,CAAK;AAAA,EACzC,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM,SAAA;AAAA,IACN,QAAA,EAAU,YAAA;AAAA,IACV,MAAA,EAAQ,MAAM,OAAO,4BAAqB,CAAA,CAAE,IAAA,CAAK,CAAA,CAAA,qBAAK,GAAA,CAAC,CAAA,CAAE,MAAA,EAAF,EAAS,CAAE;AAAA;AAEtE,CAAC;AAED,aAAe,oBAAA,CAAqB;AAAA,EAClC,QAAA,EAAU,MAAA;AAAA,EACV,UAAA,EAAY,CAAC,QAAQ,CAAA;AAAA,EACrB,MAAA,EAAQ;AAAA,IACN,IAAA,EAAM;AAAA;AAEV,CAAC,CAAA;;;;"}
@@ -0,0 +1,6 @@
1
+ import { createRouteRef } from '@backstage/frontend-plugin-api';
2
+
3
+ const rootRouteRef = createRouteRef();
4
+
5
+ export { rootRouteRef };
6
+ //# sourceMappingURL=routes.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.esm.js","sources":["../src/routes.ts"],"sourcesContent":["/*\n * Copyright 2025 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 */\nimport { createRouteRef } from '@backstage/frontend-plugin-api';\n\nexport const rootRouteRef = createRouteRef();\n"],"names":[],"mappings":";;AAiBO,MAAM,eAAe,cAAA;;;;"}
package/package.json ADDED
@@ -0,0 +1,93 @@
1
+ {
2
+ "name": "@backstage/plugin-auth",
3
+ "version": "0.0.0-nightly-20250910023713",
4
+ "backstage": {
5
+ "role": "frontend-plugin",
6
+ "pluginId": "auth",
7
+ "pluginPackages": [
8
+ "@backstage/plugin-auth",
9
+ "@backstage/plugin-auth-backend",
10
+ "@backstage/plugin-auth-node",
11
+ "@backstage/plugin-auth-react"
12
+ ],
13
+ "features": {
14
+ ".": "@backstage/FrontendPlugin"
15
+ }
16
+ },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/backstage/backstage",
23
+ "directory": "plugins/auth"
24
+ },
25
+ "license": "Apache-2.0",
26
+ "sideEffects": false,
27
+ "exports": {
28
+ ".": {
29
+ "backstage": "@backstage/FrontendPlugin",
30
+ "import": "./dist/index.esm.js",
31
+ "types": "./dist/index.d.ts",
32
+ "default": "./dist/index.esm.js"
33
+ },
34
+ "./package.json": "./package.json"
35
+ },
36
+ "main": "./dist/index.esm.js",
37
+ "types": "./dist/index.d.ts",
38
+ "typesVersions": {
39
+ "*": {
40
+ "package.json": [
41
+ "package.json"
42
+ ]
43
+ }
44
+ },
45
+ "files": [
46
+ "dist"
47
+ ],
48
+ "scripts": {
49
+ "build": "backstage-cli package build",
50
+ "clean": "backstage-cli package clean",
51
+ "lint": "backstage-cli package lint",
52
+ "prepack": "backstage-cli package prepack",
53
+ "postpack": "backstage-cli package postpack",
54
+ "start": "backstage-cli package start",
55
+ "test": "backstage-cli package test"
56
+ },
57
+ "dependencies": {
58
+ "@backstage/core-components": "0.0.0-nightly-20250910023713",
59
+ "@backstage/errors": "1.2.7",
60
+ "@backstage/frontend-plugin-api": "0.0.0-nightly-20250910023713",
61
+ "@backstage/theme": "0.6.8",
62
+ "@material-ui/core": "^4.12.2",
63
+ "@material-ui/icons": "^4.9.1",
64
+ "@material-ui/lab": "4.0.0-alpha.61",
65
+ "react-use": "^17.2.4"
66
+ },
67
+ "devDependencies": {
68
+ "@backstage/cli": "0.0.0-nightly-20250910023713",
69
+ "@backstage/dev-utils": "0.0.0-nightly-20250910023713",
70
+ "@backstage/frontend-defaults": "0.0.0-nightly-20250910023713",
71
+ "@backstage/test-utils": "0.0.0-nightly-20250910023713",
72
+ "@testing-library/jest-dom": "^6.0.0",
73
+ "@testing-library/react": "^16.0.0",
74
+ "@testing-library/user-event": "^14.0.0",
75
+ "@types/react": "^18.0.0",
76
+ "msw": "^1.0.0",
77
+ "react": "^18.0.2",
78
+ "react-dom": "^18.0.2",
79
+ "react-router-dom": "^6.3.0"
80
+ },
81
+ "peerDependencies": {
82
+ "@types/react": "^17.0.0 || ^18.0.0",
83
+ "react": "^17.0.0 || ^18.0.0",
84
+ "react-dom": "^17.0.0 || ^18.0.0",
85
+ "react-router-dom": "^6.3.0"
86
+ },
87
+ "peerDependenciesMeta": {
88
+ "@types/react": {
89
+ "optional": true
90
+ }
91
+ },
92
+ "module": "./dist/index.esm.js"
93
+ }