{"record":{"id":"7b7735c99ec5a3d4","repo":"dotnet/aspnetcore","slug":"unexpected-status-code-returned-from-authenticatio","errorCode":null,"errorMessage":"Unexpected status code returned from authentication refresh '${response.statusCode}'","messagePattern":"Unexpected status code returned from authentication refresh '(.+?)'","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/SignalR/clients/ts/signalr/src/HttpConnection.ts","lineNumber":436,"sourceCode":"        const connectionGeneration = this._connectionGeneration;\n        const headers: {[k: string]: string} = {};\n        const [name, value] = getUserAgentHeader();\n        headers[name] = value;\n\n        const refreshUrl = this._createRefreshUrl(this._connectionUrl, this._connectionToken);\n        this._logger.log(LogLevel.Debug, `Sending authentication refresh request: ${refreshUrl}.`);\n\n        const request: HttpRequest = {\n            content: \"\",\n            headers: { ...headers, ...this._options.headers },\n            timeout: this._options.timeout,\n            withCredentials: this._options.withCredentials,\n        };\n        this._httpClient.markAuthenticationRefreshRequest(request);\n        const response = await this._httpClient.post(refreshUrl, request);\n\n        if (response.statusCode !== 200) {\n            throw new Error(`Unexpected status code returned from authentication refresh '${response.statusCode}'`);\n        }\n\n        if (typeof response.content !== \"string\") {\n            throw new Error(\"Invalid authentication refresh response received: expected JSON content.\");\n        }\n\n        if (connectionGeneration !== this._connectionGeneration) {\n            return undefined;\n        }\n\n        const refreshResponse = JSON.parse(response.content) as { accessToken?: unknown, tokenLifetimeSeconds?: unknown };\n        if (typeof refreshResponse.accessToken === \"string\" && refreshResponse.accessToken) {\n            // Redirecting servers can return a transport token that should replace the current cached token.\n            this._setTransportAccessToken(refreshResponse.accessToken);\n        } else if (!this._transportAccessTokenFromServer) {\n            // Without a server-provided transport token, reuse the app token that successfully authenticated refresh.\n            const refreshRequestToken = this._httpClient.getRefreshRequestToken(response);\n            if (refreshRequestToken) {","sourceCodeStart":418,"sourceCodeEnd":454,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/SignalR/clients/ts/signalr/src/HttpConnection.ts#L418-L454","documentation":"_refreshAuthentication POSTs to a refresh URL and expects HTTP 200. Any other status code means the refresh failed (token endpoint rejected, server error, etc.), and the client throws with the offending status so the caller knows the connection's auth cannot be renewed.","triggerScenarios":"The refresh-token endpoint returns 401 (refresh token invalid/expired), 403 (forbidden), 404 (wrong refresh route), or 5xx. The client surfaces the status verbatim in the error message.","commonSituations":"Refresh token expired server-side. Refresh URL is wrong (typo, missing controller). Server-side token service down. CORS or auth middleware rejects the refresh request. The connection string changed and the old token cannot be refreshed.","solutions":["Inspect response.statusCode in the error to pick the recovery path (401 -> re-auth, 5xx -> backoff/retry).","Verify the refresh endpoint route and that it accepts the connectionToken format the client sends.","Ensure the refresh token / access token factory returns a valid token.","If transient, retry the refresh with backoff before tearing down the connection."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"async function probeRefresh(url: string, token: string) {\n  const r = await fetch(`${url}/refresh?access=${encodeURIComponent(token)}`, { method: \"POST\" });\n  if (r.status !== 200) throw new Error(`Refresh endpoint returned ${r.status}`);\n}","typeGuard":"function isRefreshFailure(e: unknown): boolean {\n  return e instanceof Error && /Unexpected status code returned from authentication refresh/.test(e.message);\n}","tryCatchPattern":"import { HttpError } from \"@microsoft/signalr\";\ntry { await connection.start(); }\ncatch (e) {\n  if (e instanceof Error && /Unexpected status code returned from authentication refresh/.test(e.message)) {\n    const m = e.message.match(/'(\\d+)'/);\n    const status = m ? Number(m[1]) : 0;\n    if (status === 401) await reAuthenticateUser();\n  }\n  throw e;\n}","preventionTips":["Inspect the embedded status code to pick recovery (401 -> re-auth, 5xx -> retry).","Verify the refresh route is correct and returns 200 with a JSON body.","Use withServerTimeout / token-lifetime config to refresh before expiry."],"tags":["authentication","token-refresh","http","lifecycle"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}