nice auth flow working with verification and stuff with token
This commit is contained in:
@@ -2,6 +2,8 @@ import { NextFunction, Request, Response } from "express";
|
|||||||
|
|
||||||
import { loadConfig } from "../config";
|
import { loadConfig } from "../config";
|
||||||
|
|
||||||
|
const jwt = require("jsonwebtoken");
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
|
|
||||||
// used by specific routes that need to authentication
|
// used by specific routes that need to authentication
|
||||||
@@ -13,16 +15,26 @@ export const authCheck = async (
|
|||||||
try {
|
try {
|
||||||
const { authorization } = req.headers;
|
const { authorization } = req.headers;
|
||||||
|
|
||||||
// verify jwt token
|
|
||||||
const jwtSecret = config.JWT_TOKEN_SECRET;
|
|
||||||
|
|
||||||
if (!authorization) {
|
if (!authorization) {
|
||||||
throw Error("No provided header");
|
throw Error("No provided header");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// verify jwt token with our api secret
|
||||||
|
var decoded: JwtClaims = jwt.verify(authorization, config.JWT_TOKEN_SECRET);
|
||||||
|
|
||||||
|
res.locals.jwtClaims = decoded;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
res.status(401).send("unauthorized");
|
res.status(401).send("unauthorized");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface JwtClaims {
|
||||||
|
userId: string;
|
||||||
|
googleUserId: string;
|
||||||
|
picture: string;
|
||||||
|
email: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,11 +27,19 @@ export default function getUserRoutes() {
|
|||||||
|
|
||||||
router.get("/login", login);
|
router.get("/login", login);
|
||||||
|
|
||||||
router.get("/authCheck", authCheck);
|
router.get("/authcheck", authCheck, handleAuthCheck);
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleAuthCheck(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
res.status(200).send();
|
||||||
|
} catch (error) {
|
||||||
|
res.status(401).send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Create user if doesn't exist
|
/** Create user if doesn't exist
|
||||||
* Returns jwt token for client and user details
|
* Returns jwt token for client and user details
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
|
import { useAuthCheck, useLogin } from "../../controller/index";
|
||||||
|
|
||||||
import { $authTokens } from "../../controller/recoil";
|
import { $authTokens } from "../../controller/recoil";
|
||||||
import Login from "../../pages/Login";
|
import Login from "../../pages/Login";
|
||||||
import NirvanaApi from "../../controller/nirvanaApi";
|
import NirvanaApi from "../../controller/nirvanaApi";
|
||||||
import { STORE_ITEMS } from "../../electron/constants";
|
import { STORE_ITEMS } from "../../electron/constants";
|
||||||
import SkeletonLoader from "../loading/skeleton";
|
import SkeletonLoader from "../loading/skeleton";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useLogin } from "../../controller/index";
|
|
||||||
import { useRecoilValue } from "recoil";
|
|
||||||
|
|
||||||
export default function ProtectedRoute({
|
export default function ProtectedRoute({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const { mutateAsync } = useLogin();
|
const { isLoading, isError, isSuccess, refetch } = useAuthCheck();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// on load of this, if we already have jwt tokens in store,
|
// on load of this, if we already have jwt tokens in store,
|
||||||
// then try using them with auth check, and if successful with simple dime call, then let them continue
|
// then try using them with auth check
|
||||||
window.electronAPI.store
|
window.electronAPI.store
|
||||||
.get(STORE_ITEMS.AUTH_SESSION_JWT)
|
.get(STORE_ITEMS.AUTH_SESSION_JWT)
|
||||||
.then((jwtToken: string) => {
|
.then((jwtToken: string) => {
|
||||||
if (jwtToken) {
|
if (jwtToken) {
|
||||||
// todo use this to do an auth check...set the necessary things to make react query run the check
|
|
||||||
// check if the jwt token is good
|
|
||||||
|
|
||||||
// then pass onto the api and such
|
|
||||||
|
|
||||||
NirvanaApi._jwtToken = jwtToken;
|
NirvanaApi._jwtToken = jwtToken;
|
||||||
|
refetch();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return <Login />;
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<div className="container h-screen w-screen flex flex-col justify-center mx-10">
|
||||||
|
<SkeletonLoader />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// if (isLoading || isIdle)
|
if (isError) {
|
||||||
// return (
|
return <Login />;
|
||||||
// <div className="container h-screen w-screen flex flex-col justify-center mx-10">
|
}
|
||||||
// <SkeletonLoader />
|
|
||||||
// </div>
|
|
||||||
// );
|
|
||||||
|
|
||||||
// if (isError) {
|
|
||||||
// return <Login />;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if we can successfully get user details, we are good to continue
|
// if we can successfully get user details, we are good to continue
|
||||||
return <>{children}</>;
|
// basic auth...any additional auth should be done at lower levels
|
||||||
|
if (isSuccess) {
|
||||||
|
return <>{children}</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Login />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import NirvanaApi, { login } from "./nirvanaApi";
|
import NirvanaApi, { authCheck, login } from "./nirvanaApi";
|
||||||
import { useMutation, useQuery } from "react-query";
|
import { useMutation, useQuery } from "react-query";
|
||||||
|
|
||||||
import { $authTokens } from "./recoil";
|
|
||||||
import { useRecoilValue } from "recoil";
|
|
||||||
|
|
||||||
// ====== QUERIES
|
// ====== QUERIES
|
||||||
|
export function useAuthCheck() {
|
||||||
|
return useQuery("AUTH_CHECK", authCheck, {
|
||||||
|
retry: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function useLogin() {
|
export function useLogin() {
|
||||||
return useMutation("LOGIN", login, {});
|
return useMutation("LOGIN", login, {});
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ export default class NirvanaApi {
|
|||||||
const fullUrl = localHost + url;
|
const fullUrl = localHost + url;
|
||||||
|
|
||||||
let res;
|
let res;
|
||||||
|
if (privateRoute && !this._jwtToken)
|
||||||
|
throw Error("No jwt token available!");
|
||||||
|
|
||||||
if (privateRoute && this._jwtToken) {
|
if (privateRoute && this._jwtToken) {
|
||||||
res = await fetch(fullUrl, {
|
res = await fetch(fullUrl, {
|
||||||
method: method,
|
method: method,
|
||||||
@@ -36,10 +39,8 @@ export default class NirvanaApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return await res.json();
|
return await res.json();
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
||||||
throw Error(error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,6 +56,6 @@ export async function login(reqLoginTokens: {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function authCheck(jwtToken: string) {
|
export async function authCheck(): Promise<void> {
|
||||||
return await NirvanaApi.fetch(`/user/authCheck`, "GET", true);
|
return await NirvanaApi.fetch(`/user/authcheck`, "GET", true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ export default function Login() {
|
|||||||
const { jwtToken, userDetails } = loginResponse;
|
const { jwtToken, userDetails } = loginResponse;
|
||||||
|
|
||||||
window.electronAPI.store.set(STORE_ITEMS.AUTH_SESSION_JWT, jwtToken);
|
window.electronAPI.store.set(STORE_ITEMS.AUTH_SESSION_JWT, jwtToken);
|
||||||
|
|
||||||
|
window.location.reload();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user