Events
Mar 31, 11 PM - Apr 2, 11 PM
The ultimate Microsoft Fabric, Power BI, SQL, and AI community-led event. March 31 to April 2, 2025.
Register todayThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
APPLIES TO: Business Central 2023 release wave 2 (version 23) and later
SecretText data type is designed to protect sensitive values from being exposed through the AL debugger when doing regular or snapshot debugging. Its use is recommended for applications that need to handle any kind of credentials like API keys, custom licensing tokens, or similar.
When a credential isn't protected by the NonDebuggable
attribute on a procedure scope or in the variable it's contained in, it's vulnerable to being exposed
in a debugging session or a snapshot for its entire lifetime in AL code. This lifetime can be split into three distinct phases.
A credential can be retrieved in multiple ways:
Any value of type Text
or Code
can be assigned to a SecretText
value. If the tokens are retrieved and then converted to a SecretText
value in the scope of a nondebuggable procedure, they're protected from the debugger during their lifetime. Furthermore, the AL compiler guarantees that a hardcoded credential can't be assigned directly to a destination of type SecretText
.
[NonDebuggable]
procedure RetrieveSessionToken(Credential: SecretText; TargetUri: Text) SessionToken : SecretText
var
Request: HttpRequestMessage;
Response: HttpResponseMessage;
Client: HttpClient;
Headers: HttpHeaders;
Content: HttpContent;
begin
Request.SetRequestUri(TargetUri);
Request.GetHeaders(Headers);
// Compose an authorization header with a secret value
Headers.Add('Authorization', SecretStrSubstNo('Bearer %1', Credential));
Client.Send(Request, Response);
ParseSessionToken(Response, SessionToken);
exit;
end;
[NonDebuggable]
procedure ParseSessionToken(Response: HttpResponseMessage; var SessionToken: SecretText) : Text
begin
// Parse the response
end;
A credential transits through AL code to reach the points where it's consumed. Transit includes:
The SecretText data type guarantees that the value remains nondebuggable by preventing any assignment from itself to any debuggable type. This constraint includes the Variant
data type. As a result, the NonDebuggable
attribute is only required during retrieval
and can be omitted for the rest of the lifetime of a credential, as all intermediate destinations are automatically protected.
procedure Assignments()
var
PlainText: Text;
Credential: SecretText;
begin
Credential := PlainText; // Allowed
PlainText := Credential; // Blocked
ConsumePlainText(PlainText); // Allowed
ConsumePlainText(Credential); // Blocked
Credential := ProduceCredential(); //Allowed
PlainText := ProduceCredential(); // Blocked
end;
procedure ConsumePlainText(PlainText: Text)
begin
end;
procedure ProduceCredential(): SecretText
begin
end;
The credential is consumed when it's used to perform an operation. A common example is communicating with an external web service via the AL HttpClient where the following steps may be required:
The AL HttpClient and all the intermediate types required to make a request support method, which accept the SecretText
data type, so that the values can be passed directly to the AL runtime without being revealed to the debugger.
The following code snippet demonstrates how all the before mentioned scenarios can be implemented through these methods.
procedure SendAuthenticatedRequestToApi(UriTemplate: Text; BearerToken: SecretText; KeyParameter: SecretText; SecretBody: SecretText)
var
Client: HttpClient;
Headers: HttpHeaders;
SecretHeader: SecretText;
SecretUri: SecretText;
RequestMessage: HttpRequestMessage;
begin
SecretHeader := SecretStrSubstNo('Bearer %1', BearerToken);
RequestMessage.GetHeaders(Headers);
// The header is added and remains hidden when debugging the headers
// of the request message
Headers.Add('Authorization', SecretHeader);
// Headers.Contains('Authorization') - false
// Headers.ContainsSecret('Authorization') - true
// Headers.GetSecretValues must be used to get the values.
// It is not possible to retrieve the header value as a plain text.
SecretUri := SecretStrSubstNo(UriTemplate, KeyParameter);
RequestMessage.SetSecretRequestUri(SecretUri);
// RequestMessage.GetSecretRequestUri can be used to retrieve the request uri.
// It cannot be retrieved by GetRequestUri as a plain text.
RequestMessage.Content.WriteFrom(SecretBody);
// RequestMessage.Content.ReadAs can only read back the body in a SecretText destination
SendMessageAndHandleResponse(Client, RequestMessage);
end;
[NonDebuggable]
procedure SendMessageAndHandleResponse(Client: HttpClient; Request: HttpRequestMessage) CredentialFromResponse: SecretText
var
Response: HttpResponseMessage;
begin
Client.Send(Request, Response);
Response.Content.ReadAs(CredentialFromResponse);
end;
The Unwrap
method allows the value to be extracted from a SecretText
to a textual destination for compatibility reasons.
It's only permitted when building applications for the 'OnPrem' scope and its use produces a warning unless it's called
inside a procedure with the NonDebuggable
attribute. It's not recommended to use this method for any other use except .NET
interoperability.
The SecretStrSubstNo
method allows for composing different values of type SecretText
without revealing their values.
Its behavior is identical to the StrSubstNo
method on Text
values with the important difference that its parameters and return value
are of type SecretText
.
Some examples are demonstrated in the following snippet:
procedure SecretStrSubstNoExamples()
var
First: SecretText;
Second: SecretText;
Result: SecretText;
begin
// Concatenation
Result := SecretStrSubstNo('%1%2', First, Second);
// Build a header value
Result := SecretStrSubstNo('Bearer %1', First);
// Build a comma separated value list
Result := SecretStrSubstNo('%1,%2', First, Second);
end;
Events
Mar 31, 11 PM - Apr 2, 11 PM
The ultimate Microsoft Fabric, Power BI, SQL, and AI community-led event. March 31 to April 2, 2025.
Register todayTraining
Module
Manage secrets in Java applications - Zero Trust and Zero Secrets - Training
In this module, you learn about managing secrets in your Java applications on Azure. You'll explore best practices like Zero Trust and Zero Secrets, and see how to apply them to a hands-on Java project using Azure Key Vault.