Skip to content
This repository has been archived by the owner on Dec 5, 2023. It is now read-only.

Commit

Permalink
Updates Auth
Browse files Browse the repository at this point in the history
  • Loading branch information
Yauheni committed Aug 26, 2023
1 parent 0917a1b commit f279544
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 24 deletions.
8 changes: 8 additions & 0 deletions frontend/src/features/Auth/atoms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { atom } from 'jotai';
import { AUTH_TOKEN_LOCAL_STORAGE_KEY } from './consts';

export const AUTH_TOKEN_ATOM = atom<string | null>(localStorage.getItem(AUTH_TOKEN_LOCAL_STORAGE_KEY));

export const TESTNET_USERNAME_ATOM = atom('');

export const IS_AUTH_READY_ATOM = atom(false);
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { Navigate, useLocation } from 'react-router';
import { useAccount } from '@gear-js/react-hooks';
import { ProtectedRouteProps } from './ProtectedRoute.interface';
import { useAuth } from '../../hooks';
import { LOGIN, NOT_AUTHORIZED } from '@/App.routes';
import { AUTH_TOKEN_LOCAL_STORAGE_KEY } from '../../consts';

function ProtectedRoute({ children }: ProtectedRouteProps) {
const { authToken } = useAuth();
const authToken = localStorage.getItem(AUTH_TOKEN_LOCAL_STORAGE_KEY);
const { account } = useAccount();
const location = useLocation();

if (!authToken && account) {
return <Navigate to={`/${NOT_AUTHORIZED}`} replace />;
}

if (!authToken && !account) {
if (!authToken) {
return <Navigate to={`/${LOGIN}`} state={{ from: location }} replace />;
}

Expand Down
12 changes: 3 additions & 9 deletions frontend/src/features/Auth/consts.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import { atom } from 'jotai';
export const AUTH_API_ADDRESS = process.env.REACT_APP_AUTH_API_ADDRESS as string;

const AUTH_API_ADDRESS = process.env.REACT_APP_AUTH_API_ADDRESS as string;
export const AUTH_MESSAGE = 'VARA';

const AUTH_MESSAGE = 'VARA';

const AUTH_TOKEN_LOCAL_STORAGE_KEY = 'authToken';

const AUTH_TOKEN_ATOM = atom<string | null>(localStorage.getItem(AUTH_TOKEN_LOCAL_STORAGE_KEY));

export { AUTH_API_ADDRESS, AUTH_MESSAGE, AUTH_TOKEN_LOCAL_STORAGE_KEY, AUTH_TOKEN_ATOM };
export const AUTH_TOKEN_LOCAL_STORAGE_KEY = 'authToken';
46 changes: 34 additions & 12 deletions frontend/src/features/Auth/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@ import { useAtom } from 'jotai';
import { useAlert, useAccount, Account } from '@gear-js/react-hooks';
import { useEffect } from 'react';
import { web3FromAddress } from '@polkadot/extension-dapp';
import { AUTH_MESSAGE, AUTH_TOKEN_ATOM, AUTH_TOKEN_LOCAL_STORAGE_KEY } from './consts';
import { AUTH_MESSAGE, AUTH_TOKEN_LOCAL_STORAGE_KEY } from './consts';
import { AUTH_TOKEN_ATOM, IS_AUTH_READY_ATOM, TESTNET_USERNAME_ATOM } from './atoms';
import { fetchAuth, post } from './utils';
import { AuthResponse, ISignInError, SignInResponse } from './types';

import { NOT_AUTHORIZED, PLAY } from '@/App.routes';

function useAuth() {
const { login, logout } = useAccount();
const { account, login, logout } = useAccount();
const alert = useAlert();
const [authToken, setAuthToken] = useAtom(AUTH_TOKEN_ATOM);
const [isAuthReady, setIsAuthReady] = useAtom(IS_AUTH_READY_ATOM);
const [testnameUsername, setTestnameUsername] = useAtom(TESTNET_USERNAME_ATOM);

const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from?.pathname || PLAY;
const isAwaitingVerification = account && !authToken;

// eslint-disable-next-line @typescript-eslint/no-shadow
const signIn = async (account: Account) => {
const { address } = account;

Expand All @@ -44,14 +48,16 @@ function useAuth() {
}

setAuthToken(null);
setTestnameUsername('');
await login(account);
navigate(NOT_AUTHORIZED, { replace: true });
} else {
const data: SignInResponse = await res.json();
const { accessToken } = data;
const { accessToken, username } = data;

await login(account);
setAuthToken(accessToken);
setTestnameUsername(username || '');
navigate(from, { replace: true });
}
} catch (e) {
Expand All @@ -65,30 +71,46 @@ function useAuth() {
};

const auth = () => {
if (!authToken) return;
const localStorageToken = localStorage.getItem(AUTH_TOKEN_LOCAL_STORAGE_KEY);

if (!localStorageToken) {
setIsAuthReady(true);
if (!isAwaitingVerification) logout();
return;
}

fetchAuth<AuthResponse>('auth/me', 'PUT', authToken).catch(({ message }: Error) => {
signOut();
alert.error(message);
});
fetchAuth<AuthResponse>('auth/me', 'PUT', localStorageToken)
.then(({ username }) => {
setAuthToken(localStorageToken);
setTestnameUsername(username || '');
})
.catch(({ message }: Error) => {
signOut();
localStorage.removeItem(AUTH_TOKEN_LOCAL_STORAGE_KEY);
alert.error(message);
})
.finally(() => setIsAuthReady(true));
};

return { authToken, signIn, signOut, auth };
return { authToken, signIn, signOut, auth, isAuthReady, isAwaitingVerification, testnameUsername };
}

function useAuthSync() {
const { authToken, auth } = useAuth();
const { isAccountReady } = useAccount();
const { authToken, isAuthReady, auth } = useAuth();

useEffect(() => {
if (!isAccountReady) return;
auth();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [authToken]);

useEffect(() => {
if (!isAuthReady) return;
if (!authToken) return localStorage.removeItem(AUTH_TOKEN_LOCAL_STORAGE_KEY);

localStorage.setItem(AUTH_TOKEN_LOCAL_STORAGE_KEY, authToken);
}, [authToken]);
}, [isAuthReady, authToken]);
}

export { useAuth, useAuthSync };
2 changes: 2 additions & 0 deletions frontend/src/features/Auth/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
type SignInResponse = {
accessToken: string;
username: string;
};

type AuthResponse = {
email: string;
id: string;
publicKey: string;
username: string;
};

export type { SignInResponse, AuthResponse };
Expand Down

0 comments on commit f279544

Please sign in to comment.