- Shipped
- October 14, 2026 at 4:16 PM UTC
- Author
- Kamo
- Commit
- 618ee73
state was base64 JSON {orgId, nonce, provider} built by the caller, the nonce was never stored or checked, and the sessionless callback trusted the decoded orgId - anyone could attach their own Zoom or Microsoft account to another org. MeetingOAuthStateStore now issues a random 64-hex token bound to org, member and provider (10-minute TTL); the callback spends it with GETDEL, one atomic command, so a forged, expired, replayed or concurrent second callback is refused before the provider is called. The redirect-URI lookup peeks. Token refresh had no lock and wrote inside the caller's transaction while Zoom rotates the refresh token on every use: two pods refreshing at once left one holding a revoked token. refreshIfNeeded now takes a Redis lock per (org, provider) (30 s lease, owner-checked release), re-reads the row in a REQUIRES_NEW transaction (a waiter usually finds the winner's fresh grant and never spends the refresh token), and stores the result through MeetingOAuthTokenWriter (REQUIRES_NEW), committed before the lock is freed.
