diff --git a/src/v2/.devcontainer/Dockerfile b/src/v2/.devcontainer/Dockerfile
index a317e41d..6c703dbd 100644
--- a/src/v2/.devcontainer/Dockerfile
+++ b/src/v2/.devcontainer/Dockerfile
@@ -3,8 +3,8 @@ FROM almalinux:latest
RUN dnf -y install \
openssh-clients \
nodejs \
- openldap-devel \
- rm -rf /var/cache/yum && \z
+ openldap-devel && \
+ rm -rf /var/cache/yum && \
npm i -g n && \
n 16
diff --git a/src/v2/client/.env b/src/v2/client/.env
new file mode 100644
index 00000000..94a970fb
--- /dev/null
+++ b/src/v2/client/.env
@@ -0,0 +1,3 @@
+BROWSER=none
+REACT_APP_AUTH_URL=https://engineering.snow.edu/aspen/auth
+REACT_APP_BASE_URL=https://localhost:44478/aspen/new
\ No newline at end of file
diff --git a/src/v2/client/package-lock.json b/src/v2/client/package-lock.json
index 8fb3396d..9dd5ecb2 100644
--- a/src/v2/client/package-lock.json
+++ b/src/v2/client/package-lock.json
@@ -22,6 +22,7 @@
"bootstrap": "^5.3.1",
"bootstrap-icons": "^1.11.1",
"eslint": "^8.50.0",
+ "oidc-client": "^1.11.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
@@ -5440,6 +5441,25 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
"node_modules/batch": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
@@ -6154,6 +6174,11 @@
"node": ">= 8"
}
},
+ "node_modules/crypto-js": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
+ "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
+ },
"node_modules/crypto-random-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
@@ -12662,6 +12687,37 @@
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
"integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="
},
+ "node_modules/oidc-client": {
+ "version": "1.11.5",
+ "resolved": "https://registry.npmjs.org/oidc-client/-/oidc-client-1.11.5.tgz",
+ "integrity": "sha512-LcKrKC8Av0m/KD/4EFmo9Sg8fSQ+WFJWBrmtWd+tZkNn3WT/sQG3REmPANE9tzzhbjW6VkTNy4xhAXCfPApAOg==",
+ "dependencies": {
+ "acorn": "^7.4.1",
+ "base64-js": "^1.5.1",
+ "core-js": "^3.8.3",
+ "crypto-js": "^4.0.0",
+ "serialize-javascript": "^4.0.0"
+ }
+ },
+ "node_modules/oidc-client/node_modules/acorn": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/oidc-client/node_modules/serialize-javascript": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
+ "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
+ "dependencies": {
+ "randombytes": "^2.1.0"
+ }
+ },
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
@@ -21656,6 +21712,11 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
+ "base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+ },
"batch": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
@@ -22178,6 +22239,11 @@
"which": "^2.0.1"
}
},
+ "crypto-js": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz",
+ "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw=="
+ },
"crypto-random-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
@@ -26879,6 +26945,33 @@
"resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
"integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="
},
+ "oidc-client": {
+ "version": "1.11.5",
+ "resolved": "https://registry.npmjs.org/oidc-client/-/oidc-client-1.11.5.tgz",
+ "integrity": "sha512-LcKrKC8Av0m/KD/4EFmo9Sg8fSQ+WFJWBrmtWd+tZkNn3WT/sQG3REmPANE9tzzhbjW6VkTNy4xhAXCfPApAOg==",
+ "requires": {
+ "acorn": "^7.4.1",
+ "base64-js": "^1.5.1",
+ "core-js": "^3.8.3",
+ "crypto-js": "^4.0.0",
+ "serialize-javascript": "^4.0.0"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
+ },
+ "serialize-javascript": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
+ "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
+ "requires": {
+ "randombytes": "^2.1.0"
+ }
+ }
+ }
+ },
"on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
diff --git a/src/v2/client/package.json b/src/v2/client/package.json
index c30ad832..4d4e529d 100644
--- a/src/v2/client/package.json
+++ b/src/v2/client/package.json
@@ -17,6 +17,7 @@
"bootstrap": "^5.3.1",
"bootstrap-icons": "^1.11.1",
"eslint": "^8.50.0",
+ "oidc-client": "^1.11.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
diff --git a/src/v2/client/src/components/LoginButton.tsx b/src/v2/client/src/components/LoginButton.tsx
new file mode 100644
index 00000000..65c88b3b
--- /dev/null
+++ b/src/v2/client/src/components/LoginButton.tsx
@@ -0,0 +1,21 @@
+import { authService } from "../services/authService";
+
+export const LoginButton = () => {
+ const loginHandler = () => {
+ authService.signinRedirect();
+ };
+ const logoutHandler = () => {
+ authService.logout();
+ };
+
+
+ return (
+ <>
+ {localStorage.getItem("LoggedInUser") === "" ? (
+
+ ) : (
+
+ )}
+ >
+ );
+};
diff --git a/src/v2/client/src/components/NavBar.tsx b/src/v2/client/src/components/NavBar.tsx
index fc2882ed..8b1f1ec2 100644
--- a/src/v2/client/src/components/NavBar.tsx
+++ b/src/v2/client/src/components/NavBar.tsx
@@ -1,4 +1,5 @@
import { Link } from "react-router-dom"
+import { LoginButton } from "./LoginButton"
export const NavBar = () => {
return (
@@ -25,7 +26,7 @@ export const NavBar = () => {
Swagger
-
+
diff --git a/src/v2/client/src/services/authService.ts b/src/v2/client/src/services/authService.ts
new file mode 100644
index 00000000..b09d46a0
--- /dev/null
+++ b/src/v2/client/src/services/authService.ts
@@ -0,0 +1,100 @@
+import { UserManager, WebStorageStateStore } from "oidc-client";
+
+const authUrl = process.env.REACT_APP_AUTH_URL
+var redirectUrl = "/landing/"
+var userManager = new UserManager({
+ userStore: new WebStorageStateStore({ store: window.localStorage }),
+ authority:
+ `${authUrl || "https://engineering.snow.edu/aspen/auth"}/realms/aspen/.well-known/openid-configuration`,
+ client_id: "aspen-web",
+ redirect_uri: window.location.origin + redirectUrl,
+ post_logout_redirect_uri: window.location.origin + "/aspen/new/",
+ silent_redirect_uri: window.location.origin + "/aspen/new/",
+ response_type: "code",
+ scope: "openid profile email",
+ loadUserInfo: true,
+ automaticSilentRenew: true,
+});
+
+userManager.startSilentRenew();
+
+export const authService = {
+
+ getUser: async () => {
+ const user = await userManager.getUser();
+ return user;
+ },
+
+ isLoggedIn: async () => {
+ const user = await userManager.getUser();
+ const loggedIn = user !== null && !user.expired;
+ return loggedIn;
+ },
+
+ signinRedirect: async () => {
+
+ const params = new URLSearchParams(window.location.search)
+ var redirectUri = window.location.pathname.replace("/aspen/new", "")
+
+ localStorage.setItem("redirectUri", redirectUri)
+ if (window.location.pathname === '/aspen/new/') {
+ localStorage.setItem("redirectUri", '/');
+ }
+ else if(redirectUri === "/TeamDetails"){
+ localStorage.setItem("redirectUri", `${redirectUri}?teamId=${params.get("teamId")}&ownerID=${params.get("ownerID")} `);
+ }
+ await userManager.signinRedirect();
+ },
+
+ signinRedirectCallback: async () => {
+ const desiredDestination = localStorage.getItem("redirectUri");
+ const tempDestination = desiredDestination?.replace('/login', '/');
+ const user = await userManager.signinRedirectCallback();
+ return { desiredDestination: tempDestination, user };
+ },
+
+ signinSilent: async () => {
+ await userManager
+ .signinSilent()
+ .then((user) => {
+ })
+ .catch((err) => {
+ });
+ },
+
+ signinSilentCallback: async () => {
+ return await userManager.signinSilentCallback();
+ },
+
+ createSigninRequest: async () => {
+ return await userManager.createSigninRequest();
+ },
+
+ logout: async () => {
+ await userManager.clearStaleState();
+ await userManager.signoutRedirect();
+ localStorage.setItem("LoggedInUser", "")
+ localStorage.setItem("LoggedInEmail", "")
+ localStorage.setItem("access_token", "")
+
+ // await userManager.signoutRedirect({
+ // id_token_hint: localStorage.getItem("id_token"),
+ // });
+ },
+
+ signoutRedirectCallback: async () => {
+ await userManager.signoutRedirectCallback().then(() => {
+ localStorage.clear();
+ window.location.replace('/');
+ });
+ await userManager.clearStaleState();
+ },
+
+}
+
+userManager.events.addSilentRenewError((e) => {
+});
+
+userManager.events.addAccessTokenExpired(() => {
+ authService.signinSilent();
+});
\ No newline at end of file