T031

How do we properly handle token refresh in our custom Flex SDK integration so the session stays alive past the initial TTL?

Ticket

Hi Twilio support team, I hope this finds someone who can help because I've been going around in circles reading the docs and I'm not 100% sure I have the full picture here. We're a mid-size SaaS company and we've been building a custom agent desktop that embeds the @twilio/flex-sdk (not using the stock Flex UI at all, just the SDK directly in our own React app). Things are generally working fine for the first hour or so of an agent's shift, but once that initial token TTL window closes we start seeing some weird behavior and I want to make sure we're handling the refresh flow correctly before we go to production. Here's what we're doing right now, roughly: 1. Agent logs in, our backend mints a Flex user token (JWE) and hands it to the frontend. 2. Frontend calls `const client = await createClient("SDK_TOKEN")` with that token. 3. Everything works great — agents can see tasks, accept voice tasks, messaging tasks come through, etc. 4. After about 3600 seconds (the default TTL I assume) we start seeing error 45775 "Failed to refresh token. Invalid token provided" show up in the console and then SDK calls start failing silently or throwing. So my first question is just: what is the correct sequence of steps to do a clean token refresh so the live client session picks up the new credentials without the agent having to log out and back in? I've seen references to `refreshToken({ refreshToken, ssoProfileSid })` and `validateToken(accountSid, token)` and then `client.updateToken(newToken, newRefreshToken)` but I'm not sure if those are all required in that order, or if some of them are optional, or if there's a timing consideration I'm missing. Right now our frontend is calling our backend to get a new token when we detect the expiry, then we're updating some local state with the new token value, but I don't think we're calling `client.updateToken(...)` at all, which based on some things I read might mean the underlying SDK clients (TaskRouter, Voice, Conversations, Sync) are still holding onto the old stale token even though our app thinks it refreshed. Is that right? Like, do all the connected services automatically pick up the new token if we call `client.updateToken(newToken, newRefreshToken)`, or do we need to do something additional for each one? Second question: is there an event we should be listening for that fires *before* the token actually expires so we can do a proactive refresh rather than reacting to failures? I've seen mention of a `tokenWillExpire` type of event pattern in some Voice SDK docs — is there an equivalent on the Flex SDK client side? Third, somewhat related question: we had one agent yesterday where after the token issue started happening, the session log showed something like `SessionState: setting degraded to true` and they could still see their task queue but inbound voice calls weren't connecting at all. The agent was convinced it was a routing problem and opened a ticket with our internal team, but it sounds to me like that degraded mode is actually a symptom of the Voice SDK client failing to reinitialize after the token problem rather than anything wrong with our TaskRouter config (Workspace WS04f7a2b1c3d8e9f0a1b2c3d4e5f6a7b8, Workflow WWab12cd34ef56ab12cd34ef56ab12cd34 if that matters). Can you confirm that's the right interpretation? And if so, does calling `client.updateToken(...)` with a fresh token recover the Voice client from degraded state automatically, or do we need to fully reinitialize the client? Fourth question and then I'll stop: we noticed error 31207 "JWT token expiration interval is too long" on a few Voice tasks. We have a separate Voice Access Token we're generating for the Voice SDK piece — is that a totally separate token from the Flex user JWE token, and does it have its own TTL constraints independent of the 3600s Flex token? I want to make sure we're not conflating two different token types here. Sorry for the wall of text — I just wanted to give you the full picture rather than go back and forth. We're on Chrome 124 mostly, a few agents on Edge 124. No specific TaskQueue or Worker SIDs are relevant to this since it's a general auth flow question, but happy to provide more if needed. Thanks so much, Daniel

Gold label: how_to / medium

with this many questions there is a danger that a TSE will see 'low' and always prioritize other tickets. a list like that needs to be addressed either by splitting tickets are getting a checklist going.

Results by run

openai · gpt-5.5

2026-10-04 17:23 UTC · prompt ef0017a

config (wrong)
medium (correct)
escalate: no

Summary

The customer’s custom Flex SDK integration is not correctly propagating refreshed credentials to the live SDK client after the initial token TTL, causing invalid-token errors and degraded Voice behavior.

Suggested first response

Thanks for the detailed context. This does sound like a token-refresh implementation issue rather than TaskRouter routing. Updating only your app state with a new token is not sufficient; the live Flex SDK client and its underlying services need to receive the refreshed credentials, so you should call the SDK token update flow after your backend mints/returns the new token. We recommend refreshing proactively before the token expires, based on the token expiry/TTL or any SDK-supported expiry event for your installed version, rather than waiting for 45775 failures. The degraded Voice state is consistent with one of the underlying SDKs becoming unavailable due to auth failure; a successful token update may recover it, but if Voice does not reconnect cleanly you may need to reinitialize the client and capture browser console/network logs for review. Also, error 31207 relates to a Voice JWT TTL constraint; that Voice Access Token is separate from the Flex user JWE and has its own expiration rules. Please share your exact @twilio/flex-sdk version and the token refresh code path so we can validate the sequence.

KB citations

kb-015

805 output tokens · 10.1s · 1 attempt(s)

anthropic · claude-sonnet-4-6

2026-10-04 17:20 UTC · prompt ef0017a

how_to (correct)
medium (correct)
escalate: no

Summary

Customer is building a custom Flex SDK integration and needs guidance on the correct token refresh flow, proactive expiry events, degraded mode recovery, and Voice Access Token TTL constraints to prevent session failures after the initial 3600s TTL.

Suggested first response

Hi Daniel, Thank you for the detailed write-up — this gives us a clear picture of what you're working through. Let me address each of your questions: 1. **Token refresh sequence:** You are correct that fetching a new token on your backend and updating local state alone is not sufficient. You must call `client.updateToken(newToken, newRefreshToken)` on the Flex SDK client instance so that the underlying sub-clients (TaskRouter, Voice, Conversations, Sync) receive the updated credentials. Without this call, those clients continue using the stale token, which is consistent with the 45775 errors you are seeing. The general sequence is: (a) detect approaching expiry, (b) call your backend to mint a fresh token, (c) call `client.updateToken(newToken, newRefreshToken)`. The `validateToken` and `refreshToken` calls you referenced are server-side helpers for token validation/issuance and are not required steps in the client-side refresh flow itself. 2. **Proactive expiry event:** Yes, you should listen for a token expiry warning event on the client rather than reacting to failures. The Flex SDK surfaces a `tokenAboutToExpire` (or equivalent `tokenWillExpire`) event that fires before the token actually expires, giving you a window to fetch and apply a new token cleanly. We recommend triggering your refresh logic from this event rather than on a fixed timer or on error detection. 3. **Degraded mode and Voice recovery:** Your interpretation is correct. The `SessionState: setting degraded to true` log entry indicates that one or more sub-clients (in this case, the Voice SDK client) failed to reinitialize after the token became invalid — this is not a TaskRouter routing or Workflow configuration issue. Calling `client.updateToken(...)` with a valid fresh token should allow the SDK to attempt to recover the degraded sub-clients. However, if the Voice client has fully disconnected, a full client reinitialization may be required in some cases. We'd recommend testing the `updateToken` path first and observing whether the Voice client transitions out of degraded state. 4. **Voice Access Token vs. Flex JWE token:** These are two distinct token types with independent TTLs. The Flex user token (JWE) governs the Flex SDK session, while the Voice Access Token (a JWT you generate with your API key and secret, scoped to the Voice grant) governs the Voice SDK client. Error 31207 means the TTL you set on the Voice Access Token exceeds the maximum allowed value (3600 seconds for Voice Access Tokens). Ensure you are generating the Voice Access Token with a TTL of 3600 seconds or less, and refresh it independently of the Flex token on the same proactive schedule. We'd recommend implementing the `tokenAboutToExpire` listener as your primary refresh trigger and confirming that `client.updateToken(...)` is called in all refresh paths before going to production. If after implementing these changes you continue to see 45775 errors or the Voice client does not recover from degraded state after a token update, please share a HAR file or console log from a reproduction session and we can dig deeper. Best regards, Twilio Support

KB citations

kb-015

1883 output tokens · 47.8s · 2 attempt(s)