{"record":{"id":"685d5d18896fbe0f","repo":"tursodatabase/turso","slug":"auth-token-requires-an-https-remote-turso-url-unle","errorCode":null,"errorMessage":"Auth Token requires an HTTPS remote Turso URL unless the host is localhost or loopback.","messagePattern":"Auth Token requires an HTTPS remote Turso URL unless the host is localhost or loopback\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data/TursoRemoteClient.cs","lineNumber":190,"sourceCode":"    {\n        if (commandTimeout <= 0)\n            return null;\n\n        var timeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n        timeout.CancelAfter(TimeSpan.FromSeconds(commandTimeout));\n        return timeout;\n    }\n\n    private static void ValidateAuthTokenTransport(Uri endpoint, string? authToken)\n    {\n        if (authToken is null\n            || endpoint.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)\n            || endpoint.IsLoopback)\n        {\n            return;\n        }\n\n        throw new InvalidOperationException(\"Auth Token requires an HTTPS remote Turso URL unless the host is localhost or loopback.\");\n    }\n\n    private static RemoteStatement BuildStatement(string sql, TursoParameterCollection parameters, bool wantRows)\n    {\n        var statement = new RemoteStatement\n        {\n            Sql = sql,\n            WantRows = wantRows,\n        };\n\n        foreach (TursoParameter parameter in parameters)\n        {\n            var value = RemoteRequestValue.FromTursoValue(parameter.ToValue());\n            if (string.IsNullOrEmpty(parameter.ParameterName))\n            {\n                statement.Args.Add(value);\n            }\n            else","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/bindings/dotnet/src/Turso.Data/TursoRemoteClient.cs#L172-L208","documentation":"The client refuses to send your Bearer auth token over plaintext HTTP. ValidateAuthTokenTransport runs in the TursoRemoteClient constructor (reached from TursoConnection.Open) and again whenever the server redirects the session via base_url: if an AuthToken is configured, the endpoint must be https, or its host must be localhost/loopback. This is a credential-leak guard thrown as an InvalidOperationException, not a server-side failure.","triggerScenarios":"Opening a connection whose string is like 'Url=http://db.example.com;AuthToken=eyJ...' via TursoConnection.Open/OpenAsync; also triggered mid-session when a pipeline response carries a base_url that points the client at a non-HTTPS, non-loopback host (UpdateSession re-validates the redirected URL).","commonSituations":"Local or containerized setups that use a LAN IP (10.x, 192.168.x), a docker service name, or a VM hostname with http:// plus a token -- Uri.IsLoopback only covers localhost and 127.0.0.1; copying a cloud token into an http test config; a load balancer advertising an http:// base_url in redirect responses.","solutions":["Change the Url in the connection string to https://.","If the target is genuinely local, use http://localhost or http://127.0.0.1 (loopback is exempt) or remove the AuthToken entirely.","If the error appeared mid-session rather than at Open, inspect what base_url the server or gateway returns and fix it to advertise https.","For self-hosted servers on a LAN, terminate TLS on a reverse proxy with a valid certificate instead of using plain HTTP."],"exampleFix":"// before\nvar cs = \"Url=http://192.168.1.50:8080;AuthToken=eyJhbGci...\";\n\n// after -- remote hosts need https; loopback or no-token needs nothing\nvar cs = \"Url=https://db.mycompany.com;AuthToken=eyJhbGci...\";\n// or, for a local server without auth:\nvar cs = \"Url=http://127.0.0.1:8080\";","handlingStrategy":"validation","validationCode":"var opts = new TursoConnectionStringBuilder(cs);\nvar uri = new Uri(opts.Url);\nif (!string.IsNullOrWhiteSpace(opts.AuthToken)\n    && !uri.Scheme.Equals(\"https\", StringComparison.OrdinalIgnoreCase)\n    && !uri.IsLoopback)\n{\n    throw new InvalidOperationException(\n        $\"Refusing to open: AuthToken over non-HTTPS {uri.Scheme}://{uri.Host}. Use https or a loopback host.\");\n}","typeGuard":"static bool TokenTransportIsSafe(Uri url, string? authToken) =>\n    string.IsNullOrEmpty(authToken)\n    || url.Scheme.Equals(\"https\", StringComparison.OrdinalIgnoreCase)\n    || url.IsLoopback;","tryCatchPattern":"try\n{\n    await conn.OpenAsync(cancellationToken);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"HTTPS remote Turso URL\"))\n{\n    // configuration error, never transient: surface a clear config failure, do not retry\n    throw new ConfigurationException(\"Turso Url must be https:// when AuthToken is set (or use localhost/127.0.0.1).\", ex);\n}","preventionTips":["Default to https:// URLs in every environment and treat http as a configuration smell.","Remember only localhost and 127.0.0.1 are loopback -- LAN IPs, docker names, and VM hosts are not.","Never reuse cloud auth tokens against plain-HTTP test servers.","Validate the connection string at startup, before the first query, and fail fast with a clear message."],"tags":["turso","dotnet","connection-string","security","https","auth-token"],"backgroundTag":"https-url-required","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}