BUG: Access denied calling checkoutCompleteWithCreditCard from iOS App

Rob_Kerr
Shopify Partner
5 0 4

I'm developing a proof-of-concept iOS app to help my company decide whether to use Shopify as a back-end for product sales.  I've followed the iOS SDK guides, and have created a working application that does nearly everything it needs:

1. Access store info

2. Access collections and product catalog

3. Build a shopping cart, update shipping address, use the cardVaultUrl and CardCiient to obtain a token (I'm in test mode, so using a test credit card number)

On the next step I use checkoutCompleteWithCreditCard to process the order, and receive back "access denied".

I see on the uinversity forum that this issue comes up a lot (see links below), with no responses from Shopify whether this opertion shoudl work or not from a private app via iOS SDK.  

Is this feature not supported?  The documentation makes no mention of it being restricted, so it appears to be a bug.

https://ecommerce.shopify.com/c/shopify-apis-and-technology/t/checkoutcompletewithcreditcard-acess-d...

https://ecommerce.shopify.com/c/shopify-apis-and-technology/t/how-to-complete-native-checkout-using-...

https://ecommerce.shopify.com/c/shopify-apis-and-technology/t/storefront-api-checkoutcompletewithtok...

https://ecommerce.shopify.com/c/shopify-apis-and-technology/t/storefront-api-process-checkout-438429

Replies 138 (138)

Dima_Bart
Shopify Staff (Retired)
74 0 8

Could you please provide a little more information on the problem to help diagnose this case? It would be helpful to see what your payload to "checkoutCompleteWithCreditCard" looks like, as well as the payload to the "vaultURL" used for vaulting the card.

Keep in mind the the vaulting service doesn't perform any validation. This happens during the checkout process instead, which might lead to falsely believing that the vaulted token is valid and can be used for payment. Seeing your payloads will help us better understand where the problem might be.

To learn more visit the Shopify Help Center or the Community Blog.

Patrice4
Shopify Partner
4 0 0

Hello Ma'am

 

I am facing same issue,

 

My Store is "RandomSellStore", please help me with this

Rob_Kerr
Shopify Partner
5 0 4

HI Dima, thanks for your reply and assistance!

The actual payload going over the wire is difficult for me to fetch since it's being sent by the shopify API, but here's the swift code makign the api call. 

The proof-of-concept app is a series of view controllers (browse catalog, add to cart, apply shipping method, submit payment).  This is the last one--payment.  

Yes, I realize the token returned by the vault may be invalid, but if it was I'd expect an error more along the lines of "payment declined" instead of "access denied" from the checkoutCompleteWithCreditCard method (?)

I'm happy to zip up the entire project and send if it would be helpful...this is a simple proof-of-concept against  development store and test merchant account..so no confidentiality issues at all.

============ PaymentTableViewController.swift  ==============

import UIKit

import MobileBuySDK

 

class PaymentTableViewController: UITableViewController {

 

    @IBOutlet weak var firstName: UITextField!

    @IBOutlet weak var lastName: UITextField!

    @IBOutlet weak var creditCardNumber: UITextField!

    @IBOutlet weak var expiresMonth: UITextField!

    @IBOutlet weak var expiresYear: UITextField!

    @IBOutlet weak var verificationCode: UITextField!

    

 

    override func viewDidLoad() {

        super.viewDidLoad()

 

        firstName.text = "John"

        lastName.text = "Smith"

        creditCardNumber.text = "4242424242424242"

        expiresMonth.text = "12"

        expiresYear.text = "2019"

        verificationCode.text = "555"

    }

 

    // MARK: - Table view data source

 

    override func numberOfSections(in tableView: UITableView) -> Int {

        return 1

    }

 

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return 6

    }

    

    func fetchPaymentToken() {

        guard let cardClient = ShoppingData.shopifyCard else {

            displayError("nil card client in \(#function)")

            return

        }

        guard let cardVaultUrl = ShoppingData.cardVaultUrl else {

            displayError("nil cardVaultUrl in \(#function)")

            return

        }

        

        let creditCard = Card.CreditCard(

            firstName:        firstName.text ?? "",

            middleName:       "A",

            lastName:         lastName.text ?? "",

            number:           creditCardNumber.text ?? "",

            expiryMonth:      expiresMonth.text ?? "",

            expiryYear:       expiresYear.text ?? "",

            verificationCode: verificationCode.text ?? ""

        )

        

        let task = cardClient.vault(creditCard, to: cardVaultUrl) { token, error in

            if let token = token {

                print("Token received is: \(token)")

                self.processOrder(paymentToken: token)

            } else {

                self.displayError(error?.localizedDescription ?? "Unknown error obtaining token")

            }

        }

        task.resume()

    }

    

    @IBAction func submitOrderTapped(_ sender: UIBarButtonItem) {

        fetchPaymentToken()

    }

    

    func processOrder(paymentToken: String) {

        guard let checkoutId = ShoppingData.checkout?.id else {

            displayError("nil checkoutId in \(#function)")

            return

        }

        guard let client = ShoppingData.shopifyClient else {

            displayError("Invalid client in \(#function)")

            return

        }

        guard let billToAddress = ShoppingData.billToAddress else {

            displayError("nil billToAddress in \(#function)")

            return

        }

        guard let paymentDue = ShoppingData.checkout?.paymentDue else {

            displayError("nil paymentDue in \(#function)")

            return

        }

        let idempotencyKey = UUID().uuidString

        

        let payment = Storefront.CreditCardPaymentInput.create(

            amount:         paymentDue,

            idempotencyKey: idempotencyKey,

            billingAddress: billToAddress,

            vaultId:        paymentToken

        )

 

        let mutation = Storefront.buildMutation { $0

            .checkoutCompleteWithCreditCard(checkoutId: checkoutId, payment: payment) { $0

                .payment { $0

                    .id()

                    .ready()

                }

                .checkout { $0

                    .id()

                    .ready()

                }

                .userErrors { $0

                    .field()

                    .message()

                }

            }

        }

        

        let task = client.mutateGraphWith(mutation) { result, error in

            if let err = error {

                self.displayError(ShoppingData.shopifyErrorMessage(err: err))

                return

            }

            

            if let userError = result?.checkoutCreate?.userErrors, userError.count > 0 {

                for err in userError {

                    self.displayError(err.message)

                }

                return

            }

 

            let checkoutReady = result?.checkoutCompleteWithCreditCard?.checkout.ready ?? false

            let paymentReady  = result?.checkoutCompleteWithCreditCard?.payment?.ready ?? false

            

            print("Checkout completed: \(checkoutReady)")

            print("Payment completed: \(paymentReady)")

        }

        task.resume()

        

    }

 

 

}

============ ShoppingData.swift =================

class ShoppingData {

    static var shopifyClient: Graph.Client?                     // endpoint to shopify store

    static var shopifyCard: Card.Client?                        // endpoint to card processing

    static var itemCollections : [CatalogCollection] = []       // all items in the catalog

    static var cartItems : [CatalogItem] = []                   // all items in the shopping cart

    static var checkout: Storefront.Checkout?                   // the checkout object (from which the checkoutId is pulled from)

    static var billToAddress: Storefront.MailingAddressInput?   // save the address to re-use in the payment submission (in real life the bill-to may be different though)

    static var cardVaultUrl: URL?                               // the URL used to obtain credit card tokens

    

    static func shopifyErrorMessage(err: Graph.QueryError) -> String {

        switch err {

        case .request(let error):

            return error?.localizedDescription ?? "Error has nil local description"

        case .http(let statusCode):

            return HTTPURLResponse.localizedString(forStatusCode: statusCode)

        case .noData:

            return err.localizedDescription

        case .jsonDeserializationFailed:

            return "json deserialization failed"

        case .invalidJson:

            return "invalid json"

        case .invalidQuery(let reasons):

            return reasons[0].message

        case .schemaViolation(let schemaError):

            return "schema error: \(schemaError.localizedDescription)"

        }

    }

}

Dima_Bart
Shopify Staff (Retired)
74 0 8

It's possible the gateway doesn't like your test card number, verification number, etc. Have you tried a different test card?

To learn more visit the Shopify Help Center or the Community Blog.

Rob_Kerr
Shopify Partner
5 0 4

Yes, I'm using the numbers pasted from your site (see below). I've tried the visa and mastercard for sure, and have the same error either way.

https://help.shopify.com/manual/payments/shopify-payments/testing-shopify-payments

Rob_Kerr
Shopify Partner
5 0 4

just to reiterate...if the payment info was invalid, the error should be "payment declined" not "access denied", right?

juno
Visitor
1 0 0

See post below

Mira_Torres
Tourist
6 0 2

Reposting with shopify shop connected account: I'm seeing the same "access denied" error when calling checkoutCompleteWithCreditCard. Using Mobile-Buy-SDK 3.1.2 on iOS with Shopify private app storefront access token. Our test payload looks very similar to powerleydev's. Our shopify payment is also in test mode, and the credit card info is the same test credit card number(4242424242424242). Please let me know what additional info I need to provide to figure out what's wrong.

Mira_Torres
Tourist
6 0 2

Request payload for checkoutCompleteWithCreditCard:

mutation{checkoutCompleteWithCreditCard(checkoutId:"Z2lkOi8vc2hvcGlmeS9DaGVja291dC9jYTdiYTk5YTFjNTY0MmU1M2I0NTFjNjBlNWU5YzlhMj9rZXk9MjAwNDk4ZWRiYTM3NDQ2MmFjMzBiNjQyMGVmNjAxNzM=",payment:{amount:"12.15",idempotencyKey:"56D2826C-B45A-4F19-8182-EC6B06F3DC9C",billingAddress:{address1:"1 Gary",address2:"",city:"San Francisco",company:null,country:"United States",firstName:"Joe",lastName:"Black",phone:"5101231234",province:"California",zip:"94110"},vaultId:"west-8c88cce51c8695bcaea71480f140ebbc",test:true}){checkout{id,ready,requiresShipping,taxesIncluded,email,shippingAddress{firstName,lastName,phone,address1,address2,city,country,countryCode,province,provinceCode,zip},shippingLine{handle,title,price},note,lineItems(first:250){edges{cursor,node{variant{id,price},title,quantity}}},webUrl,currencyCode,subtotalPrice,totalTax,totalPrice,paymentDue,order{id,orderNumber,customerUrl,email}},userErrors{field,message}}}

Response:

{
    "data": {
        "checkoutCompleteWithCreditCard": null
    },
    "errors": [{
        "message": "CheckoutCompleteWithCreditCard access denied",
        "locations": [{
            "line": 1,
            "column": 10
        }],
        "path": ["checkoutCompleteWithCreditCard"]
    }]
}

Mira_Torres
Tourist
6 0 2

Aready treid with real credit card info and turning off payment test mode, got same error.

Is there a permission that needs to added to the private app that's not avaiable to be set in the admin UI? If so, how do I get that set or whom should I contact? Already tried customer support, but they can't resolve API related issues and directed me to this forum.

Please advice on next step.

Dima_Bart
Shopify Staff (Retired)
74 0 8

Further investigation revealed that it was a misconfiguration of permissions. It has been fixed and the checkouts should be running smoothly now. Please verify that it's working as you expect.

To learn more visit the Shopify Help Center or the Community Blog.

Mira_Torres
Tourist
6 0 2

I'm still getting the same error. Could you fix the private app permission on spongerevolution.myshopify.com account too?

Dima_Bart
Shopify Staff (Retired)
74 0 8

Mira, the permissions on your store have been updated.

To learn more visit the Shopify Help Center or the Community Blog.

Mira_Torres
Tourist
6 0 2

Works now, thank you. Will newly created private app have the correct permission now?

Rob_Kerr
Shopify Partner
5 0 4

@dima, thanks for taking care of this issue. Works great now!  

gurhan
Visitor
1 0 0

I'm also getting the same error. Could you please fix the permissions for worm-app.myshopify.com account too?

Dima_Bart
Shopify Staff (Retired)
74 0 8

@gurhan Permissions adjusted. Please take look.

To learn more visit the Shopify Help Center or the Community Blog.

Daniel_Sousa
Visitor
3 0 0

Hi @Dima, I'm also facing this same error in my android proof-of-concept app. I've created a new thread some time ago describing all the steps I took to proceed with the checkout but I've got no answer. Can you please help me to figure out what I'm missing in the checkout process please? I've attached all the logs (requests and responses) for every single step.

As far as I understand from this thread the "Access denied" error is related to a misconfiguration of permissions in the store, is it right? If so, is there any way to set those missing permissions in the admin UI?

Dima_Bart
Shopify Staff (Retired)
74 0 8

Please provide your shop domain that you're using for checkout.

To learn more visit the Shopify Help Center or the Community Blog.

Patrice4
Shopify Partner
4 0 0

Hello ma'am i am facing same issue,

 

My Domain Name :  randomsellstore.com

My Private App Name : RandomSellStore

Daniel_Sousa
Visitor
3 0 0

Hi Dima, thank you very much for your quick response. I've already successfully completed the checkout with credit card. I had a live chat with a colleague of yours who set the proper permissions to my private app already. 

It would be very useful if the process to request permission for private app was better detailed in the documentation. Is there any way to set these permissions without having to ask a Shopify Employee? I mean is there any way I could set them myself in the Admin UI (or any other interface available to me)?.

Dima_Bart
Shopify Staff (Retired)
74 0 8

 

I agree that the current process is not intuitive. We are working on improving it moving forward. Unfortunately, I don't have a timeline to share at the moment

To learn more visit the Shopify Help Center or the Community Blog.

Michael32
Shopify Partner
13 0 0

I'm also getting the same error. I tried with Shopify Payments in test mode and with Bogus Gateway. Could you please check? Shop domain is 'al1234-test-store.myshopify.com'

Dima_Bart
Shopify Staff (Retired)
74 0 8

Michael, I've fixed permissions for your shop. Please verify it works.

To learn more visit the Shopify Help Center or the Community Blog.

Michael32
Shopify Partner
13 0 0

Sorry, I cannot, because it returns 404. In the Shopify Partners dashboard it moved to the tab 'Transferred stores' and now it have 'Shopify Plan' - 'Fraudulent'. Please return it back.

Dima_Bart
Shopify Staff (Retired)
74 0 8

Michael, your shop status is unrelated to permission changes. If you have any questions regarding shop status, please contact support directly.

To learn more visit the Shopify Help Center or the Community Blog.

Michael32
Shopify Partner
13 0 0

Okay, thanks. You said you have fixed permissions. But this is newly created store, I created it just a day ago. We have another development store, and our client will create real store later. Should we ask here about every shop we create? Can we change permissions ourselves in Shopify Dashboard or admin panel?

Jason
Shopify Expert
11190 225 2283

Michael - if you have a store marked as fraudulent you'll need to talk to the Shopify Support team directly. It's not something that can be helped with on the public forum.

★ I jump on these forums in my free time to help and share some insights. Not looking to be hired, and not looking for work. http://freakdesign.com.au ★

Michael32
Shopify Partner
13 0 0

Dima, please make same changes also for 'alacard-test-store.myshopify.com'.

Dima_Bart
Shopify Staff (Retired)
74 0 8

Michael, what is the name of the private app that needs these permissions?

To learn more visit the Shopify Help Center or the Community Blog.

Michael32
Shopify Partner
13 0 0

Dima, name of private app is `Alacard private app (test)`

Dima_Bart
Shopify Staff (Retired)
74 0 8

Permissions have been adjusted. Please verify.

To learn more visit the Shopify Help Center or the Community Blog.

Michael32
Shopify Partner
13 0 0

It works. Thank you very much.

GOTeam
Visitor
3 0 0

Hi, same error here.
gofindit.myshopify.com

Could you fix the permissions?

Dima_Bart
Shopify Staff (Retired)
74 0 8

GOTeam, your "Mobile App"  app already has the correct checkout permissions.

To learn more visit the Shopify Help Center or the Community Blog.

Q_2
Shopify Partner
32 0 7

 

@Dima_Bart sir, please can you fix checkout permission for us also ? Storename : https://proj-jules-james.myshopify.com/ and app name : App

 

Thanks

alberto1
New Member
7 0 0

Hello Dima, 

I also work with gofindit.myshopify.com (GOTeam user) and we are still having the access denied error, we tested on both Android and iOS and we get the same error. Any other way to fix this issue?

Dima_Bart
Shopify Staff (Retired)
74 0 8

What's the name of your private app that you're using?

To learn more visit the Shopify Help Center or the Community Blog.

alberto1
New Member
7 0 0

Go Find It Store

We are using "Storefront access token" when we configure the GraphClient. Is that right, or should we use the API key that is in the Mobile App section? It's a little confusing... 

Dima_Bart
Shopify Staff (Retired)
74 0 8

Yep, that's correct. Permissions have been updated for the "Go Find It Store" client, you should be all set.

To learn more visit the Shopify Help Center or the Community Blog.

alberto1
New Member
7 0 0

Thanks! It works now. We will be creating new stores soon, is there any way to fix this issue from our end, so that we don't have to bother you again? 🙂

Dima_Bart
Shopify Staff (Retired)
74 0 8

No problem! Unfortunetly, not yet. We'll keep you posted here if anything changes.

To learn more visit the Shopify Help Center or the Community Blog.

mahesh3
Shopify Partner
11 0 12

Hi Dima,I'm still getting the same error. Could you fix the private app permission on http://mobilecommerce.myshopify.com  domain and my private app name is  SmartCommerce

Dima_Bart
Shopify Staff (Retired)
74 0 8

Hey Mahesh, SmartCommerce is now enabled with the correct permissions. Please verify.

To learn more visit the Shopify Help Center or the Community Blog.

faizan_haidar
Tourist
4 0 0

@Dima_Bart I am having same bug, can you please do some stuff with my permissions https://www.kingofsheba.com/ and App Name "King of Sheba".

mahesh3
Shopify Partner
11 0 12

Hey dima,now it is working fine thank you but i am getting an error like this
 

{

  "data" : {

    "checkoutCompleteWithCreditCard" : {

      "userErrors" : [

        {

          "field" : [

            "payment",

            "test"

          ],

          "message" : "Test is not supported"

        }

      ],

      "checkout" : {

        "id" : "Z2lkOi8vc2hvcGlmeS9DaGVja291dC84NGE4MTFjYzM3OWExZThkZWRkNzhjMDBlNmFjNWNmZD9rZXk9ZDU0YWQ4OGY1ZGYzYzJmYmQ0YzhmMDU1OWM2ZDY1Y2Q="

      }

    }

  }

Dima_Bart
Shopify Staff (Retired)
74 0 8

The error is telling you that "test" mode is not supported. Try removing the "test" parameter or setting it to "false" in your query.

To learn more visit the Shopify Help Center or the Community Blog.

mahesh3
Shopify Partner
11 0 12

Thank you Dima,now it is working fine 

Craig6
Tourist
11 0 1

Hey, @Dima - do you mind giving me permissions for graupel-test.myshopify.com?

Thanks!!