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.
Table of Contents
- What is Domain Locking?
- Why Use Domain Locking?
- Step 1: Create a Domain Validation Function
- Step 2: Define Allowed Domains Array
- Step 3: Implement Action for Unauthorized Domains
- Step 4: Obfuscate Your Domain Locking Code
- Step 5: Test Your Domain Locking Implementation
- Advanced Domain Locking Techniques
- Limitations and Considerations
- Conclusion
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
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.
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.
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
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.
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.
Obfuscate Your Domain Locking Code
Apply advanced obfuscation techniques using JS Obfuscator Pro:
- Enable String Array with RC4 encoding to protect your domain list
- Enable Control Flow Flattening to make the validation logic harder to follow
- Enable Self-Defending code to prevent modification of the checks
- 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.
Test Your Domain Locking Implementation
Testing should cover both positive and negative cases:
- Test on allowed domains: Verify that your code functions normally on all authorized domains
- Test on unauthorized domains: Confirm that your code behaves as expected when run on unauthorized domains
- 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:
- Your JavaScript sends the domain to your server for verification
- Server validates the domain against authorized list
- 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
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.
Comments
Comments are loading...