2020-09-04 05:59:35 -07:00
|
|
|
import { useAuth0 } from "@auth0/auth0-react";
|
Start building a login form, behind a feature flag
Thinking about longevity, I think I wanna cut Auth0 loose, and just go back to using our own auth.
I had figured at the time that I didn't want to integrate with OpenNeo ID's whole mess, and I didn't want to write a whole new auth system, so Auth0 seemed to make things easier.
But now, it's just kinda a lot to be carrying along an external service as a dependency for login, especially when we've got all the stuff in the database right here. I wanna remove architecture pieces! Get it outta here!
And I'll finally build account creation from the 2020 site while I'm at it, which seemed like it was gonna be a bit of a pain with Auth0 and syncing anyway. (I think at the time I was a bit more optimistic about a full transfer from one system to another, but that's much further off than I realized, and this path will be much better for keeping things in sync.)
2022-08-16 17:34:51 -07:00
|
|
|
import { useEffect } from "react";
|
|
|
|
import { useLocalStorage } from "../util";
|
2020-09-04 05:59:35 -07:00
|
|
|
|
|
|
|
function useCurrentUser() {
|
|
|
|
const { isLoading, isAuthenticated, user } = useAuth0();
|
|
|
|
|
2021-01-05 23:22:03 -08:00
|
|
|
// In development, you can start the server with
|
|
|
|
// `IMPRESS_LOG_IN_AS=12345 vc dev` to simulate logging in as user 12345.
|
|
|
|
//
|
|
|
|
// This flag shouldn't be present in prod anyway, but the dev check is an
|
|
|
|
// extra safety precaution!
|
|
|
|
//
|
|
|
|
// NOTE: In package.json, we forward the flag to REACT_APP_IMPRESS_LOG_IN_AS,
|
|
|
|
// because create-react-app only forwards flags with that prefix.
|
|
|
|
if (
|
|
|
|
process.env["NODE_ENV"] === "development" &&
|
|
|
|
process.env["REACT_APP_IMPRESS_LOG_IN_AS"]
|
|
|
|
) {
|
|
|
|
const id = process.env["REACT_APP_IMPRESS_LOG_IN_AS"];
|
|
|
|
return {
|
|
|
|
isLoading: false,
|
|
|
|
isLoggedIn: true,
|
|
|
|
id,
|
|
|
|
username: `<Simulated User ${id}>`,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-04-19 02:16:31 -07:00
|
|
|
// Additionally, our Cypress tests do an actual end-to-end login as a test
|
|
|
|
// user. Use that token if present!
|
|
|
|
const cypressUser = readCypressLoginData()?.decodedUser;
|
|
|
|
if (cypressUser) {
|
|
|
|
return { isLoading: false, isLoggedIn: true, ...getUserInfo(cypressUser) };
|
|
|
|
}
|
|
|
|
|
2020-09-04 05:59:35 -07:00
|
|
|
if (isLoading || !isAuthenticated) {
|
2021-01-05 23:22:03 -08:00
|
|
|
return { isLoading, isLoggedIn: false, id: null, username: null };
|
2020-09-04 05:59:35 -07:00
|
|
|
}
|
|
|
|
|
2021-04-19 02:16:31 -07:00
|
|
|
return { isLoading, isLoggedIn: true, ...getUserInfo(user) };
|
|
|
|
}
|
|
|
|
|
|
|
|
export function readCypressLoginData() {
|
|
|
|
const cypressUserJsonString = window.localStorage.getItem("auth0Cypress");
|
|
|
|
if (!cypressUserJsonString) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
return JSON.parse(cypressUserJsonString);
|
|
|
|
} catch (e) {
|
|
|
|
console.warn(
|
|
|
|
"Could not parse auth0Cypress token in localStorage; ignoring."
|
|
|
|
);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
2020-09-04 05:59:35 -07:00
|
|
|
|
2021-04-19 02:16:31 -07:00
|
|
|
function getUserInfo(user) {
|
|
|
|
return {
|
|
|
|
id: user.sub?.match(/^auth0\|impress-([0-9]+)$/)?.[1],
|
|
|
|
username: user["https://oauth.impress-2020.openneo.net/username"],
|
|
|
|
};
|
2020-09-04 05:59:35 -07:00
|
|
|
}
|
|
|
|
|
Start building a login form, behind a feature flag
Thinking about longevity, I think I wanna cut Auth0 loose, and just go back to using our own auth.
I had figured at the time that I didn't want to integrate with OpenNeo ID's whole mess, and I didn't want to write a whole new auth system, so Auth0 seemed to make things easier.
But now, it's just kinda a lot to be carrying along an external service as a dependency for login, especially when we've got all the stuff in the database right here. I wanna remove architecture pieces! Get it outta here!
And I'll finally build account creation from the 2020 site while I'm at it, which seemed like it was gonna be a bit of a pain with Auth0 and syncing anyway. (I think at the time I was a bit more optimistic about a full transfer from one system to another, but that's much further off than I realized, and this path will be much better for keeping things in sync.)
2022-08-16 17:34:51 -07:00
|
|
|
/**
|
|
|
|
* useLoginActions returns a `startLogin` function to start login with Auth0,
|
|
|
|
* and a `logout` function to logout from whatever auth mode is in use.
|
|
|
|
*
|
|
|
|
* Note that `startLogin` is only supported with the Auth0 auto mode. In db
|
|
|
|
* mode, you should open a `LoginModal` instead!
|
|
|
|
*/
|
|
|
|
export function useLoginActions() {
|
|
|
|
const {
|
|
|
|
loginWithRedirect: auth0StartLogin,
|
|
|
|
logout: auth0Logout,
|
|
|
|
} = useAuth0();
|
|
|
|
const authMode = useAuthModeFeatureFlag();
|
|
|
|
|
|
|
|
if (authMode === "auth0") {
|
|
|
|
return { startLogin: auth0StartLogin, logout: auth0Logout };
|
|
|
|
} else if (authMode === "db") {
|
|
|
|
return {
|
|
|
|
startLogin: () => {
|
|
|
|
console.error(
|
|
|
|
`Error: Cannot call startLogin in db login mode. Open a ` +
|
|
|
|
`<LoginModal /> instead.`
|
|
|
|
);
|
|
|
|
alert(
|
|
|
|
`Error: Cannot call startLogin in db login mode. Open a ` +
|
|
|
|
`<LoginModal /> instead.`
|
|
|
|
);
|
|
|
|
},
|
|
|
|
logout: () => {
|
|
|
|
alert(`TODO: logout`);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
console.error(`unexpected auth mode: ${JSON.stringify(authMode)}`);
|
|
|
|
return { startLogin: () => {}, logout: () => {} };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* useAuthModeFeatureFlag returns "auth0" by default, but "db" if you're trying
|
|
|
|
* the new db-backed login mode.
|
|
|
|
*
|
|
|
|
* To set this manually, run `window.setAuthModeFeatureFlag("db")` in your
|
|
|
|
* browser console.
|
|
|
|
*/
|
|
|
|
export function useAuthModeFeatureFlag() {
|
|
|
|
// We'll probably add a like, experimental gradual rollout thing here too.
|
|
|
|
// But for now we just check your device's local storage! (This is why we
|
|
|
|
// default to `null` instead of "auth0", I want to be unambiguous that this
|
|
|
|
// is the *absence* of a localStorage value, and not risk accidentally
|
|
|
|
// setting this override value to auth0 on everyone's devices 😅)
|
|
|
|
const [savedValue] = useLocalStorage("DTIAuthModeFeatureFlag", null);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
window.setAuthModeFeatureFlag = setAuthModeFeatureFlag;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!["auth0", "db", null].includes(savedValue)) {
|
|
|
|
console.warn(
|
|
|
|
`Unexpected DTIAuthModeFeatureFlag value: %o. Treating as null.`,
|
|
|
|
savedValue
|
|
|
|
);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return savedValue || "auth0";
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* setAuthModeFeatureFlag is mounted on the window, so you can call it from the
|
|
|
|
* browser console to set this override manually.
|
|
|
|
*/
|
|
|
|
function setAuthModeFeatureFlag(newValue) {
|
|
|
|
if (!["auth0", "db", null].includes(newValue)) {
|
|
|
|
throw new Error(`Auth mode must be "auth0", "db", or null.`);
|
|
|
|
}
|
|
|
|
|
|
|
|
localStorage.setItem("DTIAuthModeFeatureFlag", JSON.stringify(newValue));
|
|
|
|
|
|
|
|
// The useLocalStorage hook isn't *quite* good enough to catch this change.
|
|
|
|
// Let's just reload the page lmao.
|
|
|
|
window.location.reload();
|
|
|
|
}
|
|
|
|
|
2020-09-04 05:59:35 -07:00
|
|
|
export default useCurrentUser;
|