Stripe: Validating Publishable and Secret API Keys
Got it!
To validate your publishable keys you need to ask stripe for a new token using cURL. If the given key is invalid the response will contain an error message starting with "Invalid API Key provided".
Here's an example written in PHP:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.stripe.com/v1/tokens");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, "card[number]=4242424242424242&card[exp_month]=12&card[exp_year]=2017&card[cvc]=123");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_USERPWD, $publishableKey . ":");
$response = json_decode(curl_exec($ch),true);
if( curl_errno($ch) ){
echo 'Error:' . curl_error($ch);
}
curl_close ($ch);
if(substr($response["error"]["message"],0, 24 ) == "Invalid API Key provided"){
echo "Invalid API Key provided";
}
Same idea for validating your secret keys.
Validating the secret key is easy, simply calling the Stripe API with any command on the server side.
But for the public key... I found a way with Stripe.js :
let stripe = Stripe( <public key to test> );
setTimeout( ()=>{
stripe.createToken('pii', {personal_id_number: 'test'})
.then( result =>{
if( result.token )
// public key is valid :o)
else
// nope !
})
}, 300 )
Note the timeout before calling stripe.createToken(). If you don't do it, the promise returned by createToken() will never come back.
UPDATE: Just received a confirmation from Stripe; this it is a valid and acceptable method.
I have been trying to figure out a good way validate provided Stripe API keys also. I figured out a way to validate the secret key without having to make a purchase by creating a test customer. I am still looking into validating the publishable key but I thought this might help someone.
Here is a PHP example:
try {
\Stripe\Stripe::setApiKey($secret_key);
// create a test customer to see if the provided secret key is valid
$response = \Stripe\Customer::create(["description" => "Test Customer - Validate Secret Key"]);
return true;
}
// error will be thrown when provided secret key is not valid
catch (\Stripe\Error\InvalidRequest $e) {
// Invalid parameters were supplied to Stripe's API
$body = $e->getJsonBody();
$err = $body['error'];
$messages = array();
$messages[] = 'Status is: ' . $e->getHttpStatus();
$messages[] = 'Type is: ' . $err['type'];
$messages[] = 'Code is: ' . $err['code'];
$messages[] = 'Decline Code is: ' . $err['decline_code'];
$messages[] = 'Message: ' . $err['message'];
return false;
}
catch (\Stripe\Error\Authentication $e) {
// Authentication with Stripe's API failed
// (maybe you changed API keys recently)
$body = $e->getJsonBody();
$err = $body['error'];
$messages = array();
$messages[] = 'Status is: ' . $e->getHttpStatus();
$messages[] = 'Type is: ' . $err['type'];
$messages[] = 'Code is: ' . $err['code'];
$messages[] = 'Decline Code is: ' . $err['decline_code'];
$messages[] = 'Message: ' . $err['message'];
return false;
}
catch (\Stripe\Error\ApiConnection $e) {
// Network communication with Stripe failed
$body = $e->getJsonBody();
$err = $body['error'];
$messages = array();
$messages[] = 'Status is: ' . $e->getHttpStatus();
$messages[] = 'Type is: ' . $err['type'];
$messages[] = 'Code is: ' . $err['code'];
$messages[] = 'Decline Code is: ' . $err['decline_code'];
$messages[] = 'Message: ' . $err['message'];
return false;
}
catch (\Stripe\Error\Base $e) {
// Display a very generic error to the user, and maybe send
// yourself an email
$body = $e->getJsonBody();
$err = $body['error'];
$messages = array();
$messages[] = 'Status is: ' . $e->getHttpStatus();
$messages[] = 'Type is: ' . $err['type'];
$messages[] = 'Code is: ' . $err['code'];
$messages[] = 'Decline Code is: ' . $err['decline_code'];
$messages[] = 'Message: ' . $err['message'];
return false;
}
catch (Exception $e) {
// Something else happened, completely unrelated to Stripe
$body = $e->getJsonBody();
$err = $body['error'];
$messages = array();
$messages[] = 'Status is: ' . $e->getHttpStatus();
$messages[] = 'Type is: ' . $err['type'];
$messages[] = 'Code is: ' . $err['code'];
$messages[] = 'Decline Code is: ' . $err['decline_code'];
$messages[] = 'Message: ' . $err['message'];
return false;
}
I am not aware of any documented api call that can be made specifically to validate keys. Here is a suggestion you might try:
Require your partners to provide a valid credit card and inform them that in order to validate their Stripe keys, you will be making a $0.50 charge to their card that will be immediately refunded.
As part of your form validation, when both keys are given, submit a hidden form that contains all the data necessary to create a card token. You should be able to examine the response in your create card token response handler and determine if the publishable key is valid.
If you get a successful response back from the stripe server containing a card token, turn right around and submit a test charge for $0.50 (the minimum charge amount).
Make sure you're properly catching all the stripe exceptions. I believe with an invalid secret key, you should catch a Stripe_InvalidRequestError. If an exception is thrown you can report to the user.
If no errors are thrown, the charge will be made. Since you don't want to charge your partners, you'll want to capture the charge id from the stripe response and immediately refund the charge.