From d9c96e85f700d9e60b145b3f1a908abbea153d46 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Tue, 4 Nov 2025 20:51:07 +0100 Subject: [PATCH] Authentication flow is functional --- matrixgw_frontend/index.html | 4 +- matrixgw_frontend/package-lock.json | 17 +++++ matrixgw_frontend/package.json | 2 + .../src/routes/auth/LoginRoute.tsx | 49 ++++++++++++- .../src/routes/auth/OIDCCbRoute.tsx | 4 +- .../src/widgets/auth/BaseLoginPage.tsx | 70 ++++++++++++++++++- 6 files changed, 140 insertions(+), 6 deletions(-) diff --git a/matrixgw_frontend/index.html b/matrixgw_frontend/index.html index 03c4e8f..5d7e649 100644 --- a/matrixgw_frontend/index.html +++ b/matrixgw_frontend/index.html @@ -2,9 +2,9 @@ - + - matrixgw_frontend + MatrixGW
diff --git a/matrixgw_frontend/package-lock.json b/matrixgw_frontend/package-lock.json index e80d450..152f32f 100644 --- a/matrixgw_frontend/package-lock.json +++ b/matrixgw_frontend/package-lock.json @@ -11,6 +11,8 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@fontsource/roboto": "^5.2.8", + "@mdi/js": "^7.4.47", + "@mdi/react": "^1.6.1", "@mui/icons-material": "^7.3.5", "@mui/material": "^7.3.5", "react": "^19.1.1", @@ -789,6 +791,21 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mdi/js": { + "version": "7.4.47", + "resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.4.47.tgz", + "integrity": "sha512-KPnNOtm5i2pMabqZxpUz7iQf+mfrYZyKCZ8QNz85czgEt7cuHcGorWfdzUMWYA0SD+a6Hn4FmJ+YhzzzjkTZrQ==", + "license": "Apache-2.0" + }, + "node_modules/@mdi/react": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@mdi/react/-/react-1.6.1.tgz", + "integrity": "sha512-4qZeDcluDFGFTWkHs86VOlHkm6gnKaMql13/gpIcUQ8kzxHgpj31NuCkD8abECVfbULJ3shc7Yt4HJ6Wu6SN4w==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.7.2" + } + }, "node_modules/@mui/core-downloads-tracker": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.5.tgz", diff --git a/matrixgw_frontend/package.json b/matrixgw_frontend/package.json index 3207e3c..823193f 100644 --- a/matrixgw_frontend/package.json +++ b/matrixgw_frontend/package.json @@ -13,6 +13,8 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@fontsource/roboto": "^5.2.8", + "@mdi/js": "^7.4.47", + "@mdi/react": "^1.6.1", "@mui/icons-material": "^7.3.5", "@mui/material": "^7.3.5", "react": "^19.1.1", diff --git a/matrixgw_frontend/src/routes/auth/LoginRoute.tsx b/matrixgw_frontend/src/routes/auth/LoginRoute.tsx index 6190120..75b9457 100644 --- a/matrixgw_frontend/src/routes/auth/LoginRoute.tsx +++ b/matrixgw_frontend/src/routes/auth/LoginRoute.tsx @@ -1,3 +1,50 @@ +import { Alert, Box, Button, CircularProgress } from "@mui/material"; +import Icon from "@mdi/react"; +import { mdiOpenid } from "@mdi/js"; +import { ServerApi } from "../../api/ServerApi"; +import React from "react"; +import { AuthApi } from "../../api/AuthApi"; + export function LoginRoute(): React.ReactElement { - return <>LoginRoute; + const [loading, setLoading] = React.useState(false); + const [error, setError] = React.useState(null); + + const authWithOpenID = async () => { + try { + setLoading(true); + + const res = await AuthApi.StartOpenIDLogin(); + window.location.href = res.url; + } catch (e) { + console.error(e); + setError("Failed to initialize OpenID login"); + } + }; + + if (loading) + return ( +
+ +
+ ); + + return ( + <> + {error && ( + + {error} + + )} + + + + + ); } diff --git a/matrixgw_frontend/src/routes/auth/OIDCCbRoute.tsx b/matrixgw_frontend/src/routes/auth/OIDCCbRoute.tsx index 90c67f8..82f80fe 100644 --- a/matrixgw_frontend/src/routes/auth/OIDCCbRoute.tsx +++ b/matrixgw_frontend/src/routes/auth/OIDCCbRoute.tsx @@ -46,8 +46,8 @@ export function OIDCCbRoute(): React.ReactElement { ); return ( - <> +
- +
); } diff --git a/matrixgw_frontend/src/widgets/auth/BaseLoginPage.tsx b/matrixgw_frontend/src/widgets/auth/BaseLoginPage.tsx index 866dd64..a6d86da 100644 --- a/matrixgw_frontend/src/widgets/auth/BaseLoginPage.tsx +++ b/matrixgw_frontend/src/widgets/auth/BaseLoginPage.tsx @@ -1,3 +1,71 @@ +import { mdiMessageTextFast } from "@mdi/js"; +import Icon from "@mdi/react"; +import { Typography } from "@mui/material"; +import MuiCard from "@mui/material/Card"; +import Stack from "@mui/material/Stack"; +import { styled } from "@mui/material/styles"; +import { Outlet } from "react-router"; + +const Card = styled(MuiCard)(({ theme }) => ({ + display: "flex", + flexDirection: "column", + alignSelf: "center", + width: "100%", + padding: theme.spacing(4), + gap: theme.spacing(2), + margin: "auto", + [theme.breakpoints.up("sm")]: { + maxWidth: "450px", + }, + boxShadow: + "hsla(220, 30%, 5%, 0.05) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.05) 0px 15px 35px -5px", + ...theme.applyStyles("dark", { + boxShadow: + "hsla(220, 30%, 5%, 0.5) 0px 5px 15px 0px, hsla(220, 25%, 10%, 0.08) 0px 15px 35px -5px", + }), +})); + +const SignInContainer = styled(Stack)(({ theme }) => ({ + height: "calc((1 - var(--template-frame-height, 0)) * 100dvh)", + minHeight: "100%", + padding: theme.spacing(2), + [theme.breakpoints.up("sm")]: { + padding: theme.spacing(4), + }, + "&::before": { + content: '""', + display: "block", + position: "absolute", + zIndex: -1, + inset: 0, + backgroundImage: + "radial-gradient(ellipse at 50% 50%, hsl(210, 100%, 97%), hsl(0, 0%, 100%))", + backgroundRepeat: "no-repeat", + ...theme.applyStyles("dark", { + backgroundImage: + "radial-gradient(at 50% 50%, hsla(210, 100%, 16%, 0.5), hsl(220, 30%, 5%))", + }), + }, +})); + export function BaseLoginPage(): React.ReactElement { - return

Todo login page route

; + return ( + + + + {" "} + MatrixGW + + + + + ); }