Skip to content

feat(socket-auth): authenticate realtime socket with customer and checkout socket tokens - #65

Open
roncodes wants to merge 1 commit into
mainfrom
feature/socket-auth
Open

roncodes wants to merge 1 commit into
mainfrom
feature/socket-auth

Conversation

@roncodes

@roncodes roncodes commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

What

Authenticates the app's realtime SocketCluster connection so it keeps working when the socket server enforces per-channel authorization.

  • Token provider (src/utils/socket-auth.ts): logged-in customers mint a short-lived token from POST storefront/v1/customers/socket-token. The request uses the store key as Bearer and the Customer-Token header, which is how every other customer request is authenticated. It reuses the existing storefront adapter's host, namespace and headers. No SDK release is needed.
  • In-memory authEngine on socketClusterClient.create. loadToken fetches a fresh token when there is none or when the current one expires within 60 s. The token is never written to MMKV, AsyncStorage or localStorage, and never goes in the URL query.
  • Refresh at expires_in - 60s via socket.authenticate(newToken).
  • Recovery: on deauthenticate, or on kickOut/subscribeFail for a tracked channel, the client mints a new token, re-authenticates and resubscribes the channels opened through the context. Retries are bounded per channel and per auth failure. Existing channel consumers keep working because SC routes channel data by name.
  • Login/logout: when the customer id changes, the socket re-authenticates with the new customer's token. On logout it drops the token, disconnects and reconnects anonymously.
  • Guest QPay: when no customer is logged in, use-qpay-checkout authenticates the socket with the checkout-scoped socket_token from the checkout initialize response before subscribing to checkout.<id>. Logged-in customers' own tokens already cover their checkouts. The response may give socket_token as either the mint object or a bare string, and both are accepted.
  • Handshake query: client=storefront-app/<version>. The version comes from the app version on native and from package.json on web.
  • Native and web SocketClusterContext both use the shared manager. useSocketClusterClient now also exposes authenticateWithCheckoutToken.

Why

Part of authenticated realtime channels: the socket server will only let a client subscribe to channels its token covers, such as the customer's own orders and the drivers/vehicles on them, or a guest's own checkout.

Old-server fallback

If the mint route returns 404 (the server has no socket auth or is an older release), there is no customer, or the request fails, the app connects anonymously, exactly as today. A 404 is remembered until the next login, so the route is not hit again on every reconnect. If socket_token is absent from the checkout response, nothing changes.

Notes

  • The app has a single configured store key and no store switching, so a store switch needs no re-authentication.
  • Guest checkout tokens cannot be refreshed client-side. Once one expires, the existing checkouts/status polling (on focus or app resume) still completes the order.
  • The FLEETBASE_KEY client is unchanged and is not used for socket tokens.
  • No version bump.

Test plan

  • Verified by CI.
  • Manual, against a server with socket auth enabled:
    • A logged-in customer's order screen receives order.<id> updates, and the token refreshes about 60 s before expiry without dropping the subscription.
    • Log out, then log in again: the socket reconnects anonymously, then re-authenticates and resubscribes.
    • A guest QPay checkout receives the checkout.<id> completion event.
  • Manual, against a server without socket auth: the mint route returns 404, the socket connects anonymously and realtime works as before.

The repo has no active unit-test setup (CI's test step is commented out), so no tests were added.

Related PRs

Part of the authenticated realtime channels rollout (socket auth), one PR per repo:

…ckout socket tokens

- In-memory authEngine delivers a customer socket token (POST
  storefront/v1/customers/socket-token, store key + Customer-Token) in the
  handshake; never persisted, never in the URL query.
- Refresh at expires_in - 60s via socket.authenticate; recover from
  deauthenticate/kickOut/subscribeFail by re-minting, re-authenticating and
  resubscribing tracked channels (bounded retries).
- Re-authenticate on login, reconnect anonymously on logout.
- Guest QPay checkout authenticates with the checkout-scoped socket_token from
  checkout initialize before subscribing to checkout.<id>.
- 404 from the mint route (older server) or no customer => anonymous, as before.
- Handshake query carries client=storefront-app/<version>.
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

Successfully merging this pull request may close these issues.

1 participant