Retrieving Masked Field Values Programmatically in Dynamics 365

By | June 23, 2025

Retrieving Masked Field Values Programmatically in Dynamics 365

Are you working on a Dynamics 365 Customer Engagement (CE) project and struggling to integrate a payment system that requires access to sensitive data—like a customer’s full bank account number?

You’re not alone.

Imagine this: you’re developing with backend plugins, operating under elevated privileges, and fully expecting the System Admin service to give you unrestricted access. But instead, you hit a wall—no matter what you try, the masked field remains partially hidden.

Sound familiar?

That’s because Dynamics 365 enforces data masking even in backend code, leaving many developers puzzled and looking for solutions. Let’s dive into what’s really going on and how to approach this challenge.

The Issue: Getting Only Masked Values

In many cases, the customer’s bank account number might be stored on the account entity. But when the user runs your payment processing plugin, you’re probably seeing field values like this: `****5678`.

Frustrating, right?

Despite having backend access, the field remains masked, making it impossible to retrieve the full value directly, even through the system admin service.

Here’s what the code looked like:

Entity account = service.Retrieve("account", accountId, new ColumnSet("new_bankaccount"));string accountNumber = account["new_bankaccount"].ToString(); // returns ****5678

This was clearly a problem—the payment gateway needs the actual account number, not a masked one. As a result, the entire payment workflow was failing.

What You Should Know About Field Masking in Dynamics 365:

Through your own testing and a deep dive into the documentation, you’ll likely uncover a few key insights that explain why sensitive fields—like bank account numbers—stay masked, even when accessed through backend code.

  1. Masking applies globally – It’s not just a front-end/UI feature. Even backend processes like plugins retrieve masked values.
  2. Plugins run in user context – So if the user doesn’t have permission to view unmasked data, your plugin won’t either.
  3. Automation can break silently – Masked fields can cause critical background processes (like payments, validations, or data exports) to fail or behave unexpectedly.

The Workaround: How to Access the Full Value

After extensive trial and error, two effective methods were identified, depending on the context in which the data is being accessed.

  1. For APIs, JavaScript

If you’re accessing data from the front-end (i.e form scripts), you can retrieve unmasked values of any masked fields by adding a special query flag:

GET /api/data/v9.2/accounts(GUID)?$select=new_bankaccount,new_creditcard,new_customfield&UnMaskedData=true

Note: If you want to unmask all the configured fields, it can be done using the same query—there’s no need to add any additional attributes.

Important: This works only on the front-end (JavaScript, Web API, etc.). It does not apply to server-side code such as plugins, workflows, or custom C# code — those still return masked values unless accessed using system context.

  1. For Plugins and Workflows (System Context)

Since plugins run in a specific user context, you need to switch to SYSTEM Context by creating a service using CreateOrganizationService(null). This essentially executes the call as the SYSTEM user itself.

Here’s how to retrieve the unmasked value inside the plugin:

public Entity GetUnmaskedBankDetails(Guid accountId, IOrganizationServiceFactory factory)
{
    // Create system-level service
    IOrganizationService sysService = factory.CreateOrganizationService(null);
    return sysService.Retrieve("account", accountId, new ColumnSet("new_bankaccount"));
}
public void Execute(IServiceProvider serviceProvider)
{
    var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
    var factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

    Entity account = GetUnmaskedBankDetails(context.PrimaryEntityId, factory);
    string fullAccountNumber = account["new_bankaccount"].ToString();

    if (!ProcessPayment(fullAccountNumber))
    {
        throw new InvalidPluginExecutionException("Payment processing failed.");
    }
}

This approach gives access to the actual bank account number, and the payment processing system started working as expected.

Conclusion:

When working with masked fields in Dynamics 365, standard access methods won’t reveal full values.
Use ?UnMaskedData=true for front-end/API calls and CreateOrganizationService(null) for backend plugins.
These techniques ensure secure access to unmasked data without breaching security protocols.
Always apply them thoughtfully to maintain compliance and data integrity.

 

Category: Dynamics 365 Technical Tags:

About Sam Kumar

Sam Kumar is the Vice President of Marketing at Inogic, a Microsoft Gold ISV Partner renowned for its innovative apps for Dynamics 365 CRM and Power Apps. With a rich history in Dynamics 365 and Power Platform development, Sam leads a team of certified CRM developers dedicated to pioneering cutting-edge technologies with Copilot and Azure AI the latest additions. Passionate about transforming the CRM industry, Sam’s insights and leadership drive Inogic’s mission to change the “Dynamics” of CRM.