Add debug information display for passkey registration process
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 49s
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 49s
Introduce a debug information section in the passkey registration flow, providing insights into the challenge, RP-ID, and origin when debugging is enabled. Enhance logging to capture detailed options and cross-device authentication information, improving troubleshooting capabilities and user guidance during the registration process.
This commit is contained in:
@@ -166,6 +166,23 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Debug Info (nur bei Passkey-Registrierung) -->
|
||||||
|
<div
|
||||||
|
v-if="usePasskey && showDebugInfo && debugChallenge"
|
||||||
|
class="bg-blue-50 border border-blue-200 rounded-lg p-4 text-xs"
|
||||||
|
>
|
||||||
|
<div class="font-semibold text-blue-900 mb-2">🔍 Debug-Informationen (QR-Code):</div>
|
||||||
|
<div class="space-y-1 text-blue-800">
|
||||||
|
<div><strong>Challenge:</strong> <code class="bg-blue-100 px-1 rounded">{{ debugChallenge.substring(0, 40) }}...</code></div>
|
||||||
|
<div><strong>RP-ID:</strong> <code class="bg-blue-100 px-1 rounded">{{ debugRpId }}</code></div>
|
||||||
|
<div><strong>Origin:</strong> <code class="bg-blue-100 px-1 rounded">{{ window.location.origin }}</code></div>
|
||||||
|
<div class="mt-2 text-blue-700">
|
||||||
|
<strong>Hinweis:</strong> Der QR-Code wird vom Browser generiert.
|
||||||
|
Prüfe in der Browser-Konsole (F12) für vollständige Debug-Ausgaben.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
@@ -226,6 +243,9 @@ const usePasskey = ref(false)
|
|||||||
const isPasskeySupported = ref(false)
|
const isPasskeySupported = ref(false)
|
||||||
const passkeySupportReason = ref('')
|
const passkeySupportReason = ref('')
|
||||||
const setPasswordForPasskey = ref(true)
|
const setPasswordForPasskey = ref(true)
|
||||||
|
const showDebugInfo = ref(false)
|
||||||
|
const debugChallenge = ref('')
|
||||||
|
const debugRpId = ref('')
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
try {
|
try {
|
||||||
@@ -384,6 +404,63 @@ const handleRegisterWithPasskey = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('[DEBUG] Calling startRegistration...')
|
console.log('[DEBUG] Calling startRegistration...')
|
||||||
|
console.log('[DEBUG] Full options object (will be encoded in QR code for Cross-Device):', JSON.stringify(pre.options, null, 2))
|
||||||
|
console.log('[DEBUG] Options summary for startRegistration:', {
|
||||||
|
challenge: pre.options?.challenge ? 'present' : 'missing',
|
||||||
|
challengeValue: pre.options?.challenge ? pre.options.challenge.substring(0, 20) + '...' : 'missing',
|
||||||
|
rp: pre.options?.rp,
|
||||||
|
rpId: pre.options?.rp?.id,
|
||||||
|
rpName: pre.options?.rp?.name,
|
||||||
|
user: pre.options?.user,
|
||||||
|
userName: pre.options?.user?.name,
|
||||||
|
userDisplayName: pre.options?.user?.displayName,
|
||||||
|
timeout: pre.options?.timeout,
|
||||||
|
timeoutSeconds: pre.options?.timeout ? Math.round(pre.options.timeout / 1000) : 'default',
|
||||||
|
pubKeyCredParams: pre.options?.pubKeyCredParams?.length,
|
||||||
|
authenticatorSelection: pre.options?.authenticatorSelection,
|
||||||
|
excludeCredentials: pre.options?.excludeCredentials?.length || 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// Vollständige Options für QR-Code-Debug (wird im QR-Code kodiert)
|
||||||
|
console.log('[DEBUG] Full options object (encoded in QR code for Cross-Device):', JSON.stringify(pre.options, null, 2))
|
||||||
|
|
||||||
|
// Prüfe, ob Cross-Device-Authentifizierung verwendet wird
|
||||||
|
console.log('[DEBUG] Cross-Device Info (QR-Code sollte zu dieser URL führen):', {
|
||||||
|
isSecureContext: window.isSecureContext,
|
||||||
|
origin: window.location.origin,
|
||||||
|
protocol: window.location.protocol,
|
||||||
|
hostname: window.location.hostname,
|
||||||
|
port: window.location.port || 'default (443 for HTTPS)',
|
||||||
|
fullUrl: window.location.href,
|
||||||
|
// Der QR-Code sollte zur aktuellen Origin führen
|
||||||
|
qrCodeShouldPointTo: window.location.origin,
|
||||||
|
// Prüfe, ob die Options die richtige Origin enthalten
|
||||||
|
optionsRpId: pre.options?.rp?.id,
|
||||||
|
optionsMatchesOrigin: pre.options?.rp?.id === window.location.hostname
|
||||||
|
})
|
||||||
|
|
||||||
|
// QR-Code-Debug: Die Challenge ist Teil der WebAuthn-Request
|
||||||
|
// Der Browser generiert automatisch einen QR-Code für Cross-Device
|
||||||
|
debugChallenge.value = pre.options?.challenge || ''
|
||||||
|
debugRpId.value = pre.options?.rp?.id || ''
|
||||||
|
showDebugInfo.value = true
|
||||||
|
|
||||||
|
console.log('[DEBUG] QR-Code Info (for Cross-Device):', {
|
||||||
|
challenge: pre.options?.challenge,
|
||||||
|
challengeLength: pre.options?.challenge?.length,
|
||||||
|
rpId: pre.options?.rp?.id,
|
||||||
|
expectedOrigin: window.location.origin,
|
||||||
|
currentURL: window.location.href,
|
||||||
|
isHTTPS: window.location.protocol === 'https:',
|
||||||
|
note: 'Der QR-Code wird vom Browser generiert und enthält die Challenge + Server-Info'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Prüfe, ob die Origin korrekt ist
|
||||||
|
if (window.location.origin.includes(':3100')) {
|
||||||
|
console.error('[DEBUG] WARNING: Current origin contains port 3100!', window.location.origin)
|
||||||
|
console.error('[DEBUG] This might cause Cross-Device authentication to fail.')
|
||||||
|
}
|
||||||
|
|
||||||
const webauthnStart = Date.now()
|
const webauthnStart = Date.now()
|
||||||
|
|
||||||
const mod = await import('@simplewebauthn/browser')
|
const mod = await import('@simplewebauthn/browser')
|
||||||
@@ -391,23 +468,45 @@ const handleRegisterWithPasskey = async () => {
|
|||||||
// @simplewebauthn/browser v13+ erwartet die Options direkt
|
// @simplewebauthn/browser v13+ erwartet die Options direkt
|
||||||
let credential
|
let credential
|
||||||
try {
|
try {
|
||||||
|
// Timeout-Warnung nach 2 Minuten
|
||||||
|
const timeoutWarning = setTimeout(() => {
|
||||||
|
console.warn('[DEBUG] startRegistration still waiting after 2 minutes. This might be a Cross-Device timeout.')
|
||||||
|
console.warn('[DEBUG] Make sure your smartphone can reach the server and CORS is configured correctly.')
|
||||||
|
console.warn('[DEBUG] Current origin:', window.location.origin)
|
||||||
|
console.warn('[DEBUG] Challenge:', pre.options?.challenge)
|
||||||
|
}, 120000)
|
||||||
|
|
||||||
|
console.log('[DEBUG] startRegistration called - QR-Code should appear now (if Cross-Device)')
|
||||||
credential = await mod.startRegistration(pre.options)
|
credential = await mod.startRegistration(pre.options)
|
||||||
|
|
||||||
|
clearTimeout(timeoutWarning)
|
||||||
|
|
||||||
const webauthnDuration = Date.now() - webauthnStart
|
const webauthnDuration = Date.now() - webauthnStart
|
||||||
console.log(`[DEBUG] startRegistration completed (${webauthnDuration}ms)`, {
|
console.log(`[DEBUG] startRegistration completed (${webauthnDuration}ms)`, {
|
||||||
hasCredential: !!credential,
|
hasCredential: !!credential,
|
||||||
credentialId: credential?.id,
|
credentialId: credential?.id,
|
||||||
responseType: credential?.response?.constructor?.name,
|
responseType: credential?.response?.constructor?.name,
|
||||||
transports: credential?.transports
|
transports: credential?.transports,
|
||||||
|
durationSeconds: Math.round(webauthnDuration / 1000)
|
||||||
})
|
})
|
||||||
} catch (webauthnError) {
|
} catch (webauthnError) {
|
||||||
const webauthnDuration = Date.now() - webauthnStart
|
const webauthnDuration = Date.now() - webauthnStart
|
||||||
console.error(`[DEBUG] WebAuthn startRegistration failed (${webauthnDuration}ms):`, {
|
console.error(`[DEBUG] WebAuthn startRegistration failed (${webauthnDuration}ms / ${Math.round(webauthnDuration / 1000)}s):`, {
|
||||||
error: webauthnError,
|
error: webauthnError,
|
||||||
message: webauthnError?.message,
|
message: webauthnError?.message,
|
||||||
name: webauthnError?.name,
|
name: webauthnError?.name,
|
||||||
|
code: webauthnError?.code,
|
||||||
stack: webauthnError?.stack
|
stack: webauthnError?.stack
|
||||||
})
|
})
|
||||||
throw new Error('Passkey-Registrierung fehlgeschlagen: ' + (webauthnError?.message || 'Unbekannter Fehler'))
|
|
||||||
|
// Spezifische Fehlermeldungen für häufige Probleme
|
||||||
|
if (webauthnError?.message?.includes('timeout') || webauthnDuration > 290000) {
|
||||||
|
throw new Error('Passkey-Registrierung: Timeout. Bitte stellen Sie sicher, dass Ihr Smartphone eine Internetverbindung hat und die Website über HTTPS erreichbar ist.')
|
||||||
|
} else if (webauthnError?.message?.includes('NotAllowedError') || webauthnError?.name === 'NotAllowedError') {
|
||||||
|
throw new Error('Passkey-Registrierung abgebrochen oder nicht erlaubt.')
|
||||||
|
} else {
|
||||||
|
throw new Error('Passkey-Registrierung fehlgeschlagen: ' + (webauthnError?.message || 'Unbekannter Fehler'))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[DEBUG] Sending credential to server...')
|
console.log('[DEBUG] Sending credential to server...')
|
||||||
|
|||||||
Reference in New Issue
Block a user