frontend/app/LoginComponentNew.tsx (89 lines of code) (raw):

import React, { useState, useEffect } from "react"; import { loadInSigningKey, validateAndDecode } from "./JwtHelpers"; import { JwtData, JwtDataShape } from "./DecodedProfile"; import OAuthConfiguration from "./OAuthConfiguration"; import { VError } from "ts-interface-checker"; import LoginRefreshComponent from "./LoginRefreshComponent"; interface LoginButtonNewProps { onLoggedIn?: () => void; onLoggedOut?: () => void; onLoginValid?: (valid: boolean, jwtDataShape?: JwtDataShape) => void; } const LoginComponentNew: React.FC<LoginButtonNewProps> = (props) => { const [isLoggedIn, setIsLoggedIn] = useState<boolean>(false); const [loginData, setLoginData] = useState<JwtDataShape | null>(null); const [expired, setExpired] = useState<boolean>(false); // config const [tokenUri, setTokenUri] = useState<string>(""); const loadConfig: () => Promise<OAuthConfiguration> = async () => { const response = await fetch("/meta/oauth/config.json"); if (response.status === 200) { const data = await response.json(); const config = new OAuthConfiguration(data); //validates the configuration and throws a VError if it fails setTokenUri(config.tokenUri); return config; } else { throw `Server returned ${response.status}`; } }; const validateToken: (config: OAuthConfiguration) => Promise<void> = async ( config: OAuthConfiguration ) => { const token = window.localStorage.getItem("vaultdoor:access-token"); if (!token) return; try { const signingKey = await loadInSigningKey(); const decodedData = await validateAndDecode(token, signingKey, config.tokenSigningCertPath); const loginData = JwtData(decodedData); setLoginData(loginData); // Login valid callback if provided if (props.onLoginValid) { props.onLoginValid(true, loginData); } setIsLoggedIn(true); } catch (error: any) { // Login valid callback if provided if (props.onLoginValid) { props.onLoginValid(false); } setIsLoggedIn(false); if (error.name === "TokenExpiredError") { console.error("Token has already expired"); setExpired(true); } else { console.error("Existing login token was not valid: ", error); } } }; /** * Load in the oauth config and validate the loaded in token */ const refresh = async () => { try { const config = await loadConfig(); await validateToken(config); } catch (err) { if (err instanceof VError) { console.log("OAuth configuration was not valid: ", err); } else { console.log("Could not load oauth configuration: ", err); } } }; useEffect(() => { refresh(); }, []); return ( <> {isLoggedIn && loginData ? ( <LoginRefreshComponent loginData={loginData} onLoggedOut={props.onLoggedOut} onLoginRefreshed={() => { refresh(); }} onLoginExpired={() => { setExpired(true); setIsLoggedIn(false); }} tokenUri={tokenUri} /> ) : null} </> ); }; export default LoginComponentNew;