Problem
rsconnect login <server> runs an OAuth authorization code flow with a loopback redirect URI (http://127.0.0.1:<port>/callback, rsconnect/oauth.py). In a hosted session — Posit Workbench, a remote container, a cloud IDE — the browser that opens is not on the same host as the CLI listener, so the callback never arrives and the login hangs.
--use-device-code is the current workaround, and posit-dev/#842 tracks falling back to it automatically. But device code only exists if the target Connect is new enough: the built-in OAuth authorization server gained RFC 8628 device code support in Connect 2026.06. Against an older Connect, login_with_device_code() correctly reports that the server does not support the flow (rsconnect/oauth.py, "Server does not support the device code flow"), and at that point there is no working path at all from a Workbench session. The error message tells the user what happened but leaves them with no route forward.
This is currently blocking agentic publishing from Workbench: see posit-dev/connect#42494 and posit-dev/connect#42503, where the connect-deploy skill was updated to prefer --use-device-code in Workbench. That fix is complete only for Connect >= 2026.06.
Requested change
Two options, not mutually exclusive:
1. Implement the legacy token claim flow as an alternate path
Posit Publisher already does this, and it works against older Connect versions because it polls rather than relying on a redirect:
- Generate an RSA 2048-bit keypair and a token ID.
POST /__api__/tokens with the public key, which returns a claim URL.
- Show the claim URL to the user.
- Poll until the token is claimed, then use the private key to sign requests.
See extensions/vscode/src/auth/generateToken.ts in posit-dev/publisher for the reference implementation. rsconnect (R) connectUser() uses the same mechanism, so rsconnect-python is the odd one out here. Because it is poll-based, it needs no reachable callback and works in any hosted environment.
2. Allow the redirect URI to be supplied
Add something like --redirect-uri, or detect Workbench directly, so the authorization code flow can use a browser-reachable callback instead of loopback. In Workbench that URL is derived from RS_SERVER_URL: Workbench exposes a generic OAuth relay at /oauth_redirect_callback that records the authorization code against the state parameter, and /oauth_code?state= hands it back once. Publisher implements exactly this in extensions/vscode/src/auth/oauth/workbench.ts (with RS_SERVER_ADDRESS used for the polling side so the browser session cookie isn't required).
Note that register_client() currently hardcodes "redirect_uris": ["http://127.0.0.1/callback"] during Dynamic Client Registration, so a configurable redirect URI has to be threaded through registration too, and Connect has to accept the non-loopback value.
Longer term, a general mechanism for "use a public callback URL when one is available" is the better answer than every tool detecting Workbench on its own — but the legacy token flow is the pragmatic near-term fix for pre-2026.06 servers.
Related
Filed at the request of @mconflitti-pbc.
Problem
rsconnect login <server>runs an OAuth authorization code flow with a loopback redirect URI (http://127.0.0.1:<port>/callback,rsconnect/oauth.py). In a hosted session — Posit Workbench, a remote container, a cloud IDE — the browser that opens is not on the same host as the CLI listener, so the callback never arrives and the login hangs.--use-device-codeis the current workaround, and posit-dev/#842 tracks falling back to it automatically. But device code only exists if the target Connect is new enough: the built-in OAuth authorization server gained RFC 8628 device code support in Connect 2026.06. Against an older Connect,login_with_device_code()correctly reports that the server does not support the flow (rsconnect/oauth.py, "Server does not support the device code flow"), and at that point there is no working path at all from a Workbench session. The error message tells the user what happened but leaves them with no route forward.This is currently blocking agentic publishing from Workbench: see posit-dev/connect#42494 and posit-dev/connect#42503, where the
connect-deployskill was updated to prefer--use-device-codein Workbench. That fix is complete only for Connect >= 2026.06.Requested change
Two options, not mutually exclusive:
1. Implement the legacy token claim flow as an alternate path
Posit Publisher already does this, and it works against older Connect versions because it polls rather than relying on a redirect:
POST /__api__/tokenswith the public key, which returns a claim URL.See
extensions/vscode/src/auth/generateToken.tsin posit-dev/publisher for the reference implementation. rsconnect (R)connectUser()uses the same mechanism, so rsconnect-python is the odd one out here. Because it is poll-based, it needs no reachable callback and works in any hosted environment.2. Allow the redirect URI to be supplied
Add something like
--redirect-uri, or detect Workbench directly, so the authorization code flow can use a browser-reachable callback instead of loopback. In Workbench that URL is derived fromRS_SERVER_URL: Workbench exposes a generic OAuth relay at/oauth_redirect_callbackthat records the authorization code against thestateparameter, and/oauth_code?state=hands it back once. Publisher implements exactly this inextensions/vscode/src/auth/oauth/workbench.ts(withRS_SERVER_ADDRESSused for the polling side so the browser session cookie isn't required).Note that
register_client()currently hardcodes"redirect_uris": ["http://127.0.0.1/callback"]during Dynamic Client Registration, so a configurable redirect URI has to be threaded through registration too, and Connect has to accept the non-loopback value.Longer term, a general mechanism for "use a public callback URL when one is available" is the better answer than every tool detecting Workbench on its own — but the legacy token flow is the pragmatic near-term fix for pre-2026.06 servers.
Related
connect-deployskill: guide agents to device code auth in WorkbenchFiled at the request of @mconflitti-pbc.