Blog: Tutorials

How to Implement Domain Locking in Your JavaScript Code

A step-by-step guide to restricting your JavaScript code to specific domains, preventing unauthorized use and protecting your intellectual property.

What is Domain Locking?

Domain locking is a JavaScript code protection technique that restricts your code to run only on specific authorized domains. When someone tries to copy your JavaScript code to another website, it will either fail to execute or perform an alternative action that you define.

This technique is particularly valuable for:

  • Premium WordPress themes and plugins
  • Commercial JavaScript libraries and components
  • SaaS applications with client-side JavaScript
  • Custom code developed for specific clients

Why Use Domain Locking?

JavaScript code that runs in a browser is inherently visible to users, making it vulnerable to copying. While obfuscation makes your code harder to understand, it doesn't prevent someone from copying it to another site. Domain locking provides an additional layer of protection by:

  • Preventing unauthorized code copying and use
  • Protecting your revenue from premium code
  • Securing client-specific implementations
  • Maintaining control over where your code executes
  • Creating a licensing system for your JavaScript libraries
Security Note

Domain locking is a deterrent, not an unbreakable solution. When combined with proper code obfuscation, it creates a significant barrier that most people won't be able to bypass. However, a determined attacker with sufficient expertise could potentially work around these protections.

Step 1: Create a Domain Validation Function

Let's start by creating a function that will extract and validate the current domain against our allowed list.

1

Create a Domain Validation Function

/**
 * Validates if the current domain is in the allowed list
 * @param {Array} allowedDomains - Array of allowed domains
 * @returns {boolean} - True if current domain is allowed, false otherwise
 */
function isDomainAllowed(allowedDomains) {
  // Get the current domain
  const currentDomain = window.location.hostname;
  
  // Check if the current domain matches any in the allowed list
  for (let i = 0; i < allowedDomains.length; i++) {
    const domain = allowedDomains[i];
    
    // Exact match
    if (currentDomain === domain) {
      return true;
    }
    
    // Subdomain support (domain starts with '.')
    if (domain.startsWith('.') && 
        (currentDomain.endsWith(domain) || 
         currentDomain === domain.slice(1))) {
      return true;
    }
  }
  
  // If we get here, the domain wasn't in the allowed list
  return false;
}

This function extracts the current domain using window.location.hostname and compares it against each entry in your allowed domains array. It also supports wildcard subdomains when a domain starts with a dot (e.g., .example.com would match both example.com and any subdomain like shop.example.com).

Step 2: Define Allowed Domains Array

Next, create an array of domains where your code is allowed to run.

2

Define Allowed Domains Array

/**
 * Array of allowed domains
 * Prefix with '.' to include all subdomains
 */
const ALLOWED_DOMAINS = [
  'mywebsite.com',        // Allow only exact match
  '.client-website.com',  // Allow client-website.com and any subdomains
  'localhost',            // Allow localhost for development
  '127.0.0.1'             // Allow IP for development
];

Customize this array with the domains where your code should be allowed to run:

  • Use exact domain names like 'example.com' to only allow that specific domain
  • Prefix with a dot like '.example.com' to allow the domain and all its subdomains
  • Include 'localhost' and '127.0.0.1' for testing during development
Pro Tip

For more flexible domain management, consider using regular expressions instead of exact matches. This would allow for more complex patterns like allowing all domains in a specific TLD or with specific naming patterns.

Step 3: Implement Action for Unauthorized Domains

Now, define what happens when your code is executed on an unauthorized domain.

3

Implement Action for Unauthorized Domains

/**
 * Handles unauthorized domain access
 * @param {string} redirectUrl - Optional URL to redirect to
 */
function handleUnauthorizedDomain(redirectUrl = null) {
  // Remove any existing functionality
  const scriptTags = document.querySelectorAll('script');
  const currentScript = scriptTags[scriptTags.length - 1];
  
  // If parent element exists, remove the script
  if (currentScript && currentScript.parentElement) {
    currentScript.parentElement.removeChild(currentScript);
  }
  
  // Option 1: Redirect to a license page
  if (redirectUrl) {
    window.location.href = redirectUrl;
    return;
  }
  
  // Option 2: Show a message
  console.error(
    'This JavaScript component is licensed for specific domains only. ' +
    'Please contact the developer to obtain a license for this domain.'
  );
  
  // Option 3: Silently disable functionality
  // This is done by the script removal above
}

