- Shipped
- September 5, 2026 at 6:30 AM UTC
- Author
- Kamo
- Commit
- bd4465d
A member's phone-settings tab asked for a JWT credential, and that was the only way to connect them. A RingCentral JWT belongs to one user and is minted by that user inside RingCentral's developer console, which they must first have been granted access to — so an organization with one service-user JWT and thirty phone users was being told to create thirty developer credentials. The org that reported this had been pasting the same service-user JWT into member after member; it stores, and every one of those softphones would have registered as the service user's extension. RingCentralMemberOAuthService is the ordinary three-legged authorization-code hop, run on the instance's OWN client id and secret — the same app the service-user JWT is presented under, so one customer's consent still cannot mint a token against another customer's account, which is the property the JWT change was introduced to gain. PKCE, the rotating refresh token persisted on every use (keep the spent one and the next refresh is indistinguishable from a revoked credential), and a 4xx refresh drops the row so the card asks for a fresh sign-in rather than retrying something that can never work. The per-member requirement itself stays, because RingCentral gives no way out of it: client-info/sip-provision takes no account, extension or device-owner field — its request body is device, sipInfo and softPhoneLineReassignment and nothing else — so it always provisions the extension owning the presented token, and it is the only endpoint that returns a WSS transport. account/{id}/device/{id}/ sip-info IS admin-readable, but returns proxy and proxyTLS only, which no browser can register on. What changes is what the member is asked FOR: a password they have, not a key they must create. The JWT route stays as the fallback it should always have been — a service account nobody signs in as, or an app with only the JWT flow enabled — so **************** now reports connected on either credential and mints through whichever is stored, preferring the sign-in. Two things a sign-in makes reachable that a JWT paste did not, closed here: completeMemberConnect refuses a credential that resolves to a different extension than the member is assigned rather than storing it with a warning, and PhoneProviderFactory stops building a member-scoped provider on a known mismatch. Everything downstream of that credential is self-scoped, so either one would have served another person's call history, voicemail and presence to this member and placed their calls as them. PkceCodes moves out of providers/teams — both providers' hops need it now.