How to Set Up SSO Authentication for Quick Builder
Quick Builder authenticates users through JWT-based SSO. Your server generates a signed JWT containing the user's identity, then redirects them to the Xeni booking engine. This article covers how to create, sign, and deliver JWT tokens.
JWT Requirements
All JWT tokens for Quick Builder must meet these requirements:
| Requirement | Value |
|---|---|
| Algorithm | HS256 (HMAC with SHA-256) |
| Secret key length | 32 characters minimum |
| Maximum expiry | 30 minutes from issue time |
Required JWT Claims
Every token must include the following claims in its payload:
| Claim | Type | Description |
|---|---|---|
iss | string | Issuer identifier — your application's domain or name |
iat | number | Issued-at time as a Unix timestamp (seconds since epoch) |
exp | number | Expiration time as a Unix timestamp (must be within 30 minutes of iat) |
userid | string | Unique identifier for the user in your system |
email | string | User's email address |
firstname | string | User's first name |
last_name | string | User's last name |
Example JWT Payload
{
"iss": "partner-app.example.com",
"iat": 1740000000,
"exp": 1740001800,
"userid": "usrabc123",
"email": "jane.doe@example.com",
"first_name": "Jane",
"last_name": "Doe"
}Generating a JWT Token
Node.js Example
const jwt = require('jsonwebtoken');
const SECRET_KEY = 'your-secret-key-at-least-32-chars!'; // 32+ characters
function generateQuickBuilderToken(user) {
const payload = {
iss: 'partner-app.example.com',
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + (30 * 60), // 30 minutes
user_id: user.id,
email: user.email,
first_name: user.firstName,
last_name: user.lastName
};
return jwt.sign(payload, SECRET_KEY, { algorithm: 'HS256' });
}
Python Example
import jwt
import time
SECRET_KEY = 'your-secret-key-at-least-32-chars!' # 32+ characters
def generatequickbuilder_token(user):
now = int(time.time())
payload = {
'iss': 'partner-app.example.com',
'iat': now,
'exp': now + (30 * 60), # 30 minutes
'user_id': user['id'],
'email': user['email'],
'firstname': user['firstname'],
'lastname': user['lastname']
}
return jwt.encode(payload, SECRET_KEY, algorithm='HS256')
Redirecting the User
Once you have a signed token, redirect the user to the Xeni SSO URL:
https://your-xeni-domain.com/sso?token={JWTTOKEN}&navigateTo={ENCODEDDESTINATION}
Example Redirect (Node.js)
app.get('/launch-booking', (req, res) => {
const token = generateQuickBuilderToken(req.user);
const destination = encodeURIComponent('/hotels/search');
const ssoUrl = https://your-xeni-domain.com/sso?token=${token}&navigateTo=${destination};
res.redirect(ssoUrl);
});
Security Best Practices
- Never expose your secret key in client-side code. JWT signing must happen on your server.
- Use a strong secret key with at least 32 characters. A randomly generated key is recommended.
- Keep expiry short. The maximum allowed is 30 minutes, but shorter values (5-10 minutes) reduce the window of risk if a token is intercepted.
- Generate a new token for each redirect. Do not reuse tokens across sessions.
- Store the secret securely using environment variables or a secrets manager — never hardcode it in source files.
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| Token rejected | Secret key mismatch | Verify the secret key matches what is configured in the Xeni admin panel |
| Token expired | exp claim is in the past | Generate a fresh token immediately before redirecting |
| Invalid algorithm | Not using HS256 | Ensure your JWT library is configured to use HS256 |
| Missing claims | Required claim omitted | Verify all seven required claims are present in the payload |
Next Steps
After you can generate valid JWT tokens, you need to build a validation endpoint that Xeni will call to verify those tokens.