Table of Contents

Authentication to your systems

The webhook's library provides three helpers, in the SESARWebHook.Core.Auth namespace, so that your handler can authenticate with the system that receives the data. Create them in Initialize, once, and reuse them.

OAuth2, client credentials

OAuth2ClientCredentialsHelper, for Microsoft Entra ID, SharePoint and Dynamics 365.

var dynamics = OAuth2ClientCredentialsHelper.ForDynamics365(tenantId, clientId, clientSecret, "https://<organization>.crm3.dynamics.com");
var graph = OAuth2ClientCredentialsHelper.ForSharePoint(tenantId, clientId, clientSecret, sharePointUrl);
var other = OAuth2ClientCredentialsHelper.ForAzureAD(tenantId, clientId, clientSecret, "api://my-api/.default");

string token = await dynamics.GetAccessTokenAsync();
Factory Requested scope
ForDynamics365 {dynamicsUrl}/.default
ForSharePoint https://graph.microsoft.com/.default, whatever SharePoint address you pass
ForAzureAD The scope you pass

The token endpoint is the one of Microsoft's public cloud: https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token.

OAuth2, refresh token

OAuth2RefreshTokenHelper, for services that issue a long-lived refresh token.

Factory Token endpoint
ForZoho(clientId, clientSecret, refreshToken, accountsDomain) {accountsDomain}/oauth/v2/token, by default https://accounts.zoho.com
ForGoogle(clientId, clientSecret, refreshToken) https://oauth2.googleapis.com/token
ForSalesforce(clientId, clientSecret, refreshToken, isSandbox) https://login.salesforce.com or, with isSandbox, https://test.salesforce.com
ForHubSpot(clientId, clientSecret, refreshToken) https://api.hubapi.com/oauth/v1/token

If the provider returns a new refresh token, the helper ignores it and keeps the old one. For a provider that rotates its refresh tokens, manage them yourself.

Shared behavior of the OAuth2 helpers

  • The access token is kept in memory and renewed on demand, 60 seconds before it expires. Obtaining it is protected against simultaneous calls.
  • A client credentials helper does not keep in memory a token without a lifetime (expires_in): each call requests a new one.
  • A refusal from the provider throws an OAuth2Exception, whose RawResponse contains the raw response. Do not log it as is: it can contain details about your tenant.
  • If your system answers 401, call InvalidateToken(), then retry once: the helpers do not do it on their own.
  • TestConnectionAsync() obtains a token and returns false on failure, without throwing an exception.

API key

ApiKeyHelper adds an API key to your requests.

var auth = ApiKeyHelper.InHeader("X-API-Key", apiKey);
auth.ApplyTo(request); // request: HttpRequestMessage
Factory Effect
InHeader(headerName, apiKey) Header of your choice
AsBearer(apiKey) Authorization: Bearer <key>
AsBasicAuth(username, apiKey) Authorization: Basic, key as password
AsBasicAuthUsername(apiKey) Authorization: Basic, key as user name, empty password
InQueryString(paramName, apiKey) Address parameter
  • Prefer ApplyTo(HttpRequestMessage), request by request. ApplyTo(HttpClient) modifies a client that may be shared: with InHeader, each call adds the value once more, and with InQueryString, it throws an exception.
  • Avoid InQueryString: the key, placed in the address, ends up in server and proxy logs.
  • Basic mode encodes in ASCII: a non-ASCII character in the name or the key is altered.

Secrets

The credentials for your systems come from the secrets file, Handlers.{id}.Secrets section, and are read with GetRequiredSetting. Never write them in appsettings.json or in the code.