fix(online-inbox): invalidate cached access token when the signed-in user changes
ZitadelAuthProvider cached the access token in memory and only re-read the refresh token when the cache expired. Re-signing as a different user saved a new refresh token but the worker kept serving the previous user's cached access token until it expired — so sync (and ownerId stamping) continued under the old identity. Track the refresh token that minted the cached token and invalidate the cache when the stored refresh token changes (user switch or sign-out). Switching users now takes effect on the next sync without a worker restart. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -152,6 +152,37 @@ public sealed class ZitadelAuthProviderTests : IDisposable
|
||||
Assert.Equal(2, handler.Requests.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ChangedRefreshToken_InvalidatesCache_AndRefreshesForNewUser()
|
||||
{
|
||||
if (!OperatingSystem.IsWindows()) return;
|
||||
|
||||
var (provider, handler, store) = Build();
|
||||
store.Save("admin-refresh");
|
||||
|
||||
// First user (admin): discovery + token.
|
||||
handler.Enqueue(".well-known", HttpStatusCode.OK,
|
||||
DiscoveryJson("https://auth.example.com/oauth/token"));
|
||||
handler.Enqueue("oauth/token", HttpStatusCode.OK,
|
||||
TokenJson("admin-access", expiresIn: 3600));
|
||||
|
||||
var adminToken = await provider.GetAccessTokenAsync();
|
||||
Assert.Equal("admin-access", adminToken);
|
||||
|
||||
// Re-sign-in as a different user writes a new refresh token to the store.
|
||||
store.Save("normal-refresh");
|
||||
|
||||
// Even though the cached admin token is still within its expiry window, the changed
|
||||
// refresh token must force a new exchange (no second discovery — it's cached).
|
||||
handler.Enqueue("oauth/token", HttpStatusCode.OK,
|
||||
TokenJson("normal-access", expiresIn: 3600));
|
||||
|
||||
var normalToken = await provider.GetAccessTokenAsync();
|
||||
|
||||
Assert.Equal("normal-access", normalToken);
|
||||
Assert.Equal(3, handler.Requests.Count); // discovery + admin token + normal token
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RotatedRefreshToken_IsPersisted()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user