currentOrLastAttemptedUser(); // TODO - Ensure user ID is somewhat long and random // See: https://webauthn-doc.spomky-labs.com/prerequisites/user-entity // Maybe hash of (app-id from settings + user id) // Or maybe a UUID/random_string which we connect via DB entry? $userEntity = PublicKeyCredentialUserEntity::create( $user->slug, $user->id, $user->name, ); $publicKeyCredentialParametersList = [ PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_ES256K), // More interesting algorithm PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_ES256), // || PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_RS256), // || PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_PS256), // \/ PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_ED256), // Less interesting algorithm ]; $credentialOptions = PublicKeyCredentialCreationOptions::create( $rpEntity, $userEntity, random_bytes(32), $publicKeyCredentialParametersList, hints: [ PublicKeyCredentialOptions::HINT_SECURITY_KEY, ], timeout: 60000, // 1 minute authenticatorSelection: AuthenticatorSelectionCriteria::create( userVerification: AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_DISCOURAGED, ) ); $attestationStatementSupportManager = AttestationStatementSupportManager::create(); $attestationStatementSupportManager->add(NoneAttestationStatementSupport::create()); $factory = new WebauthnSerializerFactory($attestationStatementSupportManager); $serializer = $factory->create(); $jsonOptions = $serializer->serialize( $credentialOptions, 'json', [ AbstractObjectNormalizer::SKIP_NULL_VALUES => true, JsonEncode::OPTIONS => JSON_THROW_ON_ERROR, ] ); // TODO - Change $this->setPageTitle(trans('auth.mfa_gen_hardware_key_title')); return view('mfa.hardware-key-generate', [ 'options' => $jsonOptions, ]); } /** * Confirm the setup of a hardware key, storing the key value against the user. * * @throws Exception */ public function confirm() { return redirect('/mfa/setup'); } /** * Verify the MFA method submission on check. * * @throws NotFoundException * @throws ValidationException */ public function verify(Request $request, MfaSession $mfaSession, LoginService $loginService) { $user = $this->currentOrLastAttemptedUser(); $this->limiter->incrementAttempts($user, $request); if ($this->limiter->hasHitLimit($user, $request)) { $this->clearLastAttemptedUser(); $this->limiter->throwException(); } } }