I'm getting a "Could not construct ApplicationDefaultCredentials" from Google Recaptcha Enterprise, but only on our remote server. I've tried everything I can think of to isolate the issue, but I've had no luck.
I have two Recaptcha Enterprise keys: One for testing, and one for prod.
The testing key works fine on localhost. I've tried both the testing and prod key on our staging server, but I keep getting the same error.
Could not construct ApplicationDefaultCredentials
Things I've checked:
Basically all the values are present (project ID, site ID, service account details) and the domain is allowed, but as soon as it's on the remote staging server, it is failing to create credentials.
I'm struggling to figure out what the difference could be.
public static function createRecaptchaAssessment(
string $siteKey, // Present
string $token, // Present
string $projectId // Present
): Assessment {
$options = [
'keyFile' => config('services.google.app_credentials'), // Present
'projectID' => $projectId
];
$client = new RecaptchaEnterpriseServiceClient($options); // <-- Throws exception for ApplicationDefaultCredentials not being able to be created
...
Things to consider: The staging server is hosted on an elasticbeanstalk.com
subdomain, and the site is password protected with .htpasswd
. I know sometimes elasticbeanstalk.com is blacklisted because it is a blanket domain, but we're only specifying the subdomain and there's no "This domain is not allowed" message from Google. And there shouldn't be any inbound connections being blocked by .htapasswd that I'm aware of.
I've tried creating a new Service Account, just incase there was something configured incorrectly (it has Recaptcha Enterprise Agent permissions) but nothing changed.
Any ideas on how else I could debug this would be gratefully appreciated. (Note: This is a PHP/Laravel 9 project hosted on AWS Elastic Beanstalk, but I don't think that's a factor.)
Key takeaway: The ApplicationDefaultCredentials
error is almost certainly related to the Service Account .json not being picked up by your application.
Full version: So apparently I took some poor advice from another SO answer which suggested you could pass the path to the Service Account credentials .json file through the following array:
$options = [
'keyFile' => config('services.app_credentials'), // DON'T DO THIS
'projectID' => $projectId
];
I spent a long time looking through the Google library only to discover that neither array keys are used. Actually what happens is this:
If the library isn't passed a path to the Service Account credentials .json file, it then looks for an environment variable called GOOGLE_APPLICATION_CREDENTIALS
.
If you have this ENV and your environment supports it, that's actually what it is going on. (Which is why you might find that it works locally, but not remotely, as I did.)
When you deploy Laravel remotely, all the .env variables are cached and so not available through getenv()
... meaning the library is not able to find GOOGLE_APPLICATION_CREDENTIALS
even if you have it included in your .env.
The solution is to add the path through an array key credentials
:
$options = [
'credentials' => config('services.app_credentials')
];
$client = new RecaptchaEnterpriseServiceClient($options);
Now it works perfectly.