Service-to-Service Authentication
Service-to-Service (S2S) authentication uses Azure AD (Entra ID) App Registrations with client credentials to authenticate BCCL without any user interaction. This is the recommended method for automated operations, Windows service mode, and scheduled scripts.
When to Use S2S Authentication
S2S authentication is the best choice when:
- You are running BCCL as a Windows service
- You need fully automated, unattended operations
- You are scheduling BCCL commands via Task Scheduler or Job Queue
- You want the most secure authentication method for cloud Business Central
- You need long-running operations that may exceed the OAuth token lifetime
- A single BCCL operation runs long enough that OAuth would stop working. OAuth access stops working after a period predefined by the tenant administrators; S2S allows BCCL to re-authenticate while the operation is still running
Unlike OAuth Device Code Flow, S2S does not require a user to open a browser and enter a code. It authenticates entirely through client credentials, making it ideal for server-to-server scenarios.
Prerequisites
Before configuring S2S authentication, you need:
- Azure AD App Registration created in the Azure portal
- Client Secret generated for the App Registration
- App granted permissions in Business Central on the Microsoft Entra Applications page
- Tenant ID for your Azure AD / Entra ID tenant
Creating an Azure AD App Registration
- Sign in to the Azure portal
- Navigate to Azure Active Directory > App registrations
- Select New registration
- Enter a name (e.g., "BCCL Integration")
- Set Supported account types to "Accounts in this organizational directory only"
- Select Register
- Note the Application (client) ID and Directory (tenant) ID
Generating a Client Secret
- In your App Registration, go to Certificates & secrets
- Select New client secret
- Add a description and set an expiration period
- Select Add
- Copy the Value immediately (it will not be shown again)
Granting Permissions in Business Central
- In Business Central, search for Microsoft Entra Applications (named Azure Active Directory Applications in older versions)
- Create a new entry and add your App Registration's Client ID
- Set the state to Enabled
- On the permission-set lines, assign the BCCL permission set
- Add permission sets for the data BCCL will read or write (see "Permissions" below)
Permissions: Authentication Is Not Authorization
Registering the Entra app and storing its credentials with --remember only establishes authentication. Authorization is separate: when BCCL runs with --auth S2S, all data access happens under the Entra application, not under a named user, so the effective permissions are the permission sets assigned to that application on the Microsoft Entra Applications page in Business Central.
- The BCCL permission set covers BCCL's own objects only. For every table BCCL will read or write, the application also needs a permission set that grants access to that table.
- Tables owned by other apps (ISV or third-party) require that app's permission set to be added as an extra line on the same Entra application record. Add-on and vertical solutions publish their own permission sets; for example LS Central requires
LSCentralPermissions.SUPER (Data)can be used as a worst-case catch-all. Repeat this for every app whose tables BCCL needs to read. - If permission sets are missing or incomplete, BCCL commands fail at runtime, even though authentication succeeded, with:
Sorry, the current permissions prevented the action. (TableData <table no.> <object name> Read: <extension/app name>)
or (TableData <object id> <table name> IndirectRead: BCCL). The parentheses name the table whose permission is missing. Add the missing app's permission set as a new line on the Entra application; do not edit the existing permission sets. Changing permissions on the Entra App Registration in the Entra admin center, or on the end user's permission sets, does not fix this. See Permission Errors.
Setup Instructions for the Business Central Owner
It is common and supported that the person configuring BCCL (a partner or third-party integrator) receives the Client ID, Tenant ID, and Secret Value from the Business Central owner and never logs into Business Central themselves. Because of a long-standing Business Central bug, a correctly configured Application Card can still make the server reject the credentials (The server has rejected the client credentials). Include the following copy-paste-ready steps up front in the setup instructions you hand to the Business Central owner, not only as a troubleshooting step, because only someone with access to the Business Central client can perform them:
- In Business Central, open Microsoft Entra Applications and open the Application Card for the application used by BCCL.
- Disable the application (turn off Enabled).
- Close the Application Card window completely.
- Re-open the Application Card.
- Enable the application again.
- Confirm that the BCCL permission set, plus the permission sets for the tables BCCL will access (including third-party app permission sets), are on the permission-set lines.
The Client ID, Tenant ID, and Secret Value do not change; the same values are reused afterwards.
Toggling the Enabled field without closing and re-opening the card is not sufficient. A working token request from an external tool such as Postman does not rule this problem out. See Authentication Issues.
Command-Line Usage
Basic S2S Command
BCCL --auth S2S --clientid "your-client-id" --clientsecret "your-secret" --tenantid "your-tenant-id" -w "https://api.businesscentral.dynamics.com/v2.0/{tenantid}/{environment}/WS/{company}/Codeunit/bccl" -t tasks
Required Parameters
| Parameter | Description |
|---|---|
--auth S2S |
Specifies S2S authentication method |
--clientid |
Azure AD Application (client) ID |
--clientsecret |
Azure AD client secret value |
--tenantid |
Azure AD Directory (tenant) ID |
-w |
Business Central web service URL |
Remembering S2S Credentials
To avoid entering credentials each time, use the --remember flag:
BCCL --auth S2S --clientid "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" --clientsecret "your-secret-here" --tenantid "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -w "https://api.businesscentral.dynamics.com/v2.0/tenantid/production/WS/CRONUS%20Canada%2C%20Inc./Codeunit/bccl" --remember
After remembering, subsequent commands only need task-specific parameters:
BCCL -t getdata -s table=18 -f csv -o customers.csv
Correct Script Layout for --remember
--remember persists only the parameters given on that one command line. Settings spread across several BCCL invocations do not accumulate. A script must therefore never contain two or more separate --remember lines, and the endpoint and the authentication must be on the same line.
Broken pattern (do not use, two lines, settings not combined):
BCCL -w "https://api.businesscentral.dynamics.com/v2.0/<tenantid>/<environment>/WS/<company>/Codeunit/bccl" --remember
BCCL --auth S2S --clientid <clientid> --clientsecret <secret> --tenantid <tenantid>
With this layout, the later getdata calls fail with An error has occurred: Cannot continue without a user for Business Central (-u --user) or authenticated with --auth.
Correct pattern (one single line):
BCCL --register <licensekey> --tenantid <tenantid>
BCCL --auth S2S --clientid <clientid> --clientsecret "<secret>" --tenantid <tenantid> -w "https://api.businesscentral.dynamics.com/v2.0/<tenantid>/<environment>/WS/<company>/Codeunit/bccl" --remember
BCCL -t getdata -s table=18 -f sql -o Customer -m customer.json --sqlconnect "..."
- The registration step (
--register) stays on its own line before the remember line. - After the combined line has run, the subsequent
BCCL -t getdata ...calls in the same script need no authentication parameters, because they use the remembered settings. - The whole remember command must be on one unbroken line in the batch file; see "Batch File Rules" in Command Reference.
- This applies to scripts that have worked previously as well: correct the layout everywhere rather than re-trying.
When Not to Rely on Remembered Credentials
For long-running transfers (large table exports, SQL replication of big tables), pass all parameters on one single command line instead of first storing them with --remember and then running a second, parameter-less task command:
BCCL --auth S2S --clientid your-client-id --clientsecret "your-client-secret" --tenantid your-tenant-id -w "https://api.businesscentral.dynamics.com/v2.0/{tenantid}/{environment}/WS/{company}/Codeunit/bccl" -t getdata -s table=27 -f sql -o Item -m mappingItem.mapping.json --sqlconnect "Server=<server>;Database=<database>;Trusted_Connection=yes"
With the credentials available to the running command, BCCL can renew the token while the transfer is in progress. This single-command form is the configuration recommended by hougaard.com support when intermittent No connection could be made because the target machine actively refused it ... (api.businesscentral.dynamics.com:443) errors or Unauthorized The credentials provided are incorrect errors appear mid-transfer. It is also required when running BCCL for several companies or in parallel sessions, because remembered settings from one session can overwrite another's. See Running Long or Unattended Transfers Reliably and Replicating Multiple Companies.
Token Management
S2S authentication handles tokens differently from OAuth:
- Automatic token acquisition: BCCL requests a token from the Microsoft OAuth endpoint using client credentials
- No user interaction: The entire process is automated
- Token refresh: BCCL renews the token during a long-running operation, provided the S2S parameters are available to the running command
- No caching between sessions: Unlike OAuth, S2S tokens are not cached to disk (credentials are sufficient to get a new token)
Token Lifetime Assumptions
BCCL renews the S2S token during a run once about 80% of the token's reported lifetime has elapsed (roughly 48 minutes for a standard 1-hour token), and only if the S2S parameters are available to the running command. If the Entra ID tenant is configured to issue very short-lived tokens, the token can expire before BCCL renews it, and the operation fails with Unauthorized The credentials provided are incorrect even when the authentication parameters are supplied on the command line. In that case use the bccl.exe from the BCCL3 beta (https://www.hougaard.com/on-premises/BCCL/beta/), which handles short-lived tokens better, in place of the existing executable for the affected run.
The token request is a POST to:
https://login.microsoftonline.com/{tenantid}/oauth2/v2.0/token
Service Mode Configuration
When running BCCL as a Windows service, S2S authentication is configured in bccl_service.json:
{
"agentid": "MY_BCCL",
"auth": "S2S",
"clientid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"tenantid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"clientsecret": "your-client-secret-here",
"url": "https://api.businesscentral.dynamics.com/v2.0/{tenantid}/{environment}/WS/{company}/Codeunit/bccl",
"defaultcompany": "CRONUS Canada, Inc.",
"verbose": "true"
}
The service reads this file on startup and uses the credentials for all subsequent operations.
Scripting with S2S
S2S is ideal for scheduled scripts. Example batch file:
@echo off
REM Export customers to SQL Server
BCCL --auth S2S ^
--clientid "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ^
--clientsecret "your-secret" ^
--tenantid "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ^
-w "https://api.businesscentral.dynamics.com/v2.0/tenantid/production/WS/CRONUS%%20Canada%%2C%%20Inc./Codeunit/bccl" ^
-t getdata -s table=18 -f sql -o Customer ^
--sqlconnect "Server=localhost;Database=BCData;Trusted_Connection=yes"
Security Best Practices
- Rotate client secrets regularly (before they expire)
- Use minimum permissions: only grant the BCCL permission set, not broader access
- Protect the secret: do not commit
bccl_service.jsonor scripts with secrets to version control - Monitor access: review Azure AD sign-in logs for the App Registration
- Use separate registrations for different environments (production, sandbox)
Troubleshooting
| Issue | Solution |
|---|---|
| "Invalid client secret" | Regenerate the secret in Azure portal; secrets expire |
| "Tenant not found" | Verify the tenant ID GUID is correct |
| "Application not authorized" | Add the app on the Microsoft Entra Applications page in Business Central, enable it, and assign permission sets |
| "AADSTS700016" | Client ID does not match any registered application |
Token expired mid-operation (Unauthorized The credentials provided are incorrect after successful batches) |
Put all S2S parameters on the task command line; check for short-lived tokens; see "Token Lifetime Assumptions" |
| "The server has rejected the client credentials" | BC-side bug: disable the Application Card, close it, re-open, enable again (see "Setup Instructions for the Business Central Owner") |
| "Cannot continue without a user for Business Central (-u --user) or authenticated with --auth" | --remember split over several lines or several --remember lines; see "Correct Script Layout" |
| "Sorry, the current permissions prevented the action" | Missing permission set on the Entra application in BC; see "Permissions" and Permission Errors |
Use the -v (verbose) flag to see detailed authentication flow information when troubleshooting.