Authentication
Every messaging provider requires some form of authentication — an API key, a bearer token, a username and password pair, or an OAuth 2.0 client credentials flow. If every connector handled auth internally, each would duplicate logic for token refresh, credential caching, and error handling. Authentication would be inconsistent across connectors, and adding a new auth scheme would require modifying every connector.
The framework separates authentication from connector logic:
Connectors declare what authentication they support in their schema via
AuthenticationConfigurationProviders (implementing
IAuthenticationProvider) handle credential acquisition and managementChannelConnectorBasedelegates to a centralIAuthenticationManagerand auto-authenticates during initializationNew auth schemes can be added without modifying existing connectors
Core types
AuthenticationScheme
AuthenticationScheme is an extensible record type that identifies an authentication mechanism. It replaces the old AuthenticationType sealed enum.
public record AuthenticationScheme(string Name)
{
public static AuthenticationScheme None { get; }
public static AuthenticationScheme ApiKey { get; }
public static AuthenticationScheme Bearer { get; }
public static AuthenticationScheme Basic { get; }
public static AuthenticationScheme OAuthClientCredentials { get; }
public static AuthenticationScheme Certificate { get; }
public static AuthenticationScheme Digest { get; }
public static AuthenticationScheme Custom { get; }
// Create custom schemes:
public static AuthenticationScheme Of(string name) => new(name);
}Built-in schemes cover the most common authentication patterns:
None
Public endpoints, no auth required
ApiKey
SendGrid, generic REST APIs
Bearer
Facebook (Page Access Token), Telegram (Bot Token)
Basic
Twilio (AccountSid + AuthToken), SMTP
OAuthClientCredentials
Server-to-server OAuth 2.0
Certificate
Firebase (service account key)
Digest
RFC 7616 digest authentication
Custom
Provider-specific schemes
Custom schemes are created with AuthenticationScheme.Of("my-scheme") — no enum modification needed.
AuthenticationField
Describes a single field that an authentication configuration expects in ConnectionSettings. It is purely descriptive — validation is handled by providers.
The AuthenticationRole property tells providers how to interpret the field:
"principal"
The primary identifier
ApiKey, Token, Username, AccountSid, Certificate
"credential"
The corresponding secret
Password, AuthToken, ClientSecret
(other)
Auxiliary, treated as optional
ProjectId, CertificatePassword
AuthenticationConfiguration
Describes the set of fields required by a particular scheme. It is purely descriptive — providers use the field definitions to extract values from ConnectionSettings.
IsSatisfiedBy
The IsSatisfiedBy method checks whether a ConnectionSettings instance has enough values to satisfy this configuration, using role-aware logic:
If the config has both
"principal"and"credential"role fields, at least one of each must be presentIf the config has only
"principal"fields, at least one must be presentAll non-principal, non-credential fields must be present
This is used by the schema validation and by ChannelConnectorBase.AuthenticateAsync() to find the correct auth configuration for a given set of connection settings.
AuthenticationCredential
Holds the result of a successful authentication.
AuthenticationResult
Wraps the outcome of an authentication operation.
Architecture
Lifecycle
Schema declares what auth methods the connector supports via
AuthenticationConfigurationConnector initializes —
ChannelConnectorBase.InitializeAsync()automatically callsAuthenticateAsync()if the schema has auth configurationsConfig selected — iterates schema configs, picks the first where
IsSatisfiedBy(ConnectionSettings)returns trueProvider matched —
IAuthenticationManagerfinds a registeredIAuthenticationProviderwhoseCanHandle(config)returns trueCredential obtained — provider reads fields from
ConnectionSettings(using the config's field definitions) and returns anAuthenticationCredentialCredential cached — the manager caches the credential in memory
Connector uses credential —
AuthenticationCredential.Value,GetAuthenticationHeader(), orGetApiKey()provide the secret for API callsExpired credentials refresh — the manager detects expiration and either refreshes via the provider or obtains a new credential
Schema auth configuration
Adding authentication to a schema
Auto-registration of principal fields
When using AddAuthenticationConfiguration() with an explicit config, any field with AuthenticationRole = "principal" is automatically added as an optional ChannelParameter in the schema if not already defined. This ensures auth fields are recognized by strict-mode validation without requiring duplicate AddParameter calls.
AddAuthenticationScheme() (which uses flexible defaults) does NOT auto-register fields, avoiding parameter list pollution from alias fields that the connector does not actually use.
Default field aliases per scheme
When AddAuthenticationScheme(AuthenticationScheme.Xxx) is used, the builder generates sensible default fields:
Basic
Username, AccountSid, User, ClientId
Password, AuthToken, Pass, ClientSecret
ApiKey
ApiKey, Key, AccessKey
—
Bearer
Token, AccessToken, BearerToken, AuthToken
—
OAuthClientCredentials
ClientId
ClientSecret
Certificate
Certificate, CertificatePath, CertificateThumbprint, PfxFile
PfxPassword, CertificatePassword
Custom
CustomAuth, AuthenticationData, Credentials, AuthConfig, SecretKey, PrivateKey, Signature, Hash
—
For production connectors, use AddAuthenticationConfiguration() with explicit fields — it avoids ambiguity and provides better documentation.
Built-in providers
ApiKeyAuthenticationProvider
Extracts an API key from connection settings using fields with "principal" role. Returns AuthenticationCredential.ForApiKey(value).
BearerTokenAuthenticationProvider
Extracts a bearer token from connection settings using fields with "principal" role. Supports optional TokenType and ExpiresAt parameters.
BasicAuthenticationProvider
Extracts a username/password pair from connection settings. Looks for fields with "principal" role (e.g. Username, AccountSid) and pairs them with fields with "credential" role (e.g. Password, AuthToken), trying each combination until a complete pair is found.
ClientCredentialsAuthenticationProvider
Implements the OAuth 2.0 Client Credentials flow. Reads ClientId, ClientSecret, and TokenEndpoint from connection settings, POSTs to the token endpoint, and caches the resulting access token.
The provider:
Reads
ClientIdandClientSecretfrom connection settingsPOSTs
grant_type=client_credentialsto the token endpointParses the JSON response for
access_token,expires_in,token_typeSupports
refresh_tokenif present in the responseCaches the resulting credential and refreshes when expired
The credential is created with AuthenticationCredential.ForClientCredentials() which uses AuthenticationScheme.Bearer (since a client credentials flow still produces a bearer token), with Properties["GrantType"] = "client_credentials".
Using auth in a connector
Connectors no longer need to call AuthenticateAsync() manually — the base class does it automatically during InitializeAsync():
If auto-authentication fails (e.g., missing connection settings), the base class logs a warning but does not prevent initialization — the connector can still authenticate later or handle the error:
Refresh
Refreshes the current credential if it has expired (or will expire within 5 minutes). Falls back to AuthenticateAsync() if no credential exists.
Credential caching
AuthenticationManager caches credentials by (connectionSettings, authConfiguration) tuple. The cache key is built from the scheme name and parameter values (using hash codes). When AuthenticateAsync is called:
Check cache for a non-expired credential
If found and not about to expire, return directly
If expired, call
RefreshCredentialAsyncon the providerIf not cached, call
ObtainCredentialAsync
Custom authentication provider
Implement IAuthenticationProvider (or extend AuthenticationProviderBase) for custom auth flows:
Schema for custom provider
Registration
Or provide a custom IAuthenticationManager implementation.
Provider matching
When IAuthenticationManager.AuthenticateAsync() is called, it:
Finds the
AuthenticationConfigurationin the schema that satisfies the connection settings (IsSatisfiedBy)Iterates registered providers, calling
CanHandle(configuration)on eachDelegates to the first matching provider
The default AuthenticationProviderBase.CanHandle() matches on Scheme equality:
Override CanHandle() for providers that handle multiple schemes or need additional checks:
Schema validation integration
The ChannelSchemaExtensions.ValidateConnectionSettings() method uses IsSatisfiedBy() to check that at least one auth configuration can be fulfilled by the provided settings. If none matches, a ValidationResult is added to the error list.
Auth field names are also added to the "known parameters" set for strict-mode validation, so they do not produce "Unknown parameter" errors even when not declared as explicit schema parameters.
Migration from AuthenticationType
The old AuthenticationType enum and AuthenticationConfigurations static factory class have been removed:
AuthenticationType.ApiKey
AuthenticationScheme.ApiKey
AuthenticationType.Token
AuthenticationScheme.Bearer
AuthenticationType.ClientCredentials
AuthenticationScheme.OAuthClientCredentials
AuthenticationConfigurations.ApiKeyAuthentication()
new AuthenticationConfiguration(...).WithField(...)
AuthenticationConfigurations.FlexibleBasicAuthentication()
new AuthenticationConfiguration(...).WithField(...) × N fields
config.RequiredFields
config.Fields
config.OptionalFields
config.Fields
config.IsSatisfiedBy(settings)
config.IsSatisfiedBy(settings) (re-added with role-aware logic)
config.Validate(settings)
removed — providers handle validation
credential.CredentialValue
credential.Value
credential.AuthenticationType
credential.Scheme
AuthenticationCredential.CreateToken(...)
AuthenticationCredential.ForBearerToken(...)
AuthenticationCredential.CreateApiKey(...)
AuthenticationCredential.ForApiKey(...)
AuthenticationCredential.CreateBasic(...)
AuthenticationCredential.ForBasic(...)
DirectCredentialAuthenticationProvider
ApiKeyAuthenticationProvider, BearerTokenAuthenticationProvider, BasicAuthenticationProvider
Last updated