DYNEXAL GUIDE • AL SECURITY

Business Central AL IsolatedStorage: Secure Secrets & API Tokens

Business Central integrations frequently need credentials such as API tokens, client secrets, refresh tokens or provider-specific keys. Putting these values directly into AL source code or ordinary setup tables can create unnecessary security exposure.

Security principle: separate configuration from secrets. Store non-sensitive settings where administrators can manage them, and use an appropriate protected storage mechanism for sensitive values.

1. What is IsolatedStorage?

Business Central AL provides IsolatedStorage for storing data that should be isolated from ordinary application data. It is commonly useful for sensitive integration values that an extension needs to retrieve later without putting the value directly into a normal application table.

Microsoft documents Isolated Storage as a way for extensions to store data isolated from the rest of the application. The API supports storing, retrieving, checking and deleting values by key, with different data scopes.

Microsoft Learn — IsolatedStorage data type

2. Why not store API tokens directly in AL code?

// ❌ Avoid this
Token := 'sk-live-xxxxxxxxxxxxxxxx';

// ❌ Avoid storing secrets in source-controlled setup code
ClientSecret := 'my-production-secret';

Source code can be downloaded, reviewed, copied into repositories, included in packages or exposed to developers who should not have access to production credentials.

Instead, keep the secret outside source code and retrieve it through a controlled server-side mechanism.

3. IsolatedStorage key/value model

A simple pattern is to use a stable key and store the secret as a text value.

procedure SaveApiToken(Token: Text)
begin
    IsolatedStorage.Set(
        'Dynexal.ApiToken',
        Token,
        DataScope::Company);
end;

procedure LoadApiToken(): Text
var
    Token: Text;
begin
    if IsolatedStorage.Get(
        'Dynexal.ApiToken',
        DataScope::Company,
        Token)
    then
        exit(Token);

    Error('API token has not been configured.');
end;

The exact scope should be selected according to the ownership and isolation requirements of the secret.

4. Understand DataScope before choosing a key

Isolated Storage supports scopes that determine how stored values are isolated. The scope is part of the storage design, not an incidental implementation detail.

For example, a credential used by one company may need company-level isolation, while an extension-level value may have a different ownership model.

Design rule: do not choose a broader scope simply because it is convenient. Ask who should be able to use the value, which company or tenant it belongs to, and whether multiple environments or extensions need independent values.

5. Company-specific integration credentials

Consider a Business Central environment containing multiple companies. If each company connects to a different Shopify store or external API account, the credential should not accidentally be shared between companies.

Company A
  └── API Token A

Company B
  └── API Token B

A company-scoped storage design can help maintain that separation when the integration's business requirement is company-specific.

6. Separate secret storage from setup configuration

A practical integration setup often contains both normal configuration and protected credentials.

Integration Setup Table
├── Enabled
├── Endpoint URL
├── Company Identifier
├── Timeout
└── Environment

IsolatedStorage
├── Access Token
├── Client Secret
└── Refresh Token

This separation keeps the setup page useful without turning the ordinary setup table into a repository for raw secrets.

7. Build a dedicated credential service

Do not scatter IsolatedStorage calls across every API codeunit. A dedicated credential service creates one place for key names, scope decisions, validation and error handling.

codeunit 50110 "Integration Credential Service"
{
    procedure SetAccessToken(Token: Text)
    begin
        if Token = '' then
            Error('Access token cannot be empty.');

        IsolatedStorage.Set(
            'Dynexal.AccessToken',
            Token,
            DataScope::Company);
    end;

    procedure GetAccessToken(): Text
    var
        Token: Text;
    begin
        if not IsolatedStorage.Get(
            'Dynexal.AccessToken',
            DataScope::Company,
            Token)
        then
            Error('Access token is not configured.');

        exit(Token);
    end;
}

8. Never log the secret

One of the easiest mistakes is protecting a token in storage and then exposing it through logs, error messages or telemetry.

// ❌ Do not do this
Session.LogMessage(
    'TOKEN_DEBUG',
    Token,
    Verbosity::Normal,
    DataClassification::SystemMetadata);

