JSON Web Tokens

Affiliate JSON Web Token Generation

When redirecting to the Quote and Buy web application you can include a small data payload in a JSON Web Token, signed and encoded as a URL parameter named token in the redirect URL.

The token payload can contain any combination of lead and sales attribution or pre-fill data. This can be used to simply the integration effort and reduce the information that needs to be keyed in and making a more joined up process.

As the token is signed the information exchange is done securely.

This guide provides information and examples of how to generate a token and how to pass this to the Quote and Buy web application.

The exact information that be passed is defined by the insurance product that you are redirecting too. Certua can provide you with the information that you will need for your specific use case.

Generating a signed JWT

In order to pass the information you will need to generate a signed JWT using a shared key that Certua will provide. This key is then used to decode the token to ensure security and validity of the token.

You can set how long the token is valid for as well.

To generate the token you can pass any combination of the information from above as a JSON payload e.g.

{
    "introducer": {
        "name": "Speciality Insurance",
        "externalId": "speciality"
    },
    "adviser": {
        "firstName": "John",
        "lastName": "Smith",
        "externalId": "12345"
    },
    "adviserFirm": {
        "name": "ACME Advisors Ltd.",
        "referenceNumber": "07296795",
        "referenceNumber": "12345678",
        "businessAddress": {
            "addressLine1": "PO Box 1234",
            "addressLine2": "",
            "addressLine3": "",
            "city": "London",
            "county": "Greater London",
            "postCode": "N1 1NN"
        },
        "businessEmail": "[email protected]",
        "businessPhone": "",
        "mobilePhone": "",
        "externalId": "67890"
    },
    "customerOrganisation": {
        "externalId": "123",
        "name": "Organisation Name",
        "correspondenceAddress": {
            "addressLine1": "1 Test Street",
            "addressLine2": "",
            "addressLine3": "",
            "city": "London",
            "county": "Greater London",
            "postcode": "N6 1DR"
        },
        "firstName": "First",
        "lastName": "Last",
        "phone": "08451231234",
        "mobilePhone": "0777111222",
        "email": "[email protected]"
    },
    "quoteDefaults": [{
            "productCode": "LTA",
            "quoteBenefitParameters": [{
                    "name": "SumAssured",
                    "value": "300000"
                }
            ]
        }
    ],
    "rulebase": {
        "Collection1": {
            "nodes": [{
                    "code": "Node1.1",
                    "questions": [{
                            "code": "NodeQuestion1.1",
                            "answers": [{
                                    "value": "Sample Value"
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    },
    "workflow": "AffiliateQuoteAndBuy",
    "nbf": 1652255135,
    "exp": 1652859934,
    "iat": 1652255135,
    "iss": "https://introducer.example.org",
    "aud": "https://target.example.org"
}

Below is an example of how to do this using C#.

public string GenerateInformationExchangeToken(GenerateAccessTokenViewModel request)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var signingKey = "SHARED_SIGNING_KEY";
    var base64String = Convert.FromBase64String(signingKey);
    var securityKey = new SymmetricSecurityKey(base64String);
    var audience = "https://example.org";

    var claims = new Dictionary<string, object>();
    claims.Add("customerIndividual", request.Payload.CustomerIndividual);
    claims.Add("customerOrganisation", request.Payload.CustomerOrganisation);
    claims.Add("introducer", request.Payload.Introducer);
    claims.Add("adviser", request.Payload.Adviser);
    claims.Add("adviserFirm", request.Payload.AdviserFirm);
    claims.Add("workflow", request.Workflow);
    claims.Add("rulebase", request.Payload.Rulebase); 
    claims.Add("quoteDefaults", request.Payload.QuoteDefaults);

    var days = request.ExpiresInDays;
    var issuer = audience;
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Expires = DateTime.UtcNow.AddDays(days),
        Issuer = issuer,
        Audience = audience,
        Claims = claims,
        SigningCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature)
    };
    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}

📘

The Shared Secret must be base64 encoded when creating the securityKey.

Generate Access Token View Model used above

public class GenerateAccessTokenViewModel
{
    public GenerateAccessTokenViewModel() { }
    public Payload Payload { get; set; }
    public string Workflow { get; set; }
    public int ExpiresInDays { get; set; }
}

public class Payload
{
    public dynamic? CustomerIndividual { get; set; }
    public dynamic? CustomerOrganisation { get; set; }
    public dynamic? Introducer { get; set; }
    public dynamic? Adviser { get; set; }
    public dynamic? AdviserFirm { get; set; }
    public dynamic? Rulebase { get; set; }
    public dynamic? QuoteDefaults { get; set; }
}

The result of this would be a JWT string containing the information

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImV4YW1wbGUifQ.eyJpbnRyb2R1Y2VyIjp7Im5hbWUiOiJTcGVjaWFsaXR5IEluc3VyYW5jZSIsImV4dGVybmFsSWQiOiJzcGVjaWFsaXR5In0sImFkdmlzZXIiOnsiZmlyc3ROYW1lIjoiSm9obiIsImxhc3ROYW1lIjoiU21pdGgiLCJleHRlcm5hbElkIjoiMTIzNDUifSwiYWR2aXNlckZpcm0iOnsibmFtZSI6IkFDTUUgQWR2aXNvcnMgTHRkLiIsInJlZmVyZW5jZU51bWJlciI6IjEyMzQ1Njc4IiwiYnVzaW5lc3NBZGRyZXNzIjp7ImFkZHJlc3NMaW5lMSI6IlBPIEJveCAxMjM0IiwiYWRkcmVzc0xpbmUyIjoiIiwiYWRkcmVzc0xpbmUzIjoiIiwiY2l0eSI6IkxvbmRvbiIsImNvdW50eSI6IkdyZWF0ZXIgTG9uZG9uIiwicG9zdENvZGUiOiJOMSAxTk4ifSwiYnVzaW5lc3NFbWFpbCI6InNhbGVzQGV4YW1wbGUub3JnIiwiYnVzaW5lc3NQaG9uZSI6IiIsIm1vYmlsZVBob25lIjoiIiwiZXh0ZXJuYWxJZCI6IjY3ODkwIn0sImN1c3RvbWVyT3JnYW5pc2F0aW9uIjp7ImV4dGVybmFsSWQiOiIxMjMiLCJuYW1lIjoiT3JnYW5pc2F0aW9uIE5hbWUiLCJjb3JyZXNwb25kZW5jZUFkZHJlc3MiOnsiYWRkcmVzc0xpbmUxIjoiMSBUZXN0IFN0cmVldCIsImFkZHJlc3NMaW5lMiI6IiIsImFkZHJlc3NMaW5lMyI6IiIsImNpdHkiOiJMb25kb24iLCJjb3VudHkiOiJHcmVhdGVyIExvbmRvbiIsInBvc3Rjb2RlIjoiTjYgMURSIn0sImZpcnN0TmFtZSI6IkZpcnN0IiwibGFzdE5hbWUiOiJMYXN0IiwicGhvbmUiOiIwODQ1MTIzMTIzNCIsIm1vYmlsZVBob25lIjoiMDc3NzExMTIyMiIsImVtYWlsIjoidGVzdEBleGFtcGxlLm9yZyJ9LCJxdW90ZURlZmF1bHRzIjpbeyJwcm9kdWN0Q29kZSI6IkxUQSIsInF1b3RlQmVuZWZpdFBhcmFtZXRlcnMiOlt7Im5hbWUiOiJTdW1Bc3N1cmVkIiwidmFsdWUiOiIzMDAwMDAifV19XSwicnVsZWJhc2UiOnsiQ29sbGVjdGlvbjEiOnsibm9kZXMiOlt7ImNvZGUiOiJOb2RlMS4xIiwicXVlc3Rpb25zIjpbeyJjb2RlIjoiTm9kZVF1ZXN0aW9uMS4xIiwiYW5zd2VycyI6W3sidmFsdWUiOiJTYW1wbGUgVmFsdWUifV19XX1dfX0sIndvcmtmbG93IjoiQWZmaWxpYXRlUXVvdGVBbmRCdXkiLCJuYmYiOjE2NTIyNTUxMzUsImV4cCI6MTY1Mjg1OTkzNCwiaWF0IjoxNjUyMjU1MTM1LCJpc3MiOiJodHRwczovL2ludHJvZHVjZXIuZXhhbXBsZS5vcmciLCJhdWQiOiJodHRwczovL3RhcmdldC5leGFtcGxlLm9yZyJ9.N37UMDW1VVdg3GkUeyfnrZmm3Zvvu0H9Q_H-0ErC72U

Passing the token to the Quote and Buy journey

Now you have a token you just need to append this to the query string that you are using to redirect people to the insurance journey e.g.

https://target.example.org/get-a-quote?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImV4YW1wbGUifQ.eyJpbnRyb2R1Y2VyIjp7Im5hbWUiOiJTcGVjaWFsaXR5IEluc3VyYW5jZSIsImV4dGVybmFsSWQiOiJzcGVjaWFsaXR5In0sImFkdmlzZXIiOnsiZmlyc3ROYW1lIjoiSm9obiIsImxhc3ROYW1lIjoiU21pdGgiLCJleHRlcm5hbElkIjoiMTIzNDUifSwiYWR2aXNlckZpcm0iOnsibmFtZSI6IkFDTUUgQWR2aXNvcnMgTHRkLiIsInJlZmVyZW5jZU51bWJlciI6IjEyMzQ1Njc4IiwiYnVzaW5lc3NBZGRyZXNzIjp7ImFkZHJlc3NMaW5lMSI6IlBPIEJveCAxMjM0IiwiYWRkcmVzc0xpbmUyIjoiIiwiYWRkcmVzc0xpbmUzIjoiIiwiY2l0eSI6IkxvbmRvbiIsImNvdW50eSI6IkdyZWF0ZXIgTG9uZG9uIiwicG9zdENvZGUiOiJOMSAxTk4ifSwiYnVzaW5lc3NFbWFpbCI6InNhbGVzQGV4YW1wbGUub3JnIiwiYnVzaW5lc3NQaG9uZSI6IiIsIm1vYmlsZVBob25lIjoiIiwiZXh0ZXJuYWxJZCI6IjY3ODkwIn0sImN1c3RvbWVyT3JnYW5pc2F0aW9uIjp7ImV4dGVybmFsSWQiOiIxMjMiLCJuYW1lIjoiT3JnYW5pc2F0aW9uIE5hbWUiLCJjb3JyZXNwb25kZW5jZUFkZHJlc3MiOnsiYWRkcmVzc0xpbmUxIjoiMSBUZXN0IFN0cmVldCIsImFkZHJlc3NMaW5lMiI6IiIsImFkZHJlc3NMaW5lMyI6IiIsImNpdHkiOiJMb25kb24iLCJjb3VudHkiOiJHcmVhdGVyIExvbmRvbiIsInBvc3Rjb2RlIjoiTjYgMURSIn0sImZpcnN0TmFtZSI6IkZpcnN0IiwibGFzdE5hbWUiOiJMYXN0IiwicGhvbmUiOiIwODQ1MTIzMTIzNCIsIm1vYmlsZVBob25lIjoiMDc3NzExMTIyMiIsImVtYWlsIjoidGVzdEBleGFtcGxlLm9yZyJ9LCJxdW90ZURlZmF1bHRzIjpbeyJwcm9kdWN0Q29kZSI6IkxUQSIsInF1b3RlQmVuZWZpdFBhcmFtZXRlcnMiOlt7Im5hbWUiOiJTdW1Bc3N1cmVkIiwidmFsdWUiOiIzMDAwMDAifV19XSwicnVsZWJhc2UiOnsiQ29sbGVjdGlvbjEiOnsibm9kZXMiOlt7ImNvZGUiOiJOb2RlMS4xIiwicXVlc3Rpb25zIjpbeyJjb2RlIjoiTm9kZVF1ZXN0aW9uMS4xIiwiYW5zd2VycyI6W3sidmFsdWUiOiJTYW1wbGUgVmFsdWUifV19XX1dfX0sIndvcmtmbG93IjoiQWZmaWxpYXRlUXVvdGVBbmRCdXkiLCJuYmYiOjE2NTIyNTUxMzUsImV4cCI6MTY1Mjg1OTkzNCwiaWF0IjoxNjUyMjU1MTM1LCJpc3MiOiJodHRwczovL2ludHJvZHVjZXIuZXhhbXBsZS5vcmciLCJhdWQiOiJodHRwczovL3RhcmdldC5leGFtcGxlLm9yZyJ9.N37UMDW1VVdg3GkUeyfnrZmm3Zvvu0H9Q_H-0ErC72U