feat: TOTP (two-factor) Authentication (#55)

* Working on some initial prototype stuff for TOTP

* Fixed a bug that prevented the change password menu from working

* Enable/disable totp working

* Added the new login procedure including TOTP! :)

* misc: Changed bad description for the TOTP_SECRET env var

* I forgot to include the migration for the new prisma stuff

* fix: refresh user context instead refreshing the page

* refactor: simplify totp error handling

* Removed U2F tab + format schema

* fix: tokens not saved in cookies

* refactor: deleted commented out code

* refactor: move password text to input description

* refactor: remove tabler icon package

Co-authored-by: Elias Schneider <login@eliasschneider.com>
Co-authored-by: Elias Schneider <58886915+stonith404@users.noreply.github.com>
This commit is contained in:
Steve
2022-12-21 11:58:37 -05:00
committed by GitHub
parent 0616a68bd2
commit 16480f6e95
27 changed files with 946 additions and 127 deletions

View File

@@ -1,4 +1,4 @@
import { getCookie, setCookies } from "cookies-next";
import { getCookie, setCookie } from "cookies-next";
import * as jose from "jose";
import api from "./api.service";
@@ -11,8 +11,25 @@ const signIn = async (emailOrUsername: string, password: string) => {
...emailOrUsernameBody,
password,
});
setCookies("access_token", response.data.accessToken);
setCookies("refresh_token", response.data.refreshToken);
return response;
};
const signInTotp = async (
emailOrUsername: string,
password: string,
totp: string,
loginToken: string
) => {
const emailOrUsernameBody = emailOrUsername.includes("@")
? { email: emailOrUsername }
: { username: emailOrUsername };
const response = await api.post("auth/signIn/totp", {
...emailOrUsernameBody,
password,
totp,
loginToken,
});
return response;
};
@@ -21,8 +38,8 @@ const signUp = async (email: string, username: string, password: string) => {
};
const signOut = () => {
setCookies("access_token", null);
setCookies("refresh_token", null);
setCookie("access_token", null);
setCookie("refresh_token", null);
window.location.reload();
};
@@ -37,7 +54,7 @@ const refreshAccessToken = async () => {
const refreshToken = getCookie("refresh_token");
const response = await api.post("auth/token", { refreshToken });
setCookies("access_token", response.data.accessToken);
setCookie("access_token", response.data.accessToken);
}
} catch {
console.info("Refresh token invalid or expired");
@@ -48,10 +65,38 @@ const updatePassword = async (oldPassword: string, password: string) => {
await api.patch("/auth/password", { oldPassword, password });
};
const enableTOTP = async (password: string) => {
const { data } = await api.post("/auth/totp/enable", { password });
return {
totpAuthUrl: data.totpAuthUrl,
totpSecret: data.totpSecret,
qrCode: data.qrCode,
};
};
const verifyTOTP = async (totpCode: string, password: string) => {
await api.post("/auth/totp/verify", {
code: totpCode,
password,
});
};
const disableTOTP = async (totpCode: string, password: string) => {
await api.post("/auth/totp/disable", {
code: totpCode,
password,
});
};
export default {
signIn,
signInTotp,
signUp,
signOut,
refreshAccessToken,
updatePassword,
enableTOTP,
verifyTOTP,
disableTOTP,
};