Add MFA handling to AuthenticationLoading component
This commit is contained in:
@@ -10,6 +10,7 @@ import { useUserProfile } from '../../queries/UserQueries'
|
|||||||
import { apiClient } from '../../utils/ApiClient'
|
import { apiClient } from '../../utils/ApiClient'
|
||||||
import { GetUserProfile } from '../../utils/Fetcher'
|
import { GetUserProfile } from '../../utils/Fetcher'
|
||||||
import { saveTokens } from '../../utils/TokenStorage'
|
import { saveTokens } from '../../utils/TokenStorage'
|
||||||
|
import MFAVerificationModal from './MFAVerificationModal'
|
||||||
|
|
||||||
const AuthenticationLoading = () => {
|
const AuthenticationLoading = () => {
|
||||||
const { data: userProfile, refetch: refetchUserProfile } = useUserProfile()
|
const { data: userProfile, refetch: refetchUserProfile } = useUserProfile()
|
||||||
@@ -18,6 +19,8 @@ const AuthenticationLoading = () => {
|
|||||||
const [message, setMessage] = useState('Authenticating')
|
const [message, setMessage] = useState('Authenticating')
|
||||||
const [subMessage, setSubMessage] = useState('Please wait')
|
const [subMessage, setSubMessage] = useState('Please wait')
|
||||||
const [status, setStatus] = useState('pending')
|
const [status, setStatus] = useState('pending')
|
||||||
|
const [mfaModalOpen, setMfaModalOpen] = useState(false)
|
||||||
|
const [mfaSessionToken, setMfaSessionToken] = useState('')
|
||||||
const { provider } = useParams()
|
const { provider } = useParams()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (provider === 'oauth2' && !hasCalledHandleOAuth2.current) {
|
if (provider === 'oauth2' && !hasCalledHandleOAuth2.current) {
|
||||||
@@ -44,6 +47,29 @@ const AuthenticationLoading = () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleMFASuccess = async data => {
|
||||||
|
await saveTokens({
|
||||||
|
accessToken: data.token,
|
||||||
|
accessTokenExpiry: data.expire,
|
||||||
|
refreshToken: data.refresh_token,
|
||||||
|
refreshTokenExpiry: data.refresh_token_expiry,
|
||||||
|
})
|
||||||
|
|
||||||
|
setMfaModalOpen(false)
|
||||||
|
setMfaSessionToken('')
|
||||||
|
|
||||||
|
getUserProfileAndNavigateToHome()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMFAClose = () => {
|
||||||
|
setMfaModalOpen(false)
|
||||||
|
setMfaSessionToken('')
|
||||||
|
setMessage('Authentication failed')
|
||||||
|
setSubMessage('Two-factor authentication was cancelled')
|
||||||
|
setStatus('error')
|
||||||
|
}
|
||||||
|
|
||||||
const handleOAuth2 = async () => {
|
const handleOAuth2 = async () => {
|
||||||
// get provider from params:
|
// get provider from params:
|
||||||
const urlParams = new URLSearchParams(window.location.search)
|
const urlParams = new URLSearchParams(window.location.search)
|
||||||
@@ -65,7 +91,8 @@ const AuthenticationLoading = () => {
|
|||||||
const redirectURI = Capacitor.isNativePlatform()
|
const redirectURI = Capacitor.isNativePlatform()
|
||||||
? 'donetick://auth/oauth2'
|
? 'donetick://auth/oauth2'
|
||||||
: `${window.location.origin}/auth/oauth2`
|
: `${window.location.origin}/auth/oauth2`
|
||||||
fetch(`${baseURL}/auth/oauth2/callback`, {
|
try {
|
||||||
|
const response = await fetch(`${baseURL}/auth/oauth2/callback`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -75,14 +102,45 @@ const AuthenticationLoading = () => {
|
|||||||
state: returnedState,
|
state: returnedState,
|
||||||
redirect_uri: redirectURI,
|
redirect_uri: redirectURI,
|
||||||
}),
|
}),
|
||||||
}).then(response => {
|
})
|
||||||
if (response.status === 200) {
|
|
||||||
return response.json().then(async data => {
|
if (!response.ok) {
|
||||||
|
console.error('Authentication failed')
|
||||||
|
setMessage('Authentication failed')
|
||||||
|
setSubMessage('Please try again')
|
||||||
|
setStatus('error')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json()
|
||||||
|
|
||||||
|
if (data.mfaRequired) {
|
||||||
|
if (!data.sessionToken) {
|
||||||
|
setMessage('Authentication failed')
|
||||||
|
setSubMessage('MFA session is missing. Please try again')
|
||||||
|
setStatus('error')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setMfaSessionToken(data.sessionToken)
|
||||||
|
setMfaModalOpen(true)
|
||||||
|
setMessage('Two-Factor Authentication Required')
|
||||||
|
setSubMessage('Please verify your login to continue')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.token && !data.access_token) {
|
||||||
|
setMessage('Authentication failed')
|
||||||
|
setSubMessage('No valid authentication token returned')
|
||||||
|
setStatus('error')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
await saveTokens({
|
await saveTokens({
|
||||||
accessToken: data.token,
|
accessToken: data.token || data.access_token,
|
||||||
accessTokenExpiry: data.expire,
|
accessTokenExpiry: data.expire || data.access_token_expiry,
|
||||||
refreshToken: data.refresh_token,
|
refreshToken: data.refresh_token,
|
||||||
refreshTokenExpiry: data.refresh_token_expiry
|
refreshTokenExpiry: data.refresh_token_expiry,
|
||||||
})
|
})
|
||||||
|
|
||||||
const redirectUrl = Cookies.get('ca_redirect')
|
const redirectUrl = Cookies.get('ca_redirect')
|
||||||
@@ -92,14 +150,12 @@ const AuthenticationLoading = () => {
|
|||||||
} else {
|
} else {
|
||||||
getUserProfileAndNavigateToHome()
|
getUserProfileAndNavigateToHome()
|
||||||
}
|
}
|
||||||
})
|
} catch (error) {
|
||||||
} else {
|
console.error('Authentication request failed', error)
|
||||||
console.error('Authentication failed')
|
|
||||||
setMessage('Authentication failed')
|
setMessage('Authentication failed')
|
||||||
setSubMessage('Please try again')
|
setSubMessage('Please try again')
|
||||||
setStatus('error')
|
setStatus('error')
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +199,17 @@ const AuthenticationLoading = () => {
|
|||||||
<Link to='/login'>Go back Login</Link>
|
<Link to='/login'>Go back Login</Link>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<MFAVerificationModal
|
||||||
|
open={mfaModalOpen}
|
||||||
|
onClose={handleMFAClose}
|
||||||
|
sessionToken={mfaSessionToken}
|
||||||
|
onSuccess={handleMFASuccess}
|
||||||
|
onError={() => {
|
||||||
|
setMessage('Authentication failed')
|
||||||
|
setSubMessage('Two-factor authentication failed. Please try again')
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user