"Unable to establish a secure connection to Square" — Mobile Payments SDK, both Reader and Tap to Pay fail identically

Hi all,

We have a custom OAuth application (Application ID: sq0idp-XVw9V87IGatCqc5bHlxH5g) built on the Mobile Payments SDK for Android, running on a dedicated kiosk device. Both the physical Square Reader and Tap to Pay on Android fail with the identical error: “Unable to establish a secure connection to Square.”

What we’ve already confirmed is NOT the problem:

- Network connectivity to Square’s servers is healthy (confirmed reachable).

- Bluetooth pairs and connects successfully at the protocol level (GATT service discovery, MTU negotiation, and connection all succeed in our logs) — yet Tap to Pay, which uses no Bluetooth reader at all, fails with the exact same error, so this isn’t reader/Bluetooth-specific.

- The app’s signing certificate is registered under this Application ID in the Developer Console, and we’ve verified via apksigner verify --print-certs that it exactly matches the certificate on the currently installed build.

- Location Services is enabled on the device.

- Location ID LC6D23CYBJV7G (“SPEDALIS CREWE”) is confirmed ACTIVE with CREDIT_CARD_PROCESSING capability via the Locations API.

- Our Square account already processes in-person card payments successfully today — we have a separate, currently “Connected” Square Reader (serial 612LS22311000418) working fine through Square’s own Register/Restaurants app on the same account. This confirms the account itself fully supports card-present payments; the failure appears isolated to this custom OAuth application.

- Our OAuth application requests scopes: MERCHANT_PROFILE_READ PAYMENTS_READ PAYMENTS_WRITE PAYMENTS_WRITE_IN_PERSON ORDERS_READ ORDERS_WRITE.

The device/reader affected:

- Kiosk’s Square Reader serial: 612LS22311000374

- Also fails identically via Tap to Pay on the same physical Android device.

Our question: given the account-level capability is proven working, is there a separate approval/review step required for the PAYMENTS_WRITE_IN_PERSON scope specifically for third-party/custom OAuth applications (as opposed to Square’s own first-party apps), that may not have been completed for this application? Or is there something else at the application/account level that would block secure-connection establishment for this specific app while leaving the account’s existing hardware unaffected?

Happy to provide logs, timestamps, or a screen recording of the failure on request.

Thanks,

Ishtiaq

Following up with some additional details that came up as useful in similar threads here, in case they help narrow this down faster:

- Location ID: LC6D23CYBJV7G (“SPEDALIS CREWE”)

- Package name: uk.spedalis.kiosk

- Mobile Payments SDK version: 2.6.1 (compileSdk 37 / targetSdk 36 / minSdk 28)

- Installation method: installed directly via `adb install` from our own signed release build. This app has never been distributed through the Google Play Store, so Play App Signing re-signing shouldn’t be a factor here (unlike a couple of similar threads I found where that was the eventual root cause).

- This is a brand new kiosk deployment — the secure connection has never succeeded even once, so it isn’t a regression from a previously-working state.

- We also tried fully disabling Developer Options and USB debugging on the device, then rebooting, then testing without touching ADB at all afterward — same error, so it doesn’t appear to be related to the device being in a debug-enabled state either.

- UTC timestamps of recent failed attempts: several within the last couple of hours as of this post, most recently right after that Developer-Options-off + reboot test at approximately 2026-09-12 15:30 UTC.

Happy to provide a screen recording or more precise timestamps if that would help.

Root cause: not server/account/certificate at all — KioskPaymentBridge.java’s authorize() cached the Mobile Payments SDK’s “already authorized” state keyed only on locationId. Since that location ID never changes, one early bad authorization attempt got permanently treated as valid for the rest of the app session, so every later reconnect attempt never actually re-ran the real handshake — explaining why Reader and Tap to Pay failed identically and everything server-side checked out clean.

Fix: added a forceRefresh flag so the staff “Square reader settings” action forces a genuinely fresh authorization, while normal payment flow keeps using the cache correctly.