#15722: fix: prefer explicit token over stored device token for remote gateways
gateway
size: XS
## Summary
When `callGateway` receives an explicit token (e.g. `gatewayToken` param from `cron wake` or other tools targeting a remote gateway), the `GatewayClient` was incorrectly preferring the locally-stored device auth token over the explicitly provided one.
## Root Cause
In `src/gateway/client.ts` line 192:
```typescript
const authToken = storedToken ?? this.opts.token ?? undefined;
```
The stored device token (from local gateway pairing) takes precedence over `this.opts.token` (the explicit `gatewayToken` parameter). When targeting a remote gateway, the local stored token is sent instead, causing `1008: unauthorized: gateway token mismatch`.
## Fix
Reverse the precedence so explicit token wins:
```typescript
const authToken = this.opts.token ?? storedToken ?? undefined;
```
Stored device token is still used as fallback when no explicit token is provided (normal local gateway connections unaffected).
## Reproduction
1. Local gateway has stored device auth token from pairing
2. Remote gateway at `ws://remote:18789` has token `abc123`
3. Call: `cron(action='wake', gatewayUrl='ws://remote:18789', gatewayToken='abc123')`
4. **Before:** Local stored token sent → `gateway closed (1008): unauthorized: gateway token mismatch`
5. **After:** Explicit `gatewayToken` sent → success
Fixes #15718
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR changes `GatewayClient`'s connect/auth token selection to prefer an explicitly provided token (`this.opts.token`, e.g. `gatewayToken` for remote gateways) over a locally stored device auth token loaded from `device-auth.json`.
The change is localized to `src/gateway/client.ts` in `sendConnect()`, and it preserves the existing fallback behavior (use stored device token only when no explicit token is provided). This avoids sending a local pairing token when connecting to a remote gateway, which can otherwise trigger `1008` unauthorized token mismatch errors.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- The change is a simple precedence swap in token selection during gateway connect; it aligns with expected behavior for remote gateways and does not alter types, control flow, or persistence logic beyond selecting the intended token.
- No files require special attention
<sub>Last reviewed commit: 8125fca</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#17279: fix: restore device token priority over config token
by MisterGuy420 · 2026-02-15
85.5%
#16310: fix(ws-connection): skip device pairing when client authenticates w...
by nawinsharma · 2026-02-14
83.8%
#17379: fix: restore device token priority in device-auth mode
by Limitless2023 · 2026-02-15
83.4%
#21651: fix(gateway): token fallback + operator.admin scope superset in pai...
by lan17 · 2026-02-20
81.6%
#10093: fix: import gateway token from URL param into localStorage
by devjiro76 · 2026-02-06
81.3%
#23503: fix: preserve pairing state on device token mismatch + migrate lega...
by dorukardahan · 2026-02-22
80.4%
#17705: fix(gateway): allow trusted-proxy auth to bypass device-pairing gates
by dashed · 2026-02-16
79.8%
#17378: fix(gateway): allow dangerouslyDisableDeviceAuth with trusted-proxy...
by ar-nadeem · 2026-02-15
79.5%
#19389: Fix #2248: Allow insecure auth bypass when device signature validat...
by cedillarack · 2026-02-17
79.3%
#19088: fix(gateway): allow startup with unset mode and fix pairing for local…
by mdanassaif · 2026-02-17
78.7%