Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Sample code uses ES6 language features such as arrow functions and promises. For compatibility with IE11, code written with these features must be either transpiled using tools like Babel or refactored accordingly using callbacks.
The ID-One Cosmo V8-n is part of the Idemia IAS ECC family of cryptographic modules called ID-One Cosmo V8. Modules within this family share the same functionalities and the description of the ID-One Cosmo V8 applies to all versions including the “-n” subject to this validation. This document describes the functionality provided by the Idemia IAS ECC ID-One smartcard - which is a PKI container - on the T1C-GCL (Generic Connector Library) implemented version:
ID-One Cosmo V8-n; FIPS 140-2 Security Policy
export interface AbstractIdemia {
allCertFilters(): string[];
allKeyRefs(): string[];
allCerts(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsResponse) => void): Promise<TokenAllCertsResponse>;
tokenData(callback?: (error: T1CLibException, data: TokenDataResponse) => void): Promise<TokenDataResponse>;
rootCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
authenticationCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
nonRepudiationCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
encryptionCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
issuerCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>
verifyPin(body: TokenVerifyPinData, callback?: (error: T1CLibException, data: TokenVerifyPinResponse) => void): Promise<TokenVerifyPinResponse>;
authenticate(body: TokenAuthenticateOrSignData, callback?: (error: T1CLibException, data: TokenAuthenticateResponse) => void): Promise<TokenAuthenticateResponse>;
sign(body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
allAlgoRefs(callback?: (error: T1CLibException, data: TokenAlgorithmReferencesResponse) => void): Promise<TokenAlgorithmReferencesResponse>
resetBulkPin(callback?: (error: T1CLibException, data: BoolDataResponse) => void): Promise<BoolDataResponse>;
}All model information can be found in the Token typings model page
T1cSdk.initialize(config).then(res => {
const idemia = res.client.idemia(readerId);
}, err => {
console.error(error)
});When initialisation is finished you can continue using the aventra object to execute the functions below.
idemia.allCertFilters().then(res => {
}, err => {
console.error(err)
})The expected response for this call should be;
{
success: true,
data: ['rootCertificate', 'authenticationCertificate', 'encryptionCertificate', 'nonRepudiationCertificate', 'issuerCertificate']
}idemia.allKeyRefs().then(res => {
}, err => {
console.error(err)
})The expected response for this call should be;
{
success: true,
data: ['authenticate', 'sign', 'encrypt']
}When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not.
const filter = ['rootCertificate', 'authenticationCertificate', 'encryptionCertificate'];
idemia.allCerts(filter).then(res => {
}, err => {
console.error(err)
})The expected response for this call should be;
{
success: true,
data: {
authenticationCertificate?: {
certificate?: TokenCertificateObject,
certificates?: Array<TokenCertificateObject>
},
citizenCertificate?: {
certificate?: TokenCertificateObject,
certificates?: Array<TokenCertificateObject>
},
nonRepudiationCertificate?: {
certificate?: TokenCertificateObject,
certificates?: Array<TokenCertificateObject>
},,
rootCertificate?: {
certificate?: TokenCertificateObject,
certificates?: Array<TokenCertificateObject>
},,
encryptionCertificate?: {
certificate?: TokenCertificateObject,
certificates?: Array<TokenCertificateObject>
},
}
}This will return information of the Aventra card.
idemia.tokenData().then(res => {
}, err => {
console.error(err)
})The expected response for this call should be;
{
success: true,
data: {
version?: string,
serialNumber?: string,
label?: string,
changeCounter?: number,
}
}When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not.
Contains the 'root certificate' stored on the smart card. The service can be called:
idemia.rootCertificate(parseCertsBoolean).then(res => {
}, err => {
console.error(err)
})Contains the 'authentication certificate' stored on the smart card. The 'authentication certificate' contains the public key corresponding to the private RSA authentication key. The 'authentication certificate' is needed for pin validation, authentication and singing. The service can be called:
idemia.authenticationCertificate(parseCertsBoolean).then(res => {
}, err => {
console.error(err)
})Contains the 'non-repudiation certificate' stored on the smart card. The 'non-repudiation certificate' contains the public key corresponding the private RSA non-repudiation key. The service can be called:
idemia.nonRepudiationCertificate(parseCertsBoolean).then(res => {
}, err => {
console.error(err)
})idemia.issuerCertificate(parseCertsBoolean).then(res => {
}, err => {
console.error(err)
})aventra.encryptionCertificate(parseCertsBoolean).then(res => {
}, err => {
console.error(err)
})The expected response for these calls should be in the following format;
{
success: true,
data: {
certificate?: TokenCertificateObject,
certificates?: Array<TokenCertificateObject>
}
}const data = {
pin: "1234", // optional
osDialog: true // optional
}
idemia.verifyPin(data).then(res => {
}, err => {
console.error(err)
})The expected response for these calls should be in the following format;
{
success: true,
data: {
"verfied": true
}
}Data can be signed using the smartcard. To do so, the SDK facilitates in:
Retrieving the certificate chain (root, intermediate and non-repudiation certificate)
Perform a sign operation (private key stays on the smart card)
Return the signed hash
To sign data, an algorithm must be specified in the algorithm property (see Supported Algorithms), and a Base64-encoded string representation of the digest bytes of the same algorithm in the data property.
Additionally, it is possible to bulk sign data without having to re-enter the PIN by adding an optional bulk parameter set to true to the request. Subsequent sign requests will not require the PIN to be re-entered until a request with bulk being set to false is sent, or the Bulk PIN Reset method is called.
When using bulk signing, great care must be taken to validate that the first signature request was successful prior to sending subsequent requests. Failing to do this will likely result in the card being blocked.
const data = {
algorithm: "sha256",
data: "E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=",
id: "123"
}
const bulk = false;
idemia.sign(data, bulk).then(res => {
}, err => {
console.error(err)
})The expected response for this call should be;
{
success: true,
data: {
data: string
}
}The PIN set for bulk signing can be reset by calling this method.
idemia.resetBulkPin().then(res => {
}, err => {
console.error(err)
})Response will look like:
{
"success": true,
"data": true
}The SDK is able to authenticate a card holder based on a challenge. The challenge can be:
provided by an external service
provided by the smart card An authentication can be interpreted as a signature use case, the challenge is signed data, that can be validated in a back-end process
const data = {
algorithm: "sha256",
data: "E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=",
id: "123"
}
idemia.authenticate(data).then(res => {
}, err => {
console.error(err)
})The expected response for this call should be;
{
success: true,
data: {
data: string
}
}idemia.allAlgoRefs(data).then(res => {
}, err => {
console.error(err)
})The expected response for this call should be;
{
success: true,
data: {
ref: ['sha256', 'md5']
}
}Sample code uses ES6 language features such as arrow functions and promises. For compatibility with IE11, code written with these features must be either transpiled using tools like Babel or refactored accordingly using callbacks.
The Belgian eID container facilitates communication with card readers with inserted Belgian eID smart card. The T1C-JS client library provides function to communicate with the smart card and facilitates integration into a web or native application. This document describes the functionality provided by the Belgian eID container on the T1C-GCL (Generic Connector Library).
All model information can be found in the
Initialise a Trust1Connector client:
Get the Belgian eID container service:
Call a function for the Belgian eID container:
The constructor for the Belgian eID expect as the parameter to be a valid reader-ID. A reader-ID can be obtained from the exposed core functionality, for more information see Core services responds with available card-readers, available card in a card-reader, etc. For example: In order to get all connected card-readers, with available cards:
This function call returns:
We notice that a card object is available in the response in the context of a detected reader.
The reader in the example above is Bit4id miniLector, has no pin-pad capabilities, and there is a card detected with given ATR and description "Belgian eID Card".
An ATR (Answer To Reset) identifies the type of a smart-card.
The reader, has a unique ID, reader_id; this reader_id must be used in order to request functionalities for the Belgian eID card.
This must be done upon instantiation of the Belgian eID container:
All methods for beid will use the selected reader - identified by the reader_id.
The card holder is the person identified using the Belgian eID card. It's important to note that all data must be validated in your backend. Data validation can be done using the appropriate certificate (public key).
Contains all card holder related data, excluding the card holder address and photo. The service can be called:
An example callback:
Response:
Contains the card holder's address. The service can be called:
Response:
Contains the card holder's picture stored on the smart card. The service can be called:
Response:
The token info contains generic information about the card and it's capabilities. This information includes the serial number, file types for object directory files, algorithms implemented on the card, etc.
Response
Exposes all the certificates publicly available on the smart card.
Contains the 'root certificate' stored on the smart card. The root certificate is used to sign the 'citizen CA certificate'. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not. The service can be called:
Response:
Contains the 'authentication certificate' stored on the smart card. The 'authentication certificate' contains the public key corresponding to the private RSA authentication key. The 'authentication certificate' is needed for pin validation and authentication. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:
Response:
Contains the citizen certificate stored on the smart card. The 'citizen certificate' is used to sign the 'authentication certificate' and the 'non-repudiation certificate'. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:
Response:
Contains the 'non-repudiation certificate' stored on the smart card. The 'non-repudiation certificate' contains the public key corresponding the private RSA non-repudiation key. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:
Response:
Contains the 'encryption certificate' stored on the smart card. The 'encryption certificate' corresponds to the private key used to sign the 'biometric' and 'Address' data. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:
Response:
All data on the smart card can be dumped at once, or using a filter. In order to read all data at once:
Response:
The filter can be used to ask a list of custom data containers. For example, we want to read only the biometric data
Response:
All certificates on the smart card can be dumped at once, or using a filter. In order to read all certificates at once:
Response:
The filter can be used to ask a list of custom data containers. For example, we want to read only the rootCertificate
Response:
Data can be signed using the Belgian eID smart card. To do so, the T1C-GCL facilitates in:
Retrieving the certificate chain (citizen-certificate, root-certificate and non-repudiation certificate)
Perform a sign operation (private key stays on the smart card)
Return the signed hash
To get the certificates necessary for signature validation in your back-end:
Response:
Depending on the connected smart card reader. A sign can be executed in 2 modes:
Using a connected card reader with 'pin-pad' capabilities (keypad and display available)
Using a connected card reader without 'pin-pad' capabilities (no keypad nor display available)
Security consideration: In order to sign a hash, security considerations prefer using a 'pin-pad'.
When signing with a crelan card reader, it is additionally possible to optionally specify a transaction ID and the language. If the card reader is not a Crelan reader, these values will be ignored. This applies to all signing methods described below.
Crelan card readers only support nl, fr, and de as languages
When the web or native application is responsible for showing the password input, the following request is used to sign a given hash:
Response is a base64 encoded signed hash:
The 'authenticationreference' property can contain the following values: sha1, sha256, sha512, md5.
When the pin entry is done on the pin-pad, the following request is used to sign a given hash:
Response is a base64 encoded signed hash:
The 'algorithm_reference' property can contain the following values: sha1, sha256, sha512, md5.
The core services lists connected readers, and if they have pin-pad capability. You can find more information in the Core Service documentation on how to verify card reader capabilities.
It is possible to bulk sign data without having to re-enter the PIN by adding an optional bulk parameter set to true to the request. Subsequent sign requests will not require the PIN to be re-entered until a request with bulk being set to false is sent, or the method is called.
When using bulk signing, great care must be taken to validate that the first signature request was successful prior to sending subsequent requests. Failing to do this will likely result in the card being blocked.
The PIN set for bulk signing can be reset by calling this method.
Response will look like:
In order to calculate a hash from the data to sign, you need to know the algorithm you will use in order to sign.
You can use the following online tool to calculate the SHA256:
Hexadecimal result:
Notice that the length of the SHA256 is always the same. Now we need to convert the hexadecimal string to a base64-encoded string, another online tool can be used for this example:
Base64-encoded result:
Now we can sign the data:
Result:
Note: If you want to convert a binary signed hash to HEX (for development) you can use for example an online hexdump tool:
When the web or native application is responsible for showing the password input, the following request is used to verify a card holder PIN:
Response:
When the pin entry is done on the pin-pad, the following request is used to verify a given PIN:
Response:
In order to inform a user upon the PIN retries left, the Belgian eID doesn't provide a request to retrieve this information. After an unsuccessful PIN verification, the error code indicates the number of retries left. For example, when executing:
Note that, when the user has at least one retry left, entering a correct PIN resets the PIN retry status.
The T1C-GCL is able to authenticate a card holder based on a challenge. The challenge can be:
provided by an external service
provided by the smart card An authentication can be interpreted as a signature use case, the challenge is signed data, that can be validated in a back-end process.
External Challenge
An external challenge is provided in the data property of the following example:
Response:
Take notice that the PIN property can be omitted when using a smart card reader with pin-pad capabilities. The 'algorithm_reference' property can contain the following values: sha1, sha256, sha512, md5.
Generated Challenge
A server generated challenge can be provided to the JavaScript library. In order to do so, an additional contract must be provided with the 'OCV API' (Open Certificate Validation API).
Via the Trust1Connector modules you are able to retrieve available algorithms to use for Signing or Authenticate
The response you can expect is a list of algorithms, an example can be found below (the values below are purely examplatory)
export interface AbstractEidBE {
allData(filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllDataResponse) => void): Promise<TokenAllDataResponse>;
allCerts(parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsResponse) => void): Promise<TokenAllCertsResponse>;
biometric(callback?: (error: T1CLibException, data: TokenBiometricDataResponse) => void): Promise<TokenBiometricDataResponse>;
tokenData(callback?: (error: T1CLibException, data: TokenDataResponse) => void): Promise<TokenDataResponse>;
address(callback?: (error: T1CLibException, data: TokenAddressResponse) => void): Promise<TokenAddressResponse>;
picture(callback?: (error: T1CLibException, data: TokenPictureResponse) => void): Promise<TokenPictureResponse>;
rootCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
intermediateCertificates(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
authenticationCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
nonRepudiationCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
encryptionCertificate(parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
verifyPin(body: TokenVerifyPinData, callback?: (error: T1CLibException, data: TokenVerifyPinResponse) => void): Promise<TokenVerifyPinResponse>;
authenticate(body: TokenAuthenticateOrSignData, callback?: (error: T1CLibException, data: TokenAuthenticateResponse) => void): Promise<TokenAuthenticateResponse>;
sign(body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
allAlgoRefs(callback?: (error: T1CLibException, data: TokenAlgorithmReferencesResponse) => void): Promise<TokenAlgorithmReferencesResponse>
resetBulkPin(callback?: (error: T1CLibException, data: BoolDataResponse) => void): Promise<BoolDataResponse>;
}T1CSdk.T1CClient.initialize(config).then(res => {
client = res;
}, err => {
console.error(error)
});var beid = client.beid(reader_id);function callback(err,data) {
if(err){console.log("Error:",JSON.stringify(err, null, ' '));}
else {console.log(JSON.stringify(data, null, ' '));}
}
beid.biometric(callback);var core = client.core();
core.readersCardAvailable(callback);{
"data": [
{
"card": {
"atr": "3B9813400AA503010101AD1311",
"description": ["Belgian eID Card"]
},
"id": "57a3e2e71c48cee9",
"name": "Bit4id miniLector",
"pinpad": false
}
],
"success": true
}var beid = client.beid(reader_id);client.beid(reader_id).biometric(callback);function callback(err,data) {
if(err){
console.log("Error:",JSON.stringify(err, null, ' '));
}
else {
console.log(JSON.stringify(data, null, ' '));
}
}{
"birthDate": "15 JUL 1993",
"birthLocation": "Roeselare",
"cardDeliveryMunicipality": "Avelgem",
"cardNumber": "592..8233",
"cardValidityDateBegin": "27.05.2015",
"cardValidityDateEnd": "27.05.2025",
"chipNumber": "U0xHk...EstwAjEpJQQg==",
"documentType": "01",
"firstNames": "Gilles Frans",
"name": "Platteeuw",
"nationalNumber": "930...154",
"nationality": "Belg",
"nobleCondition": "",
"pictureHash": "Fqva9YCp...JKyn8=",
"rawData": "AQw1OTIxMjQwNTgy...TARFBar2vWAqTW+axEIuyskBgFySsp/",
"sex": "M",
"signature": "hKys9WMjUm4ipg...14xUCg/98Y9/gP/vgG7JTRZJoKgDXLLTvLZO4qlfA==",
"specialStatus": "0",
"thirdName": "J",
"version": "0"
}client.beid(reader_id).address(callback);{
"municipality": "Hoeselt",
"rawData": "ARJLZXJrc...AAAAAA==",
"signature": "mhPyeRg25H...w==",
"streetAndNumber": "Kerkstraat X",
"version": "0",
"zipcode": "3730"
}client.beid(reader_id).picture(callback);{
"data": "/9j/4AAQSkZJRgABA...59aVpcklSDzyKUTEDGK//9k=",
"success": true
}{
"data": {
"eid_compliant":48,
"electrical_perso_interface_version":0,
"electrical_perso_version":3,
"graphical_perso_version":7,
"label":"BELPIC",
"prn_generation":4,
"raw_data":"MCcCAQAEEFNMSU4z...JFTFBJQwMCBDCeBAcDAAA=",
"serial_number":"534C494E..1231C",
"version":0,
"version_rfu":0
},
"success": true
}client.beid(reader_id).rootCertificate(parseCertsBoolean, callback);{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
},
// OR if multiple certificates
"certificates" [
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
}
}
]
}client.beid(reader_id).authenticationCertificate(parseCertsBoolean, callback);{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
},
// OR if multiple certificates
"certificates" [
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
}
}
]
}client.beid(reader_id).intermediateCertificates(parseCertsBoolean, callback);{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
},
// OR if multiple certificates
"certificates" [
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
}
}
]
}client.beid(reader_id).nonRepudiationCertificate(parseCertsBoolean, callback);{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
},
// OR if multiple certificates
"certificates" [
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
}
}
]
}client.beid(reader_id).encryptionCertificate(parseCertsBoolean, callback);{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
},
// OR if multiple certificates
"certificates" [
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
}
}
]
}var filter = [];
client.beid(reader_id).allData({ filters: filter}, callback);{
"picture": {
"picture": "/9j/4AAQSkZJRgABAgEBLAEsAAD/...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"
},
"biometric": {
"birthDate": "15 JUL 1993",
"birthLocation": "Roeselare",
"cardDeliveryMunicipality": "Avelgem",
"cardNumber": "592124058233",
"cardValidityDateBegin": "27.05.2015",
"cardValidityDateEnd": "27.05.2025",
"chipNumber": "...==",
"documentType": "01",
"firstNames": "Gilles Frans",
"name": "Platteeuw",
"nationalNumber": "...",
"nationality": "Belg",
"nobleCondition": "",
"pictureHash": "...=",
"rawData": "...+axEIuyskBgFySsp/",
"sex": "M",
"signature": ".../OlA44h4YCM/h+J14xUCg/98Y9/.../C/RB2dtVbHwFvDuafmr4ZEshTlZTLidHKlISFvFWOtsLAEPCbl5LjfQwcOKe0pDADtHb4IStBnr+aaE8oHsTaKq66Y+zt+AbwdmWOrMA5URKKf7dZkY7jt3h8KZDw36VjcytUgjxVIdqwHsDkmIjK6mJtakIwybS5wn3RiQj33/vgG7JTRZJoKgDXLLTvLZO4qlfA==",
"specialStatus": "0",
"thirdName": "J",
"version": "0"
},
"address": {
"municipality": "Hoeselt",
"rawData": "...==",
"signature": "...+Evety1PnTE4pqXaHgBxIpk+P8kRL5W3zDV+../../..+YoHBC9KqTmSpl5KULxdnKiyCt+2RyJdzE2wyoymjRmysIhJy1wW9PRnx99S1TFqQLuc0tyBmkBPR4aFqmOq4a7zqd0q2Q1g+BbnwJ4d3oa10ia5+0kBXf0THoXv3HYIHlnwhBMfAtWzPnFrYBuAKTwyl7yBF5IFfXFpGWuVZUTJElgNcmNvsHMnAhVwDw==",
"streetAndNumber": "Kerkstraat X",
"version": "0",
"zipcode": "3730"
}
}var filter = ['biometric'];
client.beid().allData({ filters: filter }, callback);{
"biometric": {
"birthDate": "15 JUL 1993",
"birthLocation": "Roeselare",
"cardDeliveryMunicipality": "Avelgem",
"cardNumber": "592124058233",
"cardValidityDateBegin": "27.05.2015",
"cardValidityDateEnd": "27.05.2025",
"chipNumber": "...==",
"documentType": "01",
"firstNames": "Gilles Frans",
"name": "Platteeuw",
"nationalNumber": "...",
"nationality": "Belg",
"nobleCondition": "",
"pictureHash": "...=",
"rawData": "...+axEIuyskBgFySsp/",
"sex": "M",
"signature": ".../OlA44h4YCM/h+J14xUCg/98Y9/.../C/RB2dtVbHwFvDuafmr4ZEshTlZTLidHKlISFvFWOtsLAEPCbl5LjfQwcOKe0pDADtHb4IStBnr+aaE8oHsTaKq66Y+zt+AbwdmWOrMA5URKKf7dZkY7jt3h8KZDw36VjcytUgjxVIdqwHsDkmIjK6mJtakIwybS5wn3RiQj33/vgG7JTRZJoKgDXLLTvLZO4qlfA==",
"specialStatus": "0",
"thirdName": "J",
"version": "0"
}
}var filter = [];
client.beid(reader_id).allCerts(parseCerts, { filters: filter}, callback);{
"rootCertificate": {
...
},
"authenticationCertificate": {
...
},
"nonRepudiationCertificate": {
...
},
"intermediateCertificates": {
...
},
"encryptionCertificate": {
...
}
}var filter = ['rootCertificate'];
client.beid(reader_id).allCerts(parseCerts, { filters: filter}, callback);{
"rootCertificate": {
...
}
}var filter = null;
client.beid(reader_id).allCerts(parseCerts, { filters: filter}, callback);{
"rootCertificate": {
...
},
"authenticationCertificate": {
...
},
"nonRepudiationCertificate": {
...
},
"intermediateCertificates": {
...
},
"encryptionCertificate": {
...
}
}var data = {
"pin":"...",
"algorithmReference":"sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
"osDialog": true,
"txId": "1234",
"language": "fr"
}
client.beid(reader_id).sign(data, callback);var data = {
"pin":"...",
"algorithmReference":"sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
"osDialog": true
}
client.beid(reader_id).sign(data, callback);{
"success": true,
"data": "W7wqvWA8m9SBALZPxN0qUCZfB1O/WLaM/silenLzSXXmeR+0nzB7hXC/Lc/fMru82m/AAqCuGTYMPKcIpQG6MtZ/SGVpZUA/71jv3D9CatmGYGZc52cpcb7cqOVT7EmhrMtwo/jyUbi/Dy5c8G05owkbgx6QxnLEuTLkfoqsW9Q="
}var data = {
"algorithmReference":"sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
"osDialog": false
}
client.beid(reader_id).sign(data, callback);{
"success": true,
"data": "W7wqvWA8m9SBALZPxN0qUCZfB1O/WLaM/silenLzSXXmeR+0nzB7hXC/Lc/fMru82m/AAqCuGTYMPKcIpQG6MtZ/SGVpZUA/71jv3D9CatmGYGZc52cpcb7cqOVT7EmhrMtwo/jyUbi/Dy5c8G05owkbgx6QxnLEuTLkfoqsW9Q="
}const data = {
algorithm: "sha256",
data: "E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=",
pin: "1234"
}
const bulk = true;
beid.sign(data, bulk).then(res => {
}, err => {
console.error(err)
})beid.resetBulkPin().then(res => {
}, err => {
console.error(err)
}){
"success": true,
"data": true
}This is sample text to demonstrate siging with Belgian eID135b870026cfbe12dec348069811fcde5bed28800ac54dbf45ecdf04eb13e95bE1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=var data = {
"pin":"...",
"algorithmReference":"sha256",
"data":"E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs="
}
client.beid(reader_id).signData(data, callback);{
"data": "C7SG5eix1+lzMcZXgL0bCL+rLxKhd8ngrSj6mvlgooWH7CloEU13Rj8QiQHdhHnZgAi4Q0fCMIqAc4dn9uW9OP+MRitimRpYZcaDsGrUehPi/JpOD1e+ko7xKZ67ijUU4KTmG4HXc114oJ7xxx3CGL7TNFfvuEphLbbZa+9IZSSnYDOOENJqhggqqu7paSbLJrxC2zaeMxODKb5WSexHnZH6NnLPl2OmvPTYtxiTUMrLbFRsDRAziF6/VQkgM8/xOm+1/9Expv5DSLRY8RQ+wha6/nMlJjx50JszYIj2aBQKp4AOxPVdPewVGEWF4NF9ffrPLrOA2v2d7t5M4q7yxA==",
"success": true
}var data = {
"pin":"..."
}
client.beid(reader_id).verifyPin(data, callback);{
"verified": true
}var data = {}
client.beid(reader_id).verifyPin(data, callback);{
"verified": true
} $("#buttonValidate").on('click', function () {
var _body={};
_body.pin = $("#psw").val(); //only when no pin-pad available
var beid = connector.beid(reader_id);
beid.verifyPin(_body, validationCallback);
});var data = {
"pin": "...",
"algorithm_reference": "sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E="
}
client.beid(reader_id).authenticate(data, callback);{
"success": true,
"data": "W7wqvWA8m9SBALZPxN0qUCZfB1O/WLaM/silenLzSXXmeR+0nzB7hXC/Lc/fMru82m/AAqCuGTYMPKcIpQG6MtZ/SGVpZUA/71jv3D9CatmGYGZc52cpcb7cqOVT7EmhrMtwo/jyUbi/Dy5c8G05owkbgx6QxnLEuTLkfoqsW9Q="
}The calculated digest of the hash is prefixed with:
DigestInfo ::= SEQUENCE {
digestAlgorithm AlgorithmIdentifier,
digest OCTET STRING
}
Make sure this has been taken into consideration in order to validate the signature in a backend process.generic.allAlgoRefs(module, callback);{
"success": true,
"data": ["sha1", "sha256"]
}Sample code uses ES6 language features such as arrow functions and promises. For compatibility with IE11, code written with these features must be either transpiled using tools like Babel or refactored accordingly using callbacks
Chambersign is only usable when the Middleware software has been installed. As integrator you can check this with the File Exchange module. Example will be described below
The Chambersign token is a token that requires for the middleware of Chambersign to be installed prior to using it on the Trust1Connector.
The chambersign software for windows requires administration rights to be installed. After installation the location will be:
x64 & x86 ; C:\Program Files\ChamberSign
To check if this has been installed we can use the File-exchange create type function and then check the contents of the (sub)-folders.
To check if the middleware is installed the sample code below is a good start to use the File-Exchange to check if the middleware has been installed and its safe to continue to use the ChamberSign middleware and the Trust1Connector.
const entity = "chambersign";
const type = "middleware";
const initPath = "C:\\Program Files\\ChamberSign"
T1CSdk.T1CClient.initialize(config).then(res => {
client = res;
core = client.core();
let fileex = client.fileex();
const middlewareInstalled = await isMiddlewareInstalled(fileex);
if (middlewareInstalled) {
// Middleware is installed you can use the chambersign token with the T1C
} else {
// Middleware not installed please install before using it with the T1C
}
}, err => {
errrorHandler(err);
});
async function isMiddlewareInstalled(fileexClient) {
fileexClient.existsType(entity, type).then(existsRes => {
if (existsRes.data) {
// Type exists
return checkFilesPresent(fileexClient);
} else {
// Type does not exist
fileexClient.createType(entity, type, initPath).then(createRes => {
return checkFilesPresent(fileexClient);
}, err => {
errrorHandler(err);
})
}
}, err => {
// Type exists error, try to create and then check if middleware is installed
fileexClient.createType(entity, type, initPath).then(createRes => {
return checkFilesPresent(fileexClient);
}, err => {
errrorHandler(err);
})
});
}
async function checkFilesPresent(fileexClient) {
await fileexClient.existsFile(entity, type, "HashLogic\\bin\\idoPKCS.dll").then(existsFileRes => {
return existsFileRes;
}, err => {
return false;
})
}export interface AbstractEidGeneric {
// getModuleDescription(module: string, callback?: (error: T1CLibException, data: DataObjectResponse) => void): Promise<DataObjectResponse>;
// allData(module: string, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllDataResponse) => void): Promise<TokenAllDataResponse>;
allCerts(module: string, parseCerts?: boolean, filters?: string[] | Options, callback?: (error: T1CLibException, data: TokenAllCertsResponse) => void): Promise<TokenAllCertsResponse>;
// biometric(module: string, callback?: (error: T1CLibException, data: TokenBiometricDataResponse) => void): Promise<TokenBiometricDataResponse>;
// tokenData(module: string, callback?: (error: T1CLibException, data: TokenDataResponse) => void): Promise<TokenDataResponse>;
// address(module: string, callback?: (error: T1CLibException, data: TokenAddressResponse) => void): Promise<TokenAddressResponse>;
// picture(module: string, callback?: (error: T1CLibException, data: TokenPictureResponse) => void): Promise<TokenPictureResponse>;
// rootCertificate(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
// intermediateCertificates(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
authenticationCertificate(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
nonRepudiationCertificate(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
// encryptionCertificate(module: string, parseCerts?: boolean, callback?: (error: T1CLibException, data: TokenCertificateResponse) => void): Promise<TokenCertificateResponse>;
verifyPin(module: string, body: TokenVerifyPinData, callback?: (error: T1CLibException, data: TokenVerifyPinResponse) => void): Promise<TokenVerifyPinResponse>;
authenticate(module: string, body: TokenAuthenticateOrSignData, callback?: (error: T1CLibException, data: TokenAuthenticateResponse) => void): Promise<TokenAuthenticateResponse>;
sign(module: string, body: TokenAuthenticateOrSignData, bulk?: boolean, callback?: (error: T1CLibException, data: TokenSignResponse) => void): Promise<TokenSignResponse>;
allAlgoRefs(module: string, callback?: (error: T1CLibException, data: TokenAlgorithmReferencesResponse) => void): Promise<TokenAlgorithmReferencesResponse>
resetBulkPin(module: string, callback?: (error: T1CLibException, data: BoolDataResponse) => void): Promise<BoolDataResponse>;
}All model information can be found in the Token typings model page
Initialise a Trust1Connector client with a valid configuration:
T1CSdk.T1CClient.initialize(config).then(res => {
client = res;
}, err => {
console.error(error)
});In order to get all connected card-readers, with available cards:
var core = client.core();
core.readersCardAvailable(callback);This function call returns:
{
"data": [
// List of reader with cards found
],
"success": true
}Using the generic interface can be done as follows;
const module = "chambersign";
var generic = client.generic(selected_reader.id);Because we're using the generic interface we can define the module variable upfront since we know we want to use the chambersign integration.
Exposes all the certificates publicly available on the smart card.
Contains the 'authentication certificate' stored on the smart card. The 'authentication certificate' contains the public key corresponding to the private RSA authentication key. The 'authentication certificate' is needed for pin validation and authentication. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:
generic.authenticationCertificate(module, parseCertsBoolean, callback);Response:
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
},
// OR if multiple certificates
"certificates" [
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
}
}
]
}Contains the 'non-repudiation certificate' stored on the smart card. The 'non-repudiation certificate' contains the public key corresponding the private RSA non-repudiation key. When additional parsing of the certificate is needed you can add a boolean to indicate if you want to parse the certificate or not The service can be called:
generic.nonRepudiationCertificate(module, parseCertsBoolean, callback);Response:
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
},
// OR if multiple certificates
"certificates" [
{
"certificate": {
"certificate": "MIIFjjCCA3agAwIBAgIIO...xg==",
"parsedCertificate": {...}
}
}
]
}All certificates on the smart card can be dumped at once, or using a filter. In order to read all certificates at once:
var filter = [];
generic.allCerts(module, parseCerts, { filters: filter}, callback);Response:
{
"authenticationCertificate": {
...
},
"nonRepudiationCertificate": {
...
}
}The filter can be used to ask a list of custom data containers. For example, we want to read only the rootCertificate
var filter = ['authenticationCertificate'];
generic.allCerts(module, { filters: filter}, callback);Response:
{
"authenticationCertificate": {
...
}
}To get the certificates necessary for signature validation in your back-end:
var filter = null;
generic.allCerts(module, { filters: filter}, callback);Response:
{
"authenticationCertificate": {
...
},
"nonRepudiationCertificate": {
...
}
}Depending on the connected smart card reader. A sign can be executed in 2 modes:
Using a connected card reader with 'pin-pad' capabilities (keypad and display available)
Using a connected card reader without 'pin-pad' capabilities (no keypad nor display available)
Security consideration: In order to sign a hash, security considerations prefer using a 'pin-pad'.
When the web or native application is responsible for showing the password input, the following request is used to sign a given hash:
var data = {
"pin":"...",
"algorithmReference":"sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
"osDialog": true
}
generic.sign(module, data, callback);Response is a base64 encoded signed hash:
{
"success": true,
"data": "W7wqvWA8m9SBALZPxN0qUCZfB1...0nzB7hXC/Lc/fMru82m/AAqCuGTYMPKcIpQG6MtZ/SGVpZUA/71jv3D9CatmGYGZc52cpcb7cqOVT7EmhrMtwo/jyUbi/Dy5c8G05owkbgx6QxnLEuTLkfoqsW9Q="
}The 'authenticationreference' property can contain the following values: sha1, sha256, sha512, md5.
When the pin entry is done on the pin-pad, the following request is used to sign a given hash:
var data = {
"algorithmReference":"sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E=",
"osDialog": false
}
generic.sign(module, data, callback);Response is a base64 encoded signed hash:
{
"success": true,
"data": "W7wqvWA8m...hXC/Lc/fMru82m/AAqCuGTYMPKcIpQG6MtZ/SGVpZUA/71jv3D9CatmGYGZc52cpcb7cqOVT7EmhrMtwo/jyUbi/Dy5c8G05owkbgx6QxnLEuTLkfoqsW9Q="
}The 'algorithm_reference' property can contain the following values: sha1, sha256, sha512, md5.
The core services lists connected readers, and if they have pin-pad capability. You can find more information in the Core Service documentation on how to verify card reader capabilities.
It is possible to bulk sign data without having to re-enter the PIN by adding an optional bulk parameter set to true to the request. Subsequent sign requests will not require the PIN to be re-entered until a request with bulk being set to false is sent, or the Bulk Sign Reset method is called.
When using bulk signing, great care must be taken to validate that the first signature request was successful prior to sending subsequent requests. Failing to do this will likely result in the card being blocked.
const data = {
algorithm: "sha256",
data: "E1uHACbPvhLew0gGmBH83lvtKIAKxU2/RezfBOsT6Vs=",
pin: "1234"
}
const bulk = true;
generic.sign(module, data, bulk).then(res => {
}, err => {
console.error(err)
})The PIN set for bulk signing can be reset by calling this method.
generic.resetBulkPin(module).then(res => {
}, err => {
console.error(err)
})Response will look like:
{
"success": true,
"data": true
}When the web or native application is responsible for showing the password input, the following request is used to verify a card holder PIN:
var data = {
"pin":"..."
}
generic.verifyPin(module, data, callback);Response:
{
"verified": true
}When the pin entry is done on the pin-pad, the following request is used to verify a given PIN:
var data = {}
generic.verifyPin(module, data, callback);Response:
{
"verified": true
}The T1C-GCL is able to authenticate a card holder based on a challenge. The challenge can be:
provided by an external service
provided by the smart card An authentication can be interpreted as a signature use case, the challenge is signed data, that can be validated in a back-end process.
External Challenge
An external challenge is provided in the data property of the following example:
var data = {
"pin": "...",
"algorithm_reference": "sha1",
"data":"I2e+u/sgy7fYgh+DWA0p2jzXQ7E="
}
generic.authenticate(module, data, callback);Response:
{
"success": true,
"data": "W7wqvWA8m9SBALZPxN0qUCZfB1O/WLaM/silenLzSXXmeR+0nzB7hXC/Lc/fMru82m/AAqCuGTYMPKcIpQG6MtZ/SGVpZUA/71jv3D9CatmGYGZc52cpcb7cqOVT7EmhrMtwo/jyUbi/Dy5c8G05owkbgx6QxnLEuTLkfoqsW9Q="
}Take notice that the PIN property can be omitted when using a smart card reader with pin-pad capabilities.
Via the Trust1Connector generic modules you are able to retrieve available algorithms to use for Signing or Authenticate
generic.allAlgoRefs(module, callback);The response you can expect is a list of algorithms, an example can be found below (the values below are purely examplatory)
{
"success": true,
"data": ["sha1", "sha256"]
}Pkcs11 module and os dialog return decryption error
Update certificate model to correctly handle multiple certificates
Device-key endpoint gets called in error handler instead of successhandler
File-exchange ArrayBuffer should be Blob
Initialising with invalid JWT does not throw an error
Entity and type response object inconsistency
Remoteloading split TX, RX and SW value based on APDU response
Use Device certificate to encrypt the pin value sent in clear text
I want to enable the module for eHerkenning
I want to enable module for Print Writer
Aventra, Idemia, Oberthur callback functions not being triggered
FileExchange typing inconsistency
Add LuxeID to the token generic interface in JS SDK
Fix imports for Pkijs
Disbable implicit any typing
Fix for bulk sign reset in JS SDK causes the reader ID not to be included in certificate retrieval
Provide separate implementation for Belgian eID with Crelan reader
Sample code uses ES6 language features such as arrow functions and promises. For compatibility with IE11, code written with these features must be either transpiled using tools like Babel or refactored accordingly using callbacks.
Migration from the v2 to the v3 of the Trust1Connector can be done in 2 ways;
Integration of the API
Integration via the deprecated Javascript SDK
Both are viable integrations but we strongly suggest to integrate via the API since the JS SDK does not include all features, only the ones which were available in the v2. When integrating via the API you have more control over the Javascript packages used.
The Javascript SDK has the following packages as dependencies;
For updating your web application first of all you need to use the new Javascript SDK. After this there are some differences in using the SDK from the v2.
The configuration from the v2 has changed, we simplified this.
The v2 had the following configuration options;
With the v3 this is significantly simplified to the following;
Some of the config options of the v3 are still in review and can be removed up until the final release of the v3, in the table below you will find more information
After you've created your configuration object you can do the initialisation of the Trust1Connector SDK. This has largely remained the same except for the error codes.
V2 example:
V3 example;
Running the Trust1Connector in a shared environment, such as Citrix, XenApp and Remote Desktop, requires additional installation steps. In this section we explain the concept and approach used.
The following schematic seems rather complicated as it explains the inner workings of the Trust1Connector components, the concept is elaborate further on this page. If you are only interested in what the integration impact is for your Web Application in a Shared Environment, you can skip directly to the section:
The Web Application can use the T1C-SDK-JS or a custom REST API client for integration purpose. As the Web Application operates in a browser context, resolving an agent, by means of a consent, will result in a browser cookie being provided.
The T1C-SDK-JS implements the detection of a Shared Environment during the initialisation of the library. When initialisation succeeds without a controlled exception, the setup is a standalone; when the initialisation throws an 401 Error, the T1C-SDK-JS can be used to request the user for a Consent.
When using the REST API directly form your web application, reading the browser cookie and performing the initialisation must be done by the integrating Web Application itself.
Compared to Trust1Connector v2, the v3 release has a separate component to be be installed on a shared host. This component is called the T1C-Proxy and only exposes the following use cases:
Verify random available ports [in a predefined range] which can be used by an Agent (Session of T1C-API running in user space)
Port reservation upon installation of a new T1C-API in an active user session
Port registration upon initialisation of a T1C-API in an active user session
Management of an in-memory list of active Agents
Management of user consents in a shared environment by means of browser cookies with an optional configurable TTL (time to live)
The T1C-Proxy operates by Default on the API port defined in the T1C-DS (Distribution Server). From a Web Application perspective, this is the only information known. When a Web Application requests the information of the device, the PROXY device type will inform the Web Application that the targeted underlying API is a PROXY, which means that the Web Application must ask for the Agent specific API port to configure an URI which can be used to execute the use cases.
When using the T1C-SDK-JS this is done implicitly during initialisation.
A T1C-API installed for a specific users runs in [User Space]. To avoid possible attack vectors, the Trust1Connector v3 will always run in [User Space].
Upon installation of the T1C-API, during the post install phase, the T1C-API will try to verify automatically if it is running in a shared environment. If this is the case, the T1C-API will ask the T1C-Proxy for available ports and will reserve those post, prior to initialisation and startup.
The ports which are reserved by the T1C-Proxy are the following:
T1C-API Port: This is the port exposing the OpenAPI interface towards Web Applications and used by the T1C-SDK-JS
T1C-gRPC Port: This is the port exposing the gRPC interface locally towards the T1C-API component. The T1C-gRPC runs in a sandboxed and hardened environment, it contains the implementation modules needed for hardware communication with local or remote peripherals.
When receiving ports during post-install, an user agent device is temporary RESERVED in the Agent Registry of the T1C-Proxy. Upon T1C-API initialisation, the port configurations will be confirmed and the Agent Registry will set the device state on REGISTERED. From this moment on, a T1C-API instance, running in an active user session, will be available for the Web Application.
The T1C-gRPC instance is inherently a component from the T1C-API, and thus is managed by the T1C-API. As each user must have it's own hardened runtime for communication purpose, the port assigned for T1C-gRPC will be registered and configured by the T1C-API (and restarted when needed).
Starting from this release (v3) of the Trust1Connector, each device must have a link with an active and running T1C-DS (Trust1Connector Distribution Server). This is to guarantee security, updates, and avoid potential risk in production.
The T1C-DS is proceeded by an API Gateway who is managing the security offloading in the application layer. For a Web Application to communicate with a T1C-Proxy or T1C-API, a JWT (Json Web Token) is needed and obliged. The T1C-DS is responsible for the key management, the certificate management and other use cases which are described in a separate wiki.
In order to retrieve a valid JWT, the T1C-DS can be requested from your application back-end with a valid api-key. The JWT is valid for a given amount of time, and sets the context used when requesting the T1C-API on a device.
Sample code uses ES6 language features such as arrow functions and promises. For compatibility with IE11, code written with these features must be either transpiled using tools like Babel or refactored accordingly using callbacks.
In order to use the JS-SDK, the library must be initialised with an api-key. The api-key is a key received upon subscription. The JS-SDK is a client library for web based consumers. As a reminder, the T1C can be used from a native applications context using a native client, or addressing directly the T1C interface. In order to work with an api-key in a browser context, 2 type of consumers can be distinguished:
SPA (Single Page Application) integration: this is a web application without any back-end
Web Application integration: this is a web application with a back-end implementation
For an SPA, an api-key (thus the access token to the Distribution Service) is considered unsafe in a browser context. For SPA's, Trust1Team configures extra security measures on infrastructure level. A mutual authentication is required and additional policies are applied (IP restriction policy, ...).
The api-key must be translated into an JWT token in order to enable communication with the T1C.
To initialise the JavaScript client library, the library must be loaded into your HTML page:
Once loaded, the script will expose a GCLLib global. This global will allow you to create a GCLConfig:
The GCLConfigOptions object will allow you to specify and/or override the configuration to be used. Configuration options can be found in the Configuration Options below. You can create a GCLConfigOptions as follows:
Now that we have a configuration, we can initialise the client library. The following example creates a Promise that will resolve with an instance of a T1CClient:
The Trust1Connector API v3 exposes a secure REST API on the client device. Trust1Team has created a t1c.t1t.io DNS entry (or customer-specific DNS entry) that points to 127.0.0.1 in order to facilitate SSL communication. This means that if the customer infrastructure uses a proxy for all network traffic, an exemption must be made for t1c.t1t.io to always point to the origin device's loopback address.
If no exemption is made and https://t1c.t1t.io is handled by a proxy, it will redirect to 127.0.0.1 IP of the proxy server instead of the local machine, and the Trust1Connector API will be unreachable.
In order to correctly function, the Trust1Connector API must be able to connect to its configured Distribution Service. You must allow REST traffic to the following URLs (if applicable):
Acceptance: https://acc-ds.t1t.io
Production: https://ds.t1t.io
The T1C-Proxy (necessary for shared environments only) requires ± 200Mb of space
The T1C-API is installed in user space and also requires ± 200Mb of space for every user.
All endpoints of the Trust1Connector API are secured and require a JWT to access. To obtain a token, an . This API key must be requested from Trust1Team, or created by the customer if they are hosting their own Distribution Service
Right now Trust1Conector support two operating systems;
MacOS 10.9 or higher
Windows 8.1 or higher
To run in user-space on Windows 8.1 or higher some components have to be set on the operating system
Below you can find a list of all registry keys that will be created for the working of the Trust1Connector, All these keys are added to HKCU
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
HKEY_CURRENT_USER\SOFTWARE\Trust1Team\Trust1Connector
When running in a shared environment a cookie is used to store the user's consent, the following cookie will be used: