publicKeyCredentialSourceRepository = $publicKeyCredentialSourceRepository; $this->rpEntity = new PublicKeyCredentialRpEntity(config('app.name'), trim($url, '/')); $this->credentialLoader = new PublicKeyCredentialLoader(new AttestationObjectLoader(new AttestationStatementSupportManager())); $this->assertionValidator = new AuthenticatorAssertionResponseValidator( $this->publicKeyCredentialSourceRepository, null, ExtensionOutputCheckerHandler::create(), AlgorithmManager::create(), ); $this->attestationValidator = new AuthenticatorAttestationResponseValidator( new AttestationStatementSupportManager(), $this->publicKeyCredentialSourceRepository, null, new ExtensionOutputCheckerHandler(), ); } /** * @throws \Webauthn\Exception\InvalidDataException */ public function getPublicKeyCredentialCreationOptions(User $user): PublicKeyCredentialCreationOptions { $excluded = $user->securityKeys->map(function (SecurityKey $key) { return $key->getPublicKeyCredentialDescriptor(); })->values()->toArray(); $challenge = Str::random(16); return (new PublicKeyCredentialCreationOptions( $this->rpEntity, $user->toPublicKeyCredentialEntity(), $challenge, [ PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_ES256), PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_ES256K), PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_ES384), PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_ES512), PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_RS256), PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_RS384), PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_RS512), PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_PS256), PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_PS384), PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_PS512), PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_ED256), PublicKeyCredentialParameters::create('public-key', Algorithms::COSE_ALGORITHM_ED512), ], )) ->setTimeout(30_000) ->excludeCredentials(...$excluded) ->setAttestation(PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE) ->setAuthenticatorSelection(AuthenticatorSelectionCriteria::create()); } /** * @throws \Webauthn\Exception\InvalidDataException */ public function generatePublicKeyCredentialRequestOptions(User $user): PublicKeyCredentialRequestOptions { $allowedCredentials = $user->securityKeys->map(function (SecurityKey $key) { return $key->getPublicKeyCredentialDescriptor(); })->values()->toArray(); return (new PublicKeyCredentialRequestOptions(Str::random(32))) ->allowCredentials(...$allowedCredentials) ->setUserVerification(PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_PREFERRED); } /** * @throws \Throwable * @throws \JsonException */ public function loadAndCheckAssertionResponse( User $user, array $data, PublicKeyCredentialRequestOptions $publicKeyCredentialRequestOptions, ServerRequestInterface $request ): PublicKeyCredentialSource { $credential = $this->credentialLoader->loadArray($data); $authenticatorAssertionResponse = $credential->getResponse(); if (!$authenticatorAssertionResponse instanceof AuthenticatorAssertionResponse) { // TODO throw new \Exception(''); } return $this->assertionValidator->check( $credential->getRawId(), $authenticatorAssertionResponse, $publicKeyCredentialRequestOptions, $request, null, // TODO: use handle? // $user->toPublicKeyCredentialEntity() ); } /** * Register a new security key for a user. * * @throws \Throwable * @throws \JsonException */ public function loadAndCheckAttestationResponse( User $user, array $data, PublicKeyCredentialCreationOptions $publicKeyCredentialCreationOptions, ServerRequestInterface $request ): PublicKeyCredentialSource { $credential = $this->credentialLoader->loadArray($data); $authenticatorAttestationResponse = $credential->getResponse(); if (!$authenticatorAttestationResponse instanceof AuthenticatorAttestationResponse) { // TODO throw new \Exception(''); } return $this->attestationValidator->check( $authenticatorAttestationResponse, $publicKeyCredentialCreationOptions, $request, ); } }