Authentication
BlueTusk negotiates PostgreSQL SCRAM-SHA-256, SCRAM-SHA-256-PLUS channel binding, PostgreSQL 18+ OAUTHBEARER, GSSAPI/Kerberos and SSPI, legacy MD5 challenges, and cleartext password challenges. TLS server certificate validation uses the platform policy by default. See PostgreSQL’s password authentication and encryption options for server configuration guidance.
Credential sources
Credentials are resolved lazily only when PostgreSQL asks for a password. A certificate-authenticated or trusted connection therefore does not read a password file or invoke a callback. The precedence for a password challenge is:
- access-token callback;
- password callback;
- explicit
Passwordconnection setting; then - the first matching PostgreSQL password-file entry.
Password and access-token callbacks are mutually exclusive. A synchronous open requires a synchronous callback; asynchronous opens prefer the asynchronous callback and fall back to the synchronous callback when necessary. Configure both callback forms when the same data source is used by synchronous and asynchronous callers:
var builder = new BlueTuskDataSourceBuilder(connectionString)
.UsePasswordProvider(request => vault.GetPassword(request.Host, request.Username))
.UsePasswordProvider(async (request, cancellationToken) =>
await vault.GetPasswordAsync(request.Host, request.Username, cancellationToken));
await using var dataSource = builder.Build();
Connection-string secrecy
Persist Security Info defaults to false. A BlueTuskConnection exposes the
original connection string until its first successful open, then permanently
omits Password and Passfile from the public ConnectionString property.
BlueTuskDataSource.ConnectionString omits them immediately because a data
source is ready to open physical sessions as soon as it is built. Authentication
continues to use the private immutable configuration, including on a later
reopen or when a pool creates another physical session.
Set Persist Security Info=true only when an application deliberately needs to
read those values back. This weakens accidental-disclosure protection and must
not be used as a substitute for a credential vault or token callback. The
connection-string builder necessarily exposes values while an application is
constructing configuration; never log the builder or its ConnectionString.
An access-token callback supplies a ready bearer/IAM token. When PostgreSQL 18+
advertises OAUTHBEARER, BlueTusk sends the token with the
RFC 7628 SASL mechanism. On servers requesting password, MD5, or SCRAM authentication, the
same callback supplies the token as the password, as required by database
services that use short-lived IAM tokens without PostgreSQL-native OAuth.
The callback is invoked once for each new physical connection, after TLS negotiation and only when the server requests a credential. Pool checkout does not refresh a token because an already-authenticated physical session does not authenticate again. Clearing or expiring a pooled session causes the next physical connection to request a new token.
await using var dataSource = new BlueTuskDataSourceBuilder(connectionString)
.UseAccessTokenProvider(async (request, cancellationToken) =>
await tokenService.GetDatabaseTokenAsync(request, cancellationToken))
.Build();
Native OAUTHBEARER always requires TLS and is incompatible with required channel binding because the standardized mechanism has no channel-binding variant. BlueTusk accepts an already-issued token; OAuth discovery, browser/device flows, and refresh-token storage remain application concerns. Optional, separately packaged cloud identity adapters integrate AWS RDS/Aurora, Azure Database for PostgreSQL, and Google Cloud SQL SDK credentials without adding vendor dependencies to the core provider. PostgreSQL still requires a correctly configured server-side OAuth validator; see PostgreSQL’s OAuth authentication guide.
GSSAPI, Kerberos, and SSPI
When PostgreSQL requests GSSAPI, BlueTusk creates a platform
NegotiateAuthentication context with the Kerberos package. A PostgreSQL SSPI
request uses the platform Negotiate package and the same opaque-token wire
exchange. Both genuine synchronous and asynchronous opens support multistep
negotiation and require the server to be mutually authenticated before
AuthenticationOk is accepted.
The default service principal target is postgres/<Host>. Set
Kerberos Service Name when PostgreSQL was configured with a different
krb_srvname value:
Host=db.example.test;Database=app;Username=worker;Kerberos Service Name=postgres
By default, the operating system supplies the process identity or credential cache. An application that deliberately owns a separate credential can attach it to the immutable data-source configuration; the credential is not placed in the connection string:
await using var dataSource = new BlueTuskDataSourceBuilder(connectionString)
.UseGssCredential(await credentialVault.GetNetworkCredentialAsync())
.Build();
GSSAPI does not invoke BlueTusk password or access-token callbacks. Returned platform tokens and protocol write buffers are cleared after each transport flush, and provider failures are reported without their original exception or token content. Kerberos authenticates the peers but this PostgreSQL exchange does not enable GSS-encrypted transport; configure TLS when database traffic must be encrypted. Server principals, keytabs, role mapping, realms, and ticket lifetime remain deployment responsibilities. See PostgreSQL’s GSSAPI authentication guide.
PostgreSQL password files
Set Passfile=/path/to/file to select a password file. When neither a callback
nor an explicit password is configured, BlueTusk checks PGPASSFILE, then the
platform default: %APPDATA%\postgresql\pgpass.conf on Windows or
$HOME/.pgpass on Unix. The file follows PostgreSQL’s
hostname:port:database:username:password
format, first-match ordering, * wildcards, and backslash escaping for colons
and backslashes.
Physical replication sessions match the special replication database field;
logical database replication continues to match its configured database name.
On Unix, group or world permissions cause the file to be ignored; use mode
0600. Windows relies on the security of the application-data directory, which
matches PostgreSQL behavior. An empty BlueTuskClientOptions.Passfile disables
default password-file lookup for low-level clients.
TLS client certificates
Low-level clients can supply BlueTuskClientOptions.ClientCertificates and an
optional LocalCertificateSelectionCallback. A data source provides fluent
equivalents and preserves them for pooled, unpooled, notification, and dedicated
replication sessions:
await using var dataSource = new BlueTuskDataSourceBuilder(connectionString)
.UseClientCertificate(clientCertificate)
.UseClientCertificateSelectionCallback(
(_, _, certificates, _, acceptableIssuers) => certificates[0])
.Build();
Certificates remain caller-owned and must stay valid for the data source’s
lifetime. The same runtime client identity and credential callbacks are retained
for EF physical-database maintenance connections. Platform server-certificate
and hostname validation remains enabled.
UseRemoteCertificateValidationCallback is available for private trust models,
but the callback becomes the security boundary and must validate the presented
certificate rather than accepting every certificate.
Cleartext and legacy MD5 compatibility
PostgreSQL MD5 challenges are supported for legacy servers, but MD5 is
deprecated by PostgreSQL and SCRAM should be preferred. A cleartext password
challenge is accepted over TLS. On plaintext transport it fails closed unless
Allow Unencrypted Password=true is explicitly configured for a trusted
compatibility environment.
Authentication protocol buffers are overwritten after transport flushes and temporary writable password/MD5/OAUTHBEARER/GSSAPI buffers are cleared. Immutable .NET strings cannot be zeroed; keep connection strings and callback results short-lived and never log them. Callback failures are reported without retaining the original exception, preventing a callback exception message from leaking a credential.