# Without `Cross-Origin-Embedder-Policy: require-corp` this works correctly
open index.html
# With `require-corp`, the Google Pay button completely fails in Chrome.
# In Safari and Firefox, the button shows an endless loading state,
# but still seems to work at first glance.
docker run -v ./Caddyfile:/etc/caddy/Caddyfile -v ./:/app -p 9000:9000 caddy
open http://localhost:9000/index.html
# Adding the `crossorigin` attribute to the `script` tag breaks with:
# "No 'Access-Control-Allow-Origin' header is present on the requested resource."
open http://localhost:9000/index-crossorigin.html
Created
May 23, 2025 06:39
-
-
Save pstadler/f69fe973d05b3fca339e13ff2ddde3d5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
debug | |
} | |
:9000 { | |
file_server browse | |
root * /app | |
header Cache-Control "no-cache, no-store, must-revalidate" | |
header Cross-Origin-Embedder-Policy require-corp | |
#header Cross-Origin-Resource-Policy cross-origin | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Google Pay COEP / crossorigin</title> | |
<script src="https://pay.google.com/gp/p/js/pay.js" crossorigin></script> | |
</head> | |
<body> | |
<div id="container"></div> | |
<script> | |
const paymentsClient = new google.payments.api.PaymentsClient({ environment: 'TEST' }); | |
const baseRequest = { | |
apiVersion: 2, | |
apiVersionMinor: 0 | |
}; | |
const allowedCardAuthMethods = ['PAN_ONLY', 'CRYPTOGRAM_3DS']; | |
const allowedCardNetworks = ['VISA', 'MASTERCARD']; | |
const tokenizationSpecification = { | |
type: 'PAYMENT_GATEWAY', | |
parameters: { | |
gateway: 'example', | |
gatewayMerchantId: 'exampleMerchantId' | |
} | |
}; | |
const baseCardPaymentMethod = { | |
type: 'CARD', | |
parameters: { | |
allowedAuthMethods: allowedCardAuthMethods, | |
allowedCardNetworks: allowedCardNetworks | |
} | |
}; | |
const cardPaymentMethod = Object.assign({}, baseCardPaymentMethod, { | |
tokenizationSpecification: tokenizationSpecification | |
}); | |
function getGoogleIsReadyToPayRequest() { | |
return Object.assign({}, baseRequest, { | |
allowedPaymentMethods: [baseCardPaymentMethod] | |
}); | |
} | |
function getGooglePaymentDataRequest() { | |
return Object.assign({}, baseRequest, { | |
allowedPaymentMethods: [cardPaymentMethod], | |
transactionInfo: { | |
totalPriceStatus: 'FINAL', | |
totalPrice: '1.00', | |
currencyCode: 'USD', | |
countryCode: 'US' | |
}, | |
merchantInfo: { | |
merchantId: '12345678901234567890', | |
merchantName: 'Demo Merchant' | |
} | |
}); | |
} | |
function onGooglePayLoaded() { | |
paymentsClient.isReadyToPay(getGoogleIsReadyToPayRequest()) | |
.then(function(response) { | |
if (response.result) { | |
const button = paymentsClient.createButton({ onClick: onGooglePaymentButtonClicked }); | |
document.getElementById('container').appendChild(button); | |
} else { | |
console.error('Google Pay is not available.'); | |
} | |
}) | |
.catch(function(err) { | |
console.error('Error determining readiness to use Google Pay: ', err); | |
}); | |
} | |
function onGooglePaymentButtonClicked() { | |
const paymentDataRequest = getGooglePaymentDataRequest(); | |
paymentsClient.loadPaymentData(paymentDataRequest) | |
.then(function(paymentData) { | |
console.log('Payment data:', paymentData); | |
}) | |
.catch(function(err) { | |
console.error('Payment failed: ', err); | |
}); | |
} | |
window.onload = onGooglePayLoaded; | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Google Pay COEP</title> | |
<script src="https://pay.google.com/gp/p/js/pay.js"></script> | |
</head> | |
<body> | |
<div id="container"></div> | |
<script> | |
const paymentsClient = new google.payments.api.PaymentsClient({ environment: 'TEST' }); | |
const baseRequest = { | |
apiVersion: 2, | |
apiVersionMinor: 0 | |
}; | |
const allowedCardAuthMethods = ['PAN_ONLY', 'CRYPTOGRAM_3DS']; | |
const allowedCardNetworks = ['VISA', 'MASTERCARD']; | |
const tokenizationSpecification = { | |
type: 'PAYMENT_GATEWAY', | |
parameters: { | |
gateway: 'example', | |
gatewayMerchantId: 'exampleMerchantId' | |
} | |
}; | |
const baseCardPaymentMethod = { | |
type: 'CARD', | |
parameters: { | |
allowedAuthMethods: allowedCardAuthMethods, | |
allowedCardNetworks: allowedCardNetworks | |
} | |
}; | |
const cardPaymentMethod = Object.assign({}, baseCardPaymentMethod, { | |
tokenizationSpecification: tokenizationSpecification | |
}); | |
function getGoogleIsReadyToPayRequest() { | |
return Object.assign({}, baseRequest, { | |
allowedPaymentMethods: [baseCardPaymentMethod] | |
}); | |
} | |
function getGooglePaymentDataRequest() { | |
return Object.assign({}, baseRequest, { | |
allowedPaymentMethods: [cardPaymentMethod], | |
transactionInfo: { | |
totalPriceStatus: 'FINAL', | |
totalPrice: '1.00', | |
currencyCode: 'USD', | |
countryCode: 'US' | |
}, | |
merchantInfo: { | |
merchantId: '12345678901234567890', | |
merchantName: 'Demo Merchant' | |
} | |
}); | |
} | |
function onGooglePayLoaded() { | |
paymentsClient.isReadyToPay(getGoogleIsReadyToPayRequest()) | |
.then(function(response) { | |
if (response.result) { | |
const button = paymentsClient.createButton({ onClick: onGooglePaymentButtonClicked }); | |
document.getElementById('container').appendChild(button); | |
} else { | |
console.error('Google Pay is not available.'); | |
} | |
}) | |
.catch(function(err) { | |
console.error('Error determining readiness to use Google Pay: ', err); | |
}); | |
} | |
function onGooglePaymentButtonClicked() { | |
const paymentDataRequest = getGooglePaymentDataRequest(); | |
paymentsClient.loadPaymentData(paymentDataRequest) | |
.then(function(paymentData) { | |
console.log('Payment data:', paymentData); | |
}) | |
.catch(function(err) { | |
console.error('Payment failed: ', err); | |
}); | |
} | |
window.onload = onGooglePayLoaded; | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment