# Technical backend implementation

**Note**: You will have to define a custom claim which will be embedded in the signed token (JWS). You have to prefix all the claims with <https://iadvize.com/>

**⚠️** The claim **<https://iadvize.com/visitorData>** is optional **⚠️**

## JWT Library

First, to deal with JWT, you will have to choose the right library which fits to your backend language.\
You can find on the [official JWT website](https://jwt.io/) a list of many libraries implemented for many languages.\
The chosen library should support "A256GCM and RSA\_OAEP\_256" for creating the JWE, the inner JWS must be signed with "RS256".

## An example in SCALA

Here you have a technical implementation of the solution in SCALA:

```
import java.security.interfaces.RSAPublicKey
import java.security.spec.{PKCS8EncodedKeySpec, X509EncodedKeySpec}
import java.security.{KeyFactory, KeyPairGenerator, PrivateKey, PublicKey}
import java.util.Date
import com.nimbusds.jose._
import com.nimbusds.jose.crypto._
import com.nimbusds.jwt.{JWTClaimsSet, SignedJWT}

object JWEBuilder {
	def main(args: Array[String]): Unit = {
		val (clientPubKey, clientPrivateKey) = getClientKeys()
		val (iadvizePubKey, iadvizePrivateKey) = getIAdvizeKeys()
		val JWS1 = createJWS(clientPrivateKey)
		val JWE1 = createJWE(iadvizePubKey, JWS1)
		println(s"JWS : ${JWS1.serialize()}")
		println(s"JWE : ${JWE1.serialize()}")
		val token = JWE1.serialize()
		val JWS2 = decryptJWE(iadvizePrivateKey, token)
		println(s"Is valid JWS : ${JWS2.verify(new RSASSAVerifier(clientPubKey.asInstanceOf[RSAPublicKey]))}")
		println(s"${JWS2.getJWTClaimsSet}")
	}
	def getClientKeys() : (PublicKey, PrivateKey) = {
		val generator = KeyPairGenerator.getInstance("RSA")
		generator.initialize(2048)
		val pairClient = generator.generateKeyPair
		val pubKeyClient = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(pairClient.getPublic.getEncoded))
		val privateKeyClient = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(pairClient.getPrivate.getEncoded))
		(pubKeyClient, privateKeyClient)
	}
	def getIAdvizeKeys() : (PublicKey, PrivateKey) = {
		val generator = KeyPairGenerator.getInstance("RSA")
		generator.initialize(2048)
		val pairIadvize = generator.generateKeyPair
		val pubKeyIadvize = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(pairIadvize.getPublic.getEncoded))
		val privateKeyIadvize = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(pairIadvize.getPrivate.getEncoded))
		(pubKeyIadvize, privateKeyIadvize)
	}
	def createJWS(clientPrivateKey: PrivateKey) : SignedJWT = {
		val claimsSet = new JWTClaimsSet.Builder()
		// You can define custom claims. Here you can define your User ID which will be embed in the signed token(JWS).
		// You have to prefix all the claims with `https://iadvize.com/”.
		// The claim https://iadvize.com/userId is mandatory.
		claimsSet.claim("https://iadvize.com/userId","c42ab96d-0637-4d1e-8be3-0a872d9d1ef1")
		// For security reason it’s better to set a quick expiration time. As this token will just be used to initialise a new secured visitor session on iAdvize 1 minute seems a good duration.
		claimsSet.expirationTime(ZonedDateTime.now().plusMinutes(1))
		val signer = new RSASSASigner(clientPrivateKey)
		val signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.RS256), claimsSet.build())
		signedJWT.sign(signer)
		signedJWT
	}
	def createJWE(iadvizePublicKey : PublicKey, jws : SignedJWT) : JWEObject = {
		val header = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM).build()
		val payload = new Payload(jws)
		val jwe = new JWEObject(header, payload)
		jwe.encrypt(new com.nimbusds.jose.crypto.RSAEncrypter(iadvizePublicKey.asInstanceOf[java.security.interfaces.RSAPublicKey]))
		jwe
	}
	def decryptJWE(iadvizePrivateKey: PrivateKey, token : String): SignedJWT = {
		val o = JWEObject.parse(token)
		o.decrypt(new RSADecrypter(iadvizePrivateKey))
		o.getPayload.toSignedJWT
	}
}
```

The key parts for you are the functions createJWS() and createJWE() which we will detail below.

createJWS()

```
def createJWS(yourPrivateKey: PrivateKey) : SignedJWT = {
	val claimsSet = new JWTClaimsSet.Builder()
	claimsSet.claim("https://iadvize.com/userId","c42ab96d-0637-4d1e-8be3-0a872d9d1ef1")
	
	// For security reason, it’s better to set a quick expiration time. As this token will just be used to initialise a new secured visitor session on iAdvize 1 minute seems a good duration.
	claimsSet.expirationTime(ZonedDateTime.now().plusMinutes(1))
	val signer = new RSASSASigner(clientPrivateKey)
	val signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.RS256), claimsSet.build())
	
	// Sign the JWT using your private key: it became a JWS.
	signedJWT.sign(signer)
	signedJWT
}
```

For security reason, it’s better to set a quick expiration time. As this token will just be used to initialize a new secured visitor session on iAdvize 1 minute seems a good duration. createJWE() Once we have a signed JWT, a JWS, we could encrypt this JWS to finally have a JWE.

```
def createJWE(iadvizePublicKey : PublicKey, jws : SignedJWT) : JWEObject =
{
	// Specify the header(encryption algorithms) and the payload (the JWS generated in the previous step).
	val header = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A128CBC_HS256).build()
	val payload = new Payload(jws)
	val jwe = new JWEObject(header, payload)
	
	// Encrypt the token using the iAdvize Public key.
	jwe.encrypt(new com.nimbusds.jose.crypto.RSAEncrypter(iadvizePublicKey.asInstanceOf[java.security.interfaces.RSAPublicKey]))
	jwe
}
```

Here is how the createJWS function would be modified to add the firstName and the lastName fields:

```
def createJWS(clientPrivateKey: PrivateKey) : SignedJWT = {
     val claimsSet = new JWTClaimsSet.Builder()
     claimsSet.claim("https://iadvize.com/userId","c42ab96d-0637-4d1e-8be3-0a872d9d1ef1")
     claimsSet.claim("https://iadvize.com/visitorData", JSONObjectUtils.parse("""{"firstName: "Jane", "lastName": "Doe"}"""))

// For security reason, it’s better to set a quick expiration time. As this token will just be used to initialise a new secured visitor 
session on iAdvize 1 minute seems a good duration.
claimsSet.expirationTime(ZonedDateTime.now().plusMinutes(1))
val signer = new RSASSASigner(clientPrivateKey)
val signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.RS256), claimsSet.build())

