Skip to content

Commit 951fd8d

Browse files
committed
extracted login
1 parent becb1b1 commit 951fd8d

3 files changed

Lines changed: 94 additions & 34 deletions

File tree

src/AuthProvider.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export interface AuthContextType {
4242
credentials: Credential[];
4343
updateCredential: (credential: Credential) => Promise<Credential>;
4444
deleteCredential: (credentialId: string) => Promise<void>;
45+
fetchWithAuth(input: string, init?: RequestInit): Promise<Response>;
4546
}
4647

4748
export interface Credential {
@@ -221,6 +222,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({
221222
credentials,
222223
updateCredential,
223224
deleteCredential,
225+
fetchWithAuth,
224226
}}
225227
>
226228
<InternalAuthProvider value={{ validateToken, setLoading }}>

src/utils.ts

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import parsePhoneNumberFromString from 'libphonenumber-js';
2-
2+
import { startAuthentication } from '@simplewebauthn/browser';
3+
import { createFetchWithAuth } from './fetchWithAuth';
34
/**
45
* isValidEmail
56
*
@@ -101,3 +102,77 @@ export function parseUserAgent() {
101102

102103
return { platform, browser, deviceInfo };
103104
}
105+
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+
};
135+
136+
const handlePasskeyLogin = async (
137+
fetchWithAuth: (input: string, init?: RequestInit) => Promise<Response>
138+
) => {
139+
try {
140+
const response = await fetchWithAuth(`/webAuthn/login/start`, {
141+
method: 'POST',
142+
});
143+
144+
if (!response.ok) {
145+
console.error('Something went wrong getting webauthn options');
146+
return;
147+
}
148+
149+
const options = await response.json();
150+
const credential = await startAuthentication({ optionsJSON: options });
151+
152+
const verificationResponse = await fetchWithAuth(`/webAuthn/login/finish`, {
153+
method: 'POST',
154+
body: JSON.stringify({ assertionResponse: credential }),
155+
});
156+
157+
if (!verificationResponse.ok) {
158+
console.error('Failed to verify passkey');
159+
}
160+
161+
const verificationResult = await verificationResponse.json();
162+
163+
// let them handle the below
164+
// if (verificationResult.message === 'Success') {
165+
// if (verificationResult.mfaLogin) {
166+
// navigate('/mfaLogin');
167+
// return;
168+
// }
169+
// await validateToken();
170+
// navigate('/');
171+
// return;
172+
// } else {
173+
// console.error('Passkey login failed:', verificationResult.message);
174+
// }
175+
} catch (error) {
176+
console.error('Passkey login error:', error);
177+
}
178+
};

src/views/Login.tsx

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ 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-
7+
import { login } from '../utils';
88
import styles from '@/styles/login.module.css';
99
import { isPasskeySupported, isValidEmail, isValidPhoneNumber } from '../utils';
1010
import { createFetchWithAuth } from '@/fetchWithAuth';
1111
import AuthFallbackOptions from '@/components/AuthFallbackOptions';
1212

1313
const Login: React.FC = () => {
1414
const navigate = useNavigate();
15-
const { apiHost, hasSignedInBefore, mode: authMode } = useAuth();
15+
const { apiHost, hasSignedInBefore, mode: authMode, fetchWithAuth } = useAuth();
1616
const { validateToken } = useInternalAuth();
1717
const [identifier, setIdentifier] = useState<string>('');
1818
const [email, setEmail] = useState<string>('');
@@ -25,15 +25,17 @@ const Login: React.FC = () => {
2525
const [passkeyAvailable, setPasskeyAvailable] = useState(false);
2626
const [showFallbackOptions, setShowFallbackOptions] = useState(false);
2727

28-
const fetchWithAuth = createFetchWithAuth({
29-
authMode,
30-
authHost: apiHost,
31-
});
28+
// const fetchWithAuth = createFetchWithAuth({
29+
// authMode,
30+
// authHost: apiHost,
31+
// });
3232

3333
useEffect(() => {
3434
async function checkSupport() {
3535
const supported = await isPasskeySupported();
36+
// console.log('checking passkey', supported);
3637
setPasskeyAvailable(supported);
38+
console.log('checking passkey', supported);
3739
}
3840

3941
checkSupport();
@@ -102,32 +104,6 @@ const Login: React.FC = () => {
102104
}
103105
};
104106

105-
const login = async () => {
106-
setFormErrors('');
107-
108-
const response = await fetchWithAuth(`/login`, {
109-
method: 'POST',
110-
body: JSON.stringify({ identifier, passkeyAvailable }),
111-
});
112-
113-
if (!response.ok) {
114-
setFormErrors('Failed to send login link. Please try again.');
115-
return;
116-
}
117-
118-
if (!passkeyAvailable) {
119-
setShowFallbackOptions(true);
120-
return;
121-
}
122-
123-
try {
124-
await handlePasskeyLogin();
125-
} catch (err) {
126-
console.error('Passkey login failed', err);
127-
setShowFallbackOptions(true);
128-
}
129-
};
130-
131107
const register = async () => {
132108
setFormErrors('');
133109

@@ -198,7 +174,14 @@ const Login: React.FC = () => {
198174
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
199175
e.preventDefault();
200176

201-
if (mode === 'login') login();
177+
if (mode === 'login') {
178+
if (passkeyAvailable) {
179+
const res = login(fetchWithAuth, identifier, passkeyAvailable);
180+
} else {
181+
setShowFallbackOptions(true);
182+
console.log(setShowFallbackOptions);
183+
}
184+
}
202185
if (mode === 'register') register();
203186
};
204187

0 commit comments

Comments
 (0)