@@ -11,8 +11,12 @@ import React, {
1111import { AuthMode , createFetchWithAuth } from './fetchWithAuth' ;
1212import LoadingSpinner from './LoadingSpinner' ;
1313import { usePreviousSignIn } from './hooks/usePreviousSignIn' ;
14+ import {
15+ AuthenticatorTransportFuture ,
16+ CredentialDeviceType ,
17+ } from '@simplewebauthn/browser' ;
1418
15- interface User {
19+ export interface User {
1620 id : string ;
1721 email : string ;
1822 phone : string ;
@@ -35,6 +39,22 @@ export interface AuthContextType {
3539 markSignedIn : ( ) => void ;
3640 hasSignedInBefore : boolean ;
3741 mode : AuthMode ;
42+ credentials : Credential [ ] ;
43+ updateCredential : ( credential : Credential ) => Promise < Credential > ;
44+ deleteCredential : ( credentialId : string ) => Promise < void > ;
45+ }
46+
47+ export interface Credential {
48+ id : string ;
49+ counter : number ;
50+ transports ?: AuthenticatorTransportFuture [ ] ;
51+ deviceType : CredentialDeviceType ;
52+ backedup : boolean ;
53+ friendlyName : string | null ;
54+ lastUsedAt : Date | null ;
55+ platform : string | null ;
56+ browser : string | null ;
57+ deviceInfo : string | null ;
3858}
3959
4060const AuthContext = createContext < AuthContextType | undefined > ( undefined ) ;
@@ -65,6 +85,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({
6585 mode = 'web' ,
6686} ) => {
6787 const [ user , setUser ] = useState < User | null > ( null ) ;
88+ const [ credentials , setCredentials ] = useState < Credential [ ] > ( [ ] ) ;
6889 const [ isAuthenticated , setIsAuthenticated ] = useState < boolean > ( false ) ;
6990 const [ loading , setLoading ] = useState < boolean > ( true ) ;
7091 const [ token , setToken ] = useState < AuthToken | null > ( null ) ;
@@ -121,8 +142,10 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({
121142 } ) ;
122143
123144 if ( response . ok ) {
124- const { user } = await response . json ( ) ;
145+ const { user, credentials } = await response . json ( ) ;
125146 setUser ( user ) ;
147+ setCredentials ( credentials ) ;
148+
126149 setIsAuthenticated ( true ) ;
127150 } else {
128151 logout ( ) ;
@@ -134,6 +157,36 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({
134157 }
135158 } ;
136159
160+ const updateCredential = async ( credential : Credential ) => {
161+ const response = await fetchWithAuth ( `users/credentials` , {
162+ method : 'POST' ,
163+ credentials : 'include' ,
164+ headers : { 'Content-Type' : 'application/json' } ,
165+ body : JSON . stringify ( { friendlyName : credential . friendlyName , id : credential . id } ) ,
166+ } ) ;
167+
168+ if ( response . ok ) {
169+ return response . json ( ) ;
170+ }
171+
172+ throw new Error ( 'Failed to update credential' ) ;
173+ } ;
174+
175+ const deleteCredential = async ( credentialId : string ) => {
176+ const response = await fetchWithAuth ( `users/credentials` , {
177+ method : 'DELETE' ,
178+ credentials : 'include' ,
179+ headers : { 'Content-Type' : 'application/json' } ,
180+ body : JSON . stringify ( { id : credentialId } ) ,
181+ } ) ;
182+
183+ if ( response . ok ) {
184+ return response . json ( ) ;
185+ }
186+
187+ throw new Error ( 'Failed to update credential' ) ;
188+ } ;
189+
137190 useEffect ( ( ) => {
138191 validateToken ( ) ;
139192 } , [ ] ) ;
@@ -165,6 +218,9 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({
165218 markSignedIn,
166219 hasSignedInBefore : autoDetectPreviousSignin ? hasSignedInBefore : false ,
167220 mode,
221+ credentials,
222+ updateCredential,
223+ deleteCredential,
168224 } }
169225 >
170226 < InternalAuthProvider value = { { validateToken, setLoading } } >
0 commit comments