//Sign the JWT using your private key: it became a JWS.
signedJWT.sign(signer)
signedJWT 
}
```

In the example above, the visitorData claim is a JSON object containing the “firstName” and “lastName” fields. Here is a complete example with all possible fields:

```
{
    "country": "France",
    "firstName": "Jane",
    "lastName": "Doe",
    "zipCode": "44000",
    "address": "9 rue Nina Simone",
    "phoneNumber": "+33651229856",
    "city": "Nantes",
    "email": "jane.doe@email.com"
  }
```

## An example in Node.js

Here is how the same function would look in Node.js:

```
const jwt = require("jsonwebtoken");

function createJWS(clientPrivateKey) {
  return jwt.sign(
    {
      "https://iadvize.com/userId": "test_documentation",
      iss: "https://test.iadvize.com",
      "https://iadvize.com/visitorData": {
        firstName: "Jane",
        lastName: "Doe",
    },
      // For security reasons, it’s better to set a small expiration time. As this token will just be used to initialise a new secured visitor session on iAdvize, 1 minute seems like a good duration.
      exp: Date.now() + 60 * 1000,
    },
    clientPrivateKey
  );
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.iadvize.dev/~/changes/39J6v2tWi3Ms7Me1qEFP/technologies/authenticated-messaging/web-backend-implementation/technical-backend-implementation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
