Add debug information display for passkey registration process
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:
Torsten Schulz (local)
2026-01-07 22:13:50 +01:00
parent a16838ff47
commit c1e93f8989

View File

@@ -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...')