Conversation
The Forest server requires client_id on /oauth/token and checks it against the client bound to the refresh token. Without it every API OAuth session was signed out about an hour after login. The session now stores the client id at code exchange. A refresh the server rejects is logged with its error code and description, and a session without a client id expires without calling the server. The contract test copies the issueToken Joi schema from forestadmin-server (packages/private-api/src/domain/oauth/oauth-route-validator.ts). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Coverage Impact This PR will not change total coverage. Modified Files with Diff Coverage (3)
馃洘 Help
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

An API OAuth session (hosted Zendesk included) now outlives the Forest access token: agent-bff refreshes it instead of signing the user out about an hour after login.
Fixes PRD-1384
Why
The Forest server requires
client_idon/oauth/tokenand checks it against the client bound to the refresh token. agent-bff sent only{ grant_type, refresh_token }, so the server answered400 invalid_request, which agent-bff maps tosession_expired.What
oauth/session-store.tsclientIdis required onCreateSessionInputandStoredSessionoauth/oauth-routes.tsrequest.clientIdin the sessionoauth/forest-server-client.tsrefreshServerToken({ refreshToken, clientId })sendsclient_id, shaped likeexchangeCodeoauth/session-lifecycle.tsensureFreshServerAccesstakes alogger. A session without a client id expires without calling the server. A refresh the server rejects is logged (Warn, error code + description,renderingId,userId)ai/ai-routes-middleware.ts,auth/forest-server-token-middleware.tsloggerBehaviour
invalid_grant,invalid_requestandinvalid_clientstill end insession_expired. The new log is what would have surfaced this bug.scopeis sent: the server falls back to the refresh token's original scope.API change
ForestServerClient.refreshServerTokenandensureFreshServerAccessare exported. Their only callers are inside agent-bff, and a refresh withoutclient_idalready fails on the server, so this ships as a fix.Tests
test/oauth/fixtures/forestadmin-server-oauth-route-validator-issue-token.tscopies the server'sissueTokenJoi schema (no.unknown(), so extra keys fail too). The bodiesrefreshServerTokenandexchangeCodeactually send pass it. Removingclient_idfrom the refresh body fails the test.session-lifecycle: the refresh uses the stored client id; a session without one ends insession_expired, logged, no server call; a rejected refresh logs the server's code and description.oauth-routes: the code exchange stores the client id.Release
Merges to
mainon its own, not held onfeat/gateway-r1. The merge redeploys the hosted API service. Rollback: revert the commit.Definition of Done
General
Security
馃 Generated with Claude Code
Note
Send
client_idon the Forest refresh grant inagent-bffclient_idin refresh-token grants, so the BFF stores the OAuth client ID in the session at authorization-code exchange time and sends it withrefresh_tokenon later refresh calls (forest-server-client.ts, session-store.ts).ensureFreshServerAccessnow requires aLoggerand rejects sessions without a stored client ID before contacting the Forest server, logging OAuth errors (invalid_grant,invalid_request,invalid_client) with rendering and user context (session-lifecycle.ts)./oauth/tokenrequest bodies, including a negative test that a refresh request withoutclient_idis rejected.clientIdnow fail assession_expiredwithout attempting a refresh.refreshServerTokenandCreateSessionInputsignatures changed.Macroscope summarized 2dbba01.