// Putting it all together
function initializeWithDomainLock() {
  if (isDomainAllowed(ALLOWED_DOMAINS)) {
    // Domain is allowed, initialize your application normally
    initializeApp();
  } else {
    // Domain is not allowed, handle accordingly
    handleUnauthorizedDomain('https://mywebsite.com/license-required');
  }
}

// Self-executing function to run immediately
(function() {
  initializeWithDomainLock();
})();

You have several options for handling unauthorized domains:

  • Redirect: Send the user to a licensing page
  • Display a message: Alert the user that the domain is unauthorized
  • Silently fail: Simply prevent the code from functioning without explanation
  • Degrade functionality: Allow basic features but disable premium functions

Step 4: Obfuscate Your Domain Locking Code

The domain locking implementation itself must be protected to prevent easy bypassing. JS Obfuscator Pro provides powerful tools to secure your domain validation code.

4

Obfuscate Your Domain Locking Code

Apply advanced obfuscation techniques using JS Obfuscator Pro:

  1. Enable String Array with RC4 encoding to protect your domain list
  2. Enable Control Flow Flattening to make the validation logic harder to follow
  3. Enable Self-Defending code to prevent modification of the checks
  4. Use Dead Code Injection to hide the actual validation logic

When properly obfuscated, your domain locking code will look something like this (simplified example):

var _0xa4f8=['\x77\x69\x6e\x64\x6f\x77','\x6c\x6f\x63\x61\x74\x69\x6f\x6e','\x68\x6f\x73\x74\x6e\x61\x6d\x65','\x6c\x65\x6e\x67\x74\x68','\x73\x74\x61\x72\x74\x73\x57\x69\x74\x68','\x2e','\x65\x6e\x64\x73\x57\x69\x74\x68','\x73\x6c\x69\x63\x65','\x6d\x79\x77\x65\x62\x73\x69\x74\x65\x2e\x63\x6f\x6d','\x2e\x63\x6c\x69\x65\x6e\x74\x2d\x77\x65\x62\x73\x69\x74\x65\x2e\x63\x6f\x6d','\x6c\x6f\x63\x61\x6c\x68\x6f\x73\x74','\x31\x32\x37\x2e\x30\x2e\x30\x2e\x31','\x68\x72\x65\x66','\x68\x74\x74\x70\x73\x3a\x2f\x2f\x6d\x79\x77\x65\x62\x73\x69\x74\x65\x2e\x63\x6f\x6d\x2f\x6c\x69\x63\x65\x6e\x73\x65\x2d\x72\x65\x71\x75\x69\x72\x65\x64'];(function(_0x41dfb9,_0xa4f8ca){var _0x3c00ed=function(_0x35139c){while(--_0x35139c){_0x41dfb9['push'](_0x41dfb9['shift']());}};_0x3c00ed(++_0xa4f8ca);}(_0xa4f8,0x158));var _0x3c00=function(_0x41dfb9,_0xa4f8ca){_0x41dfb9=_0x41dfb9-0x0;var _0x3c00ed=_0xa4f8[_0x41dfb9];return _0x3c00ed;};(function(){var _0x46709d=function(){var _0x2e413c=!![];return function(_0x3b3c3a,_0x23842f){var _0x1ce5b2=_0x2e413c?function(){if(_0x23842f){var _0x41f599=_0x23842f['apply'](_0x3b3c3a,arguments);_0x23842f=null;return _0x41f599;}}:function(){};_0x2e413c=![];return _0x1ce5b2;};}();var _0x4e6c6b=_0x46709d(this,function(){var _0x19ea86=function(){var _0x1fd7b7=_0x19ea86['constructor']('return\x20/\x22\x20+\x20this\x20+\x20\x22/')()['compile']('^([^\x20]+(\x20+[^\x20]+)+)+[^\x20]}');return!_0x1fd7b7['test'](_0x4e6c6b);};return _0x19ea86();});_0x4e6c6b();var _0x2cb8c3=[_0x3c00('0x8'),_0x3c00('0x9'),_0x3c00('0xa'),_0x3c00('0xb')];var _0x4b7360=document['createElement']('div');if(!_0x56a34d(_0x2cb8c3)){window[_0x3c00('0x0')][_0x3c00('0x1')][_0x3c00('0xc')]=_0x3c00('0xd');}function _0x56a34d(_0x21fe26){var _0x5aec9f=window[_0x3c00('0x0')][_0x3c00('0x1')][_0x3c00('0x2')];for(var _0x45e8dd=0x0;_0x45e8dd<_0x21fe26[_0x3c00('0x3')];_0x45e8dd++){var _0x25ea6a=_0x21fe26[_0x45e8dd];if(_0x5aec9f===_0x25ea6a){return!![];}if(_0x25ea6a[_0x3c00('0x4')](_0x3c00('0x5'))&&(_0x5aec9f[_0x3c00('0x6')](_0x25ea6a)||_0x5aec9f===_0x25ea6a[_0x3c00('0x7')](0x1))){return!![];}}return![];}function _0x4c3c93(){console['log']('Application\x20initialized\x20successfully!');}if(_0x56a34d(_0x2cb8c3)){_0x4c3c93();}}());

The obfuscated code hides both your domain list and the validation logic, making it much harder to bypass the protection.

Step 5: Test Your Domain Locking Implementation

Finally, test your domain locking implementation to ensure it works correctly.

5

Test Your Domain Locking Implementation

Testing should cover both positive and negative cases:

  1. Test on allowed domains: Verify that your code functions normally on all authorized domains
  2. Test on unauthorized domains: Confirm that your code behaves as expected when run on unauthorized domains
  3. Test with subdomains: If you're using wildcard subdomain matching, test with various subdomains

You can use these testing methods:

  • Local development using localhost and host file modifications
  • Staging environments on different domains
  • Copy your code to a test domain temporarily

Advanced Domain Locking Techniques

Multiple Validation Layers

For stronger protection, implement multiple validation checks at different points in your code. This makes bypassing all checks more difficult:

  • Initial check when the script loads
  • Secondary check when key functions are called
  • Periodic runtime checks at random intervals
// Initial check
if (!isDomainAllowed(ALLOWED_DOMAINS)) {
  handleUnauthorizedDomain();
}

// Function wrapper for runtime checks
function secureFunction(fn) {
  return function(...args) {
    if (!isDomainAllowed(ALLOWED_DOMAINS)) {
      return handleUnauthorizedDomain();
    }
    return fn.apply(this, args);
  };
}

// Apply to critical functions
myApp.processPayment = secureFunction(myApp.processPayment);
myApp.authenticateUser = secureFunction(myApp.authenticateUser);

Server-Side Verification

For maximum security, combine client-side domain locking with server-side verification:

  1. Your JavaScript sends the domain to your server for verification
  2. Server validates the domain against authorized list
  3. Server returns a signed token or key needed for the script to function
// Client-side code
async function verifyDomainWithServer() {
  try {
    const response = await fetch('https://api.myservice.com/verify-domain', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ 
        domain: window.location.hostname,
        licenseKey: 'YOUR-LICENSE-KEY' 
      })
    });
    
    const data = await response.json();
    
    if (data.authorized) {
      // Store activation token
      localStorage.setItem('activationToken', data.token);
      return true;
    }
    
    return false;
  } catch (error) {
    console.error('Domain verification failed:', error);
    return false;
  }
}

Limitations and Considerations

Important Considerations

Domain locking has some inherent limitations you should be aware of:

Bypass Potential

A determined attacker with JavaScript expertise could potentially:

  • Identify and modify the domain validation logic
  • Remove the domain checks from your code
  • Hook and override native browser functions used for domain detection

That's why domain locking should be combined with strong obfuscation and multiple verification layers.

Development and Testing Challenges

Domain locking can complicate development and testing workflows. Ensure you:

  • Include development domains in your allowed list
  • Have an easy way to temporarily disable checks during development
  • Document the domain requirements for your team

User Experience Considerations

If your code fails on unauthorized domains, consider providing a helpful message explaining why it's not working and how to obtain proper licensing.

Conclusion

Domain locking is a powerful technique to protect your JavaScript code from unauthorized use. While not foolproof, when combined with proper obfuscation, it creates a significant barrier that deters most unauthorized copying.

By following the steps in this tutorial, you can implement a robust domain locking system that:

  • Restricts your code to authorized domains
  • Supports exact domain matching and wildcard subdomains
  • Provides flexible options for handling unauthorized usage
  • Can be enhanced with multiple verification layers

For even stronger protection, consider using JS Obfuscator Pro's built-in domain locking feature, which combines advanced obfuscation techniques with domain validation to provide comprehensive protection for your JavaScript code.

Alex Rodriguez

About Alex Rodriguez

Alex is a JavaScript security specialist and web developer with 10+ years of experience. He specializes in code protection techniques and has helped numerous companies secure their JavaScript assets from unauthorized copying and use.

Comments

Comments are loading...