fix: apply renewed access token in embed mode with delegated authentication - #12856
fix: apply renewed access token in embed mode with delegated authentication#12856Eflyax wants to merge 1 commit into
Conversation
029fad0 to
f41b6ca
Compare
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
…cation The "owncloud-embed:update-token" message listener was registered unbound, so it crashed on `this.configStore` before applying the renewed token. It also passed the whole message payload to updateContext instead of the access token string. The embedded instance therefore kept the initial access token until it expired and the user got logged out.
f41b6ca to
39346b8
Compare
There was a problem hiding this comment.
Verified locally — the fix is correct and both defects reproduce independently:
mastersource + this PR's tests only →TypeError: ... reading 'options'atauthService.ts:409- binding fix only →
updateContextreceives{name, data:{access_token}}instead of the token string - full PR → 17/17 pass
The arrow property is the right choice over an inline .bind(this): one stable reference per instance, so the addEventListener de-dup at line 292 still holds.
Requesting changes for test hygiene only — the source changes LGTM.
One point I can't attach inline because the line is unchanged context outside the diff: in this PR's version of authService.spec.ts, line 289 asserts only expect(mockUpdateContext).toHaveBeenCalled(). That weak assertion is what let the payload defect go unnoticed since v8.0.0 — it confirmed that something was passed, never what. Tightening it to toHaveBeenCalledWith(...) belongs in this PR.
Note: only the Snyk checks have run; the web unit-test pipeline hasn't been triggered, so the new tests aren't verified in CI yet.
| ) | ||
| }) | ||
|
|
||
| describe('handleDelegatedTokenUpdate', () => { |
There was a problem hiding this comment.
This suite already has a describe('handleDelegatedTokenUpdate') block further down (line 224 in this file). Please merge the new tests into the existing block instead of adding a second one with the same name.
| ) | ||
| }) | ||
|
|
||
| it('ignores "owncloud-embed:update-token" messages from unexpected origins', async () => { |
There was a problem hiding this comment.
Minor: the two pre-existing origin-rejection tests in this same file (now at lines 231 and 248) already cover "wrong origin → no token update", so this makes a third. Not a blocker if you prefer to keep it — it does combine dispatchEvent with a wrong origin.
The test below it is the one that carries the real value: it goes through window.dispatchEvent, which is the path the browser actually uses and where this was being lost. The older tests invoke the handler directly as a method ((authService as any).handleDelegatedTokenUpdate(event), line 287), so this is bound correctly there and the defect could never surface — which is why they passed for two years while the feature was broken.
| } | ||
|
|
||
| const accessToken = event.data.data?.access_token | ||
| if (!accessToken) { |
There was a problem hiding this comment.
This new guard isn't covered by a test. Worth adding a case where an owncloud-embed:update-token message arrives without an access_token and asserting updateContext is not called.
There was a problem hiding this comment.
@Eflyax Thanks for tracking this down and for the thorough write-up in the issue. The root-cause analysis made this quick to verify. I reproduced both defects locally and confirmed the fix works.
The source changes look good. I've left a few notes on the tests only, nothing structural.
Description
Fixes token renewal in Web embed mode with delegated authentication. The
owncloud-embed:update-tokenmessage listener inAuthServicehad two defects that made renewal impossible:window.addEventListener('message', this.handleDelegatedTokenUpdate)), sothiswas not theAuthServiceinstance and the handler threwTypeErroron its first line for every incoming message. The method is now an arrow function class property, which keepsthisbound and preserves a stable reference for the listener.event.data, i.e.{ name, data: { access_token } }) toupdateContext(accessToken: string, …). It now extractsevent.data.data?.access_token— consistent with the initial token handover inoidcCallback.vue— and ignores messages without a token.Adds two unit tests: a renewed token from the configured origin is applied via
updateContext, and messages from unexpected origins are ignored. Both tests fail against the previous implementation.Related Issue
Motivation and Context
Token renewal in embed mode with delegated authentication has never worked (the defects exist since the feature was introduced in owncloud/web v8.0.0). Host applications that deliver renewed tokens per the documented contract still lose the embedded session as soon as the initial access token expires, which makes the embed mode unusable for sessions longer than one access token lifetime.
How Has This Been Tested?
owncloud-embed:update-tokenmessage logsUncaught TypeError: can't access property "options", this.configStore is undefined, requests keep the expired token, user is logged out on token expirypnpm vitest run authService.spec— 17 tests pass; the two new tests fail against the unfixed implementationScreenshots (if appropriate):
Open tasks: