Skip to content

Commit 3d89cae

Browse files
committed
abstracted out handlePassKey
1 parent 951fd8d commit 3d89cae

6 files changed

Lines changed: 168 additions & 85 deletions

File tree

src/AuthProvider.tsx

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { InternalAuthProvider } from '@/context/InternalAuthContext';
2+
import { startAuthentication } from '@simplewebauthn/browser';
23
import React, {
34
createContext,
45
ReactNode,
@@ -42,7 +43,8 @@ export interface AuthContextType {
4243
credentials: Credential[];
4344
updateCredential: (credential: Credential) => Promise<Credential>;
4445
deleteCredential: (credentialId: string) => Promise<void>;
45-
fetchWithAuth(input: string, init?: RequestInit): Promise<Response>;
46+
login: (identifier: string, passkeyAvailable: boolean) => Promise<Response>;
47+
handlePasskeyLogin: () => Promise<string>;
4648
}
4749

4850
export interface Credential {
@@ -98,6 +100,79 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({
98100
authHost: apiHost,
99101
});
100102

103+
const login = async (
104+
identifier: string,
105+
passkeyAvailable: boolean
106+
): Promise<Response> => {
107+
const response = await fetchWithAuth(`/login`, {
108+
method: 'POST',
109+
body: JSON.stringify({ identifier, passkeyAvailable }),
110+
});
111+
if (!passkeyAvailable) {
112+
// setShowFallbackOptions(true);
113+
console.log('stopped early');
114+
return response;
115+
}
116+
117+
try {
118+
// await handlePasskeyLogin();
119+
// Another ticket?
120+
return response;
121+
} catch (err) {
122+
console.error('Passkey login failed', err);
123+
// setShowFallbackOptions(true);
124+
return response;
125+
}
126+
};
127+
128+
const handlePasskeyLogin = async () => {
129+
try {
130+
const response = await fetchWithAuth(`/webAuthn/login/start`, {
131+
method: 'POST',
132+
});
133+
134+
if (!response.ok) {
135+
console.error('Something went wrong getting webauthn options');
136+
return 'Failed';
137+
}
138+
139+
const options = await response.json();
140+
const credential = await startAuthentication({ optionsJSON: options });
141+
142+
const verificationResponse = await fetchWithAuth(`/webAuthn/login/finish`, {
143+
method: 'POST',
144+
body: JSON.stringify({ assertionResponse: credential }),
145+
});
146+
147+
if (!verificationResponse.ok) {
148+
console.error('Failed to verify passkey');
149+
}
150+
151+
const verificationResult = await verificationResponse.json();
152+
153+
if (verificationResult.message === 'Success') {
154+
if (verificationResult.mfaLogin) {
155+
// navigate('/mfaLogin');
156+
// need to return "Success"
157+
158+
return 'Success';
159+
}
160+
await validateToken();
161+
// navigate('/');
162+
// need to return validateToken response/message
163+
return 'Token';
164+
} else {
165+
console.error('Passkey login failed:', verificationResult.message);
166+
// return failed
167+
return 'Failed';
168+
}
169+
} catch (error) {
170+
console.error('Passkey login error:', error);
171+
// throw error?
172+
return 'Error';
173+
}
174+
};
175+
101176
const logout = useCallback(async () => {
102177
if (user) {
103178
try {
@@ -222,7 +297,8 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({
222297
credentials,
223298
updateCredential,
224299
deleteCredential,
225-
fetchWithAuth,
300+
login,
301+
handlePasskeyLogin,
226302
}}
227303
>
228304
<InternalAuthProvider value={{ validateToken, setLoading }}>

src/AuthRoutes.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const AuthRoutes = () => (
1616
<Route path="/verifyEmailOTP" element={<EmailRegistration />} />
1717
<Route path="/verify-magiclink" element={<VerifyMagicLink />} />
1818
<Route path="/registerPasskey" element={<PasskeyRegistration />} />
19-
<Route path="/magic-link-sent" element={<MagicLinkSent />} />
19+
<Route path="/magiclinks-sent" element={<MagicLinkSent />} />
2020
<Route path="*" element={<Navigate to="/login" replace />} />
2121
</Routes>
2222
);

src/components/MagicLinkSent.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const MagicLinkSent: React.FC = () => {
3232
const resend = async () => {
3333
if (cooldown > 0) return;
3434

35-
await fetchWithAuth(`/magic-link`, {
35+
await fetchWithAuth(`/magiclinks`, {
3636
method: 'GET',
3737
headers: {
3838
'Content-Type': 'application/json',
@@ -47,7 +47,7 @@ const MagicLinkSent: React.FC = () => {
4747

4848
channel.onmessage = async event => {
4949
if (event.data?.type === 'MAGIC_LINK_AUTH_SUCCESS') {
50-
const response = await fetchWithAuth(`/magic-link/check`, {
50+
const response = await fetchWithAuth(`/magiclinks/check`, {
5151
method: 'GET',
5252
headers: {
5353
'Content-Type': 'application/json',
@@ -68,7 +68,7 @@ const MagicLinkSent: React.FC = () => {
6868
useEffect(() => {
6969
const interval = setInterval(async () => {
7070
try {
71-
const response = await fetchWithAuth(`/magic-link/check`, {
71+
const response = await fetchWithAuth(`/magiclinks/check`, {
7272
method: 'GET',
7373
headers: {
7474
'Content-Type': 'application/json',

src/utils.ts

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -103,35 +103,36 @@ export function parseUserAgent() {
103103
return { platform, browser, deviceInfo };
104104
}
105105

106-
export const login = async (
107-
fetchWithAuth: (input: string, init?: RequestInit) => Promise<Response>,
108-
identifier: string,
109-
passkeyAvailable: boolean
110-
) => {
111-
// setFormErrors('');
112-
113-
const response = await fetchWithAuth(`/login`, {
114-
method: 'POST',
115-
body: JSON.stringify({ identifier, passkeyAvailable }),
116-
});
117-
118-
// if (!response.ok) {
119-
// setFormErrors('Failed to send login link. Please try again.');
120-
// return;
121-
// }
122-
123-
// if (!passkeyAvailable) {
124-
// setShowFallbackOptions(true);
125-
// return;
126-
// }
127-
128-
try {
129-
await handlePasskeyLogin(fetchWithAuth);
130-
} catch (err) {
131-
console.error('Passkey login failed', err);
132-
// setShowFallbackOptions(true);
133-
}
134-
};
106+
// export const login = async (
107+
// fetchWithAuth: (input: string, init?: RequestInit) => Promise<Response>,
108+
// identifier: string,
109+
// passkeyAvailable: boolean
110+
// ) => {
111+
// // setFormErrors('');
112+
113+
// const response = await fetchWithAuth(`/login`, {
114+
// method: 'POST',
115+
// body: JSON.stringify({ identifier, passkeyAvailable }),
116+
// });
117+
// console.log('response from /login', response);
118+
// // if (!response.ok) {
119+
// // setFormErrors('Failed to send login link. Please try again.');
120+
// // return;
121+
// // }
122+
123+
// if (!passkeyAvailable) {
124+
// // setShowFallbackOptions(true);
125+
// console.log
126+
// return;
127+
// }
128+
129+
// try {
130+
// await handlePasskeyLogin(fetchWithAuth);
131+
// } catch (err) {
132+
// console.error('Passkey login failed', err);
133+
// // setShowFallbackOptions(true);
134+
// }
135+
// };
135136

136137
const handlePasskeyLogin = async (
137138
fetchWithAuth: (input: string, init?: RequestInit) => Promise<Response>

src/views/Login.tsx

Lines changed: 55 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ import PhoneInputWithCountryCode from '@/components/phoneInput';
44
import { useInternalAuth } from '@/context/InternalAuthContext';
55
import React, { useEffect, useState } from 'react';
66
import { useNavigate } from 'react-router-dom';
7-
import { login } from '../utils';
87
import styles from '@/styles/login.module.css';
98
import { isPasskeySupported, isValidEmail, isValidPhoneNumber } from '../utils';
109
import { createFetchWithAuth } from '@/fetchWithAuth';
1110
import AuthFallbackOptions from '@/components/AuthFallbackOptions';
1211

1312
const Login: React.FC = () => {
1413
const navigate = useNavigate();
15-
const { apiHost, hasSignedInBefore, mode: authMode, fetchWithAuth } = useAuth();
14+
const {
15+
apiHost,
16+
hasSignedInBefore,
17+
mode: authMode,
18+
login,
19+
handlePasskeyLogin,
20+
} = useAuth();
1621
const { validateToken } = useInternalAuth();
1722
const [identifier, setIdentifier] = useState<string>('');
1823
const [email, setEmail] = useState<string>('');
@@ -25,10 +30,10 @@ const Login: React.FC = () => {
2530
const [passkeyAvailable, setPasskeyAvailable] = useState(false);
2631
const [showFallbackOptions, setShowFallbackOptions] = useState(false);
2732

28-
// const fetchWithAuth = createFetchWithAuth({
29-
// authMode,
30-
// authHost: apiHost,
31-
// });
33+
const fetchWithAuth = createFetchWithAuth({
34+
authMode,
35+
authHost: apiHost,
36+
});
3237

3338
useEffect(() => {
3439
async function checkSupport() {
@@ -63,46 +68,46 @@ const Login: React.FC = () => {
6368
return isValidEmail(email) && isValidPhoneNumber(phone);
6469
};
6570

66-
const handlePasskeyLogin = async () => {
67-
try {
68-
const response = await fetchWithAuth(`/webAuthn/login/start`, {
69-
method: 'POST',
70-
});
71-
72-
if (!response.ok) {
73-
console.error('Something went wrong getting webauthn options');
74-
return;
75-
}
76-
77-
const options = await response.json();
78-
const credential = await startAuthentication({ optionsJSON: options });
79-
80-
const verificationResponse = await fetchWithAuth(`/webAuthn/login/finish`, {
81-
method: 'POST',
82-
body: JSON.stringify({ assertionResponse: credential }),
83-
});
84-
85-
if (!verificationResponse.ok) {
86-
console.error('Failed to verify passkey');
87-
}
88-
89-
const verificationResult = await verificationResponse.json();
90-
91-
if (verificationResult.message === 'Success') {
92-
if (verificationResult.mfaLogin) {
93-
navigate('/mfaLogin');
94-
return;
95-
}
96-
await validateToken();
97-
navigate('/');
98-
return;
99-
} else {
100-
console.error('Passkey login failed:', verificationResult.message);
101-
}
102-
} catch (error) {
103-
console.error('Passkey login error:', error);
104-
}
105-
};
71+
// const handlePasskeyLogin = async () => {
72+
// try {
73+
// const response = await fetchWithAuth(`/webAuthn/login/start`, {
74+
// method: 'POST',
75+
// });
76+
77+
// if (!response.ok) {
78+
// console.error('Something went wrong getting webauthn options');
79+
// return;
80+
// }
81+
82+
// const options = await response.json();
83+
// const credential = await startAuthentication({ optionsJSON: options });
84+
85+
// const verificationResponse = await fetchWithAuth(`/webAuthn/login/finish`, {
86+
// method: 'POST',
87+
// body: JSON.stringify({ assertionResponse: credential }),
88+
// });
89+
90+
// if (!verificationResponse.ok) {
91+
// console.error('Failed to verify passkey');
92+
// }
93+
94+
// const verificationResult = await verificationResponse.json();
95+
96+
// if (verificationResult.message === 'Success') {
97+
// if (verificationResult.mfaLogin) {
98+
// navigate('/mfaLogin');
99+
// return;
100+
// }
101+
// await validateToken();
102+
// navigate('/');
103+
// return;
104+
// } else {
105+
// console.error('Passkey login failed:', verificationResult.message);
106+
// }
107+
// } catch (error) {
108+
// console.error('Passkey login error:', error);
109+
// }
110+
// };
106111

107112
const register = async () => {
108113
setFormErrors('');
@@ -136,7 +141,7 @@ const Login: React.FC = () => {
136141

137142
const sendMagicLink = async () => {
138143
try {
139-
const response = await fetchWithAuth(`/magic-link`, {
144+
const response = await fetchWithAuth(`/magiclinks`, {
140145
method: 'GET',
141146
});
142147

@@ -145,7 +150,7 @@ const Login: React.FC = () => {
145150
return;
146151
}
147152

148-
navigate('/magic-link-sent');
153+
navigate('/magiclinks-sent');
149154
} catch (err) {
150155
console.error(err);
151156
setFormErrors('Failed to send magic link.');
@@ -175,8 +180,9 @@ const Login: React.FC = () => {
175180
e.preventDefault();
176181

177182
if (mode === 'login') {
183+
const res = login(identifier, passkeyAvailable);
178184
if (passkeyAvailable) {
179-
const res = login(fetchWithAuth, identifier, passkeyAvailable);
185+
console.log('herro');
180186
} else {
181187
setShowFallbackOptions(true);
182188
console.log(setShowFallbackOptions);

src/views/VerifyMagicLink.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const VerifyMagicLink: React.FC = () => {
2121

2222
useEffect(() => {
2323
const verify = async () => {
24-
const response = await fetchWithAuth(`/magic-link/verify/${token}`, {
24+
const response = await fetchWithAuth(`/magiclinks/verify/${token}`, {
2525
method: 'GET',
2626
headers: {
2727
'Content-Type': 'application/json',

0 commit comments

Comments
 (0)