Skip to content

Commit

Permalink
Web3auth (#8)
Browse files Browse the repository at this point in the history
* add web3auth and basic route auth guard

* add authSlice - set auth vars on login/logout
  • Loading branch information
Spencer-Sch authored Dec 5, 2023
1 parent de8a996 commit 641159b
Show file tree
Hide file tree
Showing 11 changed files with 2,176 additions and 45 deletions.
37 changes: 37 additions & 0 deletions packages/nextjs/auth/authSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { IProvider } from "@web3auth/base";

export type AuthProvider = IProvider | null;

export interface AuthRootState {
auth: {
isConnected: boolean;
provider: AuthProvider;
};
}

interface AuthState {
isConnected: boolean;
provider: AuthProvider;
}

export const authSlice = createSlice({
name: "auth",
initialState: {
isConnected: false,
provider: null as AuthProvider,
},
reducers: {
setAuthProvider: (state: AuthState, action: PayloadAction<{ provider: AuthProvider }>) => {
state.provider = action.payload.provider;
},

setIsConnected: (state: AuthState, action: PayloadAction<{ isConnected: boolean }>) => {
state.isConnected = action.payload.isConnected;
},
},
});

export const { setAuthProvider, setIsConnected } = authSlice.actions;

export default authSlice.reducer;
23 changes: 23 additions & 0 deletions packages/nextjs/auth/checkUserAuthentication.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { web3auth } from "~~/auth/web3auth";

export default function checkUserAuthentication(path: string) {
console.log("from checkUserAuthentication - Path = ", path);

const protectedRoutes = [
"/dapp/dashboard",
"/dapp/welcome",
"/dapp/leads",
"/dapp/settings-team",
"/dapp/calendar",
"/dapp/transactions",
"/dapp/settings-profile",
"/dapp/settings-billing",
"/dapp/charts",
"/dapp/integration",
];

if (!web3auth.connected && protectedRoutes.includes(path)) {
return false;
}
return true;
}
23 changes: 23 additions & 0 deletions packages/nextjs/auth/web3auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Web3Auth } from "@web3auth/modal";

export const web3auth = new Web3Auth({
clientId: "BM0SLNkhMCfIygw0Xi79dG6qbWGMN0o0mEeDjRT0dxlP3BEok9pnu5aqxCNfj2TZ9XT7sQaXm0ltuWbCQ1tsRNI", // Get your Client ID from the Web3Auth Dashboard
web3AuthNetwork: "sapphire_devnet", // Web3Auth Network
chainConfig: {
chainNamespace: "eip155",
chainId: "0x13881", // Mumbai
rpcTarget: "https://rpc.ankr.com/polygon_mumbai",
displayName: "Mumbai Testnet",
blockExplorer: "https://mumbai.polygonscan.com/",
ticker: "MATIC",
tickerName: "Polygon",
},
});

export async function web3AuthInit() {
try {
await web3auth.initModal();
} catch (error) {
console.error(error);
}
}
6 changes: 6 additions & 0 deletions packages/nextjs/components/dash-wind/app/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Reducer, ThunkAction, configureStore } from "@reduxjs/toolkit";
import { createWrapper } from "next-redux-wrapper";
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import { Action } from "redux";
import authSlice, { AuthProvider } from "~~/auth/authSlice";

