{"record":{"id":"14fa7f30f187937e","repo":"dotnet/aspnetcore","slug":"please-enter-a-username","errorCode":null,"errorMessage":"Please enter a username.","messagePattern":"Please enter a username\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/Identity/samples/IdentitySample.PasskeyUI/wwwroot/app.js","lineNumber":32,"sourceCode":"    function enableRouteScripts() {\n        Blazor.addEventListener('enhancednavigationend', executeScript);\n\n        if (document.readyState === 'loading') {\n            document.addEventListener('DOMContentLoaded', executeScript);\n        } else {\n            executeScript();\n        }\n    }\n\n    // Define home page JS functionality.\n    addRouteScript('/', async () => {\n        let abortController;\n        const form = document.getElementById('auth-form');\n        const statusMessage = document.getElementById('status-message');\n\n        async function fetchNewCredential(username) {\n            if (!username) {\n                throw new Error('Please enter a username.');\n            }\n\n            const optionsResponse = await fetch('/attestation/options', {\n                method: 'POST',\n                body: JSON.stringify({\n                    username,\n                }),\n                headers: {\n                    'Content-Type': 'application/json',\n                },\n                credentials: 'include',\n            });\n            const optionsJson = await optionsResponse.json();\n            const options = PublicKeyCredential.parseCreationOptionsFromJSON(optionsJson);\n            abortController?.abort();\n            abortController = new AbortController();\n            return await navigator.credentials.create({\n                publicKey: options,","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Identity/samples/IdentitySample.PasskeyUI/wwwroot/app.js#L14-L50","documentation":"Thrown by fetchNewCredential() in the PasskeyUI sample when the username form field is empty before initiating WebAuthn attestation (registration). It is a client-side guard that prevents sending an empty username to the /attestation/options endpoint. Registration requires a username so the server can associate the new credential with an account.","triggerScenarios":"User clicks the 'register' submit button on the auth form (name='action', value='register') with the username input empty or whitespace-only. FormData(form).get('username') returns null or empty string, which is falsy, so fetchNewCredential throws immediately before any fetch.","commonSituations":"First-time passkey enrollment where the user skipped the username field; form rendered without a username input (template change); HTML5 required attribute missing so the browser doesn't block submission; programmatic form.submit() bypassing the UI.","solutions":["Add required attribute to the username input in the Razor/HTML template so the browser blocks empty submission.","Trim and validate the username client-side before calling fetchNewCredential, showing a user-friendly message.","Ensure the form actually contains an input named 'username' matching FormData expectation."],"exampleFix":"// before\nasync function fetchNewCredential(username) {\n    if (!username) {\n        throw new Error('Please enter a username.');\n    }\n    // ...\n}\n\n// after (validate at call site, keep guard)\nconst username = (new FormData(form).get('username') || '').trim();\nif (!username) {\n    statusMessage.textContent = 'Please enter a username.';\n    return;\n}\ncredential = await fetchNewCredential(username);","handlingStrategy":"validation","validationCode":"function readUsername(form) {\n  const v = new FormData(form).get('username');\n  return (v == null ? '' : String(v)).trim();\n}\nconst username = readUsername(form);\nif (!username) {\n  statusMessage.textContent = 'Please enter a username.';\n  return; // do not call fetchNewCredential\n}","typeGuard":null,"tryCatchPattern":"try { await fetchNewCredential(username); } catch (e) { if (e.message === 'Please enter a username.') { statusMessage.textContent = e.message; return; } throw e; }","preventionTips":["Add the HTML required attribute to the username input for native browser validation.","Trim the username before the WebAuthn flow and short-circuit with a UI message.","Keep the form's input name attribute exactly 'username' so FormData.get returns the field."],"tags":["webauthn","passkey","validation","client-side","identity-sample"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}