authenticatorData : $authenticatorResponse->attestationObject->authData; $C = $authenticatorResponse->clientDataJSON; $rpId = $publicKeyCredentialOptions->rpId ?? $publicKeyCredentialOptions->rp->id ?? $host; $facetId = $this->getFacetId($rpId, $publicKeyCredentialOptions->extensions, $authData->extensions); $parsedRelyingPartyId = parse_url($C->origin); is_array($parsedRelyingPartyId) || throw AuthenticatorResponseVerificationException::create( 'Invalid origin' ); if (! in_array($facetId, $this->securedRelyingPartyId, true)) { $scheme = $parsedRelyingPartyId['scheme'] ?? ''; $scheme === 'https' || throw AuthenticatorResponseVerificationException::create( 'Invalid scheme. HTTPS required.' ); } $clientDataRpId = $parsedRelyingPartyId['host'] ?? ''; $clientDataRpId !== '' || throw AuthenticatorResponseVerificationException::create('Invalid origin rpId.'); $rpIdLength = mb_strlen($facetId); mb_substr( '.' . $clientDataRpId, -($rpIdLength + 1) ) === '.' . $facetId || throw AuthenticatorResponseVerificationException::create('rpId mismatch.'); } private function getFacetId( string $rpId, AuthenticationExtensions $authenticationExtensionsClientInputs, null|AuthenticationExtensions $authenticationExtensionsClientOutputs ): string { if ($authenticationExtensionsClientOutputs === null || ! $authenticationExtensionsClientInputs->has( 'appid' ) || ! $authenticationExtensionsClientOutputs->has('appid')) { return $rpId; } $appId = $authenticationExtensionsClientInputs->get('appid') ->value; $wasUsed = $authenticationExtensionsClientOutputs->get('appid') ->value; if (! is_string($appId) || $wasUsed !== true) { return $rpId; } return $appId; } }