interface CombinedReducer {
header: Reducer<{
Expand All @@ -31,13 +32,18 @@ interface CombinedReducer {
isLoading: boolean;
leads: never[];
}>;
auth: Reducer<{
isConnected: boolean;
provider: AuthProvider;
}>;
}

const combinedReducer: CombinedReducer = {
header: headerSlice,
rightDrawer: rightDrawerSlice,
modal: modalSlice,
lead: leadsSlice,
auth: authSlice,
};

// export default configureStore({
Expand Down
10 changes: 6 additions & 4 deletions packages/nextjs/components/dash-wind/containers/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import Bars3Icon from "@heroicons/react/24/outline/Bars3Icon";
import BellIcon from "@heroicons/react/24/outline/BellIcon";
import MoonIcon from "@heroicons/react/24/outline/MoonIcon";
import SunIcon from "@heroicons/react/24/outline/SunIcon";
import { setAuthProvider, setIsConnected } from "~~/auth/authSlice";
import { web3auth } from "~~/auth/web3auth";
// import UserIcon from "@heroicons/react/24/outline/UserIcon";
import { MyState, useMyDispatch, useMySelector } from "~~/components/dash-wind/app/store";
import { Address } from "~~/components/web-3-crew/Address";
Expand Down Expand Up @@ -38,10 +40,10 @@ function Header() {
dispatch(openRightDrawer({ header: "Notifications", bodyType: RIGHT_DRAWER_TYPES.NOTIFICATION }));
};

function logoutUser() {
if (typeof window !== "undefined") {
localStorage.clear();
}
async function logoutUser() {
await web3auth.logout();
dispatch(setAuthProvider({ provider: null }));
dispatch(setIsConnected({ isConnected: false }));
router.push("/");
}

Expand Down
29 changes: 27 additions & 2 deletions packages/nextjs/components/dash-wind/features/user/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import Link from "next/link";
import { useRouter } from "next/router";
import InputText from "../../components/Input/InputText";
import ErrorText from "../../components/Typography/ErrorText";
import { UpdateFormValues } from "../../types/FormTypes";
import LandingIntro from "./LandingIntro";
import { setAuthProvider, setIsConnected } from "~~/auth/authSlice";
import { web3auth } from "~~/auth/web3auth";
import { useMyDispatch } from "~~/components/dash-wind/app/store";

function Login() {
const INITIAL_LOGIN_OBJ = {
Expand All @@ -15,6 +19,26 @@ function Login() {
const [errorMessage, setErrorMessage] = useState("");
const [loginObj, setLoginObj] = useState(INITIAL_LOGIN_OBJ);

const router = useRouter();
const dispatch = useMyDispatch();

// Web3Auth
useEffect(() => {
const init = async () => {
try {
const web3authProvider = await web3auth.connect();
dispatch(setAuthProvider({ provider: web3authProvider }));
if (web3auth.connected) {
dispatch(setIsConnected({ isConnected: true }));
}
router.push("/dapp/dashboard");
} catch (error) {
console.error(error);
}
};
init();
});

const submitForm = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setErrorMessage("");
Expand All @@ -26,7 +50,8 @@ function Login() {
// Call API to check user credentials and save token in localstorage
localStorage.setItem("token", "DumyTokenHere");
setLoading(false);
window.location.href = "/dapp/welcome";
router.push("/dapp/welcome");
// window.location.href = "/dapp/welcome";
}
};

Expand Down
23 changes: 23 additions & 0 deletions packages/nextjs/components/web-3-crew/watchPathname.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use client";

import React, { useEffect } from "react";
import { usePathname } from "next/navigation";
import { useRouter } from "next/router";
import checkUserAuthentication from "~~/auth/checkUserAuthentication";

export default function WatchPathname() {
const pathname = usePathname();
const router = useRouter();

useEffect(() => {
console.log(`Route changed to: ${pathname}`);
if (pathname !== null) {
const userIsAuthenticated = checkUserAuthentication(pathname);
if (!userIsAuthenticated) {
router.replace("/login");
}
}
}, [pathname, router]);

return <></>;
}
2 changes: 2 additions & 0 deletions packages/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"@reduxjs/toolkit": "^1.9.7",
"@uniswap/sdk-core": "^4.0.1",
"@uniswap/v2-sdk": "^3.0.1",
"@web3auth/base": "^7.2.0",
"@web3auth/modal": "^7.2.0",
"axios": "^1.6.2",
"blo": "^1.0.1",
"chart.js": "^4.4.0",
Expand Down
17 changes: 15 additions & 2 deletions packages/nextjs/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import "@rainbow-me/rainbowkit/styles.css";
import type { NextPage } from "next";
import NextNProgress from "nextjs-progressbar";
import { Toaster } from "react-hot-toast";
// NEW
import { Provider } from "react-redux";
import { useDarkMode } from "usehooks-ts";
import { WagmiConfig } from "wagmi";
// NEW
import { web3AuthInit } from "~~/auth/web3auth";
import { wrapper } from "~~/components/dash-wind/app/store";
import { BlockieAvatar } from "~~/components/scaffold-eth";
import WatchPathname from "~~/components/web-3-crew/watchPathname";
import { useNativeCurrencyPrice } from "~~/hooks/scaffold-eth";
import { useGlobalState } from "~~/services/store/store";
import { wagmiConfig } from "~~/services/web3/wagmiConfig";
Expand Down Expand Up @@ -43,12 +43,25 @@ const ScaffoldEthApp = ({ Component, pageProps }: AppPropsWithLayout) => {
setIsDarkTheme(isDarkMode);
}, [isDarkMode]);

// Web3Auth
useEffect(() => {
const init = async () => {
try {
await web3AuthInit();
} catch (error) {
console.error(error);
}
};
init();
}, []);

const getLayout = Component.getLayout || (page => page);

const { store, props } = wrapper.useWrappedStore(pageProps);

return (
<WagmiConfig config={wagmiConfig}>
<WatchPathname />
<NextNProgress />
<RainbowKitProvider
chains={appChains.chains}
Expand Down
35 changes: 31 additions & 4 deletions packages/nextjs/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
import { ReactElement } from "react";
import Link from "next/link";
import { ReactElement, useEffect } from "react";
// import Link from "next/link";
import { useRouter } from "next/router";
import type { NextPageWithLayout } from "./_app";
import { setAuthProvider, setIsConnected } from "~~/auth/authSlice";
import { web3auth } from "~~/auth/web3auth";
import { MetaHeader } from "~~/components/MetaHeader";
import { useMyDispatch } from "~~/components/dash-wind/app/store";
import CleanLayout from "~~/components/layouts/CleanLayout";

const LandingPage: NextPageWithLayout = () => {
const router = useRouter();
const dispatch = useMyDispatch();

useEffect(() => {
dispatch(setAuthProvider({ provider: web3auth.provider }));

if (web3auth.connected) {
dispatch(setIsConnected({ isConnected: true }));
}
}, [dispatch]);

function launchDapp() {
if (web3auth.connected) {
// redirect to dashboard if logged in
router.push("/dapp/dashboard");
return;
}
// redirect to login if not connected
router.push("/login");
}
return (
<>
<MetaHeader /> {/* Look into MetaHeader - should it be moved to _app.tsx ??? */}
Expand All @@ -20,9 +44,12 @@ const LandingPage: NextPageWithLayout = () => {
<span className="block text-3xl font-bold">Web3Crew Constellation Project</span>
</h2>
</div>
<Link href="/login" className="btn btn-primary rounded-lg">
<button onClick={launchDapp} className="btn btn-primary rounded-lg">
Launch Dapp
</button>
{/* <Link href="/login" className="btn btn-primary rounded-lg">
Launch Dapp
</Link>
</Link> */}
</div>
</>
);
Expand Down
Loading

0 comments on commit 641159b

Please sign in to comment.