// ❌ Do not include secrets in errors
Error('Authentication failed. Token was: %1', Token);

Log identifiers, status codes and safe diagnostic information instead of credentials.

Production rule: treat access tokens, client secrets, refresh tokens and API keys as sensitive data even when they are temporarily held in AL variables.

9. Do not confuse encryption with authorization

Protecting a stored value does not mean every piece of application code should be allowed to retrieve it. Secret storage and application authorization are separate concerns.

A secure architecture considers all four layers.

10. Secret rotation

Production credentials should be replaceable without redeploying the extension.

Admin
  │
  ▼
Set New Credential
  │
  ▼
Protected Storage
  │
  ▼
Integration Service
  │
  ▼
External API

A setup action such as “Set Access Token” can validate that a non-empty value was supplied and then replace the stored credential. A separate “Clear Credential” action can remove it when appropriate.

11. Credential validation without exposing the value

A connection test should report whether authentication succeeds, not display the credential itself.

procedure TestConnection(): Boolean
var
    Token: Text;
    Response: HttpResponseMessage;
begin
    Token := CredentialService.GetAccessToken();

    // Build authenticated request.
    // Never include Token in the response or log.

    exit(Response.IsSuccessStatusCode());
end;

When troubleshooting authentication, record the endpoint, HTTP status and safe provider error details where permitted, but redact credentials.

12. IsolatedStorage is not a complete secrets-management strategy

Protected storage inside Business Central can solve an application-level secret-storage problem, but it should not be treated as a universal replacement for enterprise identity and secret-management architecture.

For cloud integrations, consider whether the external service supports modern authentication such as OAuth 2.0 and service-to-service authentication. For high-security environments, evaluate the organization's approved secret-management and identity controls.

Never place a production secret in GitHub, an AL source file, a public JavaScript file or a browser-side configuration object.

13. OAuth tokens and refresh tokens

OAuth-based integrations often have short-lived access tokens and longer-lived refresh credentials. The application should treat both as sensitive.

Access Token
   │
   ├── expires
   ▼
Refresh Token
   │
   ▼
Token Endpoint
   │
   ▼
New Access Token
   │
   ▼
Business Central API Call

If a refresh token is persisted, use protected storage and ensure that the refresh process does not write the credential into logs or user-visible error messages.

14. Multi-company and multi-environment design

Think about environment boundaries before choosing key names. Development, test and production should not accidentally reuse credentials.

Development
  └── Dynexal.ApiToken → DEV credential

Test
  └── Dynexal.ApiToken → TEST credential

Production
  └── Dynexal.ApiToken → PROD credential

The deployment architecture and storage scope determine how these values are isolated. Operational procedures should also make it obvious which environment a credential belongs to.

15. Security checklist for AL integrations

16. AI + Business Central example

For an AI-enabled Business Central extension, an AI provider API key should remain server-side. The page should call an application service, and the service should retrieve the credential internally.

Business Central Page
       │
       ▼
AI Application Service
       │
       ├── Get credential
       │       ↓
       │   IsolatedStorage
       │
       ▼
Secure HTTP request
       │
       ▼
AI Provider

The browser should never receive the provider secret. This is particularly important when an AL extension is integrated with a website or external frontend.

17. Interview-ready answer

Sample answer: “I don't store API keys or client secrets in AL source code or expose them to the frontend. For extension-level protected values, I can use IsolatedStorage with an appropriate DataScope. I keep normal integration configuration separate from credentials, centralize secret access in a service codeunit, never log tokens, support credential rotation and apply permissions around the operations that use the secret. For OAuth integrations, I also treat refresh tokens as sensitive and keep them server-side.”

18. Common mistakes

Conclusion

Secure credential handling is an important part of professional Business Central integration development. IsolatedStorage can provide an appropriate protected storage mechanism for extension data, but secure architecture also requires correct scope, permissions, authentication, logging and operational controls.

The most important rule is simple: credentials belong on the server side, outside source code and outside the browser.

Sources & references

← Back to Dynexal Insights