dotnet/aspnetcore · error · Error
Authentication refresh is only supported with HTTP-based con
Error message
Authentication refresh is only supported with HTTP-based connections.
What it means
Thrown at HubConnection.ts:625 when `refreshAuthentication()` is called on a connection whose `features.authenticationRefresh` is not set. The authentication refresh feature is only configured by HttpConnection after a successful negotiate (see _configureAuthenticationRefresh at HttpConnection.ts:402); a non-HTTP connection (custom IConnection, or skipNegotiate which skips negotiate) does not set it.
Source
Thrown at src/SignalR/clients/ts/signalr/src/HubConnection.ts:625
*/
public onreconnected(callback: (connectionId?: string) => void): void {
if (callback) {
this._reconnectedCallbacks.push(callback);
}
}
/** Refreshes the authentication state for this connection.
*
* @returns A Promise that resolves with the new server-reported token lifetime in seconds, or undefined when the server does not report one.
*/
public async refreshAuthentication(): Promise<number | undefined> {
if (this._connectionState !== HubConnectionState.Connected) {
throw new Error("Cannot refresh authentication when the connection is not active.");
}
const authenticationRefreshFeature = this.connection.features.authenticationRefresh as IAuthenticationRefreshFeature | undefined;
if (!authenticationRefreshFeature) {
throw new Error("Authentication refresh is only supported with HTTP-based connections.");
}
let newTokenLifetimeInSeconds: number | undefined;
try {
newTokenLifetimeInSeconds = await authenticationRefreshFeature.refreshAuthentication();
} catch (e) {
await this._invokeAuthenticationRefreshFailed(e);
throw e;
}
if (this._connectionState === HubConnectionState.Connected &&
this.connection.features.authenticationRefresh === authenticationRefreshFeature &&
this._isAutoAuthenticationRefreshEnabled() &&
isValidAuthenticationTokenLifetime(newTokenLifetimeInSeconds)) {
this._scheduleAuthenticationRefresh(newTokenLifetimeInSeconds);
}
await this._invokeAuthenticationRefreshed(newTokenLifetimeInSeconds);View on GitHub (pinned to 294cab2f9b)
Solutions
- If you need refresh, use a standard HTTP-based HttpConnection without skipNegotiation so negotiate runs and sets the feature.
- For a custom IConnection, expose `features.authenticationRefresh = { initialTokenLifetimeInSeconds, refreshAuthentication }`.
- If you skipped negotiate, acquire app tokens via the accessTokenFactory instead of server refresh.
Example fix
// before
new HubConnectionBuilder().withUrl(url, { skipNegotiation: true, transport: HttpTransportType.WebSockets }).build();
await hub.refreshAuthentication(); // throws - feature not set
// after - use accessTokenFactory for app-side tokens
new HubConnectionBuilder().withUrl(url, { accessTokenFactory: () => getJwt() }).build(); Defensive patterns
Strategy: type-guard
Validate before calling
function hasRefreshFeature(conn) {
return !!conn && !!conn.features && typeof conn.features.authenticationRefresh?.refreshAuthentication === 'function';
}
if (hasRefreshFeature(hub.connection)) await hub.refreshAuthentication();
else { await hub.stop(); await hub.start(); } Type guard
function supportsAuthRefresh(hub: HubConnection): boolean {
const f = (hub as any).connection?.features?.authenticationRefresh;
return !!f && typeof f.refreshAuthentication === 'function';
} Try / catch
try { await hub.refreshAuthentication(); }
catch (e) {
if (/HTTP-based connections/.test(String(e))) {
// no server-side refresh; do a full reconnect using accessTokenFactory
await hub.stop(); await hub.start();
} else throw e;
} Prevention
- Use a standard HttpConnection without skipNegotiation if you need server-side refresh.
- For custom IConnection implementations, expose the authenticationRefresh feature.
- If you skipped negotiate, use accessTokenFactory to rotate tokens client-side.
When it happens
Trigger: Using a custom IConnection implementation that doesn't expose the authenticationRefresh feature; constructing HttpConnection with `skipNegotiation: true` (which bypasses _configureAuthenticationRefresh); calling refreshAuthentication on a mock connection in tests.
Common situations: Injecting a custom IConnection (e.g. a mock or a non-HTTP transport) but expecting refresh to work; using skipNegotiation with WebSockets and still wanting server-side token refresh; tests that build a HubConnection over a fake connection.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Cannot refresh authentication before the connection is start
- Unexpected status code returned from authentication refresh
- Invalid authentication refresh response received: expected J
- Cannot refresh authentication when the connection is not act
- Authentication refreshBeforeExpirationInMilliseconds must be
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/29bf11ad972ce250.
Report an issue: GitHub.