Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid keys error when attempting to use an android_pay_card #103

Closed
mrezentes opened this issue Dec 9, 2015 · 10 comments
Closed

Invalid keys error when attempting to use an android_pay_card #103

mrezentes opened this issue Dec 9, 2015 · 10 comments

Comments

@mrezentes
Copy link

I am attempting to add support for Android Pay in the Braintree adapter in Active Merchant. When attempting to make an android pay card, I receive the following error

ArgumentError: invalid keys: android_pay_card[cardholder_name], android_pay_card[cryptogram], android_pay_card[expiration_month], android_pay_card[expiration_year], android_pay_card[number]
/Users/mrezentes/.rbenv/versions/2.1.7/lib/ruby/gems/2.1.0/gems/braintree-2.56.0/lib/braintree/util.rb:86:in `verify_keys'
/Users/mrezentes/.rbenv/versions/2.1.7/lib/ruby/gems/2.1.0/gems/braintree-2.56.0/lib/braintree/transaction_gateway.rb:10:in `create'
/Users/mrezentes/.rbenv/versions/2.1.7/lib/ruby/gems/2.1.0/gems/braintree-2.56.0/lib/braintree/transaction_gateway.rb:79:in `sale'

I have looked into the error and have a theory as to the source of the problem.
In the braintree gem, I see that there isn't an entry for the android_pay_card keys in the
transaction_gateway._create_signature https://github.com/braintree/braintree_ruby/blob/master/lib/braintree/transaction_gateway.rb#L125

Because there are entries in _create_signature for apple_pay, I am assuming there should be key values for android_pay. Out of curiosity, I added the same key values for android_pay as are listed for apple_pay but the request still failed with an Authorization Error but that seemed to take care of the invalid keys error. I am unsure what the names of the expected keys are for android pay, maybe if I had the proper key names the request would be successful.
Again, this is only a theory, I hope it is helpful.

@mrezentes
Copy link
Author

Here is the AM test that can reproduce the issue. From remote_braintree_blue_test.rb
This test is in a branch I am working on, not on master.

 def test_authorize_and_capture_with_android_pay_card
    credit_card = network_tokenization_credit_card('4111111111111111',
      :brand              => 'visa',
      :eci                => "05",
      :payment_cryptogram => "EHuWW9PiBkWvqE5juRwDzAUFBAk=",
      :source             => "android_pay"
    )

    assert auth = @gateway.authorize(@amount, credit_card, @options)
    assert_success auth
    assert_equal '1000 Approved', auth.message
    assert auth.authorization
    assert capture = @gateway.capture(@amount, auth.authorization)
    assert_success capture
  end

@mrezentes
Copy link
Author

This is the specific call to the Braintree::Gateway that can trigger the error

@braintree_gateway.transaction.send(:sale, {:amount=>"1.00", :order_id=>"1", :customer=>{:id=>nil, :email=>nil, :first_name=>"Longbob", :last_name=>"Longsen"}, :options=>{:store_in_vault=>false, :submit_for_settlement=>nil, :hold_in_escrow=>nil}, :custom_fields=>nil, :android_pay_card=>{:number=>"4111111111111111", :expiration_month=>"09", :expiration_year=>"2016", :cardholder_name=>"Longbob Longsen", :cryptogram=>"EHuWW9PiBkWvqE5juRwDzAUFBAk="}, :billing=>{:street_address=>"456 My Street", :extended_address=>"Apt 1", :company=>"Widgets Inc", :locality=>"Ottawa", :region=>"ON", :postal_code=>"K1C2N6", :country_code_alpha2=>"CA"}})

@pblesi
Copy link

pblesi commented Dec 10, 2015

Thanks @mrezentes for identifying this issue. We will look closer to verify that this is a bug and get back to you shortly.

@kexline4710
Copy link

Hi @mrezentes! I took a deeper look at your issue. You received the errors around the keys and then an Authorization error after they were altered because you cannot create a transaction with raw Android Pay card information.

# A snippet of the code you sent

@braintree_gateway.transaction.send(:sale, {
    :amount =>"1.00",
    # This is not supported
    :android_pay_card => {
        :number => "4111111111111111",
        :expiration_month => "09",
        :expiration_year => "2016",
        :cardholder_name => "Longbob Longsen",
        :cryptogram => "EHuWW9PiBkWvqE5juRwDzAUFBAk="
    }
})

I recommend implementing our payment method nonce workflow. You would use the raw Android Pay card details to create a payment method nonce in your client and then pass that nonce in your transaction call like so:

@braintree_gateway.transaction.send(:sale, {
    :amount =>"1.00",
    :payment_method_nonce => "android_payment_method_nonce"
})

We even provide a test payment method nonce for Android pay cards to use in development. I'm going to close this issue since it does not to appear to be a bug in our library, but feel free to reopen if you feel that is not the case. If you have specific questions about your implementation, I recommend reaching out to our support team so they can help you!

@rwdaigle
Copy link

Hi @kexline4710, thanks for this feedback.

Unfortunately, I don't think this approach will work for our particular use-case. This change is necessary for the ActiveMerchant library, which is unable to use the tokenization flow. It works by dealing with actual PAN data for auths, purchases etc...

What we need is the same ability you've provide for Apple Pay payment methods, which is the ability to transact with the actual PAN and cryptogram.

Is there any way to achieve parity with Apple Pay for Android Pay payment methods in this gem?

@dcopeland
Copy link

Hi, @rwdaigle and @mrezentes. I'm a developer on the Android Pay team at Braintree.

Tokenizing raw details (PAN, cryptogram, etc.) by the merchant (rather than by Google themselves) is not currently supported or on our roadmap to support. It's not something our merchants should generally consider for PCI and security reasons, so we're hesitant to expose it as an option.

That said, I assume you have a valid use case for ActiveMerchant (which I'm not personally very familiar with). If you can give me some more details on how this would be used and what the value is I'll take that back to the product management team so we can discuss whether and how it might be prioritized.

@rwdaigle
Copy link

Hi Dan,

It's not something our merchants should generally consider for PCI and security reasons, so we're hesitant to expose it as an option

Speaking specifically for the Spreedly use-case, we provide a service that lets merchants integrate with more than one gateway via a common API. So the merchant would send the encrypted Android Pay data to Spreedly, Spreedly decrypts it and sends it on Braintree. The merchant retains their minimal PCI scope (Spreedly carries that burden) so there's not additional PCI or security concerns. This is how it currently works with Apple Pay and Braintree. As you know, Apple Pay and Android Pay are quite similar in flow.

Also, by achieving Android Pay feature parity with Apple Pay there is more consistency when implementing solutions using your SDKs. Since both rely on the same underlying EMV tokenization spec it's also a more accurate reflection of the world to have them have the same API.

@dcopeland
Copy link

@rwdaigle Thanks. I'll share this with product management.

@dcopeland
Copy link

@mrezentes @rwdaigle You should be unblocked by braintree_ruby 2.59.0. See tests here for sample parameters:

context "Android Pay params" do
it "works with full params" do
params = {
:amount => "3.12",
:android_pay_card => {
:number => "4012888888881881",
:cryptogram => "AAAAAAAA/COBt84dnIEcwAA3gAAGhgEDoLABAAhAgAABAAAALnNCLw==",
:google_transaction_id => "25469d622c1dd37cb1a403c6d438e850",
:expiration_month => "10",
:expiration_year => "14",
:source_card_type => "Visa",
:source_card_last_four => "1111",
:eci_indicator => "05",
}
}
result = Braintree::Transaction.sale(params)
result.success?.should == true
result.transaction.status.should == Braintree::Transaction::Status::Authorized
end
it "works with only number, cryptogram, expiration and transaction ID (network tokenized card)" do
params = {
:amount => "3.12",
:android_pay_card => {
:number => "4012888888881881",
:cryptogram => "AAAAAAAA/COBt84dnIEcwAA3gAAGhgEDoLABAAhAgAABAAAALnNCLw==",
:google_transaction_id => "25469d622c1dd37cb1a403c6d438e850",
:expiration_month => "10",
:expiration_year => "14",
}
}
result = Braintree::Transaction.sale(params)
result.success?.should == true
result.transaction.status.should == Braintree::Transaction::Status::Authorized
end
it "works with only number, expiration and transaction ID (non-tokenized card)" do
params = {
:amount => "3.12",
:android_pay_card => {
:number => "4012888888881881",
:google_transaction_id => "25469d622c1dd37cb1a403c6d438e850",
:expiration_month => "10",
:expiration_year => "14",
}
}
result = Braintree::Transaction.sale(params)
result.success?.should == true
result.transaction.status.should == Braintree::Transaction::Status::Authorized
end
end

@rwdaigle
Copy link

Thanks, @dcopeland! We'll take a look and let you know how it goes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants