https://connect.plugchoice.com. The hosted flow runs the setup; the shell gives it a small, fixed set of native tools for what a web page can’t do: join a charger’s Wi-Fi, talk to devices on the local network, use Bluetooth, scan a QR code, ask your app for a client secret, and close with a result.
The full contract between the two is the bridge protocol: bridge/PROTOCOL.md. This page sums up what matters for a review.
Credentials and secrets
- Scoped. A client secret reaches only the chargers, sites or address your server named in its
scope. There’s no “everything”. See Client sessions. - Random and stored hashed. A client secret is 32 random bytes. Plugchoice stores only its SHA-256 hash.
- Never in a URL from the SDK. The SDK opens the hosted flow with the action in the URL fragment, never the secret. The hosted flow asks the SDK for the secret, and the SDK calls your callback. It never logs the secret and keeps no copy after handing it over.
- In a browser, the secret travels in the URL fragment (
#cs=…), which browsers never send to a server. The hosted flow reads it, then removes it from the address bar, and sends no referrer.
The hosted flow
- One origin. Only pages from
https://connect.plugchoice.comcan use the SDK’s native tools. - Its own code only. The page’s Content Security Policy allows scripts from its own origin only: no inline or third-party scripts. It sends requests only to its own origin and
api.plugchoice.com. - Never framed. The page can’t be embedded in another site (
frame-ancestors 'none',X-Frame-Options: DENY). - No analytics or telemetry, in the SDK or in the hosted flow.
What the native tools can do
Local network only
Local network only
HTTP, WebSocket, TCP and UDP reach only devices on the local network:
- IPv4 addresses in
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16(link-local) and127.0.0.0/8(loopback); ::1andlocalhost;*.localnames.
TLS to devices
TLS to devices
A device’s HTTPS is checked against the system’s trust, or against what the hosted flow passes for that device: its maker’s certificate authority, or its key’s fingerprint. Such a trust can forgive a device certificate’s expiry and host name, which some makers let lapse; there’s no “accept anything”, and the local-network rule still applies.
Wi-Fi
Wi-Fi
The SDK joins a charger’s own setup network, which has no internet, while the setup runs. It never moves your whole app onto that network: your app and the web view keep their internet. The hosted flow has the phone leave the charger’s network when that part of the setup is done.
Bluetooth
Bluetooth
The SDK talks Bluetooth LE as a client, to devices found by a scan from the same page. At most 8 connections at once; all of them end when the page changes or the screen closes.
Camera
Camera
A native scanner reads one QR code, such as a setup code on a charger’s card. The SDK never logs what it read.
Limits
Limits
One local-network search, one Bluetooth scan and one QR scan at a time; at most 64 HTTP sessions, 16 TCP sockets and 8 Bluetooth connections. Every call has a timeout. The protocol lists them all.
Permissions
- The SDK asks for a permission when the setup needs it, not when your app starts: Wi-Fi, the local network, Bluetooth, the camera, and location (to read the name of the Wi-Fi network).
- On iOS, the prompts use the usage strings in your app’s Info.plist. Without the camera or Bluetooth string, the SDK leaves that feature out: the hosted flow offers typing instead of scanning, and doesn’t use Bluetooth.
- On Android, the library’s manifest declares the permissions; removing the Bluetooth ones turns Bluetooth off. QR scanning uses Google’s code scanner from Play services, which sends usage data to Google: mention it in your Play data safety form.
Dependencies
- iOS: none beyond Apple’s frameworks.
- Android: AndroidX (Activity, Core, WebKit), OkHttp, Kotlin coroutines, and the Google code scanner (Play services).
- React Native: the iOS and Android SDKs, through Expo modules.