cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

ThingWorx Navigate is now Windchill Navigate Learn More

Translate the entire conversation x

Help with Exporting Encrypted Password BaseType to Another Server

MA8731174
15-Moonstone

Help with Exporting Encrypted Password BaseType to Another Server

Hi all,

I’m working on a project where I have a DataShape that includes a field with the base type PASSWORD.
In my implementation, I use the following logic to hash and encrypt the password:

 

Add User Service (loginPassword basetype is PASSWORD in datashape)

 

result = Things[userDataTable].CreateValues();

result.AddRow({
	loginName: loginName.toUpperCase(),
	firstName: firstName,
	lastName: lastName,
	language: language,
	emailAddress: emailAddress.toLowerCase(),
	hashedLoginName: me.SHA256({
		toHash: loginName.toUpperCase()
	}),
	groups: groups,
	loginPassword: Resources["EncryptionServices"].EncryptPropertyValue({
		data: me.SHA256({
			toHash: loginPassword
		})
	})
});
//me.UserDataBase
Things[userDataTable].AddDataTableEntry({	values: result });

 

 

 

User Login Service

 

const serviceName = "userLogin";
const LOG_PREFIX = me.name + " :: " + serviceName + " :: ";

const userDataTable = "Project_" + Location + "_Users.DT";
logger.info(LOG_PREFIX + "Start Service");

let returnToken = {};
let hashedLoginName = me.SHA256({ toHash: loginName.toUpperCase() });

let hashedLoginPassword = true ? loginPassword : me.SHA256({ toHash: loginPassword });
returnToken.result = false;

let dateNow = Date.now();
let loginTokenExpireDate = dateNow +(me.tokenExpireTime*1000);
let hashedToken = me.SHA256({ toHash: dateNow + loginName.toUpperCase() });


try{
    let EntryExists = Things[userDataTable].GetDataTableEntryByKey({ key: hashedLoginName });
    
    logger.info("tip"+ EntryExists.rows[0]);
  
    
    
    if(EntryExists && EntryExists.rows[0].hashedLoginName == hashedLoginName && EntryExists.rows[0].loginPassword == hashedLoginPassword){ //EntryExists.rows[0].loginPassword
        
         
        returnToken.loginToken = hashedToken;
        returnToken.result = true;
        returnToken.loginTokenExpireDate = loginTokenExpireDate;
        returnToken.groups = EntryExists[0].groups.ToJSON().rows;
        returnToken.firstName = EntryExists[0].firstName;
        returnToken.lastName = EntryExists[0].lastName;
        returnToken.permission = EntryExists[0].permission;
        EntryExists[0].loginToken = hashedToken;
        EntryExists[0].loginTokenExpireDate = loginTokenExpireDate;
        Things[userDataTable].UpdateDataTableEntry({ values: EntryExists });
       
    }
    
}catch(e){}

//result = "this Token : '" + hashedToken + "' is created at this time: " + new Date(dateNow) + " and  will expires at " + new Date(expireDateToken);
result = returnToken;

logger.info(LOG_PREFIX + "End Service");

 

 

SHA 256

The following SHA-256 algorithm has been implemented in the Experience app.
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest

 

 

 

UserLogout

 

const serviceName = "userLogout";
const LOG_PREFIX = me.name + " :: " + serviceName + " :: ";

const userDataTable = "Project_" + Location + "_Users.DT";
logger.info(LOG_PREFIX + "Start Service");

let returnToken = {};
returnToken.result = false;
returnToken.loginTokenExpireDate = "Token already expired!";
try{
//me.UserDataBase
let EntryExists = Things[userDataTable].QueryDataTableEntries({
query: {
"filters": {
"type": "EQ",
"fieldName": "loginToken",
"value": loginToken
}
} /* QUERY */
});

if(EntryExists && EntryExists.rows[0].loginToken == loginToken && new Date(Date.now()) < EntryExists.loginTokenExpireDate){

EntryExists.loginTokenExpireDate = '';
EntryExists.loginToken = '';
//me.UserDataBase
Things[userDataTable].UpdateDataTableEntry({
values: EntryExists /* INFOTABLE */
});

returnToken.result = true;
returnToken.loginTokenExpireDate = "Token got deleted!";
}

}catch(e){}
result = returnToken;

logger.info(LOG_PREFIX + "End Service");

 

 

Problem

Now, I’m trying to migrate this data to another ThingWorx server, using an import/export mechanism (e.g., DataTable export).

However, on the new server, the encrypted password doesn’t seem to work or decrypt properly. Even when I change the base type to STRING instead of PASSWORD, it still doesn't work.

I suspect the issue might be:

  • Something related to how encrypted properties (especially PASSWORD fields) are tied to a specific platform instance or keystore?

  • Or maybe EncryptPropertyValue() doesn’t produce a transferable string between servers?


🧩 What I’ve Tried


My Questions

  1. Is it possible to export a PASSWORD-typed value from one server to another in a usable form?

  2. What is the best way to securely transfer hashed or encrypted credentials between servers without breaking the structure?

Any insights or official guidance would be much appreciated

Thanks in advance!

ACCEPTED SOLUTION

Accepted Solutions

As you assume, this is tied to the keystore. This is why there is a "universal export" option. But it's documented it is not working on data, only on entities.

https://support.ptc.com/help/thingworx/platform/r9.6/en/index.html#page/ThingWorx/Help/Getting_Started/ImportingandExportinginThingWorx/ImportingandExportingDataEntitiesandExtensions.html

 

This is also the reason why you have to call EncryptPropertyValue manually, because it's not a simple thing property but a row in a data table.

I would suggest encrypting with a specific key that you use on both platforms. There is a EncryptWithCustomKey service for that. But I haven't verified if that works.

 

View solution in original post

3 REPLIES 3

As you assume, this is tied to the keystore. This is why there is a "universal export" option. But it's documented it is not working on data, only on entities.

https://support.ptc.com/help/thingworx/platform/r9.6/en/index.html#page/ThingWorx/Help/Getting_Started/ImportingandExportinginThingWorx/ImportingandExportingDataEntitiesandExtensions.html

 

This is also the reason why you have to call EncryptPropertyValue manually, because it's not a simple thing property but a row in a data table.

I would suggest encrypting with a specific key that you use on both platforms. There is a EncryptWithCustomKey service for that. But I haven't verified if that works.

 

MA8731174
15-Moonstone
(To:Rocko)

Thank you for the detailed insight regarding ThingWorx encryption behavior across servers — especially the keystore dependency and the difference between entity-level vs data-level encryption. That clarification helped a lot.

 

As you mentioned, EncryptPropertyValue is not suitable for encrypting data values like those stored in DataTables, since it ties the encryption to the platform-specific keystore, making cross-server migration problematic.

 

To explore an alternative, I tested the EncryptWithCustomKey and DecryptWithCustomKey services. They worked as expected: after providing a custom key (e.g., using SHA256) and input data, the output could be successfully encrypted and later decrypted with the same key on the same or another server. So for custom encryption needs, this approach is indeed valid and functional.

 

That said, after evaluating the use case — a simple login/logout process within a Vuforia Experience — I’ve decided to simplify the approach:

  • The loginPassword field in the DataTable will now use base type STRING instead of PASSWORD.

  • Passwords will be hashed using SHA256 on the frontend (before transmission).

  • The backend will store and compare hashes directly (no encryption or decryption).

This ensures:

  • Clean portability across ThingWorx servers.

  • No reliance on encryption keys or server-specific keystores.

  • Secure and modern handling of credentials using irreversible hashing (standard practice in authentication systems).

As we noted, the PASSWORD base type is more suitable for properties where ThingWorx can manage the decryption layer internally. For DataTable fields, especially in multi-server deployments, plain hashing via SHA256 stored as STRING is more practical, secure, and maintainable. If you have any suggestion or feedback please write me, I would appreciate your input regards it.

 

 

 

 

MA8731174_0-1745493339999.png

MA8731174_1-1745493351777.png

 

 

I think hashing is sufficient for this use case. Encrypting adds complexity, but only security for the case someone has access to your database and the data-at-rest. In that case you are screwed anyway.

There might be regulations though that require you to not store things unencrypted.

 

Encryption is useful when you need the clear-text value of a password, i.e. to log in to a 3rd party system. This is not the case for authenticating users in TWX. Hashed values over an secure channel (TLS) will do the trick.

Announcements


Top Tags