Skip to content

fix: refresh Keycloak token during long --waitFor polling loop#362

Open
Aman-Cool wants to merge 1 commit into
microcks:masterfrom
Aman-Cool:fix/token-expiry-polling-loop
Open

fix: refresh Keycloak token during long --waitFor polling loop#362
Aman-Cool wants to merge 1 commit into
microcks:masterfrom
Aman-Cool:fix/token-expiry-polling-loop

Conversation

@Aman-Cool
Copy link
Copy Markdown

Ran into something subtle while testing an ASYNC_API_SCHEMA conformance run with a 10-minute --waitFor.

The pipeline went red. The CLI printed success: false, inProgress: false and exited 1 ; looked exactly like a test failure. Spent a while staring at the API implementation before realising the test on the Microcks server had actually passed. The CLI had just… stopped reading it.

The culprit: in the headless path (--microcksURL + --clientId + --clientSecret), we call ConnectAndGetToken once at startup, hand the token to SetOAuthToken, and never touch it again. Five minutes in, Keycloak's default access token TTL kicks in. The Microcks API starts returning 401s.

Here's the quiet part; GetTestResult never checked resp.StatusCode. It just read the body and called json.Unmarshal on it. If Spring Security returned an empty 401 body, you'd get "failed to parse test result response: unexpected end of JSON input" (confusing, but at least loud). If it returned a JSON error object, the unmarshal succeeded into a zeroed TestResultSummary ; Success: false, InProgress: false ; and the loop broke clean, printing what looked like a completed result. No mention of auth anywhere.

The fix is in three places:

GetTestResult now checks the status code first. A 401 returns a named error that says "bearer token has expired" so the next person doesn't chase the wrong thing.

ConnectAndGetToken now returns expires_in alongside the token (and actually checks the HTTP status before asserting on access_token, which was a panic waiting to happen on a bad client secret).

In test.go, kc and tokenExpiresAt are kept in scope across the polling loop. At the top of each iteration, if we're within 30 seconds of expiry, we re-run the client credentials grant and call SetOAuthToken with the fresh token. For a 30-minute async test against a 5-minute realm, this fires roughly every 5 minutes ; transparent, no user action needed.

import and import-url just get a _ for the new return value; they don't have long-running loops so the TTL doesn't matter to them.

Bearer token was acquired once and never refreshed, causing 401s after
token TTL expired mid-poll. GetTestResult now checks HTTP status before
unmarshalling so expired-token responses surface as clear errors instead
of silently zeroing the TestResultSummary and breaking the loop early.

Signed-off-by: Aman-Cool <aman017102007@gmail.com>
@Aman-Cool Aman-Cool force-pushed the fix/token-expiry-polling-loop branch from 64525c6 to d943b52 Compare May 11, 2026 03:14
@Aman-Cool
Copy link
Copy Markdown
Author

@Harsh4902, would love a review on this when you get a chance.
It's a small fix but affects anyone running async tests with a --waitFor longer than their Keycloak token TTL ; which is pretty easy to hit without realising it.
Happy to add tests or tweak